libcrn  3.9.5
A document image processing library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CRNRect.cpp
Go to the documentation of this file.
1 /* Copyright 2006-2016 Yann LEYDIER, CoReNum, INSA-Lyon, ENS-Lyon
2  *
3  * This file is part of libcrn.
4  *
5  * libcrn is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser 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  * libcrn 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 Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with libcrn. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * file: CRNRect.cpp
19  * \author Yann LEYDIER
20  */
21 
22 #include <CRNIO/CRNIO.h>
23 #include <limits>
24 
25 #include <CRNGeometry/CRNRect.h>
26 #include <CRNData/CRNDataFactory.h>
27 #include <CRNi18n.h>
28 
29 using namespace crn;
30 
31 /*****************************************************************************/
38 bool Rect::operator==(const Rect &r) const noexcept
39 {
40  if (valid && r.valid && (GetLeft() == r.GetLeft()) && (GetRight() == r.GetRight()) &&
41  (GetTop() == r.GetTop()) && (GetBottom() == r.GetBottom()))
42  return true;
43  else if (!valid && !r.valid)
44  return true;
45  else
46  return false;
47 }
48 
49 /*****************************************************************************/
56 bool Rect::operator!=(const Rect &r) const noexcept
57 {
58  if (!valid || !r.valid)
59  return true;
60  else if ((GetLeft() != r.GetLeft()) || (GetRight() != r.GetRight()) ||
61  (GetTop() != r.GetTop()) || (GetBottom() != r.GetBottom()))
62  return true;
63  else
64  return false;
65 }
66 
67 /*****************************************************************************/
74 Rect Rect::operator&(const Rect &r) const
75 {
76  if (valid && r.valid)
77  {
78  int left, right, top, bottom;
79  left = Max(GetLeft(), r.GetLeft());
80  right = Min(GetRight(), r.GetRight());
81  top = Max(GetTop(), r.GetTop());
82  bottom = Min(GetBottom(), r.GetBottom());
83  if ((left <= right) && (top <= bottom))
84  {
85  return Rect(left, top, right, bottom);
86  }
87  }
88  return Rect();
89 }
90 
91 /*****************************************************************************/
101 int Rect::Overlap(const Rect &r, Orientation orientation) const
102 {
103  if (!!(orientation & Orientation::HORIZONTAL))
104  {
105  return std::min(GetBottom(), r.GetBottom()) - std::max(GetTop(), r.GetTop());
106  }
107  else if (!!(orientation & Orientation::VERTICAL))
108  {
109  return std::min(GetRight(), r.GetRight()) - std::max(GetLeft(), r.GetLeft());
110  }
111  else
112  throw ExceptionInvalidArgument(_("No orientation given."));
113 }
114 
115 
116 
117 /*****************************************************************************/
124 Rect Rect::operator|(const Rect &r) const
125 {
126  if (valid && r.valid)
127  {
128  int left, right, top, bottom;
129  left = Min(GetLeft(), r.GetLeft());
130  right = Max(GetRight(), r.GetRight());
131  top = Min(GetTop(), r.GetTop());
132  bottom = Max(GetBottom(), r.GetBottom());
133  return Rect(left, top, right, bottom);
134  }
135  if (valid)
136  return Rect(bx, ex, by, ey);
137  if (r.valid)
138  return Rect(r.bx, r.ex, r.by, r.ey);
139  return Rect();
140 }
141 
147 void Rect::operator&=(const Rect &r)
148 {
149  if (valid && r.valid)
150  {
151  int left, right, top, bottom;
152  left = Max(GetLeft(), r.GetLeft());
153  right = Min(GetRight(), r.GetRight());
154  top = Max(GetTop(), r.GetTop());
155  bottom = Min(GetBottom(), r.GetBottom());
156  if (left > right || top > bottom)
157  {
158  valid = false;
159  }
160  else
161  {
162  SetLeft(left);
163  SetRight(right);
164  SetTop(top);
165  SetBottom(bottom);
166  }
167  }
168  else
169  valid = false;
170 }
171 
172 /*****************************************************************************/
178 void Rect::operator|=(const Rect &r)
179 {
180  if (valid && r.valid)
181  {
182  int left, right, top, bottom;
183  left = Min(GetLeft(), r.GetLeft());
184  right = Max(GetRight(), r.GetRight());
185  top = Min(GetTop(), r.GetTop());
186  bottom = Max(GetBottom(), r.GetBottom());
187  SetLeft(left);
188  SetRight(right);
189  SetTop(top);
190  SetBottom(bottom);
191  }
192  else if (!valid && r.valid)
193  {
194  SetLeft(r.bx);
195  SetRight(r.ex);
196  SetTop(r.by);
197  SetBottom(r.ey);
198  }
199 }
200 
201 /*****************************************************************************/
207 {
208  if (valid)
209  {
210  String s(U"(");
211  s += bx;
212  s += U" x ";
213  s += by;
214  s += U"), (";
215  s += ex;
216  s += U" x ";
217  s += ey;
218  s += U") -> (";
219  s += w;
220  s += U" x ";
221  s += h;
222  s += U")";
223  return s;
224  }
225  else
226  return String(_("The rectangle isn't initialized."));
227 }
228 
237 {
238  if ((sort_direction == Direction::LEFT) || (sort_direction == Direction::RIGHT) ||
239  (sort_direction == Direction::TOP) || (sort_direction == Direction::BOTTOM))
240  {
241  direction = sort_direction;
242  }
243  else
244  {
245  throw ExceptionInvalidArgument(StringUTF8("Rect::Sorter::Sorter(int sort_direction): ") +
246  _("Wrong direction."));
247  }
248 }
249 
257 bool Rect::Sorter::operator()(const Rect &r1, const Rect &r2) const
258 {
259  if (direction == Direction::RIGHT)
260  {
261  // right to left
262  if (r1.GetRight() < r2.GetRight())
263  {
264  return true;
265  }
266  else
267  {
268  return false;
269  }
270  }
271  else if (direction == Direction::LEFT)
272  {
273  // left to right
274  if (r1.GetLeft() < r2.GetLeft())
275  {
276  return true;
277  }
278  else
279  {
280  return false;
281  }
282  }
283  else if (direction == Direction::TOP)
284  {
285  // top to bottom
286  if (r1.GetTop() < r2.GetTop())
287  {
288  return true;
289  }
290  else
291  {
292  return false;
293  }
294  }
295  else if (direction == Direction::BOTTOM)
296  {
297  // bottom to top
298  if (r1.GetBottom() < r2.GetBottom())
299  {
300  return true;
301  }
302  else
303  {
304  return false;
305  }
306  }
307  return false;
308 }
309 
310 
319 {
320  if ((sort_direction == Direction::LEFT) || (sort_direction == Direction::RIGHT) ||
321  (sort_direction == Direction::TOP) || (sort_direction == Direction::BOTTOM))
322  {
323  direction = sort_direction;
324  }
325  else
326  {
327  throw ExceptionInvalidArgument(StringUTF8("Rect::Sorter::Sorter(int sort_direction): ") +
328  _("Wrong direction."));
329  }
330 }
331 
340 bool Rect::OrthogonalSorter::operator()(const Rect &r1, const Rect &r2) const
341 {
342  if (direction == Direction::RIGHT)
343  {
344  // right to left
345  if ((r1.GetRight() > r2.GetRight()) && (r1.Overlap(r2, Orientation::HORIZONTAL) > 0))
346  {
347  return true;
348  }
349  else
350  {
351  return false;
352  }
353  }
354  else if (direction == Direction::LEFT)
355  {
356  // left to right
357  if ((r1.GetLeft() < r2.GetLeft()) && (r1.Overlap(r2, Orientation::HORIZONTAL) > 0))
358  {
359  return true;
360  }
361  else
362  {
363  return false;
364  }
365  }
366  else if (direction == Direction::TOP)
367  {
368  // top to bottom
369  if ((r1.GetTop() < r2.GetTop()) && (r1.Overlap(r2, Orientation::VERTICAL) > 0))
370  {
371  return true;
372  }
373  else
374  {
375  return false;
376  }
377  }
378  else if (direction == Direction::BOTTOM)
379  {
380  // bottom to top
381  if ((r1.GetBottom() > r2.GetBottom()) && (r1.Overlap(r2, Orientation::VERTICAL) > 0))
382  {
383  return true;
384  }
385  else
386  {
387  return false;
388  }
389  }
390  return false;
391 }
392 
401 bool Rect::InclusionSorter::operator()(const Rect &r1, const Rect &r2) const
402 {
403  int t = r1.GetTop();
404  int b = r1.GetBottom();
405  int l = r1.GetLeft();
406  int r = r1.GetRight();
407 
408  return (r2.Contains(l, t) && r2.Contains(l, b) && r2.Contains(r, t) && r2.Contains(r, b));
409 }
410 
420 {
421  double s1 = (double)r1.GetWidth() / (double)r1.GetHeight();
422  double s2 = (double)r2.GetWidth() / (double)r2.GetHeight();
423 
424  return (s1 < s2);
425 }
426 
436 const Rect& Rect::operator*=(double s)
437 {
438  if (!valid)
439  throw ExceptionUninitialized(_("The rectangle isn't initialized."));
440  if (s <= 0.0)
441  throw ExceptionInvalidArgument(_("negative scale."));
442 
443  Rect r((int)(GetLeft() * s), (int)(GetTop() * s));
444  r.SetWidth(Max((int)(GetWidth() * s), 1));
445  r.SetHeight(Max((int)(GetHeight() * s), 1));
446  *this = r;
447  return *this;
448 }
449 
450 /*****************************************************************************/
460 Rect Rect::operator*(double s) const
461 {
462  if (!valid)
463  throw ExceptionUninitialized(_("The rectangle isn't initialized."));
464  if (s <= 0.0)
465  throw ExceptionInvalidArgument(_("negative scale."));
466 
467  Rect r((int)(GetLeft() * s), (int)(GetTop() * s));
468  r.SetWidth(Max((int)(GetWidth() * s), 1));
469  r.SetHeight(Max((int)(GetHeight() * s), 1));
470  return r;
471 }
472 
473 bool Rect::iterator::operator==(const Rect::iterator &other) const noexcept
474 {
475  if (!valid && !other.valid)
476  return true;
477  if ((valid && other.valid) && (pos == other.pos) &&
478  (minx == other.minx) && (maxx == other.maxx) && (maxy == other.maxy))
479  return true;
480  return false;
481 }
482 
484 {
485  if (valid)
486  {
487  pos.X += 1;
488  if (pos.X > maxx)
489  {
490  pos.X = minx;
491  pos.Y += 1;
492  if (pos.Y > maxy)
493  valid = false;
494  }
495  }
496  return *this;
497 }
498 
500 {
501  Rect::iterator temp = *this;
502  ++(*this);
503  return temp;
504 }
505 
506 /*****************************************************************************/
514 bool Rect::Contains(int x, int y) const noexcept
515 {
516  if (x < bx)
517  return false;
518  if (x > ex)
519  return false;
520  if (y < by)
521  return false;
522  if (y > ey)
523  return false;
524  return valid;
525 }
526 
533 bool Rect::Contains(const Rect &rct) const
534 {
535  int t = rct.GetTop();
536  int b = rct.GetBottom();
537  int l = rct.GetLeft();
538  int r = rct.GetRight();
539 
540  return (Contains(l, t) && Contains(r, t) && Contains(l, b) && Contains(r, b));
541 }
542 
551 {
552  if (el.GetName() != "Rect")
553  {
554  throw ExceptionInvalidArgument(StringUTF8("void Rect::Deserialize(xml::Element &el): ") +
555  _("Wrong XML element."));
556  }
557  bx = el.GetAttribute<int>("bx");
558  ex = el.GetAttribute<int>("ex");
559  by = el.GetAttribute<int>("by");
560  ey = el.GetAttribute<int>("ey");
561  try
562  {
563  valid = el.GetAttribute<bool>("v", false);
564  }
565  catch (ExceptionNotFound&)
566  {
567  valid = true;
568  }
569  w = ex - bx + 1;
570  h = ey - by + 1;
571 }
572 
580 {
581  xml::Element el(parent.PushBackElement("Rect"));
582  el.SetAttribute("bx", bx);
583  el.SetAttribute("ex", ex);
584  el.SetAttribute("by", by);
585  el.SetAttribute("ey", ey);
586  el.SetAttribute("v", valid ? 1 : 0);
587  return el;
588 }
589 
598 void Rect::Translate(int x, int y)
599 {
600  if (!valid)
601  throw ExceptionUninitialized(_("The rectangle isn't initialized."));
602  bx += x;
603  ex += x;
604  by += y;
605  ey += y;
606 }
607 
609  rectl(r.GetLeft()),
610  rectt(r.GetTop()),
611  rectr(r.GetRight()),
612  rectb(r.GetBottom()),
613  ref(r.GetCenterX(), r.GetCenterY()),
614  dir(((r.GetWidth() >= r.GetHeight()) ? Direction::RIGHT : Direction::TOP)),
615  pass(0),
616  preproc(false),
617  valid(true)
618 {
619  pos = ref;
620  border = Min(ref.X - r.GetLeft(), ref.Y - r.GetTop());
621  framel = rectl + border;
622  framet = rectl + border;
623  framer = rectr - border;
624  frameb = rectb - border;
625  if (((framel == framer) || (framet == frameb)) && (r.GetWidth() != r.GetHeight()))
626  {
627  preproc = true;
628  if (framel == framer)
629  {
630  pdir = Point2DInt(0, 1);
631  offset = pos.Y - r.GetTop();
632  limit = pos.X - r.GetLeft() - 1;
633  if (r.GetHeight() % 2)
634  pass = 1;
635  }
636  else
637  {
638  pdir = Point2DInt(1, 0);
639  offset = pos.X - r.GetLeft();
640  limit = pos.Y - r.GetTop() - 1;
641  if (r.GetWidth() % 2)
642  pass = 1;
643  }
644  }
645 }
646 
648 {
649  if (!valid && !other.valid)
650  return true;
651  if ((valid && other.valid) && (pos == other.pos) &&
652  (rectl == other.rectl) && (rectt == other.rectt) &&
653  (rectr == other.rectr) && (rectb == other.rectb))
654  return true;
655  return false;
656 }
657 
659 {
660  if (!valid)
661  return *this;
662  if (preproc)
663  {
664  pos = ref;
665  pass ^= 1;
666  if (pass == 0)
667  {
668  offset -= 1;
669  if (offset <= limit)
670  {
671  preproc = false;
672  update();
673  return *this;
674  }
675  if (pdir.X)
676  pos.X = rectl + offset;
677  else
678  pos.Y = rectt + offset;
679  }
680  else
681  {
682  if (pdir.X)
683  pos.X = rectr - offset;
684  else
685  pos.Y = rectb - offset;
686  }
687  }
688  else
689  {
690  if (dir == Direction::RIGHT)
691  {
692  if (pos.X + 1 > framer)
693  {
694  dir = Direction::BOTTOM;
695  }
696  else
697  pos.X += 1;
698  }
699  if (dir == Direction::BOTTOM)
700  {
701  if (pos.Y + 1 > frameb)
702  {
703  dir = Direction::LEFT;
704  }
705  else
706  pos.Y += 1;
707  }
708  if (dir == Direction::LEFT)
709  {
710  if (pos.X - 1 < framel)
711  {
712  dir = Direction::TOP;
713  }
714  else
715  pos.X -= 1;
716  }
717  if (dir == Direction::TOP)
718  {
719  if (pos.Y - 1 < framet)
720  {
721  dir = Direction::RIGHT;
722  update(); // ---------,--> equivalent to goto @"if (dir = RIGHT)"
723  return ++*this; // --/
724  }
725  else
726  pos.Y -= 1;
727  }
728  update();
729  } // no preproc
730  return *this;
731 }
732 
734 {
735  spiral_iterator temp = *this;
736  ++(*this);
737  return temp;
738 }
739 
740 void Rect::spiral_iterator::update()
741 {
742  if (pos == ref)
743  {
744  border -= 1;
745  if (border < 0)
746  {
747  valid = false;
748  return;
749  }
750 
751  framel = rectl + border;
752  framet = rectt + border;
753  framer = rectr - border;
754  frameb = rectb - border;
755  if (dir == Direction::RIGHT)
756  pos.Y -= 1;
757  else if (dir == Direction::BOTTOM)
758  pos.X += 1;
759  else if (dir == Direction::LEFT)
760  pos.Y += 1;
761  else if (dir == Direction::TOP)
762  pos.X -= 1;
763  ref = pos;
764  }
765 }
766 
769  Cloner::Register<Rect>();
771 
virtual const iterator & operator++() noexcept
Definition: CRNRect.cpp:483
bool operator()(const Rect &r1, const Rect &r2) const
Comparison function.
Definition: CRNRect.cpp:340
OrthogonalSorter(Direction sort_direction)
Constructor.
Definition: CRNRect.cpp:318
bool operator==(const spiral_iterator &other) const
Definition: CRNRect.cpp:647
bool operator()(const Rect &r1, const Rect &r2) const
Comparison function.
Definition: CRNRect.cpp:257
Orientation
An enumeration of orientations.
Definition: CRNMath.h:152
bool operator()(const Rect &r1, const Rect &r2) const
Comparison function.
Definition: CRNRect.cpp:419
XML element.
Definition: CRNXml.h:135
int Overlap(const Rect &r, Orientation orientation) const
Compute overlap in a given orientation.
Definition: CRNRect.cpp:101
StringUTF8 GetName() const
Gets the label of the element.
Definition: CRNXml.h:146
#define _(String)
Definition: CRNi18n.h:51
const T & Max(const T &a, const T &b)
Returns the max of two values.
Definition: CRNMath.h:47
int GetBottom() const
Returns the bottommost coordinate.
Definition: CRNRect.h:111
Unintialized object error.
Definition: CRNException.h:155
bool operator()(const Rect &r1, const Rect &r2) const
Comparison function.
Definition: CRNRect.cpp:401
Direction
An enumeration of directions.
Definition: CRNMath.h:122
int SetHeight(int hei)
Changes the height of the rectangle.
Definition: CRNRect.h:221
Rect operator|(const Rect &r) const
Computes the union of two rectangles.
Definition: CRNRect.cpp:124
#define CRN_END_CLASS_CONSTRUCTOR(classname)
Defines a class constructor.
Definition: CRNObject.h:198
int GetTop() const
Returns the topmost coordinate.
Definition: CRNRect.h:107
int GetLeft() const
Returns the leftmost coordinate.
Definition: CRNRect.h:99
A UTF32 character string class.
Definition: CRNString.h:61
void Deserialize(xml::Element &el)
Initializes the object from an XML element. Unsafe.
Definition: CRNRect.cpp:550
int SetBottom(int endY) noexcept
Changes the bottommost coordinate.
Definition: CRNRect.h:194
#define false
Definition: ConvertUTF.cpp:56
int SetWidth(int wid)
Changes the width of the rectangle.
Definition: CRNRect.h:210
bool Contains(int x, int y) const noexcept
Checks if the rectangle contains a point.
Definition: CRNRect.cpp:514
const Rect & operator*=(double s)
Scales the rectangle.
Definition: CRNRect.cpp:436
value_type X
Definition: CRNPoint2D.h:63
#define CRN_DATA_FACTORY_REGISTER(elemname, classname)
Registers a class to the data factory.
xml::Element Serialize(xml::Element &parent) const
Dumps the object to an XML element. Unsafe.
Definition: CRNRect.cpp:579
Sorter(Direction sort_direction)
Constructor.
Definition: CRNRect.cpp:236
void SetAttribute(const StringUTF8 &name, const StringUTF8 &value)
Sets the value of an attribute.
Definition: CRNXml.cpp:595
#define true
Definition: ConvertUTF.cpp:57
void operator&=(const Rect &r)
Keeps only the intersecting part with another rectangle.
Definition: CRNRect.cpp:147
const spiral_iterator & operator++()
Definition: CRNRect.cpp:658
T GetAttribute(const StringUTF8 &name, bool silent=true) const
Gets an attribute.
Definition: CRNXml.h:219
void Translate(int x, int y)
Translates the rectangle.
Definition: CRNRect.cpp:598
int GetHeight() const
Returns the height of the rectangle.
Definition: CRNRect.h:119
Rect operator&(const Rect &r) const
Computes the intersection of two rectangles.
Definition: CRNRect.cpp:74
const T & Min(const T &a, const T &b)
Returns the min of two values.
Definition: CRNMath.h:49
Rect() noexcept
Dummy constructor. DO NOT USE.
Definition: CRNRect.h:50
value_type Y
Definition: CRNPoint2D.h:63
bool operator==(const iterator &other) const noexcept
Definition: CRNRect.cpp:473
int SetRight(int endX) noexcept
Changes the rightmost coordinate.
Definition: CRNRect.h:166
int SetTop(int begY) noexcept
Changes the topmost coordinate.
Definition: CRNRect.h:180
int GetWidth() const
Returns the width of the rectangle.
Definition: CRNRect.h:115
int GetCenterX() const
Returns the horizontal center coordinate.
Definition: CRNRect.h:135
Rect operator*(double s) const
Creates a scaled rectangle.
Definition: CRNRect.cpp:460
void operator|=(const Rect &r)
Merges with another rectangle.
Definition: CRNRect.cpp:178
String ToString() const
Dumps to a string.
Definition: CRNRect.cpp:206
iterator for a Rect
Definition: CRNRect.h:723
bool operator==(const Rect &r) const noexcept
Checks if two rectangles are identical.
Definition: CRNRect.cpp:38
A character string class.
Definition: CRNStringUTF8.h:49
bool operator!=(const Rect &r) const noexcept
Checks if two rectangles are different.
Definition: CRNRect.cpp:56
A 2D point class.
Definition: CRNPoint2DInt.h:39
int GetRight() const
Returns the rightmost coordinate.
Definition: CRNRect.h:103
int GetCenterY() const
Returns the vertical center coordinate.
Definition: CRNRect.h:139
Spiral iterator for a Rect.
Definition: CRNRect.h:758
Element PushBackElement(const StringUTF8 &name)
Adds an element at the end of the children list.
Definition: CRNXml.cpp:355
Invalid argument error (e.g.: nullptr pointer)
Definition: CRNException.h:107
#define CRN_BEGIN_CLASS_CONSTRUCTOR(classname)
Defines a class constructor.
Definition: CRNObject.h:185
int SetLeft(int begX) noexcept
Changes the leftmost coordinate.
Definition: CRNRect.h:152
An item was not found in a container.
Definition: CRNException.h:95
A rectangle class.
Definition: CRNRect.h:46