-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathECAbstractConvexPolygon.cpp
More file actions
178 lines (141 loc) · 6.17 KB
/
ECAbstractConvexPolygon.cpp
File metadata and controls
178 lines (141 loc) · 6.17 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
//
// ECAbstractConvexPolygon.h
//
//
// Created by Yufeng Wu on 1/29/21.
//
//
#include "ECAbstractConvexPolygon.h"
#include <iostream>
using namespace std;
// Convex polygon on 2D plane: interface class
// Get bounding box (i.e. smallest rectangle contaiing the shape with sides parellel to axes) of the shape
// the left-upper corner of the window is (0,0)
void ECAbstractConvexPolygon::GetBoundingBox( double &xUpperLeft, double &yUpperLeft, double &xLowerRight, double &yLowerRight ) const {
// Check for empty list
if (listNodes.size() == 0) { xUpperLeft = yUpperLeft = xLowerRight = yLowerRight = 0; return; }
// Find max/min X and Y values
double xInit = listNodes[0].xCoord;
double yInit = listNodes[0].yCoord;
double xMax = xInit,yMax = yInit,xMin = xInit,yMin = yInit;
for (EC2DPoint p : listNodes) {
if (p.xCoord > xMax) { xMax = p.xCoord; }
if (p.xCoord < xMin) { xMin = p.xCoord; }
if (p.yCoord > yMax) { yMax = p.yCoord; }
if (p.yCoord < yMin) { yMin = p.yCoord; }
}
// Upper left is actually lower left if left-upper window is (0,0)
// Lower right is actually upper right
// Upper left: (xMin, yMax) (xMax,yMax)
// Lower left : (xMin, yMin) (xMax,yMin)
xUpperLeft = xMin;
xLowerRight = xMax;
yUpperLeft = yMin;
yLowerRight = yMax;
}
// find out the center of the shape and store in (xc,yc); round down to the closest integer
void ECAbstractConvexPolygon::GetCenter(double &xc, double &yc) const {
double x1, x2, y1, y2;
GetBoundingBox(x1,y1,x2,y2);
xc = (x1 + x2) / 2;
yc = (y1 + y2) / 2;
}
bool ECAbstractConvexPolygon::IsIntersecting(const ECAbstractConvexPolygon &rhs) const {
// If either polygon has less than 3 nodes, its not a polygon
// Test cases indicate returning true in that case
if (listNodes.size() < 3 || rhs.listNodes.size() < 3) { return true; }
// If point in this is inside rhs, they must intersect
for (EC2DPoint p : listNodes) {
if (rhs.IsPointInside(p) == true) { cout << p << " is inside" << endl; return true; }
}
// If point in rhs is inside this, they must intersect
for (EC2DPoint p : rhs.listNodes) {
if (IsPointInside(p) == true) { cout << p << " is inside" << endl; return true; }
}
// Create vector of all line segments making up this
vector<ECLineSegment> poly1Lines;
for (int i = 0; i < listNodes.size(); i++) {
EC2DPoint p1 = listNodes[i];
EC2DPoint p2 = listNodes[(i+1)%listNodes.size()];
ECLineSegment seg(p1,p2);
poly1Lines.push_back(seg);
}
// Create vector of all line segments making up rhs
vector<ECLineSegment> poly2Lines;
for (int i = 0; i < rhs.listNodes.size(); i++) {
EC2DPoint p1 = rhs.listNodes[i];
EC2DPoint p2 = rhs.listNodes[(i+1)%rhs.listNodes.size()];
ECLineSegment seg(p1,p2);
poly2Lines.push_back(seg);
}
// If any line segment from one polygon intersects with another, they must intersect
for (ECLineSegment seg1 : poly1Lines) {
for (ECLineSegment seg2: poly2Lines) {
if (seg1.IsIntersect(seg2)) { return true; }
}
}
// If lines are not inersecting, and no points are within another polygon, the polygons do not intersect
return false;
}
bool ECAbstractConvexPolygon::IsPointInside(const EC2DPoint &pt) const {
// If the point is a vertex, obviously it is inside that counts as inside
for (auto p : listNodes) {
if (pt == p) { return true; }
}
// Get the max and min x and y coordinate of the polygon
double xInit = listNodes[0].xCoord;
double yInit = listNodes[0].yCoord;
double xMax = xInit,yMax = yInit,xMin = xInit,yMin = yInit;
for (EC2DPoint p : listNodes) {
if (p.xCoord > xMax) { xMax = p.xCoord; }
if (p.xCoord < xMin) { xMin = p.xCoord; }
if (p.yCoord > yMax) { yMax = p.yCoord; }
if (p.yCoord < yMin) { yMin = p.yCoord; }
}
// If the x or y coordinate of the point exceeds or does not reach any of the x or y min/maxes, it is outside the polygon
if (pt.xCoord < xMin || pt.xCoord > xMax || pt.yCoord > yMax || pt.yCoord < yMin) {
return false;
}
// Create a point far left and far right on same y axis as the point to represent an "infinite" line
EC2DPoint p1(-9999, pt.yCoord);
EC2DPoint p2(9999, pt.yCoord);
ECLineSegment infLine(p1,p2);
// Create vector of all line segments that make up polygon
vector<ECLineSegment> polyLines;
for (int i = 0; i < listNodes.size(); i++) {
EC2DPoint p1 = listNodes[i];
EC2DPoint p2 = listNodes[(i+1)%listNodes.size()];
ECLineSegment seg(p1,p2);
polyLines.push_back(seg);
}
// Search for line segments that intersect with the "infinite" line extended from the point, add to a vector to test
vector<ECLineSegment> linesToTest;
for (ECLineSegment seg : polyLines) {
if (seg.IsIntersect(infLine)) {
linesToTest.push_back(seg);
}
}
// Test line segments using the math this guy describes
// https://towardsdatascience.com/is-the-point-inside-the-polygon-574b86472119
int turns = 0;
for (ECLineSegment seg : linesToTest) {
EC2DPoint pA = seg.pStart;
EC2DPoint pB = seg.pEnd;
double result = (pt.yCoord - pA.yCoord) * (pB.xCoord - pA.xCoord)
- (pt.xCoord - pA.xCoord) * (pB.yCoord - pA.yCoord);
// If the result of that calculation is less than 0, representing the point is to the left of the line, decrement turns
// If its greater than 0, representing point is to the right, increment turns
if (result > 0) { turns--;}
if (result < 0) { turns++; }
}
// If the number of turns is 0, the point is outside the polygon
// If its not 0, it is inside the polygon
if (turns == 0) { return false; } else { return true; }
}
bool ECAbstractConvexPolygon::IsContaining(const ECAbstractConvexPolygon &rhs) const {
// If any point in rhs is not within this, the polygon itself cannot be within it either
for (EC2DPoint pt : rhs.listNodes) {
if (!IsPointInside(pt)) { return false; }
}
return true;
}