306 lines
7.8 KiB
C++
306 lines
7.8 KiB
C++
//-----------------------------------------------------------------------------
|
|
// Anything relating to plane polygons and triangles, and (generally, non-
|
|
// planar) meshes thereof.
|
|
//
|
|
// Copyright 2008-2013 Jonathan Westhues.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#ifndef __POLYGON_H
|
|
#define __POLYGON_H
|
|
|
|
class SPointList;
|
|
class SPolygon;
|
|
class SContour;
|
|
class SMesh;
|
|
class SBsp3;
|
|
|
|
class SEdge {
|
|
public:
|
|
int tag;
|
|
int auxA, auxB;
|
|
Vector a, b;
|
|
|
|
static SEdge From(Vector a, Vector b);
|
|
bool EdgeCrosses(Vector a, Vector b, Vector *pi=NULL, SPointList *spl=NULL);
|
|
};
|
|
|
|
class SEdgeList {
|
|
public:
|
|
List<SEdge> l;
|
|
|
|
void Clear(void);
|
|
void AddEdge(Vector a, Vector b, int auxA=0, int auxB=0);
|
|
bool AssemblePolygon(SPolygon *dest, SEdge *errorAt, bool keepDir=false);
|
|
bool AssembleContour(Vector first, Vector last, SContour *dest,
|
|
SEdge *errorAt, bool keepDir);
|
|
int AnyEdgeCrossings(Vector a, Vector b,
|
|
Vector *pi=NULL, SPointList *spl=NULL);
|
|
bool ContainsEdgeFrom(SEdgeList *sel);
|
|
bool ContainsEdge(SEdge *se);
|
|
void CullExtraneousEdges(void);
|
|
void MergeCollinearSegments(Vector a, Vector b);
|
|
};
|
|
|
|
// A kd-tree element needs to go on a side of a node if it's when KDTREE_EPS
|
|
// of the boundary. So increasing this number never breaks anything, but may
|
|
// result in more duplicated elements. So it's conservative to be sloppy here.
|
|
#define KDTREE_EPS (20*LENGTH_EPS)
|
|
|
|
class SEdgeLl {
|
|
public:
|
|
SEdge *se;
|
|
SEdgeLl *next;
|
|
|
|
static SEdgeLl *Alloc(void);
|
|
};
|
|
|
|
class SKdNodeEdges {
|
|
public:
|
|
int which; // whether c is x, y, or z
|
|
double c;
|
|
SKdNodeEdges *gt;
|
|
SKdNodeEdges *lt;
|
|
|
|
SEdgeLl *edges;
|
|
|
|
static SKdNodeEdges *From(SEdgeList *sel);
|
|
static SKdNodeEdges *From(SEdgeLl *sell);
|
|
static SKdNodeEdges *Alloc(void);
|
|
int AnyEdgeCrossings(Vector a, Vector b, int cnt,
|
|
Vector *pi=NULL, SPointList *spl=NULL);
|
|
};
|
|
|
|
class SPoint {
|
|
public:
|
|
int tag;
|
|
|
|
enum {
|
|
UNKNOWN = 0,
|
|
NOT_EAR = 1,
|
|
EAR = 2
|
|
};
|
|
int ear;
|
|
|
|
Vector p;
|
|
Vector auxv;
|
|
};
|
|
|
|
class SPointList {
|
|
public:
|
|
List<SPoint> l;
|
|
|
|
void Clear(void);
|
|
bool ContainsPoint(Vector pt);
|
|
int IndexForPoint(Vector pt);
|
|
void IncrementTagFor(Vector pt);
|
|
void Add(Vector pt);
|
|
};
|
|
|
|
class SContour {
|
|
public:
|
|
int tag;
|
|
int timesEnclosed;
|
|
Vector xminPt;
|
|
List<SPoint> l;
|
|
|
|
void AddPoint(Vector p);
|
|
void MakeEdgesInto(SEdgeList *el);
|
|
void Reverse(void);
|
|
Vector ComputeNormal(void);
|
|
double SignedAreaProjdToNormal(Vector n);
|
|
bool IsClockwiseProjdToNormal(Vector n);
|
|
bool ContainsPointProjdToNormal(Vector n, Vector p);
|
|
void OffsetInto(SContour *dest, double r);
|
|
void CopyInto(SContour *dest);
|
|
void FindPointWithMinX(void);
|
|
Vector AnyEdgeMidpoint(void);
|
|
|
|
bool IsEar(int bp, double scaledEps);
|
|
bool BridgeToContour(SContour *sc, SEdgeList *el, List<Vector> *vl);
|
|
void ClipEarInto(SMesh *m, int bp, double scaledEps);
|
|
void UvTriangulateInto(SMesh *m, SSurface *srf);
|
|
};
|
|
|
|
typedef struct {
|
|
uint32_t face;
|
|
RgbColor color;
|
|
} STriMeta;
|
|
|
|
class SPolygon {
|
|
public:
|
|
List<SContour> l;
|
|
Vector normal;
|
|
|
|
Vector ComputeNormal(void);
|
|
void AddEmptyContour(void);
|
|
int WindingNumberForPoint(Vector p);
|
|
double SignedArea(void);
|
|
bool ContainsPoint(Vector p);
|
|
void MakeEdgesInto(SEdgeList *el);
|
|
void FixContourDirections(void);
|
|
void Clear(void);
|
|
bool SelfIntersecting(Vector *intersectsAt);
|
|
bool IsEmpty(void);
|
|
Vector AnyPoint(void);
|
|
void OffsetInto(SPolygon *dest, double r);
|
|
void UvTriangulateInto(SMesh *m, SSurface *srf);
|
|
void UvGridTriangulateInto(SMesh *m, SSurface *srf);
|
|
};
|
|
|
|
class STriangle {
|
|
public:
|
|
int tag;
|
|
STriMeta meta;
|
|
Vector a, b, c;
|
|
Vector an, bn, cn;
|
|
|
|
static STriangle From(STriMeta meta, Vector a, Vector b, Vector c);
|
|
Vector Normal(void);
|
|
void FlipNormal(void);
|
|
double MinAltitude(void);
|
|
int WindingNumberForPoint(Vector p);
|
|
bool ContainsPoint(Vector p);
|
|
bool ContainsPointProjd(Vector n, Vector p);
|
|
};
|
|
|
|
class SBsp2 {
|
|
public:
|
|
Vector np; // normal to the plane
|
|
|
|
Vector no; // outer normal to the edge
|
|
double d;
|
|
SEdge edge;
|
|
|
|
SBsp2 *pos;
|
|
SBsp2 *neg;
|
|
|
|
SBsp2 *more;
|
|
|
|
enum { POS = 100, NEG = 101, COPLANAR = 200 };
|
|
void InsertTriangleHow(int how, STriangle *tr, SMesh *m, SBsp3 *bsp3);
|
|
void InsertTriangle(STriangle *tr, SMesh *m, SBsp3 *bsp3);
|
|
Vector IntersectionWith(Vector a, Vector b);
|
|
SBsp2 *InsertEdge(SEdge *nedge, Vector nnp, Vector out);
|
|
static SBsp2 *Alloc(void);
|
|
|
|
void DebugDraw(Vector n, double d);
|
|
};
|
|
|
|
class SBsp3 {
|
|
public:
|
|
Vector n;
|
|
double d;
|
|
|
|
STriangle tri;
|
|
SBsp3 *pos;
|
|
SBsp3 *neg;
|
|
|
|
SBsp3 *more;
|
|
|
|
SBsp2 *edges;
|
|
|
|
static SBsp3 *Alloc(void);
|
|
static SBsp3 *FromMesh(SMesh *m);
|
|
|
|
Vector IntersectionWith(Vector a, Vector b);
|
|
|
|
enum { POS = 100, NEG = 101, COPLANAR = 200 };
|
|
void InsertHow(int how, STriangle *str, SMesh *instead);
|
|
SBsp3 *Insert(STriangle *str, SMesh *instead);
|
|
|
|
void InsertConvexHow(int how, STriMeta meta, Vector *vertex, int n,
|
|
SMesh *instead);
|
|
SBsp3 *InsertConvex(STriMeta meta, Vector *vertex, int n, SMesh *instead);
|
|
|
|
void InsertInPlane(bool pos2, STriangle *tr, SMesh *m);
|
|
|
|
void GenerateInPaintOrder(SMesh *m);
|
|
|
|
void DebugDraw(void);
|
|
};
|
|
|
|
class SMesh {
|
|
public:
|
|
List<STriangle> l;
|
|
|
|
bool flipNormal;
|
|
bool keepCoplanar;
|
|
bool atLeastOneDiscarded;
|
|
|
|
void Clear(void);
|
|
void AddTriangle(STriangle *st);
|
|
void AddTriangle(STriMeta meta, Vector a, Vector b, Vector c);
|
|
void AddTriangle(STriMeta meta, Vector n, Vector a, Vector b, Vector c);
|
|
void DoBounding(Vector v, Vector *vmax, Vector *vmin);
|
|
void GetBounding(Vector *vmax, Vector *vmin);
|
|
|
|
void Simplify(int start);
|
|
|
|
void AddAgainstBsp(SMesh *srcm, SBsp3 *bsp3);
|
|
void MakeFromUnionOf(SMesh *a, SMesh *b);
|
|
void MakeFromDifferenceOf(SMesh *a, SMesh *b);
|
|
|
|
void MakeFromCopyOf(SMesh *a);
|
|
void MakeFromTransformationOf(SMesh *a,
|
|
Vector trans, Quaternion q, double scale);
|
|
void MakeFromAssemblyOf(SMesh *a, SMesh *b);
|
|
|
|
void MakeEdgesInPlaneInto(SEdgeList *sel, Vector n, double d);
|
|
void MakeEmphasizedEdgesInto(SEdgeList *sel);
|
|
|
|
bool IsEmpty(void);
|
|
void RemapFaces(Group *g, int remap);
|
|
|
|
uint32_t FirstIntersectionWith(Point2d mp);
|
|
};
|
|
|
|
// A linked list of triangles
|
|
class STriangleLl {
|
|
public:
|
|
STriangle *tri;
|
|
|
|
STriangleLl *next;
|
|
|
|
static STriangleLl *Alloc(void);
|
|
};
|
|
|
|
class SKdNode {
|
|
public:
|
|
int which; // whether c is x, y, or z
|
|
double c;
|
|
|
|
SKdNode *gt;
|
|
SKdNode *lt;
|
|
|
|
STriangleLl *tris;
|
|
|
|
static SKdNode *Alloc(void);
|
|
static SKdNode *From(SMesh *m);
|
|
static SKdNode *From(STriangleLl *tll);
|
|
|
|
void AddTriangle(STriangle *tr);
|
|
void MakeMeshInto(SMesh *m);
|
|
void ClearTags(void);
|
|
|
|
void FindEdgeOn(Vector a, Vector b, int *n, int cnt, bool coplanarIsInter,
|
|
bool *inter, bool *fwd,
|
|
uint32_t *face);
|
|
enum {
|
|
NAKED_OR_SELF_INTER_EDGES = 100,
|
|
SELF_INTER_EDGES = 200,
|
|
TURNING_EDGES = 300,
|
|
EMPHASIZED_EDGES = 400
|
|
};
|
|
void MakeCertainEdgesInto(SEdgeList *sel, int how, bool coplanarIsInter,
|
|
bool *inter, bool *leaky);
|
|
|
|
void OcclusionTestLine(SEdge orig, SEdgeList *sel, int cnt);
|
|
void SplitLinesAgainstTriangle(SEdgeList *sel, STriangle *tr);
|
|
|
|
void SnapToMesh(SMesh *m);
|
|
void SnapToVertex(Vector v, SMesh *extras);
|
|
};
|
|
|
|
#endif
|
|
|