Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

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 
50 namespace ogdf {
51 namespace internal {
52 namespace gcm {
53 namespace geometry {
54 
55 using namespace tools;
56 
57 template<typename kernel>
58 class Polygon_t : public CGAL::Polygon_2<kernel> {
59 private:
60  using poly = CGAL::Polygon_2<kernel>;
61 
62 public:
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 
89 template<typename kernel, typename Graph>
90 inline 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 
99 template<typename kernel, typename Graph>
100 inline 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 
121 template<typename kernel>
122 inline 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 
130 template<typename kernel>
131 inline 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 ;)
136 template<typename kernel>
137 LineSegment_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 
150 template<typename kernel, typename Graph>
151 inline 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 
167 template<typename kernel>
168 inline unsigned int next(const Polygon_t<kernel>& p, unsigned int i) {
169  return (i + 1) % p.size();
170 }
171 
172 template<typename kernel>
173 inline unsigned int prev(const Polygon_t<kernel>& p, unsigned int i) {
174  return std::min((size_t)i - 1, p.size() - 1);
175 }
176 
177 template<typename kernel>
178 inline 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 
183 template<typename kernel>
184 inline 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.
235 template<typename Kernel>
236 typename 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.
252 template<typename Kernel>
253 Point_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 
262 template<typename kernel>
263 inline 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 
272 template<typename kernel>
273 inline 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 
284 template<typename kernel>
285 inline bool is_clockwise(const Polygon_t<kernel>& polygon) {
286  return polygon.area() < 0;
287 }
288 
289 template<typename kernel>
290 std::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 
314 template<typename kernel>
315 std::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 
328 template<typename kernel>
329 std::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
ogdf
The namespace for all OGDF objects.
Definition: multilevelmixer.cpp:39
OGDF_ASSERT
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition: basic.h:66
ogdf::begin
HypergraphRegistry< HypernodeElement >::iterator begin(const HypergraphRegistry< HypernodeElement > &self)
Point.h
Path.h
ogdf::tlp::Attribute::size
@ size
ogdf::reverse
Reverse< T > reverse(T &container)
Provides iterators for container to make it easily iterable in reverse.
Definition: Reverse.h:74
Vector.h
Minisat::Internal::sort
void sort(T *array, int size, LessThan lt)
Definition: Sort.h:57
r
int r[]
Definition: hierarchical-ranking.cpp:13
Rectangle.h
PolylineDrawing.h
backward::details::move
const T & move(const T &v)
Definition: backward.hpp:243
Ray.h
ogdf::operator<<
std::ostream & operator<<(std::ostream &os, const ogdf::Array< E, INDEX > &a)
Prints array a to output stream os.
Definition: Array.h:983
LineSegment.h
GeometricDrawing.h
std
Definition: GML.h:111
ogdf::end
HypergraphRegistry< HypernodeElement >::iterator end(const HypergraphRegistry< HypernodeElement > &self)