Limbo 3.5.4
Loading...
Searching...
No Matches
Polygon2RectangleVec.h
Go to the documentation of this file.
1
8
9#ifndef _LIMBO_GEOMETRY_POLYGON2RECTANGLEVEC_H
10#define _LIMBO_GEOMETRY_POLYGON2RECTANGLEVEC_H
11
12#include <vector>
13#include <limits>
14
16namespace limbo
17{
19namespace geometry
20{
21
22// forward declaration
23struct point_compare_type;
24template <typename PointSet,
25 typename RectSet>
27
32template <typename PointType,
33 typename RectangleType>
34class Polygon2Rectangle<std::vector<PointType>, std::vector<RectangleType> >
35{
36 public:
38 typedef std::vector<RectangleType> rectangle_set_type;
40 typedef std::vector<PointType> point_set_type;
42 //typedef typename polygon_90_traits<polygon_type>::point_type point_type;
43 typedef typename container_traits<point_set_type>::value_type point_type;
45 //typedef typename polygon_90_traits<polygon_type>::coordinate_type coordinate_type;
46 typedef typename point_traits<point_type>::coordinate_type coordinate_type;
48 typedef typename container_traits<rectangle_set_type>::value_type rectangle_type;
53
64 Polygon2Rectangle(rectangle_set_type& vRect, slicing_orientation_2d slicing_orient = HORIZONTAL_SLICING)
65 : m_mPoint((slicing_orient != HORIZONTAL_SLICING && slicing_orient != VERTICAL_SLICING)? 2 : 1)
66 , m_vOrient2Id(2, std::numeric_limits<unsigned char>::max())
67 , m_vRect(vRect)
68 , m_slicing_orient(slicing_orient)
69 {
70 this->initialize(slicing_orient);
71 }
72
80 template <typename InputIterator>
81 Polygon2Rectangle(rectangle_set_type& vRect, InputIterator input_begin, InputIterator input_end, slicing_orientation_2d slicing_orient)
82 : m_mPoint((slicing_orient != HORIZONTAL_SLICING && slicing_orient != VERTICAL_SLICING)? 2 : 1)
83 , m_vOrient2Id(2, std::numeric_limits<unsigned char>::max())
84 , m_vRect(vRect)
85 , m_slicing_orient(slicing_orient)
86 {
87 this->initialize(slicing_orient);
88 this->initialize(input_begin, input_end);
89 }
90
96 template <typename InputIterator>
97 void initialize(InputIterator input_begin, InputIterator input_end)
98 {
99 limboAssert(input_begin != input_end);
100 // 1. collecting vertices from input container
101 // it should be ordered, clockwise or counterclockwise
102 // identical vertices are skipped
103 // extra vertices in the same line are skipped
104 std::vector<point_type> vTmpPoint;
105 InputIterator input_last = input_begin;
106 std::size_t dist = std::distance(input_begin, input_end);
107 std::advance(input_last, dist-1);
108 if (is_equal_type()(*input_begin, *input_last)) // skip identical first and last points
109 {
110 ++input_begin;
111 --dist;
112 }
113 vTmpPoint.reserve(dist); // reserve memory
114 // use only operator++ so that just forward_iteartor is enough
115 for (InputIterator itPrev = input_begin; itPrev != input_end; ++itPrev)
116 {
117 InputIterator itCur = itPrev;
118 ++itCur;
119 if (itCur == input_end)
120 itCur = input_begin;
121 InputIterator itNext = itCur;
122 ++itNext;
123 if (itNext == input_end)
124 itNext = input_begin;
125
126 // skip identical vertices
127 if (is_equal_type()(*itCur, *itNext))
128 continue;
129
130 // skip extra vertices in the same line
131 if (this->get(*itPrev, HORIZONTAL) == this->get(*itCur, HORIZONTAL)
132 && this->get(*itCur, HORIZONTAL) == this->get(*itNext, HORIZONTAL)) // vertical line
133 {
134#ifdef DEBUG
135 limboAssert(std::min(this->get(*itPrev, VERTICAL), this->get(*itNext, VERTICAL)) <= this->get(*itCur, VERTICAL)
136 && std::max(this->get(*itPrev, VERTICAL), this->get(*itNext, VERTICAL)) >= this->get(*itCur, VERTICAL));
137#endif
138 continue;
139 }
140 else if (this->get(*itPrev, VERTICAL) == this->get(*itCur, VERTICAL)
141 && this->get(*itCur, VERTICAL) == this->get(*itNext, VERTICAL)) // horizontal line
142 {
143#ifdef DEBUG
144 limboAssert(std::min(this->get(*itPrev, HORIZONTAL), this->get(*itNext, HORIZONTAL)) <= this->get(*itCur, HORIZONTAL)
145 && std::max(this->get(*itPrev, HORIZONTAL), this->get(*itNext, HORIZONTAL)) >= this->get(*itCur, HORIZONTAL));
146#endif
147 continue;
148 }
149
150 // consider edge from itCur to itNext:
152 vTmpPoint,
154 this->get(*itCur, HORIZONTAL),
155 this->get(*itCur, VERTICAL)
156 ));
157 }
158#ifdef DEBUG
159 // a simple manhattan polygon should have even number of different points
160 limboAssert(vTmpPoint.size() % 2 == 0);
161#endif
162
163 // copy from vTmpPoint to m_mPoint
164 std::sort(vTmpPoint.begin(), vTmpPoint.end(), point_compare_type(m_mPoint.front().first));
165 point_set_type& vPointFront = m_mPoint.front().second;
166 // remove points that appear more than once
167 // in other words, after following operation, contour polygon will become polygon with holes
168 vPointFront.reserve(vTmpPoint.size()); // not defined in containers like set
169 for (typename std::vector<point_type>::iterator itCur = vTmpPoint.begin(), itCure = vTmpPoint.end(); itCur != itCure; ++itCur)
170 {
171 typename std::vector<point_type>::iterator itNext = itCur;
172 ++itNext;
173 if (itNext == itCure)
174 itNext = vTmpPoint.begin();
175 if (!is_equal_type()(*itCur, *itNext))
176 vPointFront.push_back(*itCur);
177 else
178 {
179 ++itCur;
180 if (itCur == itCure) break;
181 }
182 }
183
184 // copy the vTmpPoint to the rest entries
185 for (std::size_t i = 1, ie = m_mPoint.size(); i < ie; ++i)
186 {
187 point_set_type const& vPointPrev = m_mPoint[i-1].second;
188 orientation_2d const& orient = m_mPoint[i].first;
189 point_set_type& vPoint = m_mPoint[i].second;
190
191 if (i == 1) // make use of the memory already allocated by vTmpPoint
192 vPoint.swap(vTmpPoint);
193 // copy
194 vPoint.assign(vPointPrev.begin(), vPointPrev.end());
195 // sort
196 std::sort(vPoint.begin(), vPoint.end(), point_compare_type(orient));
197 }
198 }
199
205 {
206 std::vector<rectangle_type> vRect (m_mPoint.size());
207
208 while (!m_mPoint.front().second.empty())
209 {
210 int i = 0;
211
212 for (typename std::vector<std::pair<orientation_2d, point_set_type> >::const_iterator it = m_mPoint.begin();
213 it != m_mPoint.end(); ++it, ++i)
214 {
215 orientation_2d const& orient = it->first;
216#ifdef DEBUG
217 point_set_type const& vPoint = it->second; // just for gdb
218 limboAssert(vPoint.empty() || !vPoint.empty()); // to remove annoying warning
219#endif
220
221 point_type Pk, Pl, Pm;
222
223 if (!this->find_Pk_Pl_Pm(Pk, Pl, Pm, orient))
224 return false;
225
226 rectangle_type& rect = vRect[i];
227
228 // it is safer to do it with construct because some rectangle classes may not support setting borders one-by-one
229 // for HORIZONTAL_SLICING, sort by VERTICAL, Pm decides TOP, Pl decides RIGHT
230 // for VERTICAL_SLICING, sort by HORIZONTAL, Pl decides TOP, Pm decides RIGHT
232 this->get(Pk, HORIZONTAL),
233 this->get(Pk, VERTICAL),
234 std::max(this->get(Pl, HORIZONTAL), this->get(Pm, HORIZONTAL)),
235 std::max(this->get(Pl, VERTICAL), this->get(Pm, VERTICAL)));
236#ifdef DEBUG
237 // check rectangle
238 if (this->get(rect, RIGHT) > std::numeric_limits<coordinate_type>::max()-1000
239 || this->get(rect, TOP) > std::numeric_limits<coordinate_type>::max()-1000)
240 return false;
241#endif
242 }
243 // choose rectangle
244 typename std::vector<rectangle_type>::iterator itRect = vRect.begin();
245 for (typename std::vector<rectangle_type>::iterator it = ++vRect.begin(); it != vRect.end(); ++it)
246 {
247 // it is possible to try different strategies here
248 // choose the one with heuristic
249 coordinate_distance w = this->get(*it, RIGHT)-this->get(*it, LEFT);
250 coordinate_distance h = this->get(*it, TOP)-this->get(*it, BOTTOM);
251 coordinate_distance wref = this->get(*itRect, RIGHT)-this->get(*itRect, LEFT);
252 coordinate_distance href = this->get(*itRect, TOP)-this->get(*itRect, BOTTOM);
253 switch (m_slicing_orient)
254 {
255 case HOR_VER_SLICING:
256 {
257 // compute area
258 if (w*h > wref*href) // choose large area
259 itRect = it;
260 break;
261 }
263 {
264 // compute area
265 if (w*h < wref*href) // choose small area
266 itRect = it;
267 break;
268 }
270 {
271 // compute aspect ratio = maxDelta/minDelta
272 coordinate_distance minDelta = w;
273 coordinate_distance maxDelta = h;
274 coordinate_distance minDeltaRef = wref;
275 coordinate_distance maxDeltaRef = href;
276 if (minDelta > maxDelta)
277 std::swap(minDelta, maxDelta);
278 if (minDeltaRef > maxDeltaRef)
279 std::swap(minDeltaRef, maxDeltaRef);
280 // I rearrage the aspect ratio computation to avoid division
281 if (maxDelta*minDeltaRef < minDelta*maxDeltaRef) // avoid rectangle with bad aspect ratio
282 itRect = it;
283 break;
284 }
285 default:
286 limboAssertMsg(0, "should not reach here %d", m_slicing_orient);
287 }
288 }
289 // insert or remove point
290 for (typename std::vector<std::pair<orientation_2d, point_set_type> >::iterator it = m_mPoint.begin();
291 it != m_mPoint.end(); ++it)
292 {
293 orientation_2d const& orient = it->first;
294#ifdef DEBUG
295 point_set_type const& vPoint = it->second; // just for gdb
296 limboAssert(vPoint.empty() || !vPoint.empty()); // to remove annoying warning
297#endif
298
299 F(point_traits<point_type>::construct(this->get(*itRect, LEFT), this->get(*itRect, BOTTOM)), orient);
300 F(point_traits<point_type>::construct(this->get(*itRect, LEFT), this->get(*itRect, TOP)), orient);
301 F(point_traits<point_type>::construct(this->get(*itRect, RIGHT), this->get(*itRect, BOTTOM)), orient);
302 F(point_traits<point_type>::construct(this->get(*itRect, RIGHT), this->get(*itRect, TOP)), orient);
303 }
304 // collect rectangle
306 }
307
308 return true;
309 }
310
315 {
316 return m_vRect;
317 }
318
323 bool read(string const& filename)
324 {
325 ifstream in (filename.c_str());
326 if (!in.good())
327 {
328 cout << "failed to open " << filename << endl;
329 return false;
330 }
331
332 string tag;
333 string value_str;
334 int status = 0; // status records line number
335 // if status > 0, it means in a polygon scope
336 std::vector<point_type> vPoint; // temporary point set
337
338 while (!in.eof())
339 {
340 in >> tag;
341 if (tag == "polygon" && status == 0)
342 {
343 status = 1;
344 }
345 else if (tag == "from" || tag == "to")
346 {
347 int i = 0;
348 coordinate_type value[2] = {0, 0};
349 // read until get two numbers
350 // there may be some delimiters like ',' '\'
351 while (!in.eof() && i < 2)
352 {
353 in >> value_str;
354 boost::trim_if(value_str, boost::is_any_of(", \t\\"));
355 if (::limbo::is_number(value_str))
356 {
357 value[i] = boost::lexical_cast<coordinate_type>(value_str);
358 // increment i if value_str represents a number
359 i += 1;
360 }
361 }
362 // return false if reading failed
363 if (i != 2) return false;
364 // add current point to point set
365 vPoint.push_back(point_type());
366 this->set(vPoint.back(), HORIZONTAL, value[0]);
367 this->set(vPoint.back(), VERTICAL, value[1]);
368 }
369 else if (status == 1)
370 {
371 status = 0;
372 break; // only read one polygon
373 }
374 }
375 // after reading, call initialize function
376 this->initialize(vPoint.begin(), vPoint.end());
377
378 return true;
379 }
380
384 void print(string const& filename) const
385 {
386 ofstream out (filename.c_str());
387 if (!out.good())
388 {
389 cout << "failed to open " << filename << endl;
390 return;
391 }
392 int i = 1; // gnuplot requires numbering from 1
393 point_set_type const& vPoint = m_mPoint.begin()->second;
394 // print current polygon if exists
395 if (vPoint.size() > 0)
396 {
397 out << "set obj " << i++ << " ";
398 out << "polygon \\" << endl;
399 for (typename point_set_type::const_iterator it = vPoint.begin(), ite = vPoint.end(); it != ite; ++it)
400 {
401 if (it == vPoint.begin())
402 out << "from " << this->get(*it, HORIZONTAL) << ", " << this->get(*it, VERTICAL) << " \\" << endl;
403 else
404 out << "to " << this->get(*it, HORIZONTAL) << ", " << this->get(*it, VERTICAL) << " \\" << endl;
405 }
406 out << endl;
407 }
408
409 // print rectangles
410 for (typename rectangle_set_type::const_iterator it = m_vRect.begin(); it != m_vRect.end(); ++it)
411 {
412 // print rectangle
413 out << "set obj " << i << " rectangle ";
414 out << "from " << this->get(*it, LEFT) << ", " << this->get(*it, BOTTOM) << " "
415 << "to " << this->get(*it, RIGHT) << ", " << this->get(*it, TOP) << " ";
416 out << "fc rgb \"dark-grey\" fs transparent pattern 4 bo"<< endl;
417 // print text on the center of rectangle
418 out << "set label \'" << i << "\' at "
419 << (this->get(*it, LEFT)+this->get(*it, RIGHT))/2.0 << ", " << (this->get(*it, BOTTOM)+this->get(*it, TOP))/2.0 << " "
420 << "front center tc rgb \"black\"" << endl;
421 ++i;
422 }
423 }
424
425 protected:
439 inline coordinate_type get(rectangle_type const& r, direction_2d d) const {return rectangle_traits<rectangle_type>::get(r, d);}
453 inline void set(rectangle_type& r, direction_2d d, coordinate_type v) const {rectangle_traits<rectangle_type>::set(r, d, v);}
454
459 {
466 inline bool operator() (point_type const& p1, point_type const& p2) const
467 {
468 return point_traits<point_type>::get(p1, HORIZONTAL) == point_traits<point_type>::get(p2, HORIZONTAL)
469 && point_traits<point_type>::get(p1, VERTICAL) == point_traits<point_type>::get(p2, VERTICAL);
470 }
471 };
472
478 {
479 switch (slicing_orient)
480 {
481 // only need to set orient, the initialization of point array is done implicitly
482 case HORIZONTAL_SLICING:
483 m_mPoint.at(0).first = VERTICAL;
484 m_vOrient2Id[VERTICAL] = 0;
485 break;
486 case VERTICAL_SLICING:
487 m_mPoint.at(0).first = HORIZONTAL;
488 m_vOrient2Id[HORIZONTAL] = 0;
489 break;
490 case HOR_VER_SLICING:
493 m_mPoint.at(0).first = HORIZONTAL; // since HORIZONTAL is 0
494 m_vOrient2Id[HORIZONTAL] = 0;
495 m_mPoint.at(1).first = VERTICAL; // since VERTICAL is 1
496 m_vOrient2Id[VERTICAL] = 1;
497 break;
498 default:
499 std::cout << "unknown slicing orientation" << std::endl;
500 limboAssert(0);
501 }
502 }
503
512 bool find_Pk_Pl_Pm(point_type& Pk, point_type& Pl, point_type& Pm, orientation_2d const& orient)
513 {
514 point_set_type const& vPoint = m_mPoint.at(m_vOrient2Id[orient.to_int()]).second;
515 if (vPoint.size() < 4)
516 return false;
517
518 // always keep it sorted
519 // copy first point to Pk
520 this->set(Pk, HORIZONTAL, this->get(*vPoint.begin(), HORIZONTAL));
521 this->set(Pk, VERTICAL, this->get(*vPoint.begin(), VERTICAL));
522 // copy second point to Pl
523 this->set(Pl, HORIZONTAL, this->get(*(++(vPoint.begin())), HORIZONTAL));
524 this->set(Pl, VERTICAL, this->get(*(++(vPoint.begin())), VERTICAL));
525 // determine Pm
526 this->set(Pm, HORIZONTAL, std::numeric_limits<coordinate_type>::max());
527 this->set(Pm, VERTICAL, std::numeric_limits<coordinate_type>::max());
528 for (typename point_set_type::const_iterator it = vPoint.begin(), ite = vPoint.end(); it != ite; ++it)
529 {
530 if (this->get(Pk, orient) == this->get(*it, orient))
531 continue;
532 else if (this->get(Pk, orient.get_perpendicular()) <= this->get(*it, orient.get_perpendicular())
533 && this->get(*it, orient.get_perpendicular()) <= this->get(Pl, orient.get_perpendicular()))
534 {
535 limboAssert(this->get(*it, orient) > this->get(Pk, orient));
536 this->set(Pm, HORIZONTAL, this->get(*it, HORIZONTAL));
537 this->set(Pm, VERTICAL, this->get(*it, VERTICAL));
538 break;
539 }
540 }
541 if (this->get(Pm, HORIZONTAL) == std::numeric_limits<coordinate_type>::max()
542 || this->get(Pm, VERTICAL) == std::numeric_limits<coordinate_type>::max())
543 return false;
544
545 return true;
546 }
547
553 void F(point_type const& point, orientation_2d const& orient)
554 {
555 point_set_type& vPoint = m_mPoint.at(m_vOrient2Id[orient.to_int()]).second;
556
557 // vPoint is always in order
558 typename point_set_type::iterator itr = std::lower_bound(vPoint.begin(), vPoint.end(), point, point_compare_type(orient));
559
560 if (itr == vPoint.end() || !is_equal_type()(*itr, point)) // not found, insert point
561 {
563 }
564 else // found, remove point
565 {
567 }
568 }
569 std::vector<std::pair<orientation_2d, point_set_type> > m_mPoint;
573 std::vector<unsigned char> m_vOrient2Id;
576};
577
578} // namespace geometry
579} // namespace limbo
580
581#endif
#define limboAssertMsg(condition, args...)
custom assertion with message
Definition AssertMsg.h:24
#define limboAssert(condition)
custom assertion without message
Definition AssertMsg.h:36
coordinate_type get(point_type const &p, orientation_2d o) const
get coordinate from point
void F(point_type const &point, orientation_2d const &orient)
F function in the original paper remove point if found, otherwise insert.
bool find_Pk_Pl_Pm(point_type &Pk, point_type &Pl, point_type &Pm, orientation_2d const &orient)
find Pk, Pl, Pm, please refer to the paper for definition Given points, find Pk, Pl and Pm
void initialize(slicing_orientation_2d slicing_orient)
initialize with slicing orientation it must be called before initializing other data
Polygon2Rectangle(rectangle_set_type &vRect, InputIterator input_begin, InputIterator input_end, slicing_orientation_2d slicing_orient)
constructor
point_traits< point_type >::coordinate_type coordinate_type
point set type for polygon
bool read(string const &filename)
read polygon from file try to be compatible to gnuplot format
Polygon2Rectangle(rectangle_set_type &vRect, slicing_orientation_2d slicing_orient=HORIZONTAL_SLICING)
constructor
coordinate_traits< coordinate_type >::manhattan_area_type manhattan_area_type
manhattan area type
coordinate_type get(rectangle_type const &r, direction_2d d) const
get coordinate from rectangle
container_traits< point_set_type >::value_type point_type
internal point type
void set(rectangle_type &r, direction_2d d, coordinate_type v) const
set coordinate of rectangle
container_traits< rectangle_set_type >::value_type rectangle_type
internal rectangle type
coordinate_traits< coordinate_type >::coordinate_distance coordinate_distance
coordinate distance type
void set(point_type &p, orientation_2d o, coordinate_type v) const
set coordinate of point
void print(string const &filename) const
print polygon to file in gnuplot format
void initialize(InputIterator input_begin, InputIterator input_end)
initialize polygon points
a class implement conversion from manhattan polygon to rectangle
bool operator()()
top api for limbo::geometry::Polygon2Rectangle
void initialize(InputIterator input_begin, InputIterator input_end)
initialize polygon points
coordinate_type get(point_type const &p, orientation_2d o) const
get coordinate from point
bool find_Pk_Pl_Pm(point_type &Pk, point_type &Pl, point_type &Pm, orientation_2d const &orient)
find Pk, Pl, Pm, please refer to the paper for definition Given points, find Pk, Pl and Pm
container_traits< point_set_type >::value_type point_type
internal point type
void set(point_type &p, orientation_2d o, coordinate_type v) const
set coordinate of point
void F(point_type const &point, orientation_2d const &orient)
F function in the original paper remove point if found, otherwise insert.
a class denoting orientation of lines
Definition Geometry.h:93
int to_int() const
convert orientation to integer
Definition Geometry.h:119
orientation_2d get_perpendicular() const
get perpendicular orientation
Definition Geometry.h:124
namespace for Limbo.Geometry
Definition Geometry.h:21
@ HOR_VER_SLICING
horizontal/vertical slicing and choose rectangle with larger area every time
Definition Geometry.h:43
@ HOR_VER_AR_SLICING
horizontal/vertical slicing and choose rectangle with better aspect ratio every time
Definition Geometry.h:45
@ HOR_VER_SA_SLICING
horizontal/vertical slicing and choose rectangle with smaller area every time
Definition Geometry.h:44
namespace for Limbo
std::iterator_traits< Iterator >::value_type max(Iterator first, Iterator last)
get max of an array
Definition Math.h:61
bool is_number(string const &s)
check whether string represents a number, either integer or floating point number
Definition String.h:62
type traits for containers such as vector, list, multiset
Definition Geometry.h:282
static void insert(container_type &container, value_type const &v)
insert value to container
Definition Geometry.h:291
static void erase(container_type &container, value_type const &v)
erase value from iterator
Definition Geometry.h:295
type traits for coordinates
Definition Geometry.h:146
sort helper if orient == HORIZONTAL, sort by left lower if orient == VERTICAL, sort by lower left
static coordinate_type get(const point_type &point, orientation_2d const &orient)
get coordinate from point
Definition Geometry.h:206
static point_type construct(coordinate_type const &x, coordinate_type const &y)
construct point from coordinates
Definition Geometry.h:218
static void set(point_type &point, orientation_2d const &orient, coordinate_type const &value)
set coordinate for point
Definition Geometry.h:212
static coordinate_type get(rectangle_type const &rectangle, direction_2d const &direct)
get coordinate from rectangle
Definition Geometry.h:237
static void set(rectangle_type &rectangle, direction_2d const &direct, coordinate_type const &v)
set coordinate for rectangle
Definition Geometry.h:243
static rectangle_type construct(coordinate_type const &xl, coordinate_type const &yl, coordinate_type const &xh, coordinate_type const &yh)
construct rectangle from coordinates
Definition Geometry.h:248