ZLayout EDA Library v1.0.0
Advanced Electronic Design Automation Layout Library with Bilingual Documentation
Loading...
Searching...
No Matches
polygon.cpp
Go to the documentation of this file.
1
5
6#define _USE_MATH_DEFINES
8#include <algorithm>
9#include <cmath>
10#include <limits>
11#include <sstream>
12
13// Fallback for M_PI if not defined (MSVC 2012 compatibility)
14#ifndef M_PI
15#define M_PI 3.14159265358979323846
16#endif
17
18namespace zlayout {
19namespace geometry {
20
21// Constructor implementations
22Polygon::Polygon(const std::vector<Point>& vertices) : vertices(vertices) {}
23
24Polygon::Polygon(std::initializer_list<Point> vertices) : vertices(vertices) {}
25
26// Basic operators
27bool Polygon::operator==(const Polygon& other) const {
28 return vertices == other.vertices;
29}
30
31bool Polygon::operator!=(const Polygon& other) const {
32 return !(*this == other);
33}
34
35// Basic properties
36std::vector<std::pair<Point, Point>> Polygon::edges() const {
37 std::vector<std::pair<Point, Point>> edge_list;
38 if (vertices.size() < 2) return edge_list;
39
40 for (size_t i = 0; i < vertices.size(); ++i) {
41 size_t next = (i + 1) % vertices.size();
42 edge_list.emplace_back(vertices[i], vertices[next]);
43 }
44 return edge_list;
45}
46
47double Polygon::area() const {
48 return std::abs(signed_area());
49}
50
51double Polygon::signed_area() const {
52 if (vertices.size() < 3) return 0.0;
53
54 double area = 0.0;
55 for (size_t i = 0; i < vertices.size(); ++i) {
56 size_t next = (i + 1) % vertices.size();
57 area += vertices[i].x * vertices[next].y - vertices[next].x * vertices[i].y;
58 }
59 return area / 2.0;
60}
61
62double Polygon::perimeter() const {
63 if (vertices.size() < 2) return 0.0;
64
65 double perimeter = 0.0;
66 for (size_t i = 0; i < vertices.size(); ++i) {
67 size_t next = (i + 1) % vertices.size();
68 perimeter += vertices[i].distance_to(vertices[next]);
69 }
70 return perimeter;
71}
72
74 if (vertices.empty()) return Point(0, 0);
75
76 double cx = 0.0, cy = 0.0;
77 for (const auto& vertex : vertices) {
78 cx += vertex.x;
79 cy += vertex.y;
80 }
81 return Point(cx / vertices.size(), cy / vertices.size());
82}
83
85 if (vertices.empty()) return Rectangle(0, 0, 0, 0);
86
87 double min_x = vertices[0].x, max_x = vertices[0].x;
88 double min_y = vertices[0].y, max_y = vertices[0].y;
89
90 for (const auto& vertex : vertices) {
91 min_x = std::min(min_x, vertex.x);
92 max_x = std::max(max_x, vertex.x);
93 min_y = std::min(min_y, vertex.y);
94 max_y = std::max(max_y, vertex.y);
95 }
96
97 return Rectangle(min_x, min_y, max_x - min_x, max_y - min_y);
98}
99
100// Geometric properties
101bool Polygon::is_convex() const {
102 if (vertices.size() < 3) return false;
103
104 bool sign_positive = false;
105 bool sign_negative = false;
106
107 for (size_t i = 0; i < vertices.size(); ++i) {
108 size_t j = (i + 1) % vertices.size();
109 size_t k = (i + 2) % vertices.size();
110
111 Point v1 = vertices[j] - vertices[i];
112 Point v2 = vertices[k] - vertices[j];
113 double cross = v1.x * v2.y - v1.y * v2.x;
114
115 if (cross > Point::TOLERANCE) sign_positive = true;
116 else if (cross < -Point::TOLERANCE) sign_negative = true;
117
118 if (sign_positive && sign_negative) return false;
119 }
120
121 return true;
122}
123
125 return signed_area() < 0.0;
126}
127
128bool Polygon::is_simple() const {
129 if (vertices.size() < 3) return true;
130
131 auto edge_list = edges();
132 for (size_t i = 0; i < edge_list.size(); ++i) {
133 for (size_t j = i + 2; j < edge_list.size(); ++j) {
134 if (i == 0 && j == edge_list.size() - 1) continue; // Skip adjacent edges
135
136 if (segments_intersect(edge_list[i].first, edge_list[i].second,
137 edge_list[j].first, edge_list[j].second)) {
138 return false;
139 }
140 }
141 }
142 return true;
143}
144
145// Point containment
146bool Polygon::contains_point(const Point& point) const {
147 if (vertices.size() < 3) return false;
148
149 bool inside = false;
150 size_t j = vertices.size() - 1;
151
152 for (size_t i = 0; i < vertices.size(); ++i) {
153 if (((vertices[i].y > point.y) != (vertices[j].y > point.y)) &&
154 (point.x < (vertices[j].x - vertices[i].x) * (point.y - vertices[i].y) /
155 (vertices[j].y - vertices[i].y) + vertices[i].x)) {
156 inside = !inside;
157 }
158 j = i;
159 }
160
161 return inside;
162}
163
164bool Polygon::point_on_boundary(const Point& point, double tolerance) const {
165 auto edge_list = edges();
166 for (const auto& edge : edge_list) {
167 if (point.distance_to_line(edge.first, edge.second) < tolerance) {
168 return true;
169 }
170 }
171 return false;
172}
173
174// Sharp angle detection
175std::vector<size_t> Polygon::get_sharp_angles(double threshold_degrees) const {
176 std::vector<size_t> sharp_angles;
177 if (vertices.size() < 3) return sharp_angles;
178
179 for (size_t i = 0; i < vertices.size(); ++i) {
180 double angle = vertex_angle(i);
181 if (angle < threshold_degrees) {
182 sharp_angles.push_back(i);
183 }
184 }
185
186 return sharp_angles;
187}
188
189double Polygon::vertex_angle(size_t vertex_index) const {
190 if (vertices.size() < 3 || vertex_index >= vertices.size()) return 0.0;
191
192 size_t prev = (vertex_index + vertices.size() - 1) % vertices.size();
193 size_t next = (vertex_index + 1) % vertices.size();
194
195 Point v1 = vertices[prev] - vertices[vertex_index];
196 Point v2 = vertices[next] - vertices[vertex_index];
197
198 double dot = v1.x * v2.x + v1.y * v2.y;
199 double mag1 = std::sqrt(v1.x * v1.x + v1.y * v1.y);
200 double mag2 = std::sqrt(v2.x * v2.x + v2.y * v2.y);
201
202 if (mag1 < Point::TOLERANCE || mag2 < Point::TOLERANCE) return 0.0;
203
204 double cos_angle = dot / (mag1 * mag2);
205 cos_angle = std::max(-1.0, std::min(1.0, cos_angle)); // Clamp to [-1, 1]
206
207 return std::acos(cos_angle) * 180.0 / M_PI;
208}
209
210std::vector<double> Polygon::all_vertex_angles() const {
211 std::vector<double> angles;
212 for (size_t i = 0; i < vertices.size(); ++i) {
213 angles.push_back(vertex_angle(i));
214 }
215 return angles;
216}
217
218// Distance calculations
219double Polygon::distance_to(const Polygon& other) const {
220 if (vertices.empty() || other.vertices.empty()) return 0.0;
221
222 double min_distance = std::numeric_limits<double>::max();
223
224 // Check distance from each vertex to other polygon
225 for (const auto& vertex : vertices) {
226 double dist = other.distance_to(vertex);
227 min_distance = std::min(min_distance, dist);
228 }
229
230 // Check distance from each vertex of other polygon to this polygon
231 for (const auto& vertex : other.vertices) {
232 double dist = distance_to(vertex);
233 min_distance = std::min(min_distance, dist);
234 }
235
236 return min_distance;
237}
238
239double Polygon::distance_to(const Point& point) const {
240 if (vertices.empty()) return 0.0;
241
242 if (contains_point(point)) return 0.0;
243
244 double min_distance = std::numeric_limits<double>::max();
245 auto edge_list = edges();
246
247 for (const auto& edge : edge_list) {
248 double dist = point.distance_to_line(edge.first, edge.second);
249 min_distance = std::min(min_distance, dist);
250 }
251
252 return min_distance;
253}
254
255double Polygon::distance_to_line(const Point& line_start, const Point& line_end) const {
256 double min_distance = std::numeric_limits<double>::max();
257
258 for (const auto& vertex : vertices) {
259 double dist = vertex.distance_to_line(line_start, line_end);
260 min_distance = std::min(min_distance, dist);
261 }
262
263 return min_distance;
264}
265
267 if (vertices.empty()) return Point(0, 0);
268
269 Point closest = vertices[0];
270 double min_distance = vertices[0].distance_to(point);
271
272 for (const auto& vertex : vertices) {
273 double dist = vertex.distance_to(point);
274 if (dist < min_distance) {
275 min_distance = dist;
276 closest = vertex;
277 }
278 }
279
280 return closest;
281}
282
283// Edge operations
284double Polygon::min_edge_distance_to(const Polygon& other) const {
285 auto this_edges = edges();
286 auto other_edges = other.edges();
287
288 double min_distance = std::numeric_limits<double>::max();
289
290 for (const auto& edge1 : this_edges) {
291 for (const auto& edge2 : other_edges) {
292 double dist = segment_to_segment_distance(
293 edge1.first, edge1.second, edge2.first, edge2.second);
294 min_distance = std::min(min_distance, dist);
295 }
296 }
297
298 return min_distance;
299}
300
301std::vector<std::tuple<Point, Point, double>> Polygon::find_narrow_regions(
302 const Polygon& other, double threshold_distance) const {
303
304 std::vector<std::tuple<Point, Point, double>> narrow_regions;
305 auto this_edges = edges();
306 auto other_edges = other.edges();
307
308 for (const auto& edge1 : this_edges) {
309 for (const auto& edge2 : other_edges) {
310 double dist = segment_to_segment_distance(
311 edge1.first, edge1.second, edge2.first, edge2.second);
312
313 if (dist < threshold_distance) {
314 Point closest1 = edge1.first; // Simplified - should find actual closest points
315 Point closest2 = edge2.first;
316 narrow_regions.emplace_back(closest1, closest2, dist);
317 }
318 }
319 }
320
321 return narrow_regions;
322}
323
324// Intersection detection
325bool Polygon::intersects(const Polygon& other) const {
326 auto this_edges = edges();
327 auto other_edges = other.edges();
328
329 for (const auto& edge1 : this_edges) {
330 for (const auto& edge2 : other_edges) {
331 if (segments_intersect(edge1.first, edge1.second,
332 edge2.first, edge2.second)) {
333 return true;
334 }
335 }
336 }
337
338 return false;
339}
340
341std::vector<Point> Polygon::intersection_points(const Polygon& other) const {
342 std::vector<Point> intersections;
343 auto this_edges = edges();
344 auto other_edges = other.edges();
345
346 for (const auto& edge1 : this_edges) {
347 for (const auto& edge2 : other_edges) {
348 bool intersects = false;
349 Point intersection = line_segment_intersection(
350 edge1.first, edge1.second, edge2.first, edge2.second, intersects);
351
352 if (intersects) {
353 intersections.push_back(intersection);
354 }
355 }
356 }
357
358 return intersections;
359}
360
362 auto edge_list = edges();
363
364 for (size_t i = 0; i < edge_list.size(); ++i) {
365 for (size_t j = i + 2; j < edge_list.size(); ++j) {
366 if (i == 0 && j == edge_list.size() - 1) continue; // Skip adjacent edges
367
368 if (segments_intersect(edge_list[i].first, edge_list[i].second,
369 edge_list[j].first, edge_list[j].second)) {
370 return true;
371 }
372 }
373 }
374
375 return false;
376}
377
378// Utility functions
379void Polygon::add_vertex(const Point& vertex) {
380 vertices.push_back(vertex);
381}
382
383void Polygon::insert_vertex(size_t index, const Point& vertex) {
384 if (index <= vertices.size()) {
385 vertices.insert(vertices.begin() + index, vertex);
386 }
387}
388
389void Polygon::remove_vertex(size_t index) {
390 if (index < vertices.size()) {
391 vertices.erase(vertices.begin() + index);
392 }
393}
394
395std::string Polygon::to_string() const {
396 std::stringstream ss;
397 ss << "Polygon[";
398 for (size_t i = 0; i < vertices.size(); ++i) {
399 if (i > 0) ss << ", ";
400 ss << vertices[i].to_string();
401 }
402 ss << "]";
403 return ss.str();
404}
405
406std::ostream& operator<<(std::ostream& os, const Polygon& polygon) {
407 return os << polygon.to_string();
408}
409
410// Static utility functions
412 const Point& seg1_start, const Point& seg1_end,
413 const Point& seg2_start, const Point& seg2_end) {
414
415 // Simplified implementation - return distance between midpoints
416 Point mid1((seg1_start.x + seg1_end.x) / 2, (seg1_start.y + seg1_end.y) / 2);
417 Point mid2((seg2_start.x + seg2_end.x) / 2, (seg2_start.y + seg2_end.y) / 2);
418 return mid1.distance_to(mid2);
419}
420
422 const Point& seg1_start, const Point& seg1_end,
423 const Point& seg2_start, const Point& seg2_end,
424 bool& intersects) {
425
426 intersects = false;
427
428 double x1 = seg1_start.x, y1 = seg1_start.y;
429 double x2 = seg1_end.x, y2 = seg1_end.y;
430 double x3 = seg2_start.x, y3 = seg2_start.y;
431 double x4 = seg2_end.x, y4 = seg2_end.y;
432
433 double denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
434 if (std::abs(denom) < Point::TOLERANCE) {
435 return Point(0, 0); // Parallel lines
436 }
437
438 double t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / denom;
439 double u = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) / denom;
440
441 if (t >= 0 && t <= 1 && u >= 0 && u <= 1) {
442 intersects = true;
443 return Point(x1 + t * (x2 - x1), y1 + t * (y2 - y1));
444 }
445
446 return Point(0, 0);
447}
448
450 const Point& seg1_start, const Point& seg1_end,
451 const Point& seg2_start, const Point& seg2_end) {
452
453 bool intersects = false;
454 line_segment_intersection(seg1_start, seg1_end, seg2_start, seg2_end, intersects);
455 return intersects;
456}
457
458// Hash function implementation
459std::size_t PolygonHash::operator()(const Polygon& polygon) const {
460 std::size_t hash = 0;
461 for (const auto& vertex : polygon.vertices) {
462 hash ^= std::hash<double>()(vertex.x) + std::hash<double>()(vertex.y) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
463 }
464 return hash;
465}
466
467// Global utility functions
468bool segments_intersect(const Point& seg1_start, const Point& seg1_end,
469 const Point& seg2_start, const Point& seg2_end) {
470 return Polygon::segments_intersect(seg1_start, seg1_end, seg2_start, seg2_end);
471}
472
473double angle_between_vectors(const Point& v1, const Point& v2) {
474 double dot = v1.x * v2.x + v1.y * v2.y;
475 double mag1 = std::sqrt(v1.x * v1.x + v1.y * v1.y);
476 double mag2 = std::sqrt(v2.x * v2.x + v2.y * v2.y);
477
478 if (mag1 < Point::TOLERANCE || mag2 < Point::TOLERANCE) return 0.0;
479
480 double cos_angle = dot / (mag1 * mag2);
481 cos_angle = std::max(-1.0, std::min(1.0, cos_angle)); // Clamp to [-1, 1]
482
483 return std::acos(cos_angle) * 180.0 / M_PI;
484}
485
486} // namespace geometry
487} // namespace zlayout
2D point with high-precision coordinates and utility methods
Definition point.hpp:23
double x
X coordinate.
Definition point.hpp:25
double distance_to_line(const Point &line_start, const Point &line_end) const
Calculate distance from this point to a line segment.
Definition point.cpp:68
static constexpr double TOLERANCE
Default precision tolerance for floating point comparisons.
Definition point.hpp:29
double y
Y coordinate.
Definition point.hpp:26
double distance_to(const Point &other) const
Calculate Euclidean distance to another point.
Definition point.cpp:56
Polygon class supporting both convex and concave polygons.
Definition polygon.hpp:25
bool operator==(const Polygon &other) const
Equality operator.
Definition polygon.cpp:27
std::vector< Point > intersection_points(const Polygon &other) const
Find intersection points between polygon edges.
Definition polygon.cpp:341
void remove_vertex(size_t index)
Remove vertex at specific index.
Definition polygon.cpp:389
std::vector< std::pair< Point, Point > > edges() const
Get polygon edges as pairs of consecutive vertices.
Definition polygon.cpp:36
static Point line_segment_intersection(const Point &seg1_start, const Point &seg1_end, const Point &seg2_start, const Point &seg2_end, bool &intersects)
Helper function to find intersection point of two line segments.
Definition polygon.cpp:421
bool point_on_boundary(const Point &point, double tolerance=Point::TOLERANCE) const
Check if point is on polygon boundary.
Definition polygon.cpp:164
double distance_to(const Polygon &other) const
Calculate minimum distance to another polygon.
Definition polygon.cpp:219
Rectangle bounding_box() const
Calculate axis-aligned bounding box.
Definition polygon.cpp:84
std::vector< double > all_vertex_angles() const
Get all vertex angles.
Definition polygon.cpp:210
bool operator!=(const Polygon &other) const
Inequality operator.
Definition polygon.cpp:31
std::vector< size_t > get_sharp_angles(double threshold_degrees=30.0) const
Find vertices with sharp angles.
Definition polygon.cpp:175
double vertex_angle(size_t vertex_index) const
Calculate angle at a specific vertex.
Definition polygon.cpp:189
static bool segments_intersect(const Point &seg1_start, const Point &seg1_end, const Point &seg2_start, const Point &seg2_end)
Helper function to check if two line segments intersect.
Definition polygon.cpp:449
Point centroid() const
Calculate polygon centroid.
Definition polygon.cpp:73
Point closest_point_to(const Point &point) const
Find closest point on polygon boundary to given point.
Definition polygon.cpp:266
bool intersects(const Polygon &other) const
Check if this polygon intersects with another polygon.
Definition polygon.cpp:325
std::string to_string() const
Get string representation.
Definition polygon.cpp:395
bool is_simple() const
Check if polygon is simple (no self-intersections)
Definition polygon.cpp:128
void insert_vertex(size_t index, const Point &vertex)
Insert vertex at specific index.
Definition polygon.cpp:383
double perimeter() const
Calculate polygon perimeter.
Definition polygon.cpp:62
std::vector< Point > vertices
Polygon vertices in order.
Definition polygon.hpp:27
std::vector< std::tuple< Point, Point, double > > find_narrow_regions(const Polygon &other, double threshold_distance) const
Find narrow regions where edges are too close.
Definition polygon.cpp:301
bool is_convex() const
Check if polygon is convex.
Definition polygon.cpp:101
bool is_clockwise() const
Check if polygon is clockwise oriented.
Definition polygon.cpp:124
double min_edge_distance_to(const Polygon &other) const
Calculate minimum distance between this polygon's edges and another polygon's edges.
Definition polygon.cpp:284
bool has_self_intersections() const
Check if polygon edges intersect (for self-intersection detection)
Definition polygon.cpp:361
double signed_area() const
Calculate signed area (preserves orientation)
Definition polygon.cpp:51
Polygon()=default
Default constructor - creates empty polygon.
void add_vertex(const Point &vertex)
Add vertex to polygon.
Definition polygon.cpp:379
double distance_to_line(const Point &line_start, const Point &line_end) const
Calculate minimum distance to a line segment.
Definition polygon.cpp:255
bool contains_point(const Point &point) const
Check if point is inside polygon (ray casting algorithm)
Definition polygon.cpp:146
double area() const
Calculate polygon area using shoelace formula.
Definition polygon.cpp:47
static double segment_to_segment_distance(const Point &seg1_start, const Point &seg1_end, const Point &seg2_start, const Point &seg2_end)
Helper function to calculate distance between two line segments.
Definition polygon.cpp:411
Axis-aligned rectangle for bounding boxes and simple EDA components.
Definition rectangle.hpp:26
std::ostream & operator<<(std::ostream &os, const Point &point)
Definition point.cpp:144
double angle_between_vectors(const Point &v1, const Point &v2)
Calculate angle between two vectors in degrees.
Definition polygon.cpp:473
bool segments_intersect(const Point &seg1_start, const Point &seg1_end, const Point &seg2_start, const Point &seg2_end)
Check if two line segments intersect.
Definition polygon.cpp:468
Main namespace for ZLayout library.
Definition component.hpp:20
#define M_PI
Definition polygon.cpp:15
Polygon class for complex geometric shapes and EDA components.
std::size_t operator()(const Polygon &polygon) const
Definition polygon.cpp:459