diff --git a/group.cpp b/group.cpp index 85b9ff7..7535d4b 100644 --- a/group.cpp +++ b/group.cpp @@ -212,6 +212,7 @@ void Group::MenuGroup(int id) { if(!GetOpenFile(g.impFile, SLVS_EXT, SLVS_PATTERN)) return; } g.name.strcpy("import"); + g.meshCombine = COMBINE_AS_ASSEMBLE; break; } diff --git a/groupmesh.cpp b/groupmesh.cpp index 1d62d94..8e0a31c 100644 --- a/groupmesh.cpp +++ b/groupmesh.cpp @@ -100,8 +100,10 @@ void Group::GenerateShellForStepAndRepeat(void) { if(src->meshCombine == COMBINE_AS_DIFFERENCE) { scratch->MakeFromDifferenceOf(soFar, &transd); - } else { + } else if(src->meshCombine == COMBINE_AS_UNION) { scratch->MakeFromUnionOf(soFar, &transd); + } else { + scratch->MakeFromAssemblyOf(soFar, &transd); } SWAP(SShell *, scratch, soFar); @@ -244,8 +246,7 @@ void Group::GenerateShellAndMesh(void) { } else if(meshCombine == COMBINE_AS_DIFFERENCE) { runningShell.MakeFromDifferenceOf(a, &thisShell); } else { - runningShell.MakeFromUnionOf(a, &thisShell); - // TODO, assembly + runningShell.MakeFromAssemblyOf(a, &thisShell); } done: diff --git a/srf/boolean.cpp b/srf/boolean.cpp index d98523c..c8e5164 100644 --- a/srf/boolean.cpp +++ b/srf/boolean.cpp @@ -498,6 +498,78 @@ void SShell::CleanupAfterBoolean(void) { } } +//----------------------------------------------------------------------------- +// All curves contain handles to the two surfaces that they trim. After a +// Boolean or assembly, we must rewrite those handles to refer to the curves +// by their new IDs. +//----------------------------------------------------------------------------- +void SShell::RewriteSurfaceHandlesForCurves(SShell *a, SShell *b) { + SCurve *sc; + + for(sc = curve.First(); sc; sc = curve.NextAfter(sc)) { + if(sc->source == SCurve::FROM_A) { + sc->surfA = a->surface.FindById(sc->surfA)->newH; + sc->surfB = a->surface.FindById(sc->surfB)->newH; + } else if(sc->source == SCurve::FROM_B) { + sc->surfA = b->surface.FindById(sc->surfA)->newH; + sc->surfB = b->surface.FindById(sc->surfB)->newH; + } else if(sc->source == SCurve::FROM_INTERSECTION) { + sc->surfA = a->surface.FindById(sc->surfA)->newH; + sc->surfB = b->surface.FindById(sc->surfB)->newH; + } else { + oops(); + } + } +} + +//----------------------------------------------------------------------------- +// Copy all the surfaces and curves from two different shells into a single +// shell. The only difficulty is to rewrite all of their handles; we don't +// look for any surface intersections, so if two objects interfere then the +// result is just self-intersecting. This is used for assembly, since it's +// much faster than merging as union. +//----------------------------------------------------------------------------- +void SShell::MakeFromAssemblyOf(SShell *a, SShell *b) { + Vector t = Vector::From(0, 0, 0); + Quaternion q = Quaternion::IDENTITY; + int i = 0; + SShell *ab; + + // First, copy over all the curves. Note which shell (a or b) each curve + // came from, but assign it a new ID. + SCurve *c, cn; + for(i = 0; i < 2; i++) { + ab = (i == 0) ? a : b; + for(c = ab->curve.First(); c; c = ab->curve.NextAfter(c)) { + cn = SCurve::FromTransformationOf(c, t, q); + cn.source = (i == 0) ? SCurve::FROM_A : SCurve::FROM_B; + // surfA and surfB are wrong now, and we can't fix them until + // we've assigned IDs to the surfaces. So we'll get that later. + c->newH = curve.AddAndAssignId(&cn); + } + } + + // Likewise copy over all the surfaces. + SSurface *s, sn; + for(i = 0; i < 2; i++) { + ab = (i == 0) ? a : b; + for(s = ab->surface.First(); s; s = ab->surface.NextAfter(s)) { + sn = SSurface::FromTransformationOf(s, t, q, true); + // All the trim curve IDs get rewritten; we know the new handles + // to the curves since we recorded them in the previous step. + STrimBy *stb; + for(stb = sn.trim.First(); stb; stb = sn.trim.NextAfter(stb)) { + stb->curve = ab->curve.FindById(stb->curve)->newH; + } + s->newH = surface.AddAndAssignId(&sn); + } + } + + // Finally, rewrite the surfaces associated with each curve to use the + // new handles. + RewriteSurfaceHandlesForCurves(a, b); +} + void SShell::MakeFromBoolean(SShell *a, SShell *b, int type) { a->MakeClassifyingBsps(); b->MakeClassifyingBsps(); @@ -540,20 +612,7 @@ void SShell::MakeFromBoolean(SShell *a, SShell *b, int type) { // Now that we've copied the surfaces, we know their new hSurfaces, so // rewrite the curves to refer to the surfaces by their handles in the // result. - for(sc = curve.First(); sc; sc = curve.NextAfter(sc)) { - if(sc->source == SCurve::FROM_A) { - sc->surfA = a->surface.FindById(sc->surfA)->newH; - sc->surfB = a->surface.FindById(sc->surfB)->newH; - } else if(sc->source == SCurve::FROM_B) { - sc->surfA = b->surface.FindById(sc->surfA)->newH; - sc->surfB = b->surface.FindById(sc->surfB)->newH; - } else if(sc->source == SCurve::FROM_INTERSECTION) { - sc->surfA = a->surface.FindById(sc->surfA)->newH; - sc->surfB = b->surface.FindById(sc->surfB)->newH; - } else { - oops(); - } - } + RewriteSurfaceHandlesForCurves(a, b); // And clean up the piecewise linear things we made as a calculation aid a->CleanupAfterBoolean(); diff --git a/srf/surface.h b/srf/surface.h index b878afd..33ddf86 100644 --- a/srf/surface.h +++ b/srf/surface.h @@ -297,6 +297,7 @@ public: bool seg, bool trimmed, bool inclTangent); void MakeCoincidentEdgesInto(SSurface *proto, bool sameNormal, SEdgeList *el, SShell *useCurvesFrom); + void RewriteSurfaceHandlesForCurves(SShell *a, SShell *b); void CleanupAfterBoolean(void); static const int INSIDE = 100; @@ -312,6 +313,7 @@ public: void MakeFromCopyOf(SShell *a); void MakeFromTransformationOf(SShell *a, Vector trans, Quaternion q); + void MakeFromAssemblyOf(SShell *a, SShell *b); void TriangulateInto(SMesh *sm); void MakeEdgesInto(SEdgeList *sel); diff --git a/wishlist.txt b/wishlist.txt index 1c5f694..a8b01a9 100644 --- a/wishlist.txt +++ b/wishlist.txt @@ -2,7 +2,6 @@ marching algorithm for surface intersection tangent intersections put back the meshes -assembly ----- line styles (color, thickness)