-
Notifications
You must be signed in to change notification settings - Fork 0
/
geometry.h
306 lines (251 loc) · 10.5 KB
/
geometry.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
// geometry.h : interface file
//
// General purpose computational geometry wrapper class for MS VC++
//
// Author : Chris Maunder (cmaunder@mail.com)
// Date : First written sometime in 1998
//
// Copyright © Chris Maunder 1998-2002. All Rights Reserved
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed unmodified by any means PROVIDING it is
// not sold for profit without the authors written consent, and
// providing that this notice and the authors name is included. If
// the source code in this file is used in any commercial application
// then a simple email would be nice.
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability for any damage, in any form, caused
// by this code. Use it at your own risk and as with all code expect bugs!
// It's been tested but I'm not perfect.
//
// Please use and enjoy. Please let me know of any bugs/mods/improvements
// that you have found/implemented and I will fix/incorporate them into this
// file.
#ifndef GEOMETRY_H
#define GEOMETRY_H
#include <math.h>
#include <float.h>
/////////////////////////////////////////////////////////////////////////////////////////
// Specify what sort of floating point data type to use
//#define USING_DOUBLE // double precision floating point (64 bit)
#define USING_FLOAT // single precision floating point (32 bit)
#if defined(USING_DOUBLE)
#define DEG2RAD 0.0175 // converts degrees to radians
#define RAD2DEG 57.2957795 // ...and back again.
#define EPSILON 0.001 // used for REAL comparisons and stuff
#define PI 3.1415926535898 // pi
#define HALF_PI PI/2.0 // pi/2
#define TWO_PI PI*2.0 // pi*2
#define REAL_MAX DBL_MAX // Max number that can be represented.
#define REAL double
#define D2Real(x) (x) // double => REAL
#define F2Real(x) (x) // float => REAL
#define Real2D(x) (x) // REAL => double
#define Real2F(x) ((float)(x)) // REAL => float
#define Int2Real(x) ((double)(x)) // int => REAL
//#define Real2Int(x) ((int)(x)) // REAL => int
inline int Real2Int(double d0) // REAL => int (faster than a (cast)).
{
static double intScale = 6755399441055744.0;
static double d1;
static int *pInt = (int*) &d1;
d1 = d0 + intScale;
return *pInt;
}
#elif defined(USING_FLOAT)
#define DEG2RAD 0.0175f // converts degrees to radians
#define RAD2DEG 57.2957795f // ...and back again.
#define EPSILON 0.001f // used for REAL comparisons and stuff
#define PI 3.1415926535898f // pi
#define HALF_PI PI/2.0f // pi/2
#define TWO_PI PI*2.0f // pi*2
#define REAL_MAX FLT_MAX
#define REAL float
#define D2Real(x) ((float)(x)) // double => REAL
#define F2Real(x) (x) // float => REAL
#define Real2D(x) (x) // REAL => double
#define Real2F(x) (x) // REAL => float
#define Int2Real(x) ((float)(x)) // int => REAL
//#define Real2Int(d) ((int)(d)) // REAL => int
// First, some magic, borrowed from Terje Mathisen, to omit
// compiler drowsiness when converting float to int:
#pragma optimize( "", off )
inline long Real2Int(float d)
{
const double S = 65536.0;
const double Magic = (((S * S * 16) + (S*.5)) * S);
double dtemp = Magic + d;
return (*(long *)&dtemp) - 0x80000000;
}
#pragma optimize( "", on )
#elif
#error Must select USING_DOUBLE or USING_FLOAT in geometry.h
#endif
/////////////////////////////////////////////////////////////////////////////////////////
#define ABS(x) ((x) < D2Real(0.0) ? -(x) : (x))
class C3Point {
// Attributes
public:
REAL x,y,z;
//Operations
public:
C3Point() {}
C3Point(double a, double b, double c) { x = D2Real(a); y = D2Real(b); z = D2Real(c); }
REAL Length2() { return (x*x + y*y + z*z); }
REAL Length() { return D2Real(sqrt(x*x + y*y + z*z)); }
void Scale(REAL factor) { x *= factor; y *= factor; z *= factor; }
void Normalise();
void operator=(C3Point& P) { x = P.x; y = P.y; z = P.z; } // assign
C3Point operator-(C3Point P) { return C3Point(x-P.x, y-P.y, z-P.z); } // subtract
C3Point operator-() { return C3Point(-x, -y, -z); } // unary -
C3Point operator+(C3Point P) { return C3Point(x+P.x, y+P.y, z+P.z); } // add
C3Point operator+=(C3Point P) { x += P.x; y += P.y; z += P.z; return *this; } // add +=
C3Point operator-=(C3Point P) { x -= P.x; y -= P.y; z -= P.z; return *this; } // subtract -=
REAL operator*(C3Point P) { return x*P.x + y*P.y + z*P.z; } // dot product
C3Point operator*(REAL f) { return C3Point(x*f, y*f, z*f); } // scalar product
C3Point operator/(REAL f) { return C3Point(x/f, y/f, z/f); } // scalar div
C3Point operator*=(REAL f) { x *= f; y *= f; z *= f; return *this; } // scalar mult *=
C3Point operator/=(REAL f) { x /= f; y /= f; z /= f; return *this; } // scalar div /=
C3Point operator^(C3Point P) { return C3Point(y*P.z-P.y*z, P.x*z-x*P.z, x*P.y-P.x*y); } // cross product
BOOL operator==(C3Point& P); // is equal to?
BOOL operator!=(C3Point& P) { return !(*this == P); } // is not equal to?
};
typedef struct {
REAL x,y;
} C2Point;
#define VECTOR C3Point
class CPolygon // : public CObject
{
// Attributes
private:
int m_n; // Number of vertices
C3Point *m_point; // array of C3Points defining vertices
// Operations
public:
CPolygon();
CPolygon(int);
~CPolygon();
BOOL Closed(); // Is the polygon closed?
int GetSize() { return m_n; } // Number of points
BOOL InSpan(int, int, int); // is point in span of polygon?
BOOL InSpanProper(int, int, int); // is point in span of polygon?
BOOL PointIn(C3Point P); // Is point inside polygon?
BOOL SetSize(int); // Change size of polygon
void RemoveAll() { SetSize(0); } // Empty polygon of all points
BOOL Trim(int, int); // Trim off ends of polygon
BOOL Close(); // Make polygon closed
BOOL Add(C3Point); // Add point to polygon
BOOL SetAt(int nPos, C3Point& p); // set point nPos as p
void Delete(int); // Delete a vertex
BOOL InsertAt(int nPosition, C3Point P); // insert point P at pos nPosition (0..m_n-1)
void FreeExtra(); // Free extra memory left over after deletes
int PointSeparation(int Point1, int Point2); // Distance (in pts) between 2 points
void Rationalise(int); // Combine colinear edges
REAL SegmentLength(int,int); // Length of a segment of the polygon
C3Point GetClosestPoint(C3Point p, int *nIndex = NULL);
REAL Area(); // returns polygon area
C3Point Centroid(); // Calculate centroid of polygon
BOOL GetAttributes(REAL *pArea, C3Point *pCentroid, C3Point *pNorm,
REAL *pSlope, REAL *pAspect);
BOOL Diagonal(int, int); // Is edge a diagonal?
virtual void Translate(VECTOR v); // Translate polygon
BOOL Intersected(C3Point& p1, C3Point& p2); // Does p1-p2 intersect polygon?
BOOL IntersectedProp(C3Point& p1, C3Point& p2); // Does p1-p2 intersect polygon properly?
BOOL Triangulate(CPolygon*); // Triangulate: Ear clip
BOOL CPTriangulate(CPolygon*, C3Point); // Central point triangulation
BOOL DelauneyTri(CPolygon*); // Triangulate: Delauney
// Load polygon from X-Y or X-Y-Z data file
BOOL LoadXY(LPCTSTR Filename, REAL Zdefault = D2Real(0.0));
BOOL LoadXY(FILE* fp, REAL Zdefault = D2Real(0.0));
BOOL LoadXYZ(LPCTSTR Filename, BOOL bWarn = TRUE);
BOOL LoadXYZ(FILE* fp);
BOOL Save(LPCTSTR Filename, BOOL bAsPoints = FALSE, BOOL bWarn = TRUE);
void NaturalSpline(double*& b, double*& c, double*& d);
REAL Curvature(int i);
REAL Curvature(int nIndex, int nSampleSize);
C3Point& operator[](int index);
C3Point& Point(int index);
void operator=(CPolygon& P);
private:
BOOL Diagonalie(int, int);
BOOL InCone(int, int);
};
inline REAL Dot(C3Point V1, C3Point V2) { return V1.x*V2.x + V1.y*V2.y + V1.z*V2.z; }
inline C3Point Cross(C3Point p1, C3Point p2) { return C3Point(p1.y*p2.z - p2.y*p1.z,
p2.x*p1.z - p1.x*p2.z,
p1.x*p2.y - p2.x*p1.y); }
BOOL Xor(BOOL x, BOOL y);
C3Point GetClosestPoint2D(C3Point& start, C3Point& end, C3Point& P);
REAL Angle(C3Point, C3Point, C3Point);
REAL Angle(VECTOR v, VECTOR u);
REAL TriArea2(C3Point, C3Point, C3Point);
REAL TriArea2(VECTOR u, VECTOR v);
BOOL IntersectProp(C3Point, C3Point, C3Point, C3Point);
BOOL Left(C3Point, C3Point, C3Point);
BOOL LeftOn(C3Point, C3Point, C3Point);
BOOL Colinear(C3Point, C3Point, C3Point);
BOOL Between(C3Point, C3Point, C3Point);
BOOL Intersect(C3Point, C3Point, C3Point, C3Point);
VECTOR Normal(C3Point p1, C3Point p2, C3Point p3);
VECTOR Scale(REAL factor, VECTOR v);
///////////////////////////////////////////////////////////////////////////////////////////
// inline functions
inline C3Point& CPolygon::operator[](int index)
{
ASSERT(index >= 0 && index < m_n);
return m_point[index];
}
inline C3Point& CPolygon::Point(int index)
{
ASSERT(index >= 0 && index < m_n);
return m_point[index];
}
inline BOOL CPolygon::SetAt(int nPos, C3Point& p)
{
if (nPos < 0 || nPos >= m_n) return FALSE;
m_point[nPos] = p;
return TRUE;
}
inline BOOL Left(C3Point a, C3Point b, C3Point c)
// Returns true iff c is strictly to the left of the directed line through a to b.
{
//return TriArea2( a, b, c ) > D2Real(0.0); // inefficient
REAL CrossZ = (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
return (CrossZ > D2Real(0.0));
}
inline BOOL LeftOn(C3Point a, C3Point b, C3Point c)
{
//return TriArea2(a, b, c) >= D2Real(0.0); // inefficient
REAL CrossZ = (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
return (CrossZ >= D2Real(0.0));
}
inline BOOL Colinear(C3Point a, C3Point b, C3Point c)
{
// return (ABS(TriArea2(a, b, c)) < EPSILON); // inefficient
REAL CrossZ = (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
return (ABS(CrossZ) < EPSILON);
}
inline BOOL CPolygon::IntersectedProp(C3Point& p1, C3Point& p2)
{
REAL Length = (p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y);
for (int i = 0; i < m_n-1; i++) {
REAL Distance = (p1.x - m_point[i].x)*(p1.x - m_point[i].x)
+ (p1.y - m_point[i].y)*(p1.y - m_point[i].y);
if (Distance > Length) continue;
if (IntersectProp(p1,p2, m_point[i], m_point[i+1])) return TRUE;
}
return FALSE;
}
inline BOOL CPolygon::Intersected(C3Point& p1, C3Point& p2)
{
REAL Length = (p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y);
for (int i = 0; i < m_n-1; i++) {
REAL Distance = (p1.x - m_point[i].x)*(p1.x - m_point[i].x)
+ (p1.y - m_point[i].y)*(p1.y - m_point[i].y);
if (Distance > Length) continue;
if (Intersect(p1,p2, m_point[i], m_point[i+1])) return TRUE;
}
return FALSE;
}
#endif