solvespace/srf/merge.cpp
Jonathan Westhues 2d653eada8 Add code to identify planes and cylindrical surfaces from a solid
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]
2009-06-04 21:38:41 -08:00

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();
}