1 //
2 //   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 //   Free Software Foundation, Inc
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU 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 // This program 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 General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 
19 //
20 // Original author: Sandro Santilli <strk@keybit.net>
21 //
22 
23 #ifndef GNASH_RANGE2D_H
24 #define GNASH_RANGE2D_H
25 
26 #include <ostream>
27 #include <limits>
28 #include <algorithm>
29 #include <cassert> // for inlines
30 #include <cmath> // for floor / ceil
31 #include <cstdint>
32 
33 namespace gnash {
34 
35 namespace geometry {
36 
37 /// Kinds of a range
38 enum RangeKind {
39 	/// Valid range, using finite values
40 	finiteRange,
41 
42 	/// A NULL range is a range enclosing NO points.
43 	nullRange,
44 
45 	/// \brief
46 	/// A WORLD range2d is a range including
47 	/// all points on the plane.
48 	//
49 	/// Note that scaling, shifting and unioning
50 	/// will NOT change a WORLD range.
51 	///
52 	worldRange
53 };
54 
55 namespace detail {
56     template <typename U> struct Promote { typedef U type; };
57     template <> struct Promote<float> { typedef double type; };
58     template <> struct Promote<int> { typedef std::int64_t type; };
59     template <> struct Promote<unsigned int> { typedef std::uint64_t type; };
60 }
61 
62 /// 2d Range template class
63 //
64 /// The class stores 4 values of the type specified
65 /// as template argument, representing the set of points
66 /// enclosed by the given min and max values for the 2 dimensions,
67 /// and provides methods for manipulating them.
68 /// The parameter type must be a numeric type.
69 ///
70 /// The two dimensions are called X and Y.
71 ///
72 /// Note that the range is "open", which means that the points
73 /// on its boundary are considered internal to the range.
74 ///
75 ///
76 template <typename T>
77 class Range2d
78 {
79 public:
80 
81 	/// Ouput operator
82 	template <typename U>
83 	friend std::ostream& operator<< (std::ostream& os, const Range2d<U>& rect);
84 
85 	/// Equality operator
86 	//
87 	/// This is needed to take NULL kind into account
88 	/// since we don't explicitly set all members when constructing
89 	/// NULL ranges
90 	///
91 	template <typename U>
92 	friend bool operator== (const Range2d<U>& r1, const Range2d<U>& r2);
93 
94 	/// Inequality operator
95 	//
96 	/// This is needed to take NULL kind into account
97 	/// since we don't explicitly set all members when constructing
98 	/// NULL ranges
99 	///
100 	template <typename U>
101 	friend bool operator!= (const Range2d<U>& r1, const Range2d<U>& r2);
102 
103 	/// Return a rectangle being the intersetion of the two rectangles
104 	//
105 	/// Any NULL operand will make the result also NULL.
106 	///
107 	template <typename U> friend Range2d<U>
108 	Intersection(const Range2d<U>& r1, const Range2d<U>& r2);
109 
110 	/// Return a rectangle being the union of the two rectangles
111 	template <typename U> friend Range2d<U>
112 	Union(const Range2d<U>& r1, const Range2d<U>& r2);
113 
114 	/// Construct a Range2d of the given kind.
115 	//
116 	/// The default is building a nullRange.
117 	/// If finiteRange is given the range will be set to
118 	/// enclose the origin.
119 	///
120 	/// See RangeKind
121 	///
122 	Range2d(RangeKind kind=nullRange)
123 		:
124 		_xmin(T()),
125 		_xmax(T()),
126 		_ymin(T()),
127 		_ymax(T())
128 	{
129 		switch ( kind )
130 		{
131 			case worldRange:
132 				setWorld();
133 				break;
134 			case nullRange:
135 				setNull();
136 				break;
137 			default:
138 			case finiteRange:
139 				break;
140 		}
141 	}
142 
143 	/// Construct a finite Range2d with the given values
144 	//
145 	/// Make sure that the min <= max, or an assertion
146 	/// would fail. We could as well swap the values
147 	/// in this case, but it is probably better to
148 	/// force caller to deal with this, as a similar
149 	/// case might as well expose a bug in the code.
150 	///
151 	Range2d(T xmin, T ymin, T xmax, T ymax)
152 		:
153 		_xmin(xmin),
154 		_xmax(xmax),
155 		_ymin(ymin),
156 		_ymax(ymax)
157 	{
158 		// use the default ctor to make a NULL Range2d
159 		assert(_xmin <= _xmax);
160 		assert(_ymin <= _ymax);
161 		// .. or should we raise an exception .. ?
162 	}
163 
164 	/// Templated copy constructor, for casting between range types
165 	template <typename U>
166 	Range2d(const Range2d<U>& from)
167 	{
168 		if ( from.isWorld() ) {
169 			setWorld();
170 		} else if ( from.isNull() ) {
171 			setNull();
172 		} else {
173 			_xmin = roundMin(from.getMinX());
174 			_ymin = roundMin(from.getMinY());
175 			_xmax = roundMax(from.getMaxX());
176 			_ymax = roundMax(from.getMaxY());
177 		}
178 	}
179 
180 	/// Returns true if this is the NULL Range2d
181 	bool isNull() const
182 	{
183 		return _xmax < _xmin;
184 	}
185 
186 	/// Set the Range2d to the NULL value
187 	//
188 	/// @return a reference to this instance
189 	///
190 	Range2d<T>& setNull()
191 	{
192 		_xmin = std::numeric_limits<T>::max();
193 		_xmax = std::numeric_limits<T>::min();
194 		_ymin = 0;
195 		_ymax = 0;
196 		return *this;
197 	}
198 
199 	/// Returns true if this is the WORLD Range2d
200 	bool isWorld() const
201 	{
202 		return _xmax == std::numeric_limits<T>::max()
203 			&& _xmin == std::numeric_limits<T>::min();
204 	}
205 
206 	/// Returns true if this is a finite Range2d
207 	//
208 	/// See RangeKind::finiteRange
209 	///
210 	bool isFinite() const
211 	{
212 		return ( ! isNull() && ! isWorld() );
213 	}
214 
215 	/// Set the Range2d to the WORLD value
216 	//
217 	/// This is implemented using the minimum and maximum
218 	/// values of the parameter type.
219 	///
220 	/// See RangeType::worldRange
221 	///
222 	/// @return a reference to this instance
223 	///
224 	Range2d<T>& setWorld()
225 	{
226 		_xmin = std::numeric_limits<T>::min();
227 		_xmax = std::numeric_limits<T>::max();
228 		_ymin = 0;
229 		_ymax = 0;
230 		return *this;
231 	}
232 
233 	/// \brief
234 	/// Return true if this rectangle contains the point with
235 	/// given coordinates (boundaries are inclusive).
236 	//
237 	/// Note that WORLD rectangles contain every point
238 	/// and NULL rectangles contain no point.
239 	///
240 	template <typename U>
241 	bool contains(U x, U y) const
242 	{
243 		if ( isNull() ) return false;
244 		if ( isWorld() ) return true;
245 		if (x < _xmin || x > _xmax || y < _ymin || y > _ymax)
246 		{
247 			return false;
248 		}
249 		return true;
250 	}
251 
252 	/// \brief
253 	/// Return true if this rectangle contains the given rectangle.
254 	//
255 	/// Note that:
256 	///
257 	///	- WORLD ranges contain every range except NULL ones
258 	///	  and are only contained in WORLD ranges
259 	///
260 	///	- NULL ranges contain no ranges and are contained in no ranges.
261 	///
262 	bool contains(const Range2d<T>& other) const
263 	{
264 		if ( isNull() || other.isNull() ) return false;
265 		if ( isWorld() ) return true;
266 		if ( other.isWorld() ) return false;
267 
268 		return _xmin <= other._xmin &&
269 			_xmax >= other._xmax &&
270 			_ymin <= other._ymin &&
271 			_ymax >= other._ymax;
272 	}
273 
274 	/// \brief
275 	/// Return true if this rectangle intersects the point with
276 	/// given coordinates (boundaries are inclusive).
277 	//
278 	/// Note that NULL rectangles don't intersect anything
279 	/// and WORLD rectangles intersects everything except a NULL rectangle.
280 	///
281 	bool intersects(const Range2d<T>& other) const
282 	{
283 		if ( isNull() || other.isNull() ) return false;
284 		if ( isWorld() || other.isWorld() ) return true;
285 
286 		if ( _xmin > other._xmax ) return false;
287 		if ( _xmax < other._xmin ) return false;
288 		if ( _ymin > other._ymax ) return false;
289 		if ( _ymax < other._ymin ) return false;
290 		return true;
291 	}
292 
293 	/// Expand this Range2d to enclose the given point.
294 	//
295 	/// @return a reference to this instance
296 	///
297 	Range2d<T>& expandTo(T x, T y)
298 	{
299 		// A WORLD range already enclose every point
300 		if ( isWorld() ) return *this;
301 
302 		if ( isNull() )
303 		{
304 			setTo(x,y);
305 		}
306 		else
307 		{
308 			_xmin = std::min(_xmin, x);
309 			_ymin = std::min(_ymin, y);
310 			_xmax = std::max(_xmax, x);
311 			_ymax = std::max(_ymax, y);
312 		}
313 
314 		return *this;
315 	}
316 
317 	/// Expand this Range2d to enclose the given circle.
318 	//
319 	/// @return a reference to this instance
320 	///
321 	Range2d<T>& expandToCircle(T x, T y, T radius)
322 	{
323 		// A WORLD range already enclose every point
324 		if ( isWorld() ) return *this;
325 
326         expandTo(x-radius, y);
327         expandTo(x+radius, y);
328 
329         expandTo(x, y-radius);
330         expandTo(x, y+radius);
331 
332 		return *this;
333 	}
334 
335 	/// Set ourself to bound the given point
336 	//
337 	/// @return a reference to this instance
338 	///
339 	Range2d<T>& setTo(T x, T y)
340 	{
341 		_xmin = _xmax = x;
342 		_ymin = _ymax = y;
343 		return *this;
344 	}
345 
346 	/// Set coordinates to given values
347 	//
348 	/// Make sure that the min <= max, or an assertion
349 	/// would fail. We could as well swap the values
350 	/// in this case, but it is probably better to
351 	/// force caller to deal with this, as a similar
352 	/// case might as well expose a bug in the code.
353 	//
354 	/// @return a reference to this instance
355 	///
356 	Range2d<T>& setTo(T xmin, T ymin, T xmax, T ymax)
357 	{
358 		_xmin = xmin;
359 		_xmax = xmax;
360 		_ymin = ymin;
361 		_ymax = ymax;
362 
363 		// use the default ctor to make a NULL Range2d
364 		assert(_xmin <= _xmax);
365 		assert(_ymin <= _ymax);
366 
367 		return *this;
368 	}
369 
370 	/// Return width this Range2d
371 	//
372 	/// Don't call this function on a WORLD rectangle!
373 	///
374 	T width() const
375 	{
376 		assert ( ! isWorld() );
377 		if ( isNull() ) return 0;
378 		return _xmax-_xmin;
379 	}
380 
381 	/// Return height this Range2dangle
382 	//
383 	/// Don't call this function on a WORLD rectangle!
384 	///
385 	T height() const
386 	{
387 		assert ( ! isWorld() );
388 		if ( isNull() ) return 0;
389 		return _ymax-_ymin;
390 	}
391 
392 	/// Shift this Range2dangle horizontally
393 	//
394 	/// A positive offset will shift to the right,
395 	/// A negative offset will shift to the left.
396 	///
397 	/// WORLD or NULL ranges will be unchanged
398 	///
399 	/// @return a reference to this instance
400 	///
401 	Range2d<T>& shiftX(T offset)
402 	{
403 		if ( isNull() || isWorld() ) return *this;
404 		_xmin += offset;
405 		_xmax += offset;
406 		return *this;
407 	}
408 
409 	/// Shift this Range2dangle vertically
410 	//
411 	/// A positive offset will increment y values.
412 	/// A negative offset will decrement y values.
413 	///
414 	/// WORLD or NULL ranges will be unchanged
415 	///
416 	/// @return a reference to this instance
417 	///
418 	Range2d<T>& shiftY(T offset)
419 	{
420 		if ( isNull() || isWorld() ) return *this;
421 		_ymin += offset;
422 		_ymax += offset;
423 		return *this;
424 	}
425 
426 	/// Scale this Range2d horizontally
427 	Range2d<T>& scaleX(float factor)
428 	{
429 		return scale(factor, 1);
430 	}
431 
432 	/// Scale this Range2d vertically
433 	Range2d<T>& scaleY(float factor)
434 	{
435 		return scale(1, factor);
436 	}
437 
438 	/// Scale this Range2d
439 	//
440 	/// WORLD or NULL ranges will be unchanged
441 	///
442 	/// For finite ranges:
443 	///  Any factor of 0 will make the range NULL.
444 	///  A factor of 1 will leave the corresponding size unchanged.
445 	///  A factor > 1 will make the corresponding size bigger.
446 	///  A factor < 1 factor will make the corresponding size smaller.
447 	///
448 	/// Computation is done in single floating point precision.
449 	/// Specializations for integer types ensure that when rounding
450 	/// back the resulting range is not smaller then the floating
451 	/// range computed during scaling (in all directions).
452 	///
453 	/// Control point is the origin (0,0).
454 	///
455 	/// If the range so scaled will hit the numerical limit
456 	/// of the range an assertion will fail
457 	/// (TODO: throw an exception instead!).
458 	///
459 	/// @param xfactor
460 	///	The horizontal scale factor. It's a float
461 	///	to allow for fractional scale even for integer
462 	///	ranges.
463 	///
464 	/// @param yfactor
465 	///	The vertical scale factor. It's a float
466 	///	to allow for fractional scale even for integer
467 	///	ranges.
468 	///
469 	/// @return a reference to this instance
470 	///
471 	Range2d<T>& scale(float xfactor, float yfactor)
472 	{
473 		assert(xfactor >= 0 && yfactor >= 0);
474 
475 		if ( ! isFinite() ) return *this;
476 
477 		if ( xfactor == 0 || yfactor == 0 )
478 		{
479 			return setNull();
480 		}
481 
482 		if ( xfactor != 1 )
483 		{
484 			_xmin = scaleMin(_xmin, xfactor);
485 			_xmax = scaleMax(_xmax, xfactor);
486 			assert(_xmin <= _xmax); // in case of overflow...
487 		}
488 
489 		if ( yfactor != 1 )
490 		{
491 			_ymin = scaleMin(_ymin, yfactor);
492 			_ymax = scaleMax(_ymax, yfactor);
493 			assert(_ymin <= _ymax); // in case of overflow...
494 		}
495 
496 		return *this;
497 	}
498 
499 	/// Scale this Range2d in both directions with the same factor
500 	Range2d<T>& scale(float factor)
501 	{
502 		return scale(factor, factor);
503 	}
504 
505 	/// Grow this range by the given amout in all directions.
506 	//
507 	/// WORLD or NULL ranges will be unchanged.
508 	///
509 	/// If a growing range hits the numerical limit for T
510 	/// it will be set to the WORLD range.
511 	///
512 	/// @param amount
513 	/// 	The amount of T to grow this range in all directions.
514 	///	If negative the range will shrink.
515 	///	If negative the range will shrink.
516 	///	See shrinkBy().
517 	///
518 	/// @return a reference to this instance
519 	///
520 	Range2d<T>& growBy(T amount)
521 	{
522 		if ( isNull() || isWorld() || amount==0 ) return *this;
523 
524 		// NOTE: this trigger a compiler warning when T is an
525 		//       unsigned type (Coverity CID 1154656 -
526 		//       logically dead code)
527 		if ( amount < 0 ) return shrinkBy(-amount);
528 
529 		T newxmin = _xmin - amount;
530 		if (newxmin > _xmin ) return setWorld();
531 		else _xmin = newxmin;
532 
533 		T newxmax = _xmax + amount;
534 		if (newxmax < _xmax ) return setWorld();
535 		else _xmax = newxmax;
536 
537 		T newymin = _ymin - amount;
538 		if (newymin > _ymin ) return setWorld();
539 		else _ymin = newymin;
540 
541 		T newymax = _ymax + amount;
542 		if (newymax < _ymax ) return setWorld();
543 		else _ymax = newymax;
544 
545 		return *this;
546 
547 	}
548 
549 	/// Shirnk this range by the given amout in all directions.
550 	//
551 	/// WORLD or NULL ranges will be unchanged.
552 	///
553 	/// If a shrinking range will collapse in either the horizontal
554 	/// or vertical dimension it will be set to the NULL range.
555 	///
556 	/// @param amount
557 	/// 	The amount of T to shink this range in all directions.
558 	///	If negative the range will grow.
559 	///	See growBy().
560 	///
561 	/// @return a reference to this instance
562 	///
563 	/// NOTE: This method assumes that the numerical type used
564 	///       as parameter does allow both positive and negative
565 	///       values. Using this method against an instance of
566 	///	  an 'unsigned' Range2d will likely raise unexpected
567 	///	  results.
568 	///
569 	/// TODO: change the interface to never make the Range null,
570 	///       as we might always use the Range *center* point
571 	///       instead of forgetting about it!
572 	///
573 	Range2d<T>& shrinkBy(T amount)
574 	{
575 		if ( isNull() || isWorld() || amount==0 ) return *this;
576 
577 		// NOTE: this trigger a compiler warning when T is an
578 		//       unsigned type (Coverity CID 1154655 -
579 		//       logically dead code)
580 		if ( amount < 0 ) return growBy(-amount);
581 
582 		// Turn this range into the NULL range
583 		// if any dimension collapses.
584 		// Don't use width() and height() to
585 		// avoid superflous checks.
586 
587 		if ( _xmax - _xmin <= amount ) return setNull();
588 		if ( _ymax - _ymin <= amount ) return setNull();
589 
590 		_xmin += amount;
591 		_ymin += amount;
592 		_xmax -= amount;
593 		_ymax -= amount;
594 
595 		return *this;
596 
597 	}
598 
599 	/// Get min X ordinate.
600 	//
601 	/// Don't call this against a NULL or WORLD Range2
602 	///
603 	T getMinX() const
604 	{
605 		assert ( isFinite() );
606 		return _xmin;
607 	}
608 
609 	/// Get max X ordinate.
610 	//
611 	/// Don't call this against a NULL or WORLD Range2d
612 	///
613 	T getMaxX() const
614 	{
615 		assert ( isFinite() );
616 		return _xmax;
617 	}
618 
619 	/// Get min Y ordinate.
620 	//
621 	/// Don't call this against a NULL or WORLD Range2d
622 	///
623 	T getMinY() const
624 	{
625 		assert ( isFinite() );
626 		return _ymin;
627 	}
628 
629 	/// Get max Y ordinate.
630 	//
631 	/// Don't call this against a NULL or WORLD Range2d
632 	///
633 	T getMaxY() const
634 	{
635 		assert ( isFinite() );
636 		return _ymax;
637 	}
638 
639 
640         /// Get area (width*height)
641         //
642         typename detail::Promote<T>::type
643         getArea() const {
644             assert ( !isWorld() );
645             if ( isNull() ) return 0;
646             return static_cast<typename detail::Promote<T>::type>(_xmax - _xmin)
647                    * (_ymax - _ymin);
648             // this implementation is for float types, see specialization below
649             // for ints...
650         }
651 
652 	/// Expand this range to include the given Range2d
653 	//
654 	/// WORLD ranges force result to be the WORLD range.
655 	/// A NULL range will have no effect on the result.
656 	///
657 	void expandTo(const Range2d<T>& r)
658 	{
659 		if ( r.isNull() )
660 		{
661 			// the given range will add nothing
662 			return;
663 		}
664 
665 		if ( isNull() )
666 		{
667 			// being null ourself, we'll equal the given range
668 			*this = r;
669 			return;
670 		}
671 
672 		if ( isWorld() || r.isWorld() )
673 		{
674 			// union with world is always world...
675 			setWorld();
676 			return;
677 		}
678 
679 		_xmin = std::min(_xmin, r._xmin);
680 		_xmax = std::max(_xmax, r._xmax);
681 		_ymin = std::min(_ymin, r._ymin);
682 		_ymax = std::max(_ymax, r._ymax);
683 
684 	}
685 
686 private:
687 
688 	T _xmin, _xmax, _ymin, _ymax;
689 
690 	T scaleMin(T min, float scale) const {
691 		return roundMin(static_cast<float>(min) * scale);
692 	}
693 
694 	T scaleMax(T max, float scale) const {
695 		return roundMax(static_cast<float>(max) * scale);
696 	}
697 
698 	T roundMin(float v) const {
699 		return static_cast<T>(v);
700 	}
701 
702 	T roundMax(float v) const {
703 		return static_cast<T>(v);
704 	}
705 
706 
707 };
708 
709 template <typename T> inline std::ostream&
710 operator<< (std::ostream& os, const Range2d<T>& rect)
711 {
712 	if ( rect.isNull() ) return os << "Null range";
713 	if ( rect.isWorld() ) return os << "World range";
714 
715 	return os << "Finite range (" << rect._xmin << "," << rect._ymin
716 		<< " " << rect._xmax << "," << rect._ymax << ")";
717 }
718 
719 template <typename T> inline bool
720 operator== (const Range2d<T>& r1, const Range2d<T>& r2)
721 {
722 	// These checks are needed becase
723 	// we don't initialize *all* memebers
724 	// when setting to Null or World
725 
726 	if ( r1.isNull() ) return r2.isNull();
727 	if ( r2.isNull() ) return r1.isNull();
728 	if ( r1.isWorld() ) return r2.isWorld();
729 	if ( r2.isWorld() ) return r1.isWorld();
730 
731 	return r1._xmin == r2._xmin && r1._ymin == r2._ymin &&
732 		r1._xmax == r2._xmax && r1._ymax == r2._ymax;
733 }
734 
735 template <typename T> inline bool
736 operator!= (const Range2d<T>& r1, const Range2d<T>& r2)
737 {
738 	return ! ( r1 == r2 );
739 }
740 
741 /// Return true of the two ranges intersect (boundaries included)
742 template <typename T> inline bool
743 Intersect(const Range2d<T>& r1, const Range2d<T>& r2)
744 {
745 	return r1.intersects(r2);
746 }
747 
748 /// Return a rectangle being the union of the two rectangles
749 template <typename T> inline Range2d<T>
750 Union(const Range2d<T>& r1, const Range2d<T>& r2)
751 {
752 	Range2d<T> ret = r1;
753 	ret.expandTo(r2);
754 	return ret;
755 }
756 
757 /// Return a rectangle being the intersetion of the two rectangles
758 //
759 /// Any NULL operand will make the result also NULL.
760 ///
761 template <typename T> inline Range2d<T>
762 Intersection(const Range2d<T>& r1, const Range2d<T>& r2)
763 {
764 	if ( r1.isNull() || r2.isNull() ) {
765 		// NULL ranges intersect nothing
766 		return Range2d<T>(nullRange);
767 	}
768 
769 	if ( r1.isWorld() ) {
770 		// WORLD range intersect everything
771 		return r2;
772 	}
773 
774 	if ( r2.isWorld() ) {
775 		// WORLD range intersect everything
776 		return r1;
777 	}
778 
779 	if ( ! r1.intersects(r2) ) {
780 		// No intersection results in a NULL range
781 		return Range2d<T>(nullRange);
782 	}
783 
784 	return Range2d<T> (
785 		std::max(r1._xmin, r2._xmin), // xmin
786 		std::max(r1._ymin, r2._ymin), // ymin
787 		std::min(r1._xmax, r2._xmax), // xmax
788 		std::min(r1._ymax, r2._ymax)  // ymax
789 	);
790 
791 }
792 
793 /// Specialization of minimum value rounding for int type.
794 //
795 /// Use floor.
796 ///
797 template<> inline int
798 Range2d<int>::roundMin(float min) const
799 {
800 	return static_cast<int>(std::floor(min));
801 }
802 
803 /// Specialization of minimum value rounding for unsigned int type.
804 //
805 /// Use floor.
806 ///
807 template<> inline unsigned int
808 Range2d<unsigned int>::roundMin(float min) const
809 {
810 	return static_cast<unsigned int>(std::floor(min));
811 }
812 
813 /// Specialization of maximum value rounding for int type.
814 //
815 /// Use ceil.
816 ///
817 template<> inline int
818 Range2d<int>::roundMax(float max) const
819 {
820 	return static_cast<int>(std::ceil(max));
821 }
822 
823 /// Specialization of maximum value rounding for unsigned int type.
824 //
825 /// Use ceil.
826 ///
827 template<> inline unsigned int
828 Range2d<unsigned int>::roundMax(float max) const
829 {
830 	return static_cast<unsigned int>(std::ceil(max));
831 }
832 
833 /// Specialization of area value for int type.
834 //
835 /// Add one.
836 ///
837 template<> inline
838 detail::Promote<int>::type
839 Range2d<int>::getArea() const
840 {
841     assert ( !isWorld() );
842     if ( isNull() ) return 0;
843     return static_cast<detail::Promote<int>::type>(_xmax - _xmin + 1) *
844                (_ymax - _ymin + 1);
845 }
846 
847 /// Specialization of area value for unsigned int type.
848 //
849 /// Add one.
850 ///
851 template<> inline
852 detail::Promote<unsigned int>::type
853 Range2d<unsigned int>::getArea() const
854 {
855     assert ( isFinite() );
856     return static_cast<detail::Promote<unsigned int>::type>(_xmax - _xmin + 1) *
857               (_ymax - _ymin + 1);
858 }
859 
860 
861 } // namespace gnash::geometry
862 } // namespace gnash
863 
864 #endif // GNASH_RANGE2D_H
865 
866 
867 // Local Variables:
868 // mode: C++
869 // indent-tabs-mode: t
870 // End:
871