-
Notifications
You must be signed in to change notification settings - Fork 146
Expand file tree
/
Copy pathgeometry.h
More file actions
343 lines (329 loc) · 10.8 KB
/
Copy pathgeometry.h
File metadata and controls
343 lines (329 loc) · 10.8 KB
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
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
#ifndef _GEOMETRY_H_
#define _GEOMETRY_H_
#define _USE_MATH_DEFINES
#include <iostream>
#include <cmath>
#include <algorithm>
/************************************************************************/
/* CVector */
/************************************************************************/
class CVector {
public:
CVector() : _x(0), _y(0) {}
CVector(double x, double y) : _x(x), _y(y) {}
CVector(const CVector& v) : _x(v.x()), _y(v.y()) {}
bool setVector(double x, double y) {
_x = x;
_y = y;
return true;
}
double mod() const {
return std::sqrt(_x * _x + _y * _y);
}
double mod2() const {
return (_x * _x + _y * _y);
}
double dir() const {
return std::atan2(y(), x());
}
double theta(const CVector& v) {
// the angle between this vector and vector v
double _theta;
_theta = std::atan2(_y, _x) - std::atan2(v.y(), v.x());
if (_theta > M_PI) return _theta - 2 * M_PI;
if (_theta < -M_PI) return _theta + 2 * M_PI;
return _theta;
}
CVector rotate(double angle) const;
CVector unit() const {
CVector vector(_x, _y);
if (vector.mod() < 1e-8) {
return CVector(1, 0);
}
return CVector(vector.x() / vector.mod(),
vector.y() / vector.mod());
}
double x() const {
return _x;
}
double y() const {
return _y;
}
double value(double angle) const {
return mod() * std::cos(dir() - angle);
}
CVector operator +(const CVector& v) const {
return CVector(_x + v.x(), _y + v.y());
}
CVector operator -(const CVector& v) const {
return CVector(_x - v.x(), _y - v.y());
}
CVector operator *(double a) const {
return CVector(_x * a, _y * a);
}
double operator *(CVector b) const {
// dot product
return double(_x * b.x() + _y * b.y());
}
double operator ^(CVector b) const {
// length of cross product, signed
return double(_x * b.y() - _y * b.x());
}
CVector operator ^(double b) const {
// cross product with a verticle vector of length b
return CVector(copysign(_y, b), -copysign(_x, b));
}
CVector operator /(double a) const {
return CVector(_x / a, _y / a);
}
CVector operator -() const {
return CVector(-1 * _x, -1 * _y);
}
friend std::ostream& operator <<(std::ostream& os, const CVector& v) {
return os << "(" << v.x() << ":" << v.y() << ")";
}
private:
double _x, _y;
};
/************************************************************************/
/* CGeoPoint */
/************************************************************************/
class CGeoPoint {
public:
CGeoPoint() : _x(0), _y(0) {}
~CGeoPoint() {}
CGeoPoint(double x, double y) : _x(x), _y(y) {}
CGeoPoint(const CGeoPoint& p) : _x(p.x()), _y(p.y()) {}
bool operator==(const CGeoPoint& rhs) {
return ((this->x() == rhs.x()) && (this->y() == rhs.y()));
}
double x() const {
return _x;
}
double y() const {
return _y;
}
void setX(double x) {
_x = x;
}
void setY(double y) {
_y = y;
}
bool fill(double x, double y) {
_x = x;
_y = y;
return true;
}
double dist(const CGeoPoint& p) const {
return CVector(p - CGeoPoint(_x, _y)).mod();
}
double dist2(const CGeoPoint& p) const {
return CVector(p - CGeoPoint(_x, _y)).mod2();
}
CGeoPoint operator+(const CVector& v) const {
return CGeoPoint(_x + v.x(), _y + v.y());
}
CGeoPoint operator*(const double& a) const {
return CGeoPoint(_x * a, _y * a);
}
CVector operator-(const CGeoPoint& p) const {
return CVector(_x - p.x(), _y - p.y());
}
CGeoPoint midPoint(const CGeoPoint& p) const {
return CGeoPoint((_x + p.x()) / 2, (_y + p.y()) / 2);
}
friend std::ostream& operator <<(std::ostream& os, const CGeoPoint& v) {
return os << "(" << v.x() << ":" << v.y() << ")";
}
private:
double _x, _y;
};
/************************************************************************/
/* CGeoLine */
/************************************************************************/
class CGeoLine {
public:
CGeoLine() {}
CGeoLine(const CGeoPoint& p1, const CGeoPoint& p2) : _p1(p1), _p2(p2) {
calABC();
}
CGeoLine(const CGeoPoint& p, double angle) : _p1(p), _p2(p.x() + std::cos(angle), p.y() + std::sin(angle)) {
calABC();
}
void calABC() {
if (_p1.y() == _p2.y()) {
_a = 0;
_b = 1;
_c = -1.0 * _p1.y();
} else {
_a = 1;
_b = -1.0 * (_p1.x() - _p2.x()) / (_p1.y() - _p2.y());
_c = (_p1.x() * _p2.y() - _p1.y() * _p2.x()) / (_p1.y() - _p2.y());
}
}
CGeoPoint projection(const CGeoPoint& p) const {
if (_p2.x() == _p1.x()) {
return CGeoPoint(_p1.x(), p.y());
} else {
double k = (_p2.y() - _p1.y()) / (_p2.x() - _p1.x());
// equation: y = k* ( x - pt1.x) + pt1.y
// equation of perpendicular line: y = (-1/k) * (x - p.x) + p.y
// solve the two equations
double x = (k * k * _p1.x() + k * (p.y() - _p1.y()) + p.x()) / (k * k + 1);
double y = k * (x - _p1.x()) + _p1.y();
return CGeoPoint(x, y);
}
}
CGeoPoint point1() const {
return _p1;
}
CGeoPoint point2() const {
return _p2;
}
bool operator==(const CGeoLine& rhs) {
return ((this->point1().x() == rhs.point1().x()) && (this->point1().y() == rhs.point1().y())
&& (this->point2().x() == rhs.point2().x()) && (this->point2().y() == rhs.point2().y()));
}
const double& a() const {
return _a;
}
const double& b() const {
return _b;
}
const double& c() const {
return _c;
}
private:
CGeoPoint _p1;
CGeoPoint _p2;
// a*x+b*y+c=0, a>=0
double _a;
double _b;
double _c;
};
class CGeoLineLineIntersection {
public:
CGeoLineLineIntersection(const CGeoLine& line_1, const CGeoLine& line_2);
bool Intersectant() const {
return _intersectant;
}
const CGeoPoint& IntersectPoint() const {
return _point;
}
private:
bool _intersectant;
CGeoPoint _point;
};
/************************************************************************/
/* CGeoSegment */
/************************************************************************/
class CGeoSegment : public CGeoLine {
public:
CGeoSegment() {}
CGeoSegment(const CGeoPoint& p1, const CGeoPoint& p2) : CGeoLine(p1, p2), _start(p1), _end(p2) {
_compareX = std::abs(p1.x() - p2.x()) > std::abs(p1.y() - p2.y());
_center = CGeoPoint((p1.x() + p2.x()) / 2, (p1.y() + p2.y()) / 2);
}
bool IsPointOnLineOnSegment(const CGeoPoint& p) const {
if (_compareX) {
return p.x() > (std::min)(_start.x(), _end.x()) && p.x() < (std::max)(_start.x(), _end.x());
}
return p.y() > (std::min)(_start.y(), _end.y()) && p.y() < (std::max)(_start.y(), _end.y());
}
bool IsSegmentsIntersect(const CGeoSegment& p) const {
CGeoLineLineIntersection tmpInter(*this, p);
CGeoPoint interPoint = tmpInter.IntersectPoint();
return (IsPointOnLineOnSegment(interPoint) && p.IsPointOnLineOnSegment(interPoint));
}
CGeoPoint segmentsIntersectPoint(const CGeoSegment& p) const {
CGeoLineLineIntersection tmpInter(*this, p);
CGeoPoint interPoint = tmpInter.IntersectPoint();
if (IsPointOnLineOnSegment(interPoint) && p.IsPointOnLineOnSegment(interPoint))
return interPoint;
else return CGeoPoint(9999, 9999);
}
double dist2Point(const CGeoPoint& p) {
CGeoPoint tmpProj = projection(p);
if (IsPointOnLineOnSegment(tmpProj)) return p.dist(tmpProj);
else return std::min(_start.dist(p), _end.dist(p));
}
double dist2Segment(const CGeoSegment& s) {
if (IsSegmentsIntersect(s)) return 0;
else return std::min(dist2Point(s.point1()), dist2Point(s.point2()));
}
const CGeoPoint& start() const {
return _start;
}
const CGeoPoint& end() const {
return _end;
}
const CGeoPoint& center() {
return _center;
}
private:
CGeoPoint _start;
CGeoPoint _end;
CGeoPoint _center;
bool _compareX;
};
/************************************************************************/
/* CGeoShape */
/************************************************************************/
class CGeoShape {
public:
virtual ~CGeoShape() { }
virtual bool HasPoint(const CGeoPoint& p) const = 0;
};
/************************************************************************/
/* CGeoQuadrilateral */
/************************************************************************/
class CGeoQuadrilateral : public CGeoShape {
public:
CGeoQuadrilateral() :CGeoQuadrilateral(CGeoPoint(), CGeoPoint(), CGeoPoint(), CGeoPoint()) {}
CGeoQuadrilateral(const CGeoPoint p1, const CGeoPoint p2, const CGeoPoint p3, const CGeoPoint p4);
virtual bool HasPoint(const CGeoPoint& p) const;
CGeoPoint _point[4];
CGeoPoint _center;
};
/************************************************************************/
/* CGeoCircle */
/************************************************************************/
class CGeoCirlce : public CGeoShape {
public:
CGeoCirlce() { }
CGeoCirlce(const CGeoPoint& c, double r) : _radius(r), _center(c) { }
virtual bool HasPoint(const CGeoPoint& p) const;
CGeoPoint Center() const {
return _center;
}
double Radius() const {
return _radius;
}
double Radius2() const {
return _radius * _radius;
}
private:
double _radius;
CGeoPoint _center;
};
/************************************************************************/
/* CGeoCircleTangent */
/************************************************************************/
class CGeoCircleTangent {
public:
CGeoCircleTangent(const CGeoCirlce& circle, const CGeoPoint& p);
const CGeoPoint& point1() const {
return _point1;
}
const CGeoPoint& point2() const {
return _point2;
}
int size() {
return tangent_size;
}
private:
int tangent_size;
CGeoPoint _point1;
CGeoPoint _point2;
};
#endif