1 /**********************************************************************
2 * File: rect.h (Formerly box.h)
3 * Description: Bounding box class definition.
4 * Author: Phil Cheatle
5 * Created: Wed Oct 16 15:18:45 BST 1991
6 *
7 * (C) Copyright 1991, Hewlett-Packard Ltd.
8 ** Licensed under the Apache License, Version 2.0 (the "License");
9 ** you may not use this file except in compliance with the License.
10 ** You may obtain a copy of the License at
11 ** http://www.apache.org/licenses/LICENSE-2.0
12 ** Unless required by applicable law or agreed to in writing, software
13 ** distributed under the License is distributed on an "AS IS" BASIS,
14 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 ** See the License for the specific language governing permissions and
16 ** limitations under the License.
17 *
18 **********************************************************************/
19
20 #ifndef RECT_H
21 #define RECT_H
22
23 #include <math.h>
24 #include "points.h"
25 #include "ndminx.h"
26 #include "tprintf.h"
27 #include "scrollview.h"
28
29 class DLLSYM TBOX { // bounding box
30 public:
TBOX()31 TBOX (): // empty constructor making a null box
32 bot_left (MAX_INT16, MAX_INT16), top_right (-MAX_INT16, -MAX_INT16) {
33 }
34
35 TBOX( //constructor
36 const ICOORD pt1, //one corner
37 const ICOORD pt2); //the other corner
38
39 TBOX( // constructor
40 inT16 left, inT16 bottom, inT16 right, inT16 top);
41
42 TBOX( //box around FCOORD
43 const FCOORD pt);
44
null_box()45 bool null_box() const { // Is box null
46 return ((left () >= right ()) || (top () <= bottom ()));
47 }
48
top()49 inT16 top() const { // coord of top
50 return top_right.y ();
51 }
set_top(int y)52 void set_top(int y) {
53 top_right.set_y(y);
54 }
55
bottom()56 inT16 bottom() const { // coord of bottom
57 return bot_left.y ();
58 }
set_bottom(int y)59 void set_bottom(int y) {
60 bot_left.set_y(y);
61 }
62
left()63 inT16 left() const { // coord of left
64 return bot_left.x ();
65 }
set_left(int x)66 void set_left(int x) {
67 bot_left.set_x(x);
68 }
69
right()70 inT16 right() const { // coord of right
71 return top_right.x ();
72 }
set_right(int x)73 void set_right(int x) {
74 top_right.set_x(x);
75 }
76
botleft()77 const ICOORD &botleft() const { // access function
78 return bot_left;
79 }
80
botright()81 ICOORD botright() const { // ~ access function
82 return ICOORD (top_right.x (), bot_left.y ());
83 }
84
topleft()85 ICOORD topleft() const { // ~ access function
86 return ICOORD (bot_left.x (), top_right.y ());
87 }
88
topright()89 const ICOORD &topright() const { // access function
90 return top_right;
91 }
92
height()93 inT16 height() const { //how high is it?
94 if (!null_box ())
95 return top_right.y () - bot_left.y ();
96 else
97 return 0;
98 }
99
width()100 inT16 width() const { //how high is it?
101 if (!null_box ())
102 return top_right.x () - bot_left.x ();
103 else
104 return 0;
105 }
106
area()107 inT32 area() const { //what is the area?
108 if (!null_box ())
109 return width () * height ();
110 else
111 return 0;
112 }
113
move_bottom_edge(const inT16 y)114 void move_bottom_edge( // move one edge
115 const inT16 y) { // by +/- y
116 bot_left += ICOORD (0, y);
117 }
118
move_left_edge(const inT16 x)119 void move_left_edge( // move one edge
120 const inT16 x) { // by +/- x
121 bot_left += ICOORD (x, 0);
122 }
123
move_right_edge(const inT16 x)124 void move_right_edge( // move one edge
125 const inT16 x) { // by +/- x
126 top_right += ICOORD (x, 0);
127 }
128
move_top_edge(const inT16 y)129 void move_top_edge( // move one edge
130 const inT16 y) { // by +/- y
131 top_right += ICOORD (0, y);
132 }
133
move(const ICOORD vec)134 void move( // move box
135 const ICOORD vec) { // by vector
136 bot_left += vec;
137 top_right += vec;
138 }
139
move(const FCOORD vec)140 void move( // move box
141 const FCOORD vec) { // by float vector
142 bot_left.set_x ((inT16) floor (bot_left.x () + vec.x ()));
143 //round left
144 bot_left.set_y ((inT16) floor (bot_left.y () + vec.y ()));
145 //round down
146 top_right.set_x ((inT16) ceil (top_right.x () + vec.x ()));
147 //round right
148 top_right.set_y ((inT16) ceil (top_right.y () + vec.y ()));
149 //round up
150 }
151
scale(const float f)152 void scale( // scale box
153 const float f) { // by multiplier
154 bot_left.set_x ((inT16) floor (bot_left.x () * f)); // round left
155 bot_left.set_y ((inT16) floor (bot_left.y () * f)); // round down
156 top_right.set_x ((inT16) ceil (top_right.x () * f)); // round right
157 top_right.set_y ((inT16) ceil (top_right.y () * f)); // round up
158 }
scale(const FCOORD vec)159 void scale( // scale box
160 const FCOORD vec) { // by float vector
161 bot_left.set_x ((inT16) floor (bot_left.x () * vec.x ()));
162 bot_left.set_y ((inT16) floor (bot_left.y () * vec.y ()));
163 top_right.set_x ((inT16) ceil (top_right.x () * vec.x ()));
164 top_right.set_y ((inT16) ceil (top_right.y () * vec.y ()));
165 }
166
167 // rotate doesn't enlarge the box - it just rotates the bottom-left
168 // and top-right corners. Use rotate_large if you want to guarantee
169 // that all content is contained within the rotated box.
rotate(const FCOORD & vec)170 void rotate(const FCOORD& vec) { // by vector
171 bot_left.rotate (vec);
172 top_right.rotate (vec);
173 *this = TBOX (bot_left, top_right);
174 }
175 // rotate_large constructs the containing bounding box of all 4
176 // corners after rotating them. It therefore guarantees that all
177 // original content is contained within, but also slightly enlarges the box.
178 void rotate_large(const FCOORD& vec);
179
180 bool contains( // is pt inside box
181 const FCOORD pt) const;
182
183 bool contains( // is box inside box
184 const TBOX &box) const;
185
186 bool overlap( // do boxes overlap
187 const TBOX &box) const;
188
189 bool major_overlap( // do boxes overlap more than half
190 const TBOX &box) const;
191
192 // Do boxes overlap on x axis.
193 bool x_overlap(const TBOX &box) const;
194
195 // Do boxes overlap on x axis by more than
196 // half of the width of the narrower box.
197 bool major_x_overlap(const TBOX &box) const;
198
199 // Do boxes overlap on y axis.
200 bool y_overlap(const TBOX &box) const;
201
202 // Do boxes overlap on y axis by more than
203 // half of the height of the shorter box.
204 bool major_y_overlap(const TBOX &box) const;
205
206 // fraction of current box's area covered by other
207 double overlap_fraction(const TBOX &box) const;
208
209 TBOX intersection( //shared area box
210 const TBOX &box) const;
211
212 TBOX bounding_union( //box enclosing both
213 const TBOX &box) const;
214
print()215 void print() const { // print
216 tprintf ("Bounding box=(%d,%d)->(%d,%d)\n",
217 left (), bottom (), right (), top ());
218 }
219
220 #ifndef GRAPHICS_DISABLED
plot(ScrollView * fd)221 void plot( //use current settings
222 ScrollView* fd) const { //where to paint
223 fd->Rectangle(bot_left.x (), bot_left.y (), top_right.x (),
224 top_right.y ());
225 }
226
227 void plot( //paint box
228 ScrollView* fd, //where to paint
229 ScrollView::Color fill_colour, //colour for inside
230 ScrollView::Color border_colour) const; //colour for border
231 #endif
232
233 friend DLLSYM TBOX & operator+= (TBOX &, const TBOX &);
234 //in place union
235 friend DLLSYM TBOX & operator-= (TBOX &, const TBOX &);
236 //in place intrsection
237
238 void serialise_asc( //convert to ascii
239 FILE *f);
240 void de_serialise_asc( //convert from ascii
241 FILE *f);
242
243 private:
244 ICOORD bot_left; //bottom left corner
245 ICOORD top_right; //top right corner
246 };
247
248 /**********************************************************************
249 * TBOX::TBOX() Constructor from 1 FCOORD
250 *
251 **********************************************************************/
252
TBOX(const FCOORD pt)253 inline TBOX::TBOX( //construtor
254 const FCOORD pt //floating centre
255 ) {
256 bot_left = ICOORD ((inT16) floor (pt.x ()), (inT16) floor (pt.y ()));
257 top_right = ICOORD ((inT16) ceil (pt.x ()), (inT16) ceil (pt.y ()));
258 }
259
260
261 /**********************************************************************
262 * TBOX::contains() Is point within box
263 *
264 **********************************************************************/
265
contains(const FCOORD pt)266 inline bool TBOX::contains(const FCOORD pt) const {
267 return ((pt.x () >= bot_left.x ()) &&
268 (pt.x () <= top_right.x ()) &&
269 (pt.y () >= bot_left.y ()) && (pt.y () <= top_right.y ()));
270 }
271
272
273 /**********************************************************************
274 * TBOX::contains() Is box within box
275 *
276 **********************************************************************/
277
contains(const TBOX & box)278 inline bool TBOX::contains(const TBOX &box) const {
279 return (contains (box.bot_left) && contains (box.top_right));
280 }
281
282
283 /**********************************************************************
284 * TBOX::overlap() Do two boxes overlap?
285 *
286 **********************************************************************/
287
overlap(const TBOX & box)288 inline bool TBOX::overlap( // do boxes overlap
289 const TBOX &box) const {
290 return ((box.bot_left.x () <= top_right.x ()) &&
291 (box.top_right.x () >= bot_left.x ()) &&
292 (box.bot_left.y () <= top_right.y ()) &&
293 (box.top_right.y () >= bot_left.y ()));
294 }
295
296 /**********************************************************************
297 * TBOX::major_overlap() Do two boxes overlap by at least half of the smallest?
298 *
299 **********************************************************************/
300
major_overlap(const TBOX & box)301 inline bool TBOX::major_overlap( // Do boxes overlap more that half.
302 const TBOX &box) const {
303 int overlap = MIN(box.top_right.x(), top_right.x());
304 overlap -= MAX(box.bot_left.x(), bot_left.x());
305 overlap += overlap;
306 if (overlap < MIN(box.width(), width()))
307 return false;
308 overlap = MIN(box.top_right.y(), top_right.y());
309 overlap -= MAX(box.bot_left.y(), bot_left.y());
310 overlap += overlap;
311 if (overlap < MIN(box.height(), height()))
312 return false;
313 return true;
314 }
315
316 /**********************************************************************
317 * TBOX::overlap_fraction() Fraction of area covered by the other box
318 *
319 **********************************************************************/
320
overlap_fraction(const TBOX & box)321 inline double TBOX::overlap_fraction(const TBOX &box) const {
322 double fraction = 0.0;
323 if (this->area()) {
324 fraction = this->intersection(box).area() * 1.0 / this->area();
325 }
326 return fraction;
327 }
328
329 /**********************************************************************
330 * TBOX::x_overlap() Do two boxes overlap on x-axis
331 *
332 **********************************************************************/
333
x_overlap(const TBOX & box)334 inline bool TBOX::x_overlap(const TBOX &box) const {
335 return ((box.bot_left.x() <= top_right.x()) &&
336 (box.top_right.x() >= bot_left.x()));
337 }
338
339 /**********************************************************************
340 * TBOX::major_x_overlap() Do two boxes overlap by more than half the
341 * width of the narrower box on the x-axis
342 *
343 **********************************************************************/
344
major_x_overlap(const TBOX & box)345 inline bool TBOX::major_x_overlap(const TBOX &box) const {
346 inT16 overlap = box.width();
347 if (this->left() > box.left()) {
348 overlap -= this->left() - box.left();
349 }
350 if (this->right() < box.right()) {
351 overlap -= box.right() - this->right();
352 }
353 return (overlap >= box.width() / 2 || overlap >= this->width() / 2);
354 }
355
356 /**********************************************************************
357 * TBOX::y_overlap() Do two boxes overlap on y-axis
358 *
359 **********************************************************************/
360
y_overlap(const TBOX & box)361 inline bool TBOX::y_overlap(const TBOX &box) const {
362 return ((box.bot_left.y() <= top_right.y()) &&
363 (box.top_right.y() >= bot_left.y()));
364 }
365
366 /**********************************************************************
367 * TBOX::major_y_overlap() Do two boxes overlap by more than half the
368 * height of the shorter box on the y-axis
369 *
370 **********************************************************************/
371
major_y_overlap(const TBOX & box)372 inline bool TBOX::major_y_overlap(const TBOX &box) const {
373 inT16 overlap = box.height();
374 if (this->bottom() > box.bottom()) {
375 overlap -= this->bottom() - box.bottom();
376 }
377 if (this->top() < box.top()) {
378 overlap -= box.top() - this->top();
379 }
380 return (overlap >= box.height() / 2 || overlap >= this->height() / 2);
381 }
382 #endif
383