Limbo
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Polygon2RectangleVec.h
Go to the documentation of this file.
1 
9 #ifndef _LIMBO_GEOMETRY_POLYGON2RECTANGLEVEC_H
10 #define _LIMBO_GEOMETRY_POLYGON2RECTANGLEVEC_H
11 
12 #include <vector>
13 #include <limits>
14 
16 namespace limbo
17 {
19 namespace geometry
20 {
21 
22 // forward declaration
23 struct point_compare_type;
24 template <typename PointSet,
25  typename RectSet>
26 class Polygon2Rectangle;
27 
32 template <typename PointType,
33  typename RectangleType>
34 class 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  }
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  }
96  template <typename InputIterator>
97  void initialize(InputIterator input_begin, InputIterator input_end)
98  {
99  assert(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  assert(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  assert(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  assert(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 
204  bool operator()()
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  assert(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  }
262  case HOR_VER_SA_SLICING:
263  {
264  // compute area
265  if (w*h < wref*href) // choose small area
266  itRect = it;
267  break;
268  }
269  case HOR_VER_AR_SLICING:
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  assert_msg(0, "should not reach here " << 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  assert(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  }
314  rectangle_set_type const& get_rectangles() const
315  {
316  return m_vRect;
317  }
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  }
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:
432  inline coordinate_type get(point_type const& p, orientation_2d o) const {return point_traits<point_type>::get(p, o);}
439  inline coordinate_type get(rectangle_type const& r, direction_2d d) const {return rectangle_traits<rectangle_type>::get(r, d);}
446  inline void set(point_type& p, orientation_2d o, coordinate_type v) const {point_traits<point_type>::set(p, o, v);}
453  inline void set(rectangle_type& r, direction_2d d, coordinate_type v) const {rectangle_traits<rectangle_type>::set(r, d, v);}
454 
458  struct is_equal_type
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  };
477  void initialize(slicing_orientation_2d slicing_orient)
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:
491  case HOR_VER_SA_SLICING:
492  case HOR_VER_AR_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  assert(0);
501  }
502  }
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  assert(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  }
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  {
562  container_traits<point_set_type>::insert(vPoint, itr, point);
563  }
564  else // found, remove point
565  {
567  }
568  }
569  std::vector<std::pair<orientation_2d, point_set_type> > m_mPoint;
570  std::vector<unsigned char> m_vOrient2Id;
574  rectangle_set_type& m_vRect;
576 };
577 
578 } // namespace geometry
579 } // namespace limbo
580 
581 #endif
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:221
static coordinate_type get(const point_type &point, orientation_2d const &orient)
get coordinate from point
Definition: Geometry.h:179
int to_int() const
convert orientation to integer
Definition: Geometry.h:119
Polygon2Rectangle(rectangle_set_type &vRect, InputIterator input_begin, InputIterator input_end, slicing_orientation_2d slicing_orient)
constructor
static void set(rectangle_type &rectangle, direction_2d const &direct, coordinate_type const &v)
set coordinate for rectangle
Definition: Geometry.h:216
map< orientation_2d, point_set_type > m_mPoint
static void set(point_type &point, orientation_2d const &orient, coordinate_type const &value)
set coordinate for point
Definition: Geometry.h:185
void F(point_type const &point, orientation_2d const &orient)
F function in the original paper remove point if found, otherwise insert.
container_traits< rectangle_set_type >::value_type rectangle_type
internal rectangle type
direction_2d
direction type for rectangles
Definition: Geometry.h:72
horizontal/vertical slicing and choose rectangle with smaller area every time
Definition: Geometry.h:44
sort helper if orient == HORIZONTAL, sort by left lower if orient == VERTICAL, sort by lower left ...
slicing_orientation_2d m_slicing_orient
slicing orient
void initialize(slicing_orientation_2d slicing_orient)
initialize with slicing orientation it must be called before initializing other data ...
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(InputIterator input_begin, InputIterator input_end)
initialize polygon points
slicing_orientation_2d
orientation type for slicing
Definition: Geometry.h:39
void set(point_type &p, orientation_2d o, coordinate_type v) const
set coordinate of point
type traits for containers such as vector, list, multiset
Definition: Geometry.h:254
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 ...
a class implement conversion from manhattan polygon to rectangle
point_traits< point_type >::coordinate_type coordinate_type
point set type for polygon
bool is_number(string const &s)
check whether string represents a number, either integer or floating point number ...
Definition: String.h:62
static coordinate_type get(rectangle_type const &rectangle, direction_2d const &direct)
get coordinate from rectangle
Definition: Geometry.h:210
horizontal/vertical slicing and choose rectangle with better aspect ratio every time ...
Definition: Geometry.h:45
orientation_2d get_perpendicular() const
get perpendicular orientation
Definition: Geometry.h:124
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< point_set_type >::value_type point_type
internal point type
namespace for Limbo
Definition: GraphUtility.h:22
std::iterator_traits< Iterator >::value_type max(Iterator first, Iterator last)
get max of an array
Definition: Math.h:61
type traits for coordinates
Definition: Geometry.h:146
static void insert(container_type &container, value_type const &v)
insert value to container
Definition: Geometry.h:264
void print(string const &filename) const
print polygon to file in gnuplot format
void F(point_type const &point, orientation_2d const &orient)
F function in the original paper remove point if found, otherwise insert.
horizontal/vertical slicing and choose rectangle with larger area every time
Definition: Geometry.h:43
rectangle_set_type & m_vRect
save all rectangles from conversion
type traits for point
Definition: Geometry.h:168
static void erase(container_type &container, value_type const &v)
erase value from iterator
Definition: Geometry.h:268
coordinate_traits< coordinate_type >::coordinate_distance coordinate_distance
coordinate distance type
bool operator()(point_type const &p1, point_type const &p2) const
is equal helper
std::iterator_traits< Iterator >::value_type min(Iterator first, Iterator last)
get min of an array
Definition: Math.h:77
coordinate_traits< coordinate_type >::manhattan_area_type manhattan_area_type
manhattan area type
bool read(string const &filename)
read polygon from file try to be compatible to gnuplot format
#define assert_msg(condition, message)
assertion with message
Definition: AssertMsg.h:34
a class denoting orientation of lines
Definition: Geometry.h:92
void initialize(InputIterator input_begin, InputIterator input_end)
initialize polygon points
void set(point_type &p, orientation_2d o, coordinate_type v) const
set coordinate of point
Polygon2Rectangle(rectangle_set_type &vRect, slicing_orientation_2d slicing_orient=HORIZONTAL_SLICING)
constructor