solvespace/srf/merge.cpp

91 lines
3.3 KiB
C++
Raw Normal View History

//-----------------------------------------------------------------------------
// Routines to merge multiple coincident surfaces (each with their own trim
// curves) into a single surface, with all of the trim curves.
//-----------------------------------------------------------------------------
#include "../solvespace.h"
void SShell::MergeCoincidentSurfaces(void) {
surface.ClearTags();
int i, j;
SSurface *si, *sj;
for(i = 0; i < surface.n; i++) {
si = &(surface.elem[i]);
if(si->tag) continue;
// Let someone else clean up the empty surfaces; we can certainly merge
// them, but we don't know how to calculate a reasonable bounding box.
if(si->trim.n == 0) continue;
SEdgeList sel;
ZERO(&sel);
bool merged = false;
for(j = i + 1; j < surface.n; j++) {
sj = &(surface.elem[j]);
if(sj->tag) continue;
if(!sj->CoincidentWith(si, true)) continue;
if(sj->color != si->color) continue;
// But we do merge surfaces with different face entities, since
// otherwise we'd hardly ever merge anything.
// This surface is coincident, so it gets merged.
sj->tag = 1;
merged = true;
sj->MakeEdgesInto(this, &sel, false);
sj->trim.Clear();
// All the references to this surface get replaced with the new srf
SCurve *sc;
for(sc = curve.First(); sc; sc = curve.NextAfter(sc)) {
if(sc->surfA.v == sj->h.v) sc->surfA = si->h;
if(sc->surfB.v == sj->h.v) sc->surfB = si->h;
}
}
if(merged) {
si->MakeEdgesInto(this, &sel, false);
sel.CullExtraneousEdges();
si->trim.Clear();
si->TrimFromEdgeList(&sel, false);
// And we must choose control points such that all the trims lie
// with u and v in [0, 1], so that the bbox tests work.
Vector u, v, n;
si->TangentsAt(0.5, 0.5, &u, &v);
u = u.WithMagnitude(1);
v = v.WithMagnitude(1);
n = si->NormalAt(0.5, 0.5).WithMagnitude(1);
v = (n.Cross(u)).WithMagnitude(1);
double umax = VERY_NEGATIVE, umin = VERY_POSITIVE,
vmax = VERY_NEGATIVE, vmin = VERY_POSITIVE;
SEdge *se;
for(se = sel.l.First(); se; se = sel.l.NextAfter(se)) {
double ut = (se->a).Dot(u), vt = (se->a).Dot(v);
umax = max(umax, ut);
vmax = max(vmax, vt);
umin = min(umin, ut);
vmin = min(vmin, vt);
}
// We move in the +v direction as v goes from 0 to 1, and in the
// +u direction as u goes from 0 to 1. So our normal ends up
// pointed the same direction.
double nt = (si->ctrl[0][0]).Dot(n);
si->ctrl[0][0] =
Vector::From(umin, vmin, nt).ScaleOutOfCsys(u, v, n);
si->ctrl[0][1] =
Vector::From(umin, vmax, nt).ScaleOutOfCsys(u, v, n);
si->ctrl[1][1] =
Vector::From(umax, vmax, nt).ScaleOutOfCsys(u, v, n);
si->ctrl[1][0] =
Vector::From(umax, vmin, nt).ScaleOutOfCsys(u, v, n);
}
}
surface.RemoveTagged();
}