1 /* === S Y N F I G ========================================================= */
2 /*!	\file rect.h
3 **	\brief Rectangle Class
4 **
5 **	$Id$
6 **
7 **	\legal
8 **	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **	Copyright (c) 2007, 2008 Chris Moore
10 **
11 **	This package is free software; you can redistribute it and/or
12 **	modify it under the terms of the GNU General Public License as
13 **	published by the Free Software Foundation; either version 2 of
14 **	the License, or (at your option) any later version.
15 **
16 **	This package is distributed in the hope that it will be useful,
17 **	but WITHOUT ANY WARRANTY; without even the implied warranty of
18 **	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 **	General Public License for more details.
20 **	\endlegal
21 */
22 /* ========================================================================= */
23 
24 /* === S T A R T =========================================================== */
25 
26 #ifndef __SYNFIG_RECT_H
27 #define __SYNFIG_RECT_H
28 
29 /* === H E A D E R S ======================================================= */
30 
31 #include <ETL/rect>
32 #include "real.h"
33 #include "vector.h"
34 #include <limits>
35 #include <cmath>
36 
37 /* === M A C R O S ========================================================= */
38 
39 /* === T Y P E D E F S ===================================================== */
40 
41 /* === C L A S S E S & S T R U C T S ======================================= */
42 
43 namespace synfig {
44 
45 class RectInt : public etl::rect<int>
46 {
47 public:
48 	typedef etl::rect<int> baserect;
49 
50 	using baserect::set_point;
51 	using baserect::expand;
52 	using baserect::set;
53 
zero()54 	static RectInt zero()
55 	{
56 		return RectInt(
57 			0,
58 			0,
59 			0,
60 			0
61 		);
62 	}
63 
RectInt()64 	RectInt(): baserect(0, 0, 0, 0) { }
65 
RectInt(const PointInt & x)66 	RectInt(const PointInt& x) { set_point(x); }
67 
RectInt(const PointInt & min,const PointInt & max)68 	RectInt(const PointInt& min, const PointInt& max) { set_point(min); expand(max); }
69 
RectInt(const value_type & x1,const value_type & y1)70 	RectInt(const value_type &x1,const value_type &y1)	{ set_point(x1,y1); }
71 
RectInt(const value_type & x1,const value_type & y1,const value_type & x2,const value_type & y2)72 	RectInt(const value_type &x1,const value_type &y1,
73 			const value_type &x2,const value_type &y2)
74 	{
75 		set_point(x1,y1);
76 		expand(x2,y2);
77 	}
78 
set_point(const PointInt & max)79 	void set_point(const PointInt& max) { set_point(max[0],max[1]);	}
80 
expand(const PointInt & max)81 	RectInt& expand(const PointInt& max) { expand(max[0],max[1]); return *this; }
82 
expand(const int & r)83 	RectInt& expand(const int& r) { minx-=r; miny-=r; maxx+=r; maxy+=r; return *this; }
84 
expand_x(const int & r)85 	RectInt& expand_x(const int& r) { minx-=r; maxx+=r; return *this; }
86 
expand_y(const int & r)87 	RectInt& expand_y(const int& r) { miny-=r; maxy+=r; return *this; }
88 
set(const PointInt & min,const PointInt & max)89 	RectInt& set(const PointInt& min,const PointInt& max) { set(min[0],min[1],max[0],max[1]); return *this; }
90 
get_min()91 	PointInt get_min()const { return PointInt(minx,miny); }
get_max()92 	PointInt get_max()const { return PointInt(maxx,maxy); }
get_size()93 	VectorInt get_size()const { return get_max() - get_min(); }
get_width()94 	value_type get_width()const { return maxx - minx; }
get_height()95 	value_type get_height()const { return maxy - miny; }
96 
is_inside(const PointInt & x)97 	bool is_inside(const PointInt& x) { return x[0]>=minx && x[0]<maxx && x[1]>=miny && x[1]<maxy; }
98 
area()99 	int area()const
100 	{
101 		return (maxx-minx)*(maxy-miny);
102 	}
103 
104 	// Operators
105 
106 	RectInt& operator+=(const VectorInt& rhs)
107 	{
108 		minx+=rhs[0]; miny+=rhs[1];
109 		maxx+=rhs[0]; maxy+=rhs[1];
110 		return *this;
111 	}
112 
113 	RectInt& operator-=(const VectorInt& rhs)
114 	{
115 		minx-=rhs[0]; miny-=rhs[1];
116 		maxx-=rhs[0]; maxy-=rhs[1];
117 		return *this;
118 	}
119 
120 	RectInt& operator*=(const int& rhs)
121 	{
122 		minx*=rhs; miny*=rhs;
123 		maxx*=rhs; maxy*=rhs;
124 		return *this;
125 	}
126 
127 	RectInt& operator/=(int rhs)
128 	{
129 		minx/=rhs; miny/=rhs;
130 		maxx/=rhs; maxy/=rhs;
131 		return *this;
132 	}
133 
134 	RectInt& operator&=(const RectInt& rhs)
135 	{
136 		if(rhs.valid() && valid())
137 			etl::set_intersect(*this,*this,rhs);
138 		else
139 			*this=zero();
140 		return *this;
141 	}
142 
143 	RectInt& operator|=(const RectInt& rhs)
144 	{
145 		if(rhs.valid()>0 && valid()>0)
146 			etl::set_union(*this,*this,rhs);
147 		else
148 		{
149 			if(area()<rhs.area())
150 				*this=rhs;
151 		}
152 		return *this;
153 	}
154 
155 	RectInt operator+(const VectorInt& rhs)const { return RectInt(*this)+=rhs; }
156 
157 	RectInt operator-(const VectorInt& rhs)const { return RectInt(*this)-=rhs; }
158 
159 	RectInt operator*(const int& rhs)const { return RectInt(*this)*=rhs; }
160 
161 	RectInt operator/(const int& rhs)const { return RectInt(*this)/=rhs; }
162 
163 	RectInt operator&(const RectInt& rhs)const { return RectInt(*this)&=rhs; }
164 
165 	RectInt operator|(const RectInt& rhs)const { return RectInt(*this)|=rhs; }
166 
167 	bool operator&&(const RectInt& rhs)const { return valid() && rhs.valid() && etl::intersect(*this, rhs); }
168 
169 	bool operator==(const RectInt &rhs)const { return get_min() == rhs.get_min() && get_max() == rhs.get_max(); }
170 
171 	bool operator!=(const RectInt &rhs)const { return get_min() != rhs.get_min() || get_max() != rhs.get_max(); }
172 
contains(const RectInt & x)173 	bool contains(const RectInt &x)const { return etl::contains(*this, x); }
174 
is_valid()175 	bool is_valid()const { return valid(); }
176 
177 	template<typename List>
merge(List & list)178 	static void merge(List &list)
179 		{ etl::rects_merge(list); }
180 
181 	template<typename List>
list_add(List & list)182 	void list_add(List &list)
183 		{ etl::rects_add(list, *this); merge(list); }
184 
185 	template<typename List>
list_subtract(List & list)186 	void list_subtract(List &list)
187 		{ etl::rects_subtract(list, *this); merge(list); }
188 
multiply_coords(const VectorInt & rhs)189 	RectInt multiply_coords(const VectorInt &rhs) const
190 		{ return RectInt(minx*rhs[0], miny*rhs[1], maxx*rhs[0], maxy*rhs[1]); }
divide_coords(const VectorInt & rhs)191 	RectInt divide_coords(const VectorInt &rhs) const
192 		{ return RectInt(minx/rhs[0], miny/rhs[1], maxx/rhs[0], maxy/rhs[1]); }
193 }; // END of class RectInt
194 
195 
196 class Rect : public etl::rect<Real>
197 {
198 public:
199 	typedef etl::rect<Real> baserect;
200 
201 	using baserect::set_point;
202 	using baserect::expand;
203 	using baserect::set;
204 
205 	static Rect full_plane();
206 
207 	static Rect horizontal_strip(const value_type &y1, const value_type &y2);
208 	static Rect vertical_strip(const value_type &x1, const value_type &x2);
209 
zero()210 	static Rect zero()
211 	{
212 		return Rect(
213 			0,
214 			0,
215 			0,
216 			0
217 		);
218 	}
219 
infinite()220 	static Rect infinite()
221 	{
222 		return Rect(
223 			-INFINITY,
224 			-INFINITY,
225 			INFINITY,
226 			INFINITY
227 		);
228 	}
229 
Rect()230 	Rect(): baserect(0, 0, 0, 0) { }
231 
Rect(const Point & x)232 	Rect(const Point& x) { set_point(x); }
233 
Rect(const Point & min,const Point & max)234 	Rect(const Point& min, const Point& max) { set_point(min); expand(max); }
235 
Rect(const value_type & x1,const value_type & y1)236 	Rect(const value_type &x1,const value_type &y1)	{ set_point(x1,y1); }
237 
Rect(const value_type & x1,const value_type & y1,const value_type & x2,const value_type & y2)238 	Rect(const value_type &x1,const value_type &y1,
239 			const value_type &x2,const value_type &y2)
240 	{
241 		set_point(x1,y1);
242 		expand(x2,y2);
243 	}
244 
set_point(const Point & max)245 	void set_point(const Point& max) { set_point(max[0],max[1]);	}
246 
expand(const Point & max)247 	Rect& expand(const Point& max) { expand(max[0],max[1]); return *this; }
248 
expand(const Real & r)249 	Rect& expand(const Real& r) { minx-=r; miny-=r; maxx+=r; maxy+=r; return *this; }
250 
expand_x(const Real & r)251 	Rect& expand_x(const Real& r) { minx-=r; maxx+=r; return *this; }
252 
expand_y(const Real & r)253 	Rect& expand_y(const Real& r) { miny-=r; maxy+=r; return *this; }
254 
set(const Point & min,const Point & max)255 	Rect& set(const Point& min,const Point& max) { set(min[0],min[1],max[0],max[1]); return *this; }
256 
get_min()257 	Point get_min()const { return Point(minx,miny); }
get_max()258 	Point get_max()const { return Point(maxx,maxy); }
get_size()259 	Vector get_size()const { return get_max() - get_min(); }
get_width()260 	value_type get_width()const { return maxx - minx; }
get_height()261 	value_type get_height()const { return maxy - miny; }
262 
is_inside(const Point & x)263 	bool is_inside(const Point& x)
264 	{
265 		return approximate_less_or_equal(minx, x[0])
266 			&& approximate_less_or_equal(x[0], maxx)
267 			&& approximate_less_or_equal(miny, x[1])
268 			&& approximate_less_or_equal(x[1], maxy);
269 	}
270 
area()271 	Real area()const
272 	{
273 		return (maxx-minx)*(maxy-miny);
274 	}
275 
276 	// Operators
277 
278 	Rect& operator+=(const Vector& rhs)
279 	{
280 		minx+=rhs[0]; miny+=rhs[1];
281 		maxx+=rhs[0]; maxy+=rhs[1];
282 		return *this;
283 	}
284 
285 	Rect& operator-=(const Vector& rhs)
286 	{
287 		minx-=rhs[0]; miny-=rhs[1];
288 		maxx-=rhs[0]; maxy-=rhs[1];
289 		return *this;
290 	}
291 
292 	Rect& operator*=(const Real& rhs)
293 	{
294 		minx*=rhs; miny*=rhs;
295 		maxx*=rhs; maxy*=rhs;
296 		return *this;
297 	}
298 
299 	Rect& operator/=(Real rhs)
300 	{
301 		rhs=1.0/rhs; // Avoid doing several divisions
302 		minx*=rhs; miny*=rhs;
303 		maxx*=rhs; maxy*=rhs;
304 		return *this;
305 	}
306 
307 	Rect& operator&=(const Rect& rhs)
308 	{
309 		if ( rhs.valid() && valid()
310 		  && rhs.area()>0.00000001 && area()>0.00000001 )
311 			etl::set_intersect(*this,*this,rhs);
312 		else
313 			*this=zero();
314 		return *this;
315 	}
316 
317 	Rect& operator|=(const Rect& rhs)
318 	{
319 		if ( rhs.valid() && valid()
320 		  && rhs.area()>0.00000001 && area()>0.00000001 )
321 			etl::set_union(*this,*this,rhs);
322 		else
323 		{
324 			if(area()<rhs.area())
325 				*this=rhs;
326 		}
327 		return *this;
328 	}
329 
330 	Rect operator+(const Vector& rhs)const { return Rect(*this)+=rhs; }
331 
332 	Rect operator-(const Vector& rhs)const { return Rect(*this)-=rhs; }
333 
334 	Rect operator*(const Real& rhs)const { return Rect(*this)*=rhs; }
335 
336 	Rect operator/(const Real& rhs)const { return Rect(*this)/=rhs; }
337 
338 	Rect operator&(const Rect& rhs)const { return Rect(*this)&=rhs; }
339 
340 	Rect operator|(const Rect& rhs)const { return Rect(*this)|=rhs; }
341 
342 	bool operator&&(const Rect& rhs)const { return valid() && rhs.valid() && etl::intersect(*this, rhs); }
343 
344 	bool operator==(const Rect &rhs)const { return get_min() == rhs.get_min() && get_max() == rhs.get_max(); }
345 
346 	bool operator!=(const Rect &rhs)const { return get_min() != rhs.get_min() || get_max() != rhs.get_max(); }
347 
contains(const Rect & x)348 	bool contains(const Rect &x)const { return etl::contains(*this, x, approximate_less<Real>); }
349 
valid()350 	bool valid()const { return etl::rect<value_type>::valid(approximate_less<Real>); }
is_valid()351 	bool is_valid()const { return valid(); }
is_nan_or_inf()352 	bool is_nan_or_inf()const
353 	{
354 		return std::isnan(minx)
355 			|| std::isnan(miny)
356 			|| std::isinf(maxx)
357 			|| std::isinf(maxy);
358 	}
359 
360 	template<typename List>
merge(List & list)361 	static void merge(List &list)
362 		{ etl::rects_merge(list, approximate_less<Real>); }
363 
364 	template<typename List>
list_add(List & list)365 	void list_add(List &list)
366 		{ etl::rects_add(list, *this, approximate_less<Real>); merge(list); }
367 
368 	template<typename List>
list_subtract(List & list)369 	void list_subtract(List &list)
370 		{ etl::rects_subtract(list, *this, approximate_less<Real>); merge(list); }
371 
multiply_coords(const Vector & rhs)372 	Rect multiply_coords(const Vector &rhs) const
373 		{ return Rect(minx*rhs[0], miny*rhs[1], maxx*rhs[0], maxy*rhs[1]); }
divide_coords(const Vector & rhs)374 	Rect divide_coords(const Vector &rhs) const
375 		{ return Rect(minx/rhs[0], miny/rhs[1], maxx/rhs[0], maxy/rhs[1]); }
376 }; // END of class Rect
377 
378 }; // END of namespace synfig
379 
380 /* === E N D =============================================================== */
381 
382 #endif
383