403 lines
14 KiB
C++
403 lines
14 KiB
C++
|
|
#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;
|
|
|
|
static const int INSIDE = 100;
|
|
static const int OUTSIDE = 200;
|
|
static const int EDGE_PARALLEL = 300;
|
|
static const int EDGE_ANTIPARALLEL = 400;
|
|
static const int 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:
|
|
DWORD v;
|
|
};
|
|
|
|
class hSCurve {
|
|
public:
|
|
DWORD 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<SCurvePt> *l, double chordTol=0);
|
|
void MakePwlInto(SContour *sc, double chordTol=0);
|
|
void MakePwlInto(List<Vector> *l, double chordTol=0);
|
|
void MakePwlWorker(List<Vector> *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, bool mirror);
|
|
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<SBezier> 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<SBezier> 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<SBezierLoop> 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<SBezierLoopSet> 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;
|
|
static const int FROM_A = 100;
|
|
static const int FROM_B = 200;
|
|
static const int FROM_INTERSECTION = 300;
|
|
int source;
|
|
|
|
bool isExact;
|
|
SBezier exact;
|
|
|
|
List<SCurvePt> pts;
|
|
|
|
hSSurface surfA;
|
|
hSSurface surfB;
|
|
|
|
static SCurve FromTransformationOf(SCurve *a, Vector t, Quaternion q,
|
|
bool mirror);
|
|
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 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;
|
|
|
|
int color;
|
|
DWORD face;
|
|
|
|
int degm, degn;
|
|
Vector ctrl[4][4];
|
|
double weight[4][4];
|
|
|
|
List<STrimBy> 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,
|
|
bool mirror,
|
|
bool includingTrims);
|
|
void ScaleSelfBy(double s);
|
|
|
|
void EdgeNormalsWithinSurface(Point2d auv, Point2d buv,
|
|
Vector *pt, Vector *enin, Vector *enout,
|
|
Vector *surfn,
|
|
DWORD 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<SInter> *l,
|
|
bool seg, bool trimmed, bool inclTangent);
|
|
void AllPointsIntersectingUntrimmed(Vector a, Vector b,
|
|
int *cnt, int *level,
|
|
List<Inter> *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
|
|
static const int AS_UV = 0x01;
|
|
static const int 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<double> *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<SCurve,hSCurve> curve;
|
|
IdList<SSurface,hSSurface> surface;
|
|
|
|
bool booleanFailed;
|
|
|
|
void MakeFromExtrusionOf(SBezierLoopSet *sbls, Vector t0, Vector t1,
|
|
int color);
|
|
void MakeFromRevolutionOf(SBezierLoopSet *sbls, Vector pt, Vector axis,
|
|
int color);
|
|
|
|
void MakeFromUnionOf(SShell *a, SShell *b);
|
|
void MakeFromDifferenceOf(SShell *a, SShell *b);
|
|
static const int AS_UNION = 10;
|
|
static const int AS_DIFFERENCE = 11;
|
|
static const int 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<SInter> *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.
|
|
static const int INSIDE = 100;
|
|
static const int OUTSIDE = 200;
|
|
static const int COINC_SAME = 300;
|
|
static const int 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,
|
|
bool mirror);
|
|
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
|
|
|