//----------------------------------------------------------------------------- // Functions relating to rational polynomial surfaces, which are trimmed by // curves (either rational polynomial curves, or piecewise linear // approximations to curves of intersection that can't be represented // exactly in ratpoly form), and assembled into watertight shells. // // Copyright 2008-2013 Jonathan Westhues. //----------------------------------------------------------------------------- #ifndef __SURFACE_H #define __SURFACE_H // Utility functions, Bernstein polynomials of order 1-3 and their derivatives. double Bernstein(int k, int deg, double t); double BernsteinDerivative(int k, int deg, double t); class SSurface; class SCurvePt; // Utility data structure, a two-dimensional BSP to accelerate polygon // operations. class SBspUv { public: Point2d a, b; SBspUv *pos; SBspUv *neg; SBspUv *more; enum { INSIDE = 100, OUTSIDE = 200, EDGE_PARALLEL = 300, EDGE_ANTIPARALLEL = 400, EDGE_OTHER = 500 }; static SBspUv *Alloc(void); static SBspUv *From(SEdgeList *el, SSurface *srf); void ScalePoints(Point2d *pt, Point2d *a, Point2d *b, SSurface *srf); double ScaledSignedDistanceToLine(Point2d pt, Point2d a, Point2d b, SSurface *srf); double ScaledDistanceToLine(Point2d pt, Point2d a, Point2d b, bool seg, SSurface *srf); SBspUv *InsertEdge(Point2d a, Point2d b, SSurface *srf); int ClassifyPoint(Point2d p, Point2d eb, SSurface *srf); int ClassifyEdge(Point2d ea, Point2d eb, SSurface *srf); double MinimumDistanceToEdge(Point2d p, SSurface *srf); }; // Now the data structures to represent a shell of trimmed rational polynomial // surfaces. class SShell; class hSSurface { public: uint32_t v; }; class hSCurve { public: uint32_t v; }; // Stuff for rational polynomial curves, of degree one to three. These are // our inputs, and are also calculated for certain exact surface-surface // intersections. class SBezier { public: int tag; int auxA, auxB; int deg; Vector ctrl[4]; double weight[4]; Vector PointAt(double t); Vector TangentAt(double t); void ClosestPointTo(Vector p, double *t, bool converge=true); void SplitAt(double t, SBezier *bef, SBezier *aft); bool PointOnThisAndCurve(SBezier *sbb, Vector *p); Vector Start(void); Vector Finish(void); bool Equals(SBezier *b); void MakePwlInto(SEdgeList *sel, double chordTol=0); void MakePwlInto(List *l, double chordTol=0); void MakePwlInto(SContour *sc, double chordTol=0); void MakePwlInto(List *l, double chordTol=0); void MakePwlWorker(List *l, double ta, double tb, double chordTol); void AllIntersectionsWith(SBezier *sbb, SPointList *spl); void GetBoundingProjd(Vector u, Vector orig, double *umin, double *umax); void Reverse(void); bool IsInPlane(Vector n, double d); bool IsCircle(Vector axis, Vector *center, double *r); bool IsRational(void); SBezier TransformedBy(Vector t, Quaternion q, double scale); SBezier InPerspective(Vector u, Vector v, Vector n, Vector origin, double cameraTan); void ScaleSelfBy(double s); static SBezier From(Vector p0, Vector p1, Vector p2, Vector p3); static SBezier From(Vector p0, Vector p1, Vector p2); static SBezier From(Vector p0, Vector p1); static SBezier From(Vector4 p0, Vector4 p1, Vector4 p2, Vector4 p3); static SBezier From(Vector4 p0, Vector4 p1, Vector4 p2); static SBezier From(Vector4 p0, Vector4 p1); }; class SBezierList { public: List l; void Clear(void); void ScaleSelfBy(double s); void CullIdenticalBeziers(void); void AllIntersectionsWith(SBezierList *sblb, SPointList *spl); bool GetPlaneContainingBeziers(Vector *p, Vector *u, Vector *v, Vector *notCoplanarAt); }; class SBezierLoop { public: int tag; List l; inline void Clear(void) { l.Clear(); } bool IsClosed(void); void Reverse(void); void MakePwlInto(SContour *sc, double chordTol=0); void GetBoundingProjd(Vector u, Vector orig, double *umin, double *umax); static SBezierLoop FromCurves(SBezierList *spcl, bool *allClosed, SEdge *errorAt); }; class SBezierLoopSet { public: List l; Vector normal; Vector point; static SBezierLoopSet From(SBezierList *spcl, SPolygon *poly, double chordTol, bool *allClosed, SEdge *errorAt, SBezierList *openContours); void GetBoundingProjd(Vector u, Vector orig, double *umin, double *umax); void MakePwlInto(SPolygon *sp); void Clear(void); }; class SBezierLoopSetSet { public: List l; void FindOuterFacesFrom(SBezierList *sbl, SPolygon *spxyz, SSurface *srfuv, double chordTol, bool *allClosed, SEdge *notClosedAt, bool *allCoplanar, Vector *notCoplanarAt, SBezierList *openContours); void AddOpenPath(SBezier *sb); void Clear(void); }; // Stuff for the surface trim curves: piecewise linear class SCurvePt { public: int tag; Vector p; bool vertex; }; class SCurve { public: hSCurve h; // In a Boolean, C = A op B. The curves in A and B get copied into C, and // therefore must get new hSCurves assigned. For the curves in A and B, // we use newH to record their new handle in C. hSCurve newH; enum { FROM_A = 100, FROM_B = 200, FROM_INTERSECTION = 300 }; int source; bool isExact; SBezier exact; List pts; hSSurface surfA; hSSurface surfB; static SCurve FromTransformationOf(SCurve *a, Vector t, Quaternion q, double scale); SCurve MakeCopySplitAgainst(SShell *agnstA, SShell *agnstB, SSurface *srfA, SSurface *srfB); void RemoveShortSegments(SSurface *srfA, SSurface *srfB); SSurface *GetSurfaceA(SShell *a, SShell *b); SSurface *GetSurfaceB(SShell *a, SShell *b); void Clear(void); }; // A segment of a curve by which a surface is trimmed: indicates which curve, // by its handle, and the starting and ending points of our segment of it. // The vector out points out of the surface; it, the surface outer normal, // and a tangent to the beginning of the curve are all orthogonal. class STrimBy { public: hSCurve curve; bool backwards; // If a trim runs backwards, then start and finish still correspond to // the actual start and finish, but they appear in reverse order in // the referenced curve. Vector start; Vector finish; static STrimBy EntireCurve(SShell *shell, hSCurve hsc, bool bkwds); }; // An intersection point between a line and a surface class SInter { public: int tag; Vector p; SSurface *srf; Point2d pinter; Vector surfNormal; // of the intersecting surface, at pinter bool onEdge; // pinter is on edge of trim poly }; // A rational polynomial surface in Bezier form. class SSurface { public: int tag; hSSurface h; // Same as newH for the curves; record what a surface gets renamed to // when I copy things over. hSSurface newH; uint32_t color; uint32_t face; int degm, degn; Vector ctrl[4][4]; double weight[4][4]; List trim; // For testing whether a point (u, v) on the surface lies inside the trim SBspUv *bsp; SEdgeList edges; // For caching our initial (u, v) when doing Newton iterations to project // a point into our surface. Point2d cached; static SSurface FromExtrusionOf(SBezier *spc, Vector t0, Vector t1); static SSurface FromRevolutionOf(SBezier *sb, Vector pt, Vector axis, double thetas, double thetaf); static SSurface FromPlane(Vector pt, Vector u, Vector v); static SSurface FromTransformationOf(SSurface *a, Vector t, Quaternion q, double scale, bool includingTrims); void ScaleSelfBy(double s); void EdgeNormalsWithinSurface(Point2d auv, Point2d buv, Vector *pt, Vector *enin, Vector *enout, Vector *surfn, uint32_t auxA, SShell *shell, SShell *sha, SShell *shb); void FindChainAvoiding(SEdgeList *src, SEdgeList *dest, SPointList *avoid); SSurface MakeCopyTrimAgainst(SShell *parent, SShell *a, SShell *b, SShell *into, int type); void TrimFromEdgeList(SEdgeList *el, bool asUv); void IntersectAgainst(SSurface *b, SShell *agnstA, SShell *agnstB, SShell *into); void AddExactIntersectionCurve(SBezier *sb, SSurface *srfB, SShell *agnstA, SShell *agnstB, SShell *into); typedef struct { int tag; Point2d p; } Inter; void WeightControlPoints(void); void UnWeightControlPoints(void); void CopyRowOrCol(bool row, int this_ij, SSurface *src, int src_ij); void BlendRowOrCol(bool row, int this_ij, SSurface *a, int a_ij, SSurface *b, int b_ij); double DepartureFromCoplanar(void); void SplitInHalf(bool byU, SSurface *sa, SSurface *sb); void AllPointsIntersecting(Vector a, Vector b, List *l, bool seg, bool trimmed, bool inclTangent); void AllPointsIntersectingUntrimmed(Vector a, Vector b, int *cnt, int *level, List *l, bool segment, SSurface *sorig); void ClosestPointTo(Vector p, Point2d *puv, bool converge=true); void ClosestPointTo(Vector p, double *u, double *v, bool converge=true); bool ClosestPointNewton(Vector p, double *u, double *v, bool converge=true); bool PointIntersectingLine(Vector p0, Vector p1, double *u, double *v); Vector ClosestPointOnThisAndSurface(SSurface *srf2, Vector p); void PointOnSurfaces(SSurface *s1, SSurface *s2, double *u, double *v); Vector PointAt(double u, double v); Vector PointAt(Point2d puv); void TangentsAt(double u, double v, Vector *tu, Vector *tv); Vector NormalAt(Point2d puv); Vector NormalAt(double u, double v); bool LineEntirelyOutsideBbox(Vector a, Vector b, bool segment); void GetAxisAlignedBounding(Vector *ptMax, Vector *ptMin); bool CoincidentWithPlane(Vector n, double d); bool CoincidentWith(SSurface *ss, bool sameNormal); bool IsExtrusion(SBezier *of, Vector *along); bool IsCylinder(Vector *axis, Vector *center, double *r, Vector *start, Vector *finish); void TriangulateInto(SShell *shell, SMesh *sm); // these are intended as bitmasks, even though there's just one now enum { AS_UV = 0x01, AS_XYZ = 0x00 }; void MakeTrimEdgesInto(SEdgeList *sel, int flags, SCurve *sc, STrimBy *stb); void MakeEdgesInto(SShell *shell, SEdgeList *sel, int flags, SShell *useCurvesFrom=NULL); Vector ExactSurfaceTangentAt(Vector p, SSurface *srfA, SSurface *srfB, Vector dir); void MakeSectionEdgesInto(SShell *shell, SEdgeList *sel, SBezierList *sbl); void MakeClassifyingBsp(SShell *shell, SShell *useCurvesFrom); double ChordToleranceForEdge(Vector a, Vector b); void MakeTriangulationGridInto(List *l, double vs, double vf, bool swapped); Vector PointAtMaybeSwapped(double u, double v, bool swapped); void Reverse(void); void Clear(void); }; class SShell { public: IdList curve; IdList surface; bool booleanFailed; void MakeFromExtrusionOf(SBezierLoopSet *sbls, Vector t0, Vector t1, uint32_t color); void MakeFromRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis, uint32_t color); void MakeFromUnionOf(SShell *a, SShell *b); void MakeFromDifferenceOf(SShell *a, SShell *b); enum { AS_UNION = 10, AS_DIFFERENCE = 11, AS_INTERSECT = 12 }; void MakeFromBoolean(SShell *a, SShell *b, int type); void CopyCurvesSplitAgainst(bool opA, SShell *agnst, SShell *into); void CopySurfacesTrimAgainst(SShell *sha, SShell *shb, SShell *into, int type); void MakeIntersectionCurvesAgainst(SShell *against, SShell *into); void MakeClassifyingBsps(SShell *useCurvesFrom); void AllPointsIntersecting(Vector a, Vector b, List *il, bool seg, bool trimmed, bool inclTangent); void MakeCoincidentEdgesInto(SSurface *proto, bool sameNormal, SEdgeList *el, SShell *useCurvesFrom); void RewriteSurfaceHandlesForCurves(SShell *a, SShell *b); void CleanupAfterBoolean(void); // Definitions when classifying regions of a surface; it is either inside, // outside, or coincident (with parallel or antiparallel normal) with a // shell. enum { INSIDE = 100, OUTSIDE = 200, COINC_SAME = 300, COINC_OPP = 400 }; static const double DOTP_TOL; int ClassifyRegion(Vector edge_n, Vector inter_surf_n, Vector edge_surf_n); bool ClassifyEdge(int *indir, int *outdir, Vector ea, Vector eb, Vector p, Vector edge_n_in, Vector edge_n_out, Vector surf_n); void MakeFromCopyOf(SShell *a); void MakeFromTransformationOf(SShell *a, Vector trans, Quaternion q, double scale); void MakeFromAssemblyOf(SShell *a, SShell *b); void MergeCoincidentSurfaces(void); void TriangulateInto(SMesh *sm); void MakeEdgesInto(SEdgeList *sel); void MakeSectionEdgesInto(Vector n, double d, SEdgeList *sel, SBezierList *sbl); bool IsEmpty(void); void RemapFaces(Group *g, int remap); void Clear(void); }; #endif