1 #ifndef RECTANGLE_CLASS
2 #define RECTANGLE_CLASS
4 /*****************************************************************************\
7 * Author : Chris Koeritz *
9 *******************************************************************************
10 * Copyright (c) 1992-$now By Author. This program is free software; you can *
11 * redistribute it and/or modify it under the terms of the GNU General Public *
12 * License as published by the Free Software Foundation; either version 2 of *
13 * the License or (at your option) any later version. This is online at: *
14 * http://www.fsf.org/copyleft/gpl.html *
15 * Please send any updates to: fred@gruntose.com *
16 \*****************************************************************************/
20 #include <basis/functions.h>
24 //! Represents a geometric rectangle.
26 template <class numeric_type>
27 class rectangle : public basis::packable
30 rectangle(const point<numeric_type> &vertex_1,
31 const point<numeric_type> &vertex_2);
32 rectangle(numeric_type x_1 = 0, numeric_type y_1 = 0,
33 numeric_type x_2 = 0, numeric_type y_2 = 0);
35 numeric_type height() const;
36 numeric_type width() const;
38 rectangle order() const;
39 //!< Re-orders the vertices of the line to be increasing.
40 /*!< Orients the vertices such that the x and y coordinates of the first
41 vertex are respectively closer to the origin than the x and y
42 coordinates of the second vertex (or they are equidistant). */
44 point<numeric_type> top_left() const;
45 point<numeric_type> bottom_left() const;
46 point<numeric_type> top_right() const;
47 point<numeric_type> bottom_right() const;
48 //!< returns the appropriate point as represented by our rectangle.
49 /*!< note that these are with respect to a normal cartesian coordinate
50 system. if you want points for a screen based coordinate system (with
51 the origin in the top left), then bottom_left and top_right return the
52 appropriate bounding points for that rectangle. */
54 numeric_type minimum_x() const;
55 //!< Return the smallest x from the points in the rectangle.
56 numeric_type minimum_y() const;
57 //!< Return the smallest y from the points in the rectangle.
58 numeric_type maximum_x() const;
59 //!< Return the largest x from the points in the rectangle.
60 numeric_type maximum_y() const;
61 //!< Return the largest y from the points in the rectangle.
63 point<numeric_type> center() const;
64 //!< Returns the point at the center of the rectangle.
66 bool inside(const point<numeric_type> &to_check) const;
67 //!< Returns true if `to_check' is inside `this' rectangle.
69 bool operator == (const rectangle &to_compare) const;
70 //!< Returns true if `to_compare' has vertices equal to `this'.
72 rectangle operator + (const point<numeric_type> &to_add) const;
73 //!< Returns the rectangle resulting from adding a point to its vertices.
74 rectangle operator - (const point<numeric_type> &to_subtract) const;
75 //!< Returns the rectangle resulting from subtracting "to_subtract".
77 rectangle &operator += (const point<numeric_type> &to_add);
78 //!< Adds the point "to_add" to our vertices.
79 rectangle &operator -= (const point<numeric_type> &to_subtract);
80 //!< Subtracts the point "to_add" to our vertices.
82 void encompass(const rectangle &to_adjust_to);
83 //!< Finds the largest dimension needed to contain all rectangles passed in.
84 /*!< The original dimension of `this' rectangle is compared with
85 all subsequent rectangles passed to adjust_dimension, and it is
86 modified (joined with `to_adjust_to') if the extent of `to_adjust_to'
87 is greater or lesser than the current extent of `this' rectangle. */
89 bool intersect(const rectangle &r2) const;
90 //!< Returns true if `this' & `r2' cover any common points.
92 bool disjoint(const rectangle &r2) const;
93 //!< Returns true if `this' & `r2' have mutually exclusive extents.
95 bool join_intersecting(const rectangle &r2, rectangle &result);
96 //!< Sets "result" to encompass this and "r2" if they intersect.
97 /*!< If `this' and `r2' intersect, `result' is adjusted to their dimension
98 and true is returned. If not, false is returned and `result' is
101 bool intersection(const rectangle &r2, rectangle &result);
102 //!< Sets "result" to the intersection of this and "r2".
103 /*!< If `this' and `r2' intersect, then `result' is set to their
104 intersecting extent and true is returned. If not, then false is returned
105 and `result' is undefined. */
107 basis::astring text_form() const;
108 //!< Prints out the contents of the rectangle.
110 bool from_text(const basis::astring &text);
111 //!< Returns true if the "text" is parsed into this rectangle.
113 point<numeric_type> vertex_1() const;
114 point<numeric_type> vertex_2() const;
116 void vertex_1(const point<numeric_type> &to_set);
117 void vertex_2(const point<numeric_type> &to_set);
119 virtual int packed_size() const;
120 virtual void pack(basis::byte_array &packed_form) const;
121 virtual bool unpack(basis::byte_array &packed_form);
124 point<numeric_type> _vertex_1;
125 point<numeric_type> _vertex_2;
130 //!< A commonly used rectangle of integers.
132 typedef rectangle<int> int_rectangle;
136 // implementations below...
138 template <class numeric_type>
139 rectangle<numeric_type>::rectangle(const point<numeric_type> &lb, const point<numeric_type> &rt)
140 : _vertex_1(lb), _vertex_2(rt) {}
142 template <class numeric_type>
143 rectangle<numeric_type>::rectangle(numeric_type left, numeric_type bottom, numeric_type right, numeric_type top)
144 : _vertex_1(point<numeric_type>(left, bottom)),
145 _vertex_2(point<numeric_type>(right, top)) {}
147 template <class numeric_type>
148 point<numeric_type> rectangle<numeric_type>::vertex_1() const
149 { return _vertex_1; }
151 template <class numeric_type>
152 point<numeric_type> rectangle<numeric_type>::vertex_2() const
153 { return _vertex_2; }
155 template <class numeric_type>
156 void rectangle<numeric_type>::vertex_1(const point<numeric_type> &to_set)
157 { _vertex_1 = to_set; }
159 template <class numeric_type>
160 void rectangle<numeric_type>::vertex_2(const point<numeric_type> &to_set)
161 { _vertex_2 = to_set; }
163 template <class numeric_type>
164 numeric_type rectangle<numeric_type>::height() const
165 { return absolute_value(_vertex_2.y() - _vertex_1.y()); }
167 template <class numeric_type>
168 numeric_type rectangle<numeric_type>::width() const
169 { return absolute_value(_vertex_2.x() - _vertex_1.x()); }
171 template <class numeric_type>
172 numeric_type rectangle<numeric_type>::minimum_x() const
173 { return basis::minimum(_vertex_1.x(), _vertex_2.x()); }
175 template <class numeric_type>
176 numeric_type rectangle<numeric_type>::minimum_y() const
177 { return basis::minimum(_vertex_1.y(), _vertex_2.y()); }
179 template <class numeric_type>
180 numeric_type rectangle<numeric_type>::maximum_x() const
181 { return basis::maximum(_vertex_1.x(), _vertex_2.x()); }
183 template <class numeric_type>
184 numeric_type rectangle<numeric_type>::maximum_y() const
185 { return basis::maximum(_vertex_1.y(), _vertex_2.y()); }
187 template <class numeric_type>
188 rectangle<numeric_type> rectangle<numeric_type>::order() const
190 numeric_type x1 = _vertex_1.x();
191 numeric_type x2 = _vertex_2.x();
192 numeric_type y1 = _vertex_1.y();
193 numeric_type y2 = _vertex_2.y();
194 basis::flip_increasing(x1, x2);
195 basis::flip_increasing(y1, y2);
196 return rectangle<numeric_type>(x1, y1, x2, y2);
199 template <class numeric_type>
200 point<numeric_type> rectangle<numeric_type>::top_left() const
202 rectangle temp(order());
203 return point<numeric_type>(temp.vertex_1().x(), temp.vertex_2().y());
206 template <class numeric_type>
207 point<numeric_type> rectangle<numeric_type>::bottom_left() const
209 rectangle temp(order());
210 return point<numeric_type>(temp.vertex_1().x(), temp.vertex_1().y());
213 template <class numeric_type>
214 point<numeric_type> rectangle<numeric_type>::top_right() const
216 rectangle temp(order());
217 return point<numeric_type>(temp.vertex_2().x(), temp.vertex_2().y());
220 template <class numeric_type>
221 point<numeric_type> rectangle<numeric_type>::bottom_right() const
223 rectangle temp(order());
224 return point<numeric_type>(temp.vertex_2().x(), temp.vertex_1().y());
227 template <class numeric_type>
228 point<numeric_type> rectangle<numeric_type>::center() const
230 return point<numeric_type>(numeric_type((_vertex_1.x()
231 + _vertex_2.x()) / 2.0), numeric_type((_vertex_1.y()
232 + _vertex_2.y()) / 2.0));
235 template <class numeric_type>
236 bool rectangle<numeric_type>::inside(const point<numeric_type> &to_check) const
238 rectangle<numeric_type> ordered_me = this->order();
239 return bool( (to_check.x() >= ordered_me._vertex_1.x())
240 && (to_check.x() <= ordered_me._vertex_2.x())
241 && (to_check.y() >= ordered_me._vertex_1.y())
242 && (to_check.y() <= ordered_me._vertex_2.y()) );
245 template <class numeric_type>
246 bool rectangle<numeric_type>::operator == (const rectangle &to_compare) const
248 point<numeric_type> min1(minimum_x(), minimum_y());
249 point<numeric_type> max1(maximum_x(), maximum_y());
250 point<numeric_type> min2(to_compare.minimum_x(), to_compare.minimum_y());
251 point<numeric_type> max2(to_compare.maximum_x(), to_compare.maximum_y());
252 if ( (min1 == min2) && (max1 == max2) ) return true;
256 template <class numeric_type>
257 rectangle<numeric_type> &rectangle<numeric_type>::operator += (const point<numeric_type> &p)
258 { _vertex_1 += p; _vertex_2 += p; return *this; }
260 template <class numeric_type>
261 rectangle<numeric_type> &rectangle<numeric_type>::operator -= (const point<numeric_type> &p)
262 { _vertex_1 -= p; _vertex_2 -= p; return *this; }
264 template <class numeric_type>
265 rectangle<numeric_type> rectangle<numeric_type>::operator + (const point<numeric_type> &p) const
267 rectangle to_return(*this);
272 template <class contents>
273 int rectangle<contents>::packed_size() const
275 basis::byte_array temp;
278 return temp.length();
281 template <class contents>
282 void rectangle<contents>::pack(basis::byte_array &packed_form) const
284 _vertex_1.pack(packed_form);
285 _vertex_2.pack(packed_form);
288 template <class contents>
289 bool rectangle<contents>::unpack(basis::byte_array &packed_form)
291 if (!_vertex_1.unpack(packed_form)) return false;
292 if (!_vertex_2.unpack(packed_form)) return false;
296 template <class numeric_type>
297 rectangle<numeric_type> rectangle<numeric_type>::operator - (const point<numeric_type> &p) const
299 rectangle to_return(*this);
304 template <class numeric_type>
305 void rectangle<numeric_type>::encompass(const rectangle &to_adjust_to)
307 if (to_adjust_to._vertex_1.x() < _vertex_1.x())
308 _vertex_1.set(to_adjust_to._vertex_1.x(), _vertex_1.y());
309 if (to_adjust_to._vertex_1.y() < _vertex_1.y())
310 _vertex_1.set(_vertex_1.x(), to_adjust_to._vertex_1.y());
311 if (to_adjust_to._vertex_2.x() > _vertex_2.x())
312 _vertex_2.set(to_adjust_to._vertex_2.x(), _vertex_2.y());
313 if (to_adjust_to._vertex_2.y() > _vertex_2.y())
314 _vertex_2.set(_vertex_2.x(), to_adjust_to._vertex_2.y());
317 template <class numeric_type>
318 bool rectangle<numeric_type>::disjoint(const rectangle &r2) const
320 if ( (maximum_x() < r2.minimum_x())
321 || (minimum_x() > r2.maximum_x())
322 || (maximum_y() < r2.minimum_y())
323 || (minimum_y() > r2.maximum_y()) ) return true;
327 template <class numeric_type>
328 bool rectangle<numeric_type>::intersect(const rectangle &r2) const
329 { return bool(!disjoint(r2)); }
331 template <class numeric_type>
332 bool rectangle<numeric_type>::join_intersecting(const rectangle &r2, rectangle &result)
334 if (disjoint(r2)) return false;
336 result.encompass(r2);
340 template <class numeric_type>
341 bool rectangle<numeric_type>::intersection(const rectangle &r2, rectangle &result)
343 if (disjoint(r2)) return false;
344 result = rectangle<numeric_type>(basis::maximum(minimum_x(), r2.minimum_x()),
345 basis::maximum(minimum_y(), r2.minimum_y()),
346 basis::minimum(maximum_x(), r2.maximum_x()),
347 basis::minimum(maximum_y(), r2.maximum_y()));
351 template <class numeric_type>
352 basis::astring rectangle<numeric_type>::text_form() const
354 return basis::astring("[") + _vertex_1.text_form() + basis::astring(" ")
355 + _vertex_2.text_form() + basis::astring("]");
358 template <class numeric_type>
359 bool rectangle<numeric_type>::from_text(const basis::astring &_text)
361 numeric_type nums[4] = { 0, 0, 0, 0 };
362 // setup the scanning specifier.
363 basis::astring spec(numeric_specifier(nums[0]));
364 // scan the string for values.
365 basis::astring text(_text);
366 for (int i = 0; i < 4; i++) {
367 text = crop_non_numeric(text);
368 nums[i] = text.convert(nums[i]);
369 text = crop_numeric(text);
371 vertex_1(point<numeric_type>(nums[0], nums[1]));
372 vertex_2(point<numeric_type>(nums[2], nums[3]));