-
Notifications
You must be signed in to change notification settings - Fork 570
Expand file tree
/
Copy pathmerge.cpp
More file actions
127 lines (110 loc) · 4.93 KB
/
merge.cpp
File metadata and controls
127 lines (110 loc) · 4.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//-----------------------------------------------------------------------------
// Routines to merge multiple coincident surfaces (each with their own trim
// curves) into a single surface, with all of the trim curves.
//
// Copyright 2008-2013 Jonathan Westhues.
//-----------------------------------------------------------------------------
#include "../solvespace.h"
void SShell::MergeCoincidentSurfaces() {
surface.ClearTags();
int i, j;
SSurface *si, *sj;
for(i = 0; i < surface.n; i++) {
si = &(surface[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.IsEmpty())
continue;
// And for now we handle only coincident planes, so no sense wasting
// time on other surfaces.
if(si->degm != 1 || si->degn != 1) continue;
SEdgeList sel = {};
si->MakeEdgesInto(this, &sel, SSurface::MakeAs::XYZ);
bool mergedThisTime, merged = false;
do {
mergedThisTime = false;
for(j = i + 1; j < surface.n; j++) {
sj = &(surface[j]);
if(sj->tag) continue;
if(!sj->CoincidentWith(si, /*sameNormal=*/true)) continue;
if(!sj->color.Equals(si->color)) continue;
// But we do merge surfaces with different face entities, since
// otherwise we'd hardly ever merge anything.
// This surface is coincident. But let's not merge coincident
// surfaces if they contain disjoint contours; that just makes
// the bounding box tests less effective, and possibly things
// less robust.
SEdgeList tel = {};
sj->MakeEdgesInto(this, &tel, SSurface::MakeAs::XYZ);
if(!sel.ContainsEdgeFrom(&tel)) {
tel.Clear();
continue;
}
tel.Clear();
sj->tag = 1;
merged = true;
mergedThisTime = true;
sj->MakeEdgesInto(this, &sel, SSurface::MakeAs::XYZ);
sj->trim.Clear();
// All the references to this surface get replaced with the
// new srf
for(SCurve &sc : curve) {
if(sc.surfA == sj->h) sc.surfA = si->h;
if(sc.surfB == sj->h) sc.surfB = si->h;
}
}
// If this iteration merged a contour onto ours, then we have to
// go through the surfaces again; that might have made a new
// surface touch us.
} while(mergedThisTime);
if(merged) {
sel.CullExtraneousEdges();
si->trim.Clear();
si->TrimFromEdgeList(&sel, /*asUv=*/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);
}
// An interesting problem here; the real curve could extend
// slightly beyond the bounding box of the piecewise linear
// bits. Not a problem for us, but some apps won't import STEP
// in that case. So give a bit of extra room; in theory just
// a chord tolerance, but more can't hurt.
double muv = max((umax - umin), (vmax - vmin));
double tol = muv/50 + 3*SS.ChordTolMm();
umax += tol;
vmax += tol;
umin -= tol;
vmin -= tol;
// 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);
}
sel.Clear();
}
surface.RemoveTagged();
}