DeSiGNAR  0.5a
Data Structures General Library
geometricalgorithms.H
Go to the documentation of this file.
1 /*
2  This file is part of Designar.
3  Copyright (C) 2017 by Alejandro J. Mujica
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  Any user request of this software, write to
19 
20  Alejandro Mujica
21 
22  aledrums@gmail.com
23 */
24 
25 # ifndef DSGGEOMETRICALGORITHMS_H
26 # define DSGGEOMETRICALGORITHMS_H
27 
28 # include <polygon.H>
29 # include <list.H>
30 # include <set.H>
31 # include <sort.H>
32 
33 namespace Designar
34 {
35 
36  // Convex hull algorithms
37 
43  template <class PolygonType>
45  {
46  using PointType = typename PolygonType::PointType;
47  using SegmentType = typename PolygonType::SegmentType;
48 
49  struct CmpSegment
50  {
51  bool cmp_point(const PointType & p1, const PointType & p2) const
52  {
53  if (p1.get_x() < p2.get_x())
54  return true;
55 
56  return not (p2.get_x() < p1.get_x()) and p1.get_y() < p2.get_y();
57  }
58 
59  bool operator () (const SegmentType & s1, const SegmentType & s2)
60  {
61  if (cmp_point(s1.get_src_point(), s2.get_src_point()))
62  return true;
63 
64  return not (cmp_point(s2.get_src_point(), s1.get_src_point())) and
65  cmp_point(s1.get_tgt_point(), s2.get_tgt_point());
66  }
67  };
68 
70 
71  using PointTypeIt = typename SLList<PointType>::Iterator;
72 
73  bool are_all_points_on_left(const SLList<PointType> & l,
74  const SegmentType & s)
75  {
76  return l.all([&s] (const PointType & p)
77  {
78  return
79  p.is_to_left_on_from(s.get_src_point(), s.get_tgt_point());
80  });
81  }
82 
83  SegmentTypeSet extreme_edges(const SLList<PointType> & point_set)
84  {
85  SegmentTypeSet ret;
86 
87  for (PointTypeIt i(point_set); i.has_curr(); i.next())
88  {
89  const PointType & p_i = i.get_curr();
90 
91  for (PointTypeIt j(point_set); j.has_curr(); j.next())
92  {
93  const PointType & p_j = j.get_curr();
94 
95  if (p_i == p_j)
96  continue;
97 
98  SegmentType s(p_i, p_j);
99 
100  if (are_all_points_on_left(point_set, s))
101  ret.insert(s);
102  }
103  }
104 
105  return ret;
106  }
107 
108  public:
109  PolygonType operator () (const SLList<PointType> & point_set)
110  {
111  PolygonType ret;
112 
113  SegmentTypeSet extremes = extreme_edges(point_set);
114 
115  SegmentType first_segment = extremes.remove_pos(0);
116  ret.add_vertex(first_segment.get_src_point());
117  ret.add_vertex(first_segment.get_tgt_point());
118 
119  while (true)
120  {
121  const PointType & last_vertex = ret.get_last_vertex();
122 
123  SegmentType * ptr =
124  extremes.search_ptr([&last_vertex](const SegmentType & s) {
125  return s.get_src_point() == last_vertex;
126  });
127 
128  assert(ptr != nullptr);
129 
130  if (ptr->get_tgt_point() == ret.get_first_vertex())
131  break;
132 
133  ret.add_vertex(ptr->get_tgt_point());
134 
135  extremes.remove(*ptr);
136  }
137 
138  return ret;
139  }
140  };
141 
147  template <class PolygonType>
148  class QuickHull
149  {
150  using PointType = typename PolygonType::PointType;
151  using SegmentType = typename PolygonType::SegmentType;
152  using NumType = typename PointType::NumberType;
153  using PointTypeIt = typename SLList<PointType>::Iterator;
154 
155  PointType get_fartest_point(const SLList<PointType> & point_set,
156  const SegmentType & s)
157  {
158  NumType max_distance = 0;
159  PointType ret;
160 
161  for (PointTypeIt it(point_set); it.has_curr(); it.next())
162  {
163  const PointType & p = it.get_curr();
164 
165  SegmentType s1 = s.get_perpendicular(p);
166 
167  NumType sz = s1.length();
168 
169  if (sz > max_distance)
170  {
171  ret = p;
172  max_distance = sz;
173  }
174  }
175 
176  return ret;
177  }
178 
179  std::pair<SLList<PointType>, SLList<PointType>>
180  get_right_points(SLList<PointType> & point_set,
181  const PointType & a, const PointType & b,
182  const PointType & c)
183  {
184  std::pair<SLList<PointType>, SLList<PointType>> ret;
185 
186  while (not point_set.is_empty())
187  {
188  PointType p = point_set.remove_first();
189 
190  if (p != a and p != c and p.is_to_right_from(a, c))
191  {
192  ret.first.append(p);
193  continue;
194  }
195 
196  if (p != c and p != b and p.is_to_right_from(c, b))
197  ret.second.append(p);
198  }
199 
200  return ret;
201  }
202 
203  SLList<PointType> quick_hull(SLList<PointType> & point_set,
204  const PointType & a,
205  const PointType & b)
206  {
207  if (point_set.is_empty())
208  return SLList<PointType>();
209 
210  PointType c = get_fartest_point(point_set, SegmentType(a, b));
211 
212  auto r = get_right_points(point_set, a, b, c);
213 
214  SLList<PointType> ret = quick_hull(r.first, a, c);
215  SLList<PointType> tmp = quick_hull(r.second, c, b);
216  ret.append(c);
217  ret.concat(tmp);
218 
219  return ret;
220  }
221 
222  std::pair<PointType, PointType>
223  search_extremes(const SLList<PointType> & point_set)
224  {
225  PointTypeIt it(point_set);
226  PointType leftmost = it.get_curr();
227  PointType rightmost = it.get_curr();
228  it.next();
229 
230  for ( ; it.has_curr(); it.next())
231  {
232  const PointType & p = it.get_curr();
233 
234  if (p.get_x() < leftmost.get_x())
235  leftmost = p;
236 
237  if (p.get_x() > rightmost.get_x())
238  rightmost = p;
239  }
240 
241  return std::make_pair(leftmost, rightmost);
242  }
243 
244  std::pair<SLList<PointType>, SLList<PointType>>
245  partition(SLList<PointType> & point_set, const PointType & a,
246  const PointType & b)
247  {
248  std::pair<SLList<PointType>, SLList<PointType>> ret;
249 
250  for (PointTypeIt it(point_set); it.has_curr(); it.next())
251  {
252  const PointType & p = it.get_curr();
253 
254  if (p.is_to_right_from(a, b))
255  ret.first.append(p);
256  else
257  ret.second.append(p);
258  }
259 
260  return ret;
261  }
262 
263  public:
264  PolygonType operator () (SLList<PointType> & point_set)
265  {
266  PolygonType ret;
267 
268  auto e = search_extremes(point_set);
269  auto p = partition(point_set, e.first, e.second);
270 
271  SLList<PointType> s1 = quick_hull(p.first, e.first, e.second);
272  SLList<PointType> s2 = quick_hull(p.second, e.second, e.first);
273 
274  SLList<PointType> convex_set;
275  convex_set.append(e.first);
276  convex_set.concat(s1);
277  convex_set.append(e.second);
278  convex_set.concat(s2);
279 
280  for (PointTypeIt it(convex_set); it.has_curr(); it.next())
281  ret.add_vertex(it.get_curr());
282 
283  return ret;
284  }
285  };
286 
287 } // end namespace Designar
288 
289 # endif // DSGGEOMETRICALGORITHMS_H
RetType< RET_CPY, T, T & > get_curr()
Definition: iterator.H:55
T remove_first()
Definition: list.H:313
void concat(SLList &l)
Definition: list.H:331
T & append(const T &item)
Definition: list.H:265
PolygonType operator()(const SLList< PointType > &point_set)
Definition: geometricalgorithms.H:109
Definition: geometricalgorithms.H:44
bool is_empty() const
Definition: list.H:80
Definition: geometricalgorithms.H:148
Definition: italgorithms.H:33
Definition: array.H:32
Definition: set.H:562
lint_t partition(ArrayType &, lint_t, lint_t, Cmp &)
Definition: sort.H:224
bool all(Pred &pred) const
Definition: containeralgorithms.H:161
Definition: list.H:354