mailmap to correct stray other addrs to fred
[feisty_meow.git] / graphiq / library / geometric / rectangle.h
1 #ifndef RECTANGLE_CLASS
2 #define RECTANGLE_CLASS
3
4 /*****************************************************************************\
5 *                                                                             *
6 *  Name   : rectangle                                                         *
7 *  Author : Chris Koeritz                                                     *
8 *                                                                             *
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 \*****************************************************************************/
17
18 #include "point.h"
19
20 #include <basis/functions.h>
21
22 namespace geometric {
23
24 //! Represents a geometric rectangle.
25
26 template <class numeric_type>
27 class rectangle : public basis::packable
28 {
29 public:
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);
34
35   numeric_type height() const;
36   numeric_type width() const;
37
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). */
43
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. */
53
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.
62
63   point<numeric_type> center() const;
64     //!< Returns the point at the center of the rectangle.
65
66   bool inside(const point<numeric_type> &to_check) const;
67     //!< Returns true if `to_check' is inside `this' rectangle.
68
69   bool operator == (const rectangle &to_compare) const;
70     //!< Returns true if `to_compare' has vertices equal to `this'.
71
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".
76
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.
81
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. */
88
89   bool intersect(const rectangle &r2) const;
90     //!< Returns true if `this' & `r2' cover any common points.
91
92   bool disjoint(const rectangle &r2) const;
93     //!< Returns true if `this' & `r2' have mutually exclusive extents.
94
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
99     undefined. */
100
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. */
106
107   basis::astring text_form() const;
108     //!< Prints out the contents of the rectangle.
109
110   bool from_text(const basis::astring &text);
111     //!< Returns true if the "text" is parsed into this rectangle.
112
113   point<numeric_type> vertex_1() const;
114   point<numeric_type> vertex_2() const;
115
116   void vertex_1(const point<numeric_type> &to_set);
117   void vertex_2(const point<numeric_type> &to_set);
118
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);
122
123 protected:
124   point<numeric_type> _vertex_1;
125   point<numeric_type> _vertex_2;
126 };
127
128 //////////////
129
130 //!< A commonly used rectangle of integers.
131
132 typedef rectangle<int> int_rectangle;
133
134 //////////////
135
136 // implementations below...
137
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) {}
141
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)) {}
146
147 template <class numeric_type>
148 point<numeric_type> rectangle<numeric_type>::vertex_1() const
149 { return _vertex_1; }
150
151 template <class numeric_type>
152 point<numeric_type> rectangle<numeric_type>::vertex_2() const
153 { return _vertex_2; }
154
155 template <class numeric_type>
156 void rectangle<numeric_type>::vertex_1(const point<numeric_type> &to_set)
157 { _vertex_1 = to_set; }
158
159 template <class numeric_type>
160 void rectangle<numeric_type>::vertex_2(const point<numeric_type> &to_set)
161 { _vertex_2 = to_set; }
162
163 template <class numeric_type>
164 numeric_type rectangle<numeric_type>::height() const
165 { return absolute_value(_vertex_2.y() - _vertex_1.y()); }
166
167 template <class numeric_type>
168 numeric_type rectangle<numeric_type>::width() const
169 { return absolute_value(_vertex_2.x() - _vertex_1.x()); }
170
171 template <class numeric_type>
172 numeric_type rectangle<numeric_type>::minimum_x() const
173 { return basis::minimum(_vertex_1.x(), _vertex_2.x()); }
174
175 template <class numeric_type>
176 numeric_type rectangle<numeric_type>::minimum_y() const
177 { return basis::minimum(_vertex_1.y(), _vertex_2.y()); }
178
179 template <class numeric_type>
180 numeric_type rectangle<numeric_type>::maximum_x() const
181 { return basis::maximum(_vertex_1.x(), _vertex_2.x()); }
182
183 template <class numeric_type>
184 numeric_type rectangle<numeric_type>::maximum_y() const
185 { return basis::maximum(_vertex_1.y(), _vertex_2.y()); }
186
187 template <class numeric_type>
188 rectangle<numeric_type> rectangle<numeric_type>::order() const
189 {
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);
197 }
198
199 template <class numeric_type>
200 point<numeric_type> rectangle<numeric_type>::top_left() const
201 {
202   rectangle temp(order());
203   return point<numeric_type>(temp.vertex_1().x(), temp.vertex_2().y());
204 }
205
206 template <class numeric_type>
207 point<numeric_type> rectangle<numeric_type>::bottom_left() const
208 {
209   rectangle temp(order());
210   return point<numeric_type>(temp.vertex_1().x(), temp.vertex_1().y());
211 }
212
213 template <class numeric_type>
214 point<numeric_type> rectangle<numeric_type>::top_right() const
215 {
216   rectangle temp(order());
217   return point<numeric_type>(temp.vertex_2().x(), temp.vertex_2().y());
218 }
219
220 template <class numeric_type>
221 point<numeric_type> rectangle<numeric_type>::bottom_right() const
222 {
223   rectangle temp(order());
224   return point<numeric_type>(temp.vertex_2().x(), temp.vertex_1().y());
225 }
226
227 template <class numeric_type>
228 point<numeric_type> rectangle<numeric_type>::center() const
229 {
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));
233 }
234
235 template <class numeric_type>
236 bool rectangle<numeric_type>::inside(const point<numeric_type> &to_check) const
237 {
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()) );
243 }
244
245 template <class numeric_type>
246 bool rectangle<numeric_type>::operator == (const rectangle &to_compare) const
247 {
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;
253   else return false;
254 }
255
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; }
259
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; }
263
264 template <class numeric_type>
265 rectangle<numeric_type> rectangle<numeric_type>::operator + (const point<numeric_type> &p) const
266 {
267   rectangle to_return(*this);
268   to_return += p;
269   return to_return;
270 }
271
272 template <class contents>
273 int rectangle<contents>::packed_size() const
274 {
275   basis::byte_array temp;
276 //hmmm: inefficient!
277   pack(temp);
278   return temp.length();
279 }
280
281 template <class contents>
282 void rectangle<contents>::pack(basis::byte_array &packed_form) const
283 {
284   _vertex_1.pack(packed_form);
285   _vertex_2.pack(packed_form);
286 }
287
288 template <class contents>
289 bool rectangle<contents>::unpack(basis::byte_array &packed_form)
290 {
291   if (!_vertex_1.unpack(packed_form)) return false;
292   if (!_vertex_2.unpack(packed_form)) return false;
293   return true;
294 }
295
296 template <class numeric_type>
297 rectangle<numeric_type> rectangle<numeric_type>::operator - (const point<numeric_type> &p) const
298 {
299   rectangle to_return(*this);
300   to_return -= p;
301   return to_return;
302 }
303
304 template <class numeric_type>
305 void rectangle<numeric_type>::encompass(const rectangle &to_adjust_to)
306 {
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());
315 }
316
317 template <class numeric_type>
318 bool rectangle<numeric_type>::disjoint(const rectangle &r2) const
319 {
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;
324   else return false;
325 }
326
327 template <class numeric_type>
328 bool rectangle<numeric_type>::intersect(const rectangle &r2) const
329 { return bool(!disjoint(r2)); }
330
331 template <class numeric_type>
332 bool rectangle<numeric_type>::join_intersecting(const rectangle &r2, rectangle &result)
333 {
334   if (disjoint(r2)) return false;
335   result = *this;
336   result.encompass(r2);
337   return true;
338 }
339
340 template <class numeric_type>
341 bool rectangle<numeric_type>::intersection(const rectangle &r2, rectangle &result)
342 {
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()));
348   return true;
349 }
350
351 template <class numeric_type>
352 basis::astring rectangle<numeric_type>::text_form() const
353 {
354   return basis::astring("[") + _vertex_1.text_form() + basis::astring(" ")
355       + _vertex_2.text_form() + basis::astring("]");
356 }
357
358 template <class numeric_type>
359 bool rectangle<numeric_type>::from_text(const basis::astring &_text)
360 {
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);
370   }
371   vertex_1(point<numeric_type>(nums[0], nums[1]));
372   vertex_2(point<numeric_type>(nums[2], nums[3]));
373   return true;
374 }
375
376 } // namespace.
377
378 #endif
379