Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

Loading...
Searching...
No Matches
Polygon.h
Go to the documentation of this file.
1
31#pragma once
32
33#ifdef OGDF_INCLUDE_CGAL
34
43
44# include <limits>
45# include <list>
46# include <vector>
47
48# include <CGAL/Polygon_2.h>
49
50namespace ogdf {
51namespace internal {
52namespace gcm {
53namespace geometry {
54
55using namespace tools;
56
57template<typename kernel>
58class Polygon_t : public CGAL::Polygon_2<kernel> {
59private:
60 using poly = CGAL::Polygon_2<kernel>;
61
62public:
63 using poly::poly; //inherit constructors
64
65 Polygon_t(const poly& p) : poly(p) { }
66
67 Polygon_t(const poly&& p) : poly(std::move(p)) { }
68
69 Polygon_t() { }
70
71 Polygon_t(const Polygon_t<kernel>& p) : poly(p) { }
72
73 inline typename poly::Edge_const_iterator begin() const { return poly::edges_begin(); }
74
75 inline typename poly::Edge_const_iterator end() const { return poly::edges_end(); };
76
77 void push_back(const Point_t<kernel>& x) {
78 if (poly::is_empty() || (poly::container().back() != x)) {
79 poly::push_back(x);
80 }
81 }
82
83 Polygon_t<kernel> operator=(const Polygon_t<kernel>& p) {
84 (poly)(*this) = p;
85 return *this;
86 }
87};
88
89template<typename kernel, typename Graph>
90inline Polygon_t<kernel> get_polygon(const graph::GeometricDrawing<kernel, Graph>& drawing,
91 const graph::Path& path) { //TODO
92 Polygon_t<kernel> polygon;
93 for (auto& v : path.nodes()) {
94 polygon.push_back(drawing.get_point(v));
95 }
96 return polygon;
97}
98
99template<typename kernel, typename Graph>
100inline Polygon_t<kernel> get_polygon(const graph::PolylineDrawing<kernel, Graph>& drawing,
101 const graph::Path& path) {
102 Polygon_t<kernel> polygon;
103
104 for (unsigned int i = 0; i < path.edges().size(); ++i) {
105 auto e = path.edges()[i];
106
107 if (!path.is_reversed(i)) {
108 for (auto& p : drawing.get_polyline(e)) {
109 polygon.push_back(p);
110 }
111 } else {
112 auto& p = drawing.get_polyline(e);
113 for (auto itr = p.rbegin(); itr != p.rend(); ++itr) {
114 polygon.push_back(*itr);
115 }
116 }
117 }
118 return polygon;
119}
120
121template<typename kernel>
122inline Polygon_t<kernel> get_polygon(const Rectangle_t<kernel>& rect) {
123 Polygon_t<kernel> p;
124 for (unsigned int i = 0; i < 4; ++i) {
125 p.push_back(rect[i]);
126 }
127 return p;
128}
129
130template<typename kernel>
131inline Polygon_t<kernel> get_polygon(const CGAL::Bbox_2& bb) {
132 return get_polygon(Rectangle_t<kernel>(bb));
133}
134
135//TODO move somewhere usefull ;)
136template<typename kernel>
137LineSegment_t<kernel> clip(const Rectangle_t<kernel>& rect, const Line_t<kernel>& line) {
138 //assume line intersects rect twice
139 std::vector<Point_t<kernel>> is;
140 Polygon_t<kernel> p = get_polygon(rect);
141 for (auto s : p) {
142 if (geometry::do_intersect_wo_target(line, s)) {
143 is.push_back(geometry::intersect(line, s));
144 }
145 }
146
147 return LineSegment_t<kernel>(is[0], is[1]);
148}
149
150template<typename kernel, typename Graph>
151inline std::vector<typename Graph::Node> graph_from_polygon(const Polygon_t<kernel>& polygon,
152 graph::GeometricDrawing<kernel, Graph>& drawing) {
153 std::vector<typename Graph::Node> node_map;
154 for (unsigned int i = 0; i < polygon.size(); ++i) {
155 typename Graph::Node u = drawing.get_graph().add_node();
156 drawing.set_point(u, polygon[i]);
157 node_map.push_back(u);
158 }
159
160 for (unsigned int i = 0; i < polygon.size(); ++i) {
161 drawing.get_graph().add_edge(node_map[i], node_map[(i + 1) % polygon.size()]);
162 }
163
164 return node_map;
165}
166
167template<typename kernel>
168inline unsigned int next(const Polygon_t<kernel>& p, unsigned int i) {
169 return (i + 1) % p.size();
170}
171
172template<typename kernel>
173inline unsigned int prev(const Polygon_t<kernel>& p, unsigned int i) {
174 return std::min((size_t)i - 1, p.size() - 1);
175}
176
177template<typename kernel>
178inline Polygon_t<kernel> reverse(const Polygon_t<kernel>& polygon) {
179 Polygon_t<kernel> revPolygon(polygon.container().rbegin(), polygon.container().rend());
180 return revPolygon;
181}
182
183template<typename kernel>
184inline bool contains(const Polygon_t<kernel>& polygon, const geometry::Point_t<kernel>& p) {
185 OGDF_ASSERT(!is_clockwise(polygon));
186 if (polygon.size() == 0) {
187 return false;
188 }
189 if (polygon.size() == 1) {
190 return polygon[0] == p;
191 }
192 if (CGAL::is_zero(CGAL::abs(polygon.area()))) {
193 // all segments are nearly colinear, check if p is on one of them
194 for (const auto& s : polygon) {
195 if (is_on(s, p)) {
196 return true;
197 }
198 }
199 return false;
200 }
201
202 unsigned int segment = -1;
203 geometry::LineSegment_t<kernel> l;
204 do {
205 ++segment;
206 l = {p, polygon[segment] + polygon.edge(segment).to_vector() * 0.5};
207 } while (overlapping(l, polygon.edge(segment)));
208
209 OGDF_ASSERT((size_t)segment < polygon.size());
210
211 geometry::Ray_t<kernel> r(p, l.to_vector());
212 unsigned int nof_intersections = 0;
213 bool is_on_border = false;
214
215 for (unsigned int i = 0; i < polygon.size(); ++i) {
216 auto s = polygon.edge(i);
217
218 if (geometry::do_intersect_wo_target(s, r)) {
219 auto is = geometry::intersect(s, r);
220 if (is == s.source()) {
221 auto prev_seg = polygon.edge(prev(polygon, i));
222 if (!geometry::right_turn(prev_seg, s)) { // not a concave corner
223 ++nof_intersections;
224 }
225 } else {
226 ++nof_intersections;
227 }
228 }
229 is_on_border = is_on_border || is_on(s, p);
230 }
231 return nof_intersections % 2 == 1 || is_on_border;
232}
233
234//returns the distance of the point to the polygon. The Value is negative, if the point is not contained in the interior of the polygon.
235template<typename Kernel>
236typename Kernel::FT squared_distance(const Polygon_t<Kernel>& polygon, const Point_t<Kernel>& point) {
237 typename Kernel::FT min_dist = CGAL::squared_distance(*polygon.begin(), point);
238 for (const auto& e : polygon) {
239 typename Kernel::FT sq = CGAL::squared_distance(e, point);
240 if (sq < min_dist) {
241 min_dist = sq;
242 }
243 }
244 if (min_dist > 1e-12 && !contains(polygon, point)) {
245 min_dist = -min_dist;
246 }
247
248 return min_dist;
249}
250
251//returns the distance of the point to the polygon. The Value is negative, if the point is not contained in the interior of the polygon.
252template<typename Kernel>
253Point_t<Kernel> centroid(const Polygon_t<Kernel>& polygon) {
254 Point_t<Kernel> p(0, 0);
255 for (const Point_t<Kernel>& q : polygon.container()) {
256 p = p + q;
257 }
258 p = p * (1.0 / polygon.size());
259 return p;
260}
261
262template<typename kernel>
263inline Point_t<kernel> intersect(const Polygon_t<kernel>& polygon, const Ray_t<kernel>& ray,
264 unsigned int& idx) {
265 // FIXME implement me
266 OGDF_ASSERT(false);
267 (void)polygon;
268 (void)ray;
269 (void)idx;
270}
271
272template<typename kernel>
273inline Point_t<kernel> intersect(const Polygon_t<kernel>& polygon, const Ray_t<kernel>& ray) {
274 OGDF_ASSERT(contains(polygon, ray.source()));
275 Point_t<kernel> p;
276 for (auto s : polygon) {
277 if (geometry::do_intersect_wo_target(s, ray)) {
278 return geometry::intersect(s, ray);
279 }
280 }
281 return {-1, -1};
282}
283
284template<typename kernel>
285inline bool is_clockwise(const Polygon_t<kernel>& polygon) {
286 return polygon.area() < 0;
287}
288
289template<typename kernel>
290std::vector<unsigned int> find_duplicates(const Polygon_t<kernel>& polygon) {
291 std::vector<unsigned int> segment_ids(polygon.size(), 0);
292 for (unsigned int i = 0; i < polygon.size(); ++i) {
293 segment_ids[i] = i;
294 }
295 std::sort(segment_ids.begin(), segment_ids.end(), [&](unsigned int i, unsigned int j) {
296 return (polygon.edge(i).min() < polygon.edge(j).min())
297 || (polygon.edge(i).min() == polygon.edge(j).min()
298 && polygon.edge(i).max() < polygon.edge(j).max());
299 });
300
301 std::vector<unsigned int> is_duplicate(polygon.size(), -1);
302 for (unsigned int i = 0; i + 1 < polygon.size(); ++i) {
303 unsigned int a = segment_ids[i];
304 unsigned int b = segment_ids[i + 1];
305 if (polygon.edge(a).min() == polygon.edge(b).min()
306 && polygon.edge(a).max() == polygon.edge(b).max()) {
307 is_duplicate[a] = b;
308 is_duplicate[b] = a;
309 }
310 }
311 return is_duplicate;
312}
313
314template<typename kernel>
315std::string ggb(const Polygon_t<kernel>& polygon) {
316 std::stringstream os;
317 os << "polygon[";
318 for (unsigned int i = 0; i < polygon.size(); ++i) {
319 os << polygon[i];
320 if (i + 1 < polygon.size()) {
321 os << ",";
322 }
323 }
324 os << "]";
325 return os.str();
326}
327
328template<typename kernel>
329std::ostream& operator<<(std::ostream& os, const Polygon_t<kernel>& p) {
330 os << ggb(p);
331 return os;
332}
333
334
335} //namespace
336}
337}
338}
339
340#endif
Reverse< T > reverse(T &container)
Provides iterators for container to make it easily iterable in reverse.
Definition Reverse.h:74
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition basic.h:52
const T & move(const T &v)
Definition backward.hpp:243
The namespace for all OGDF objects.
std::ostream & operator<<(std::ostream &os, const ogdf::Array< E, INDEX > &a)
Prints array a to output stream os.
Definition Array.h:983
HypergraphRegistry< HypernodeElement >::iterator begin(const HypergraphRegistry< HypernodeElement > &self)
HypergraphRegistry< HypernodeElement >::iterator end(const HypergraphRegistry< HypernodeElement > &self)
Definition GML.h:111