@@ -20,6 +20,32 @@ void SShell::MakeFromIntersectionOf(SShell *a, SShell *b) {
2020 MakeFromBoolean (a, b, SSurface::CombineAs::INTERSECTION);
2121}
2222
23+ // We will be inserting existing verticies into curves to split them
24+ // todo: this is only using the ends of exact curves, and it is only
25+ // using them to split existing curves, not new intersections.
26+ // It resolves some issues but we could do better. We will need to
27+ // reorder things so the surface intersection curves exist prior to
28+ // splitting any curves at all in order to have their verticies too.
29+ // Better still would be to get curve/surface intersection to work
30+ // more reliably at the edges - maybe do curve/curve tests as part
31+ // of the curve-surface intersection test.
32+ static void FindVertsOnCurve (List<SInter> *l, const SCurve *curve, SShell *sh) {
33+ for (auto sc : sh->curve ) {
34+ if (!sc.isExact ) continue ;
35+ for (int i=0 ; i<2 ; i++) {
36+ Vector pt = sc.exact .ctrl [ i==0 ? 0 : sc.exact .deg ];
37+ double t;
38+ curve->exact .ClosestPointTo (pt, &t, /* must converge=*/ false );
39+ double d = pt.Minus (curve->exact .PointAt (t)).Magnitude ();
40+ if ((t>LENGTH_EPS) && (t<(1.0 -LENGTH_EPS)) && (d < LENGTH_EPS)) {
41+ SInter inter;
42+ inter.p = pt;
43+ l->Add (&inter);
44+ }
45+ }
46+ }
47+ }
48+
2349// -----------------------------------------------------------------------------
2450// Take our original pwl curve. Wherever an edge intersects a surface within
2551// either agnstA or agnstB, split the piecewise linear element. Then refine
@@ -35,12 +61,19 @@ SCurve SCurve::MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB,
3561 ret = *this ;
3662 ret.pts = {};
3763
64+ // First find any vertex that lies on our curve.
65+ List<SInter> vertpts = {};
66+ if (agnstA)
67+ FindVertsOnCurve (&vertpts, this , agnstA);
68+ if (agnstB)
69+ FindVertsOnCurve (&vertpts, this , agnstB);
70+
3871 const SCurvePt *p = pts.First ();
3972 ssassert (p != NULL , " Cannot split an empty curve" );
4073 SCurvePt prev = *p;
4174 ret.pts .Add (p);
4275 p = pts.NextAfter (p);
43-
76+
4477 for (; p; p = pts.NextAfter (p)) {
4578 List<SInter> il = {};
4679
@@ -100,12 +133,22 @@ SCurve SCurve::MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB,
100133 pi->p = (pi->srf )->PointAt (puv);
101134 }
102135 il.RemoveTagged ();
136+ }
137+ // Now add any vertex that is on this segment
138+ const Vector lineStart = prev.p ;
139+ const Vector lineDirection = (p->p ).Minus (prev.p );
140+ for (auto vtx : vertpts) {
141+ double t = (vtx.p .Minus (lineStart)).DivProjected (lineDirection);
142+ if ((0.0 < t) && (t < 1.0 )) {
143+ il.Add (&vtx);
144+ }
145+ }
146+ if (!il.IsEmpty ()) {
147+ SInter *pi;
103148
104149 // And now sort them in order along the line. Note that we must
105150 // do that after refining, in case the refining would make two
106151 // points switch places.
107- const Vector lineStart = prev.p ;
108- const Vector lineDirection = (p->p ).Minus (prev.p );
109152 std::sort (il.begin (), il.end (), [&](const SInter &a, const SInter &b) {
110153 double ta = (a.p .Minus (lineStart)).DivProjected (lineDirection);
111154 double tb = (b.p .Minus (lineStart)).DivProjected (lineDirection);
@@ -133,6 +176,7 @@ SCurve SCurve::MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB,
133176 ret.pts .Add (p);
134177 prev = *p;
135178 }
179+ vertpts.Clear ();
136180 return ret;
137181}
138182
0 commit comments