1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkVector.h
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 
16 /**
17  * @class   vtkRect
18  * @brief   templated base type for storage of 2D rectangles.
19  *
20  *
21  * This class is a templated data type for storing and manipulating rectangles.
22  * The memory layout is a contiguous array of the specified type, such that a
23  * float[4] can be cast to a vtkRectf and manipulated. Also a float[12] could
24  * be cast and used as a vtkRectf[3].
25  */
26 
27 #ifndef vtkRect_h
28 #define vtkRect_h
29 
30 #include "vtkVector.h"
31 
32 #include "vtkMath.h" // for Min, Max
33 
34 template <typename T>
35 class vtkRect : public vtkVector<T, 4>
36 {
37 public:
38   vtkRect() = default;
39 
vtkRect(const T & x,const T & y,const T & width,const T & height)40   vtkRect(const T& x, const T& y, const T& width, const T& height)
41   {
42     this->Data[0] = x;
43     this->Data[1] = y;
44     this->Data[2] = width;
45     this->Data[3] = height;
46   }
47 
vtkRect(const T * init)48   explicit vtkRect(const T* init)
49     : vtkVector<T, 4>(init)
50   {
51   }
52 
53   ///@{
54   /**
55    * Set the x, y components of the rectangle, and the width/height.
56    */
Set(const T & x,const T & y,const T & width,const T & height)57   void Set(const T& x, const T& y, const T& width, const T& height)
58   {
59     this->Data[0] = x;
60     this->Data[1] = y;
61     this->Data[2] = width;
62     this->Data[3] = height;
63   }
64   ///@}
65 
66   /**
67    * Set the x component of the rectangle bottom corner, i.e. element 0.
68    */
SetX(const T & x)69   void SetX(const T& x) { this->Data[0] = x; }
70 
71   /**
72    * Get the x component of the rectangle bottom corner, i.e. element 0.
73    */
GetX()74   const T& GetX() const { return this->Data[0]; }
75 
76   /**
77    * Set the y component of the rectangle bottom corner, i.e. element 1.
78    */
SetY(const T & y)79   void SetY(const T& y) { this->Data[1] = y; }
80 
81   /**
82    * Get the y component of the rectangle bottom corner, i.e. element 1.
83    */
GetY()84   const T& GetY() const { return this->Data[1]; }
85 
86   /**
87    * Set the width of the rectanle, i.e. element 2.
88    */
SetWidth(const T & width)89   void SetWidth(const T& width) { this->Data[2] = width; }
90 
91   /**
92    * Get the width of the rectangle, i.e. element 2.
93    */
GetWidth()94   const T& GetWidth() const { return this->Data[2]; }
95 
96   /**
97    * Set the height of the rectangle, i.e. element 3.
98    */
SetHeight(const T & height)99   void SetHeight(const T& height) { this->Data[3] = height; }
100 
101   /**
102    * Get the height of the rectangle, i.e. element 3.
103    */
GetHeight()104   const T& GetHeight() const { return this->Data[3]; }
105 
106   /**
107    * Get the left boundary of the rectangle along the X direction.
108    */
GetLeft()109   const T& GetLeft() const { return this->Data[0]; }
110 
111   /**
112    * Get the right boundary of the rectangle along the X direction.
113    */
GetRight()114   T GetRight() const { return this->Data[0] + this->Data[2]; }
115 
116   /**
117    * Get the top boundary of the rectangle along the Y direction.
118    */
GetTop()119   T GetTop() const { return this->Data[1] + this->Data[3]; }
120 
121   /**
122    * Get the bottom boundary of the rectangle along the Y direction.
123    */
GetBottom()124   const T& GetBottom() const { return this->Data[1]; }
125 
126   /**
127    * Get the bottom left corner of the rect as a vtkVector.
128    */
GetBottomLeft()129   vtkVector2<T> GetBottomLeft() const { return vtkVector2<T>(this->GetLeft(), this->GetBottom()); }
130 
131   /**
132    * Get the top left corner of the rect as a vtkVector.
133    */
GetTopLeft()134   vtkVector<T, 2> GetTopLeft() const { return vtkVector2<T>(this->GetLeft(), this->GetTop()); }
135 
136   /**
137    * Get the bottom right corner of the rect as a vtkVector.
138    */
GetBottomRight()139   vtkVector<T, 2> GetBottomRight() const
140   {
141     return vtkVector2<T>(this->GetRight(), this->GetBottom());
142   }
143 
144   /**
145    * Get the bottom left corner of the rect as a vtkVector.
146    */
GetTopRight()147   vtkVector<T, 2> GetTopRight() const { return vtkVector2<T>(this->GetRight(), this->GetTop()); }
148 
149   ///@{
150   /**
151    * Expand this rect to contain the point passed in.
152    */
AddPoint(const T point[2])153   void AddPoint(const T point[2])
154   {
155     // This code is written like this to ensure that adding a point gives
156     // exactly the same result as AddRect(vtkRect(x,y,0,0)
157     if (point[0] < this->GetX())
158     {
159       T dx = this->GetX() - point[0];
160       this->SetX(point[0]);
161       this->SetWidth(dx + this->GetWidth());
162     }
163     else if (point[0] > this->GetX())
164     {
165       // this->GetX() is already correct
166       T dx = point[0] - this->GetX();
167       this->SetWidth(vtkMath::Max(dx, this->GetWidth()));
168     }
169     ///@}
170 
171     if (point[1] < this->GetY())
172     {
173       T dy = this->GetY() - point[1];
174       this->SetY(point[1]);
175       this->SetHeight(dy + this->GetHeight());
176     }
177     else if (point[1] > this->GetY())
178     {
179       // this->GetY() is already correct
180       T dy = point[1] - this->GetY();
181       this->SetHeight(vtkMath::Max(dy, this->GetHeight()));
182     }
183   }
184 
185   ///@{
186   /**
187    * Expand this rect to contain the point passed in.
188    */
AddPoint(T x,T y)189   void AddPoint(T x, T y)
190   {
191     T point[2] = { x, y };
192     this->AddPoint(point);
193   }
194   ///@}
195 
196   ///@{
197   /**
198    * Expand this rect to contain the rect passed in.
199    */
AddRect(const vtkRect<T> & rect)200   void AddRect(const vtkRect<T>& rect)
201   {
202     if (rect.GetX() < this->GetX())
203     {
204       T dx = this->GetX() - rect.GetX();
205       this->SetX(rect.GetX());
206       this->SetWidth(vtkMath::Max(dx + this->GetWidth(), rect.GetWidth()));
207     }
208     else if (rect.GetX() > this->GetX())
209     {
210       T dx = rect.GetX() - this->GetX();
211       // this->GetX() is already correct
212       this->SetWidth(vtkMath::Max(dx + rect.GetWidth(), this->GetWidth()));
213     }
214     else
215     {
216       // this->GetX() is already correct
217       this->SetWidth(vtkMath::Max(rect.GetWidth(), this->GetWidth()));
218     }
219     ///@}
220 
221     if (rect.GetY() < this->GetY())
222     {
223       T dy = this->GetY() - rect.GetY();
224       this->SetY(rect.GetY());
225       this->SetHeight(vtkMath::Max(dy + this->GetHeight(), rect.GetHeight()));
226     }
227     else if (rect.GetY() > this->GetY())
228     {
229       T dy = rect.GetY() - this->GetY();
230       // this->GetY() is already correct
231       this->SetHeight(vtkMath::Max(dy + rect.GetHeight(), this->GetHeight()));
232     }
233     else
234     {
235       // this->GetY() is already correct
236       this->SetHeight(vtkMath::Max(rect.GetHeight(), this->GetHeight()));
237     }
238   }
239 
240   /**
241    * Returns true if the rect argument overlaps this rect.
242    * If the upper bound of one rect is equal to the lower bound of
243    * the other rect, then this will return false (in that case, the
244    * rects would be considered to be adjacent but not overlapping).
245    */
IntersectsWith(const vtkRect<T> & rect)246   bool IntersectsWith(const vtkRect<T>& rect) const
247   {
248     bool intersects = true;
249 
250     if (rect.GetX() < this->GetX())
251     {
252       T dx = this->GetX() - rect.GetX();
253       intersects &= (dx < rect.GetWidth());
254     }
255     else if (rect.GetX() > this->GetX())
256     {
257       T dx = rect.GetX() - this->GetX();
258       intersects &= (dx < this->GetWidth());
259     }
260 
261     if (rect.GetY() < this->GetY())
262     {
263       T dy = this->GetY() - rect.GetY();
264       intersects &= (dy < rect.GetHeight());
265     }
266     else if (rect.GetY() > this->GetY())
267     {
268       T dy = rect.GetY() - this->GetY();
269       intersects &= (dy < this->GetHeight());
270     }
271 
272     return intersects;
273   }
274 
275   /**
276    * Move the rectangle, moving the bottom-left corner
277    * to the given position. The rectangles size remains unchanged.
278    */
MoveTo(T x,T y)279   void MoveTo(T x, T y)
280   {
281     this->Data[0] = x;
282     this->Data[1] = y;
283   }
284 
285   /**
286    * Intersect with `other` rectangle. If `this->IntersectsWith(other)` is true,
287    * this method will update this rect to the intersection of `this` and
288    * `other` and return true. If `this->IntersectsWith(other)` returns false,
289    * then this method will return false leaving this rect unchanged.
290    *
291    * Returns true if the intersection was performed otherwise false.
292    */
Intersect(const vtkRect<T> & other)293   bool Intersect(const vtkRect<T>& other)
294   {
295     if (this->IntersectsWith(other))
296     {
297       const T left = vtkMath::Max(this->GetLeft(), other.GetLeft());
298       const T bottom = vtkMath::Max(this->GetBottom(), other.GetBottom());
299       const T right = vtkMath::Min(this->GetRight(), other.GetRight());
300       const T top = vtkMath::Min(this->GetTop(), other.GetTop());
301 
302       this->Data[0] = left;
303       this->Data[1] = bottom;
304       this->Data[2] = (right - left);
305       this->Data[3] = (top - bottom);
306       return true;
307     }
308     return false;
309   }
310 
311   /**
312    * Returns the center of the rect as a vtkVector2d.
313    */
GetCenter()314   vtkVector2d GetCenter() const
315   {
316     return vtkVector2d(
317       this->GetX() + 0.5 * this->GetWidth(), this->GetY() + 0.5 * this->GetHeight());
318   }
319 };
320 
321 class vtkRecti : public vtkRect<int>
322 {
323 public:
324   vtkRecti() = default;
vtkRecti(int x,int y,int width,int height)325   vtkRecti(int x, int y, int width, int height)
326     : vtkRect<int>(x, y, width, height)
327   {
328   }
vtkRecti(const int * init)329   explicit vtkRecti(const int* init)
330     : vtkRect<int>(init)
331   {
332   }
333 };
334 
335 class vtkRectf : public vtkRect<float>
336 {
337 public:
338   vtkRectf() = default;
vtkRectf(float x,float y,float width,float height)339   vtkRectf(float x, float y, float width, float height)
340     : vtkRect<float>(x, y, width, height)
341   {
342   }
vtkRectf(const float * init)343   explicit vtkRectf(const float* init)
344     : vtkRect<float>(init)
345   {
346   }
347 };
348 
349 class vtkRectd : public vtkRect<double>
350 {
351 public:
352   vtkRectd() = default;
vtkRectd(double x,double y,double width,double height)353   vtkRectd(double x, double y, double width, double height)
354     : vtkRect<double>(x, y, width, height)
355   {
356   }
vtkRectd(const double * init)357   explicit vtkRectd(const double* init)
358     : vtkRect<double>(init)
359   {
360   }
361 };
362 
363 #endif // vtkRect_h
364 // VTK-HeaderTest-Exclude: vtkRect.h
365