From 7a874c20c0b5c546c2ec37df12ac840ec5f84ec0 Mon Sep 17 00:00:00 2001 From: Jonathan Westhues Date: Fri, 16 Jan 2009 21:28:49 -0800 Subject: [PATCH] Remove old sweep/helical sweep code for meshes, and add some untested stuff to start making exact surface shells. [git-p4: depot-paths = "//depot/solvespace/": change = 1896] --- groupmesh.cpp | 156 ------------------------------------------------ sketch.h | 2 - srf/ratpoly.cpp | 97 ++++++++++++++++++++++++++++++ srf/surface.h | 24 +++++++- 4 files changed, 120 insertions(+), 159 deletions(-) diff --git a/groupmesh.cpp b/groupmesh.cpp index 1116560..94c555b 100644 --- a/groupmesh.cpp +++ b/groupmesh.cpp @@ -200,153 +200,6 @@ void Group::GenerateMeshForStepAndRepeat(void) { thisMesh.Clear(); } -void Group::GenerateMeshForSweep(bool helical, - Vector axisp, Vector axis, Vector onHelix) -{ - STriMeta meta = { 0, color }; - int a, i; - - // The closed section that will be swept along the curve - Group *section = SS.GetGroup(helical ? opA : opB); - SEdgeList edges; - ZERO(&edges); - (section->poly).MakeEdgesInto(&edges); - - // The trajectory along which the section will be swept - SContour traj; - ZERO(&traj); - if(helical) { - double r0 = onHelix.DistanceToLine(axisp, axis); - int n = (int)(SS.CircleSides(r0)*valA) + 4; - Vector origin = onHelix.ClosestPointOnLine(axisp, axis); - Vector u = (onHelix.Minus(origin)).WithMagnitude(1); - Vector v = (axis.Cross(u)).WithMagnitude(1); - for(i = 0; i <= n; i++) { - double turns = (i*valA)/n; - double theta = turns*2*PI; - double r = r0 + turns*valC; - if(subtype == LEFT_HANDED) theta = -theta; - Vector p = origin.Plus( - u.ScaledBy(r*cos(theta)).Plus( - v.ScaledBy(r*sin(theta)).Plus( - axis.WithMagnitude(turns*valB)))); - traj.AddPoint(p); - } - } else { - GetTrajectory(opA, &traj, &(section->poly)); - } - - if(traj.l.n <= 0) { - edges.Clear(); - return; // no trajectory, nothing to do - } - - // Initial offset/orientation determined by first pwl in trajectory - Vector origRef = traj.l.elem[0].p; - Vector origNormal = (traj.l.elem[1].p).Minus(origRef); - origNormal = origNormal.WithMagnitude(1); - Vector oldRef = origRef, oldNormal = origNormal; - - Vector oldU, oldV; - if(helical) { - oldU = axis.WithMagnitude(1); - oldV = (oldNormal.Cross(oldU)).WithMagnitude(1); - // numerical fixup, since pwl segment isn't exactly tangent... - oldU = (oldV.Cross(oldNormal)).WithMagnitude(1); - } else { - oldU = oldNormal.Normal(0); - oldV = oldNormal.Normal(1); - } - - // The endcap at the start of the curve - SPolygon cap; - ZERO(&cap); - edges.l.ClearTags(); - edges.AssemblePolygon(&cap, NULL); - cap.normal = cap.ComputeNormal(); - if(oldNormal.Dot(cap.normal) > 0) { - cap.normal = (cap.normal).ScaledBy(-1); - } - cap.TriangulateInto(&thisMesh, meta); - cap.Clear(); - - // Rewrite the source polygon so that the trajectory is along the - // z axis, and the poly lies in the xy plane - for(i = 0; i < edges.l.n; i++) { - SEdge *e = &(edges.l.elem[i]); - e->a = ((e->a).Minus(oldRef)).DotInToCsys(oldU, oldV, oldNormal); - e->b = ((e->b).Minus(oldRef)).DotInToCsys(oldU, oldV, oldNormal); - } - Vector polyn = - (section->poly.normal).DotInToCsys(oldU, oldV, oldNormal); - - for(a = 1; a < traj.l.n; a++) { - Vector thisRef = traj.l.elem[a].p; - Vector thisNormal, useNormal; - if(a == traj.l.n - 1) { - thisNormal = oldNormal; - useNormal = oldNormal; - } else { - thisNormal = (traj.l.elem[a+1].p).Minus(thisRef); - useNormal = (thisNormal.Plus(oldNormal)).ScaledBy(0.5); - } - - Vector useV, useU; - useNormal = useNormal.WithMagnitude(1); - if(helical) { - // The axis of rotation is always a basis vector - useU = axis.WithMagnitude(1); - useV = (useNormal.Cross(useU)).WithMagnitude(1); - } else { - // Choose a new coordinate system, normal to the trajectory and - // with the minimum possible twist about the normal. - useV = (useNormal.Cross(oldU)).WithMagnitude(1); - useU = (useV.Cross(useNormal)).WithMagnitude(1); - } - - Quaternion qi = Quaternion::From(oldU, oldV); - Quaternion qf = Quaternion::From(useU, useV); - - for(i = 0; i < edges.l.n; i++) { - SEdge *edge = &(edges.l.elem[i]); - Vector ai, bi, af, bf; - ai = qi.Rotate(edge->a).Plus(oldRef); - bi = qi.Rotate(edge->b).Plus(oldRef); - - af = qf.Rotate(edge->a).Plus(thisRef); - bf = qf.Rotate(edge->b).Plus(thisRef); - - Vector ab = (edge->b).Minus(edge->a); - Vector out = polyn.Cross(ab); - out = qf.Rotate(out); - - AddQuadWithNormal(meta, out, ai, bi, bf, af); - } - oldRef = thisRef; - oldNormal = thisNormal; - oldU = useU; - oldV = useV; - } - - Quaternion q = Quaternion::From(oldU, oldV); - for(i = 0; i < edges.l.n; i++) { - SEdge *edge = &(edges.l.elem[i]); - (edge->a) = q.Rotate(edge->a).Plus(oldRef); - (edge->b) = q.Rotate(edge->b).Plus(oldRef); - } - edges.l.ClearTags(); - edges.AssemblePolygon(&cap, NULL); - cap.normal = cap.ComputeNormal(); - if(oldNormal.Dot(cap.normal) < 0) { - cap.normal = (cap.normal).ScaledBy(-1); - } - cap.TriangulateInto(&thisMesh, meta); - cap.Clear(); - - traj.l.Clear(); - edges.Clear(); -} - void Group::GenerateMesh(void) { thisMesh.Clear(); STriMeta meta = { 0, color }; @@ -472,15 +325,6 @@ void Group::GenerateMesh(void) { AddQuadWithNormal(meta, out, ai, bi, bf, af); } } - } else if(type == SWEEP) { - Vector zp = Vector::From(0, 0, 0); - GenerateMeshForSweep(false, zp, zp, zp); - } else if(type == HELICAL_SWEEP) { - Entity *ln = SS.GetEntity(predef.entityB); - Vector lna = SS.GetEntity(ln->point[0])->PointGetNum(), - lnb = SS.GetEntity(ln->point[1])->PointGetNum(); - Vector onh = SS.GetEntity(predef.origin)->PointGetNum(); - GenerateMeshForSweep(true, lna, lnb.Minus(lna), onh); } else if(type == IMPORTED) { // Triangles are just copied over, with the appropriate transformation // applied. diff --git a/sketch.h b/sketch.h index 3349bab..c6db90a 100644 --- a/sketch.h +++ b/sketch.h @@ -207,8 +207,6 @@ public: void AddQuadWithNormal(STriMeta meta, Vector out, Vector a, Vector b, Vector c, Vector d); void GenerateMeshForStepAndRepeat(void); - void GenerateMeshForSweep(bool helical, - Vector axisp, Vector axis, Vector onHelix); void GenerateMesh(void); void Draw(void); diff --git a/srf/ratpoly.cpp b/srf/ratpoly.cpp index 189d720..c716970 100644 --- a/srf/ratpoly.cpp +++ b/srf/ratpoly.cpp @@ -123,7 +123,104 @@ void SPolyCurve::MakePwlWorker(List *l, double ta, double tb) { } } +void SPolyCurve::Reverse(void) { + int i; + for(i = 0; i < (deg+1)/2; i++) { + SWAP(Vector, ctrl[i], ctrl[deg-i]); + SWAP(double, weight[i], weight[deg-i]); + } +} + void SPolyCurveList::Clear(void) { l.Clear(); } +SPolyCurveLoop SPolyCurveLoop::FromCurves(SPolyCurveList *spcl, bool *notClosed) +{ + SPolyCurveLoop loop; + ZERO(&loop); + + if(spcl->l.n < 1) return loop; + spcl->l.ClearTags(); + + SPolyCurve *first = &(spcl->l.elem[0]); + first->tag = 1; + loop.l.Add(first); + Vector start = first->Start(); + Vector hanging = first->Finish(); + + spcl->l.RemoveTagged(); + + while(spcl->l.n > 0 && !hanging.Equals(start)) { + int i; + for(i = 0; i < spcl->l.n; i++) { + SPolyCurve *test = &(spcl->l.elem[i]); + + if((test->Finish()).Equals(hanging)) { + test->Reverse(); + } + if((test->Start()).Equals(hanging)) { + test->tag = 1; + loop.l.Add(test); + hanging = test->Finish(); + spcl->l.RemoveTagged(); + break; + } + } + if(i >= spcl->l.n) { + // Didn't find the next curve in the loop + *notClosed = true; + return loop; + } + } + if(hanging.Equals(start)) { + *notClosed = false; + } else { + *notClosed = true; + } + + return loop; +} + +SSurface SSurface::FromExtrusionOf(SPolyCurve *spc, Vector t0, Vector t1) { + SSurface ret; + ZERO(&ret); + + ret.degm = spc->deg; + ret.degn = 1; + + int i; + for(i = 0; i <= ret.degm; i++) { + ret.ctrl[i][0] = (spc->ctrl[i]).Plus(t0); + ret.weight[i][0] = spc->weight[i]; + + ret.ctrl[i][1] = (spc->ctrl[i]).Plus(t1); + ret.weight[i][1] = spc->weight[i]; + } + + return ret; +} + +SShell SShell::FromExtrusionOf(SPolyCurveList *spcl, Vector t0, Vector t1) { + SShell ret; + ZERO(&ret); + + // Find the plane that contains our input section. + + // Group the input curves into loops; this will reverse some of the + // curves if necessary for consistent (but not necessarily correct yet) + // direction. + + // Generate a polygon from the curves, and use this to test how many + // times each loop is enclosed. Then set the direction (cw/ccw) to + // be correct for outlines/holes, so that we generate correct normals. + + // Now generate all the surfaces, top/bottom planes plus extrusions. + + // And now all the curves, trimming the top and bottom and their extrusion + + // And the lines, trimming adjacent extrusion surfaces. + return ret; +} + + diff --git a/srf/surface.h b/srf/surface.h index 17582d3..8cf55be 100644 --- a/srf/surface.h +++ b/srf/surface.h @@ -19,6 +19,7 @@ public: // our inputs. class SPolyCurve { public: + int tag; int deg; Vector ctrl[4]; double weight[4]; @@ -29,6 +30,8 @@ public: void MakePwlInto(List *l); void MakePwlWorker(List *l, double ta, double tb); + void Reverse(void); + static SPolyCurve From(Vector p0, Vector p1, Vector p2, Vector p3); static SPolyCurve From(Vector p0, Vector p1, Vector p2); static SPolyCurve From(Vector p0, Vector p1); @@ -41,13 +44,23 @@ public: void Clear(void); }; +class SPolyCurveLoop { +public: + List l; + + bool IsClockwiseProjdToNormal(Vector n); + + static SPolyCurveLoop FromCurves(SPolyCurveList *spcl, bool *notClosed); +}; + // Stuff for the surface trim curves: piecewise linear class SCurve { public: hSCurve h; - List pts; + SPolyCurve exact; // or deg = 0 if we don't know the exact form + List pts; hSSurface srfA; hSSurface srfB; }; @@ -71,14 +84,23 @@ public: int degm, degn; Vector ctrl[4][4]; double weight[4][4]; + Vector out00; // outer normal at ctrl[0][0] List trim; + + static SSurface FromExtrusionOf(SPolyCurve *spc, Vector t0, Vector t1); + + void TriangulateInto(SMesh *sm); }; class SShell { public: IdList curve; IdList surface; + + static SShell FromExtrusionOf(SPolyCurveList *spcl, Vector t0, Vector t1); + + static SShell FromUnionOf(SShell *a, SShell *b); }; #endif