1 #ifndef RECTANGLE_WARPER_CLASS
2 #define RECTANGLE_WARPER_CLASS
4 /*****************************************************************************\
6 * Name : rectangle_warper *
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 \*****************************************************************************/
18 //! Warps points in one frame of reference to a different one.
20 This class encapsulates the notion of a rectangular region that is
21 referred to from two different points of view. This relates two
22 two-dimensional frames of reference to each other. Each frame of reference
23 is specified by two rectangles. A point that is measured in one frame of
24 reference can be transformed into a point that is measured in the other,
28 #include "rectangle.h"
30 #include <basis/astring.h>
34 template <class numeric_type>
35 class rectangle_warper
38 //! describes where a rectangle's origin is located on the rectangle.
39 /*! our model is to consider the first vertex point of the rectangle as its
40 origin and the second vertex point (diagonally opposite the first point) as
41 its extent. since it may make sense for that first vertex point to be
42 located at any one of the vertices of the rectangle (as in windowing
43 coordinate system conversions), the enumeration below allows any one of the
44 rectangle's vertices to be chosen as its origin. */
45 enum origin_vertex { BOTTOM_LEFT, TOP_LEFT, TOP_RIGHT, BOTTOM_RIGHT };
47 rectangle_warper(const rectangle<numeric_type> &system_1,
48 const rectangle<numeric_type> &system_2,
49 origin_vertex system_1_origin = BOTTOM_LEFT,
50 origin_vertex system_2_origin = BOTTOM_LEFT);
51 //!< constructs a warper given the two reference systems.
52 /*!< constructs a warper where the first rectangular system is in
53 "system_1", the second system is in "system_2" and the respective origins
54 for these systems are in "system_1_origin" and "system_2_origin". */
58 point<numeric_type> to_system_1(const point<numeric_type> &in_system_2) const;
59 //!< Converts from the second system into the first.
60 /*!< This returns a point that is measured in the first frame of reference
61 when given a point "in_system_2" that is measured in the second frame of
64 point<numeric_type> to_system_2(const point<numeric_type> &in_system_1) const;
65 //!< Converts from the first system into the second.
66 /*!< This returns a point that is measured in the second frame of reference
67 when given a point "in_system_1" that is measured in the first frame of
70 rectangle<numeric_type> to_system_1
71 (const rectangle<numeric_type> &in_system_2) const;
72 //!< flips a rectangle from the second system into the first.
73 rectangle<numeric_type> to_system_2
74 (const rectangle<numeric_type> &in_system_1) const;
75 //!< flips a rectangle from the first system into the second.
77 rectangle<numeric_type> system_1() const { return _system_1; }
78 rectangle<numeric_type> system_2() const { return _system_2; }
79 origin_vertex origin_1() const { return _vert_1; }
80 origin_vertex origin_2() const { return _vert_2; }
82 void system_1(const rectangle<numeric_type> &to_set,
83 origin_vertex origin_corner = BOTTOM_LEFT);
84 void system_2(const rectangle<numeric_type> &to_set,
85 origin_vertex origin_corner = BOTTOM_LEFT);
87 basis::astring text_form() const;
88 //!< Prints out the two systems held in the rectangle_warper.
90 basis::astring vertex_name(origin_vertex v) const;
91 //!< Prints out the name of the vertex location.
93 enum vertical_component { RW_BOTTOM, RW_TOP };
94 enum horizontal_component { RW_LEFT, RW_RIGHT };
96 void separate_vertical(origin_vertex v, vertical_component &to_set) const;
97 void separate_horizontal(origin_vertex v, horizontal_component &to_set) const;
98 //!< separates out a component of the placement of the vertex.
101 rectangle<numeric_type> _system_1;
102 rectangle<numeric_type> _system_2;
103 origin_vertex _vert_1;
104 origin_vertex _vert_2;
106 point<numeric_type> scale_point(const rectangle<numeric_type> &source,
107 const rectangle<numeric_type> &target,
108 origin_vertex v1, origin_vertex v2,
109 const point<numeric_type> &old) const;
110 rectangle<numeric_type> scale_rectangle(const rectangle<numeric_type> &source,
111 const rectangle<numeric_type> &target,
112 origin_vertex v1, origin_vertex v2,
113 const rectangle<numeric_type> &old) const;
114 rectangle<numeric_type> flip_accordingly
115 (const rectangle<numeric_type> &to_flip, origin_vertex to_flip_origin,
116 origin_vertex target_origin) const;
117 //!< Flips the points in "to_flip" to match the "target_origin".
118 /*!< swaps the points contained in a rectangle that uses a particular point
119 as the vertex ("to_flip_origin") so that the points are arranged
120 according to a second choice of vertex ("target_origin"). */
125 // implementations for longer methods below...
127 template <class numeric_type>
128 rectangle_warper<numeric_type>::rectangle_warper
129 (const rectangle<numeric_type> &system_1,
130 const rectangle<numeric_type> &system_2,
131 origin_vertex v1, origin_vertex v2)
132 : _system_1(system_1), _system_2(system_2), _vert_1(v1), _vert_2(v2)
135 template <class numeric_type>
136 rectangle_warper<numeric_type>::~rectangle_warper() {}
138 template <class numeric_type>
139 void rectangle_warper<numeric_type>::system_1
140 (const rectangle<numeric_type> &to_set, origin_vertex v)
141 { _system_1 = to_set; _vert_1 = v; }
143 template <class numeric_type>
144 void rectangle_warper<numeric_type>::system_2
145 (const rectangle<numeric_type> &to_set, origin_vertex v)
146 { _system_2 = to_set; _vert_2 = v; }
148 template <class numeric_type>
149 point<numeric_type> rectangle_warper<numeric_type>::to_system_1
150 (const point<numeric_type> &in_system_2) const
151 { return scale_point(_system_2, _system_1, _vert_2, _vert_1, in_system_2); }
153 template <class numeric_type>
154 point<numeric_type> rectangle_warper<numeric_type>::to_system_2
155 (const point<numeric_type> &in_system_1) const
156 { return scale_point(_system_1, _system_2, _vert_1, _vert_2, in_system_1); }
158 template <class numeric_type>
159 rectangle<numeric_type> rectangle_warper<numeric_type>::to_system_1
160 (const rectangle<numeric_type> &in_system_2) const
162 return scale_rectangle(_system_2, _system_1, _vert_2, _vert_1,
166 template <class numeric_type>
167 rectangle<numeric_type> rectangle_warper<numeric_type>::to_system_2
168 (const rectangle<numeric_type> &in_system_1) const
170 return scale_rectangle(_system_1, _system_2, _vert_1, _vert_2,
174 template <class numeric_type>
175 void rectangle_warper<numeric_type>::separate_vertical
176 (origin_vertex v, vertical_component &to_set) const
178 if ( (v == BOTTOM_LEFT) || (v == BOTTOM_RIGHT) ) to_set = RW_BOTTOM;
182 template <class numeric_type>
183 void rectangle_warper<numeric_type>::separate_horizontal
184 (origin_vertex v, horizontal_component &to_set) const
186 if ( (v == BOTTOM_LEFT) || (v == TOP_LEFT) ) to_set = RW_LEFT;
190 template <class numeric_type>
191 rectangle<numeric_type> rectangle_warper<numeric_type>::flip_accordingly
192 (const rectangle<numeric_type> &to_flip, origin_vertex flipo,
193 origin_vertex targo) const
195 //LOG(basis::astring("flipping ") + to_flip.text_form() + " from " + flipo.text_form() + " to " + targo.text_form());
196 if (flipo == targo) return to_flip;
197 numeric_type x1(to_flip.vertex_1().x());
198 numeric_type y1(to_flip.vertex_1().y());
199 numeric_type x2(to_flip.vertex_2().x());
200 numeric_type y2(to_flip.vertex_2().y());
201 horizontal_component horiz1;
202 separate_horizontal(flipo, horiz1);
203 horizontal_component horiz2;
204 separate_horizontal(targo, horiz2);
205 bool flip_x = bool(horiz1 != horiz2);
206 vertical_component vert1;
207 separate_vertical(flipo, vert1);
208 vertical_component vert2;
209 separate_vertical(targo, vert2);
210 bool flip_y = bool(vert1 != vert2);
211 if (flip_x) swap_values(x1, x2);
212 if (flip_y) swap_values(y1, y2);
213 //LOG(basis::astring("it becomes ") + rectangle<numeric_type>(x1, y1, x2, y2).text_form());
214 return rectangle<numeric_type>(x1, y1, x2, y2);
217 template <class numeric_type>
218 rectangle<numeric_type> rectangle_warper<numeric_type>::scale_rectangle
219 (const rectangle<numeric_type> &source,
220 const rectangle<numeric_type> &target, origin_vertex source_origin,
221 origin_vertex target_origin, const rectangle<numeric_type> &old) const
223 rectangle<numeric_type> s = rectangle<numeric_type>
224 (flip_accordingly(source, source_origin, BOTTOM_LEFT));
225 numeric_type width_source = s.vertex_2().x() - s.vertex_1().x();
226 numeric_type height_source = s.vertex_2().y() - s.vertex_1().y();
227 if ( !width_source || !height_source ) {
228 // cerr << "degenerate rectangle in rectangle_warper::scaler: " << s
232 rectangle<numeric_type> t(flip_accordingly(target, target_origin, BOTTOM_LEFT));
233 numeric_type width_target = t.vertex_2().x() - t.vertex_1().x();
234 numeric_type height_target = t.vertex_2().y() - t.vertex_1().y();
235 numeric_type x_scale = width_target / width_source;
236 numeric_type y_scale = height_target / height_source;
238 //LOG(basis::astring("scaler: source ") + source.text_form() + " with vert " + source_origin.text_form() + " becomes " + s + " target " + target + " with vert " + target_origin + " becomes " + t + ".");
240 rectangle<numeric_type> o(flip_accordingly(old, source_origin, BOTTOM_LEFT));
242 rectangle<numeric_type> to_return = flip_accordingly(rectangle<numeric_type>
243 ((o.vertex_1().x() - s.vertex_1().x()) * x_scale + t.vertex_1().x(),
244 (o.vertex_1().y() - s.vertex_1().y()) * y_scale + t.vertex_1().y(),
245 (o.vertex_2().x() - s.vertex_1().x()) * x_scale + t.vertex_1().x(),
246 (o.vertex_2().y() - s.vertex_1().y()) * y_scale + t.vertex_1().y()),
247 BOTTOM_LEFT, target_origin);
249 // LOG(basis::astring("old ") + old.text_form() + " with source vert becomes " + o.text_form() + " and then is moved into " + to_return.text_form());
254 template <class numeric_type>
255 point<numeric_type> rectangle_warper<numeric_type>::scale_point
256 (const rectangle<numeric_type> &source, const rectangle<numeric_type> &target,
257 origin_vertex source_origin, origin_vertex target_origin,
258 const point<numeric_type> &old) const
261 return scale_rectangle(source, target, source_origin, target_origin,
262 rectangle<numeric_type>(old, old)).vertex_1();
265 template <class numeric_type>
266 basis::astring rectangle_warper<numeric_type>::vertex_name(origin_vertex v) const
268 basis::astring name("unknown");
270 case BOTTOM_LEFT: name = "bottom-left"; break;
271 case BOTTOM_RIGHT: name = "bottom-right"; break;
272 case TOP_LEFT: name = "top-left"; break;
273 case TOP_RIGHT: name = "top-right"; break;
278 template <class numeric_type>
279 basis::astring rectangle_warper<numeric_type>::text_form() const
281 return basis::astring("<warps from: ") + _system_1.text_form()
282 + basis::astring(" with vertex at ") + vertex_name(_vert_1)
283 + basis::astring(" into ") + _system_2.text_form()
284 + basis::astring(" with vertex at ") + vertex_name(_vert_2)
285 + basis::astring(">");