
of revolution, and put them in the same form as if they had been draw by an extrusion (so that we can use all the same special case intersection curves). And add code to merge coincident faces into one. That turns out to be more than a cosmetic/efficiency thing, since edge splitting fails at the join between two coincident faces. [git-p4: depot-paths = "//depot/solvespace/": change = 1965]
88 lines
3.1 KiB
C++
88 lines
3.1 KiB
C++
//-----------------------------------------------------------------------------
|
|
// 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;
|
|
|
|
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();
|
|
}
|
|
|