solvespace/srf/boolean.cpp
Jonathan Westhues 07ddd62a3a Preparatory work for Boolean. Make the u and v coordinates of the
trim curves for all surfaces lie between 0 and 1. And add routines
to merge the curves and surfaces from two shells into one, and to
split the trim curves into their piecewise linear segments and then
reassemble them into trim curves.

[git-p4: depot-paths = "//depot/solvespace/": change = 1905]
2009-01-25 03:52:29 -08:00

145 lines
4.4 KiB
C++

#include "solvespace.h"
void SShell::MakeFromUnionOf(SShell *a, SShell *b) {
MakeFromBoolean(a, b, AS_UNION);
}
void SShell::MakeFromDifferenceOf(SShell *a, SShell *b) {
MakeFromBoolean(a, b, AS_DIFFERENCE);
}
SCurve SCurve::MakeCopySplitAgainst(SShell *against) {
SCurve ret;
ZERO(&ret);
ret.isExact = isExact;
ret.exact = exact;
Vector *p;
for(p = pts.First(); p; p = pts.NextAfter(p)) {
ret.pts.Add(p);
}
return ret;
}
void SShell::CopyCurvesSplitAgainst(SShell *against, SShell *into) {
SCurve *sc;
for(sc = curve.First(); sc; sc = curve.NextAfter(sc)) {
SCurve scn = sc->MakeCopySplitAgainst(against);
hSCurve hsc = into->curve.AddAndAssignId(&scn);
// And note the new ID so that we can rewrite the trims appropriately
sc->newH = hsc;
}
}
void SShell::MakeEdgeListUseNewCurveIds(SEdgeList *el) {
SEdge *se;
for(se = el->l.First(); se; se = el->l.NextAfter(se)) {
hSCurve oldh = { se->auxA };
SCurve *osc = curve.FindById(oldh);
se->auxA = osc->newH.v;
// auxB is the direction, which is unchanged
}
}
void SSurface::TrimFromEdgeList(SEdgeList *el) {
el->l.ClearTags();
STrimBy stb;
ZERO(&stb);
for(;;) {
// Find an edge, any edge; we'll start from there.
SEdge *se;
for(se = el->l.First(); se; se = el->l.NextAfter(se)) {
if(se->tag) continue;
break;
}
if(!se) break;
se->tag = 1;
stb.start = se->a;
stb.finish = se->b;
stb.curve.v = se->auxA;
stb.backwards = se->auxB ? true : false;
// Find adjoining edges from the same curve; those should be
// merged into a single trim.
bool merged;
do {
merged = false;
for(se = el->l.First(); se; se = el->l.NextAfter(se)) {
if(se->tag) continue;
if(se->auxA != stb.curve.v) continue;
if(( se->auxB && !stb.backwards) ||
(!se->auxB && stb.backwards)) continue;
if((se->a).Equals(stb.finish)) {
stb.finish = se->b;
se->tag = 1;
merged = true;
} else if((se->b).Equals(stb.start)) {
stb.start = se->a;
se->tag = 1;
merged = true;
}
}
} while(merged);
// And add the merged trim, with xyz (not uv like the polygon) pts
stb.start = PointAt(stb.start.x, stb.start.y);
stb.finish = PointAt(stb.finish.x, stb.finish.y);
trim.Add(&stb);
}
}
//-----------------------------------------------------------------------------
// Trim this surface against the specified shell, in the way that's appropriate
// for the specified Boolean operation type (and which operand we are). We
// also need a pointer to the shell that contains our own surface, since that
// contains our original trim curves.
//-----------------------------------------------------------------------------
SSurface SSurface::MakeCopyTrimAgainst(SShell *against, SShell *shell,
int type, bool opA)
{
SSurface ret;
// The returned surface is identical, just the trim curves change
ret = *this;
ZERO(&(ret.trim));
SEdgeList el;
ZERO(&el);
MakeEdgesInto(shell, &el, true);
shell->MakeEdgeListUseNewCurveIds(&el);
ret.TrimFromEdgeList(&el);
el.Clear();
return ret;
}
void SShell::CopySurfacesTrimAgainst(SShell *against, SShell *into,
int type, bool opA)
{
SSurface *ss;
for(ss = surface.First(); ss; ss = surface.NextAfter(ss)) {
SSurface ssn;
ssn = ss->MakeCopyTrimAgainst(against, this, type, opA);
into->surface.AddAndAssignId(&ssn);
}
}
void SShell::MakeFromBoolean(SShell *a, SShell *b, int type) {
// Copy over all the original curves, splitting them so that a
// piecwise linear segment never crosses a surface from the other
// shell.
a->CopyCurvesSplitAgainst(b, this);
b->CopyCurvesSplitAgainst(a, this);
// Generate the intersection curves for each surface in A against all
// the surfaces in B
// Then trim and copy the surfaces
a->CopySurfacesTrimAgainst(b, this, type, true);
b->CopySurfacesTrimAgainst(a, this, type, false);
}