00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef RECT_H
00021 #define RECT_H
00022
00023 #include <math.h>
00024 #include "points.h"
00025 #include "ndminx.h"
00026 #include "scrollview.h"
00027 #include "tprintf.h"
00028
00029 class DLLSYM TBOX {
00030 public:
00031 TBOX ():
00032 bot_left (MAX_INT16, MAX_INT16), top_right (-MAX_INT16, -MAX_INT16) {
00033 }
00034
00035 TBOX(
00036 const ICOORD pt1,
00037 const ICOORD pt2);
00038
00039 TBOX(
00040 inT16 left, inT16 bottom, inT16 right, inT16 top);
00041
00042 TBOX(
00043 const FCOORD pt);
00044
00045 bool null_box() const {
00046 return ((left () >= right ()) || (top () <= bottom ()));
00047 }
00048
00049 bool operator==(const TBOX& other) const {
00050 return bot_left == other.bot_left && top_right == other.top_right;
00051 }
00052
00053 inT16 top() const {
00054 return top_right.y ();
00055 }
00056 void set_top(int y) {
00057 top_right.set_y(y);
00058 }
00059
00060 inT16 bottom() const {
00061 return bot_left.y ();
00062 }
00063 void set_bottom(int y) {
00064 bot_left.set_y(y);
00065 }
00066
00067 inT16 left() const {
00068 return bot_left.x ();
00069 }
00070 void set_left(int x) {
00071 bot_left.set_x(x);
00072 }
00073
00074 inT16 right() const {
00075 return top_right.x ();
00076 }
00077 void set_right(int x) {
00078 top_right.set_x(x);
00079 }
00080
00081 const ICOORD &botleft() const {
00082 return bot_left;
00083 }
00084
00085 ICOORD botright() const {
00086 return ICOORD (top_right.x (), bot_left.y ());
00087 }
00088
00089 ICOORD topleft() const {
00090 return ICOORD (bot_left.x (), top_right.y ());
00091 }
00092
00093 const ICOORD &topright() const {
00094 return top_right;
00095 }
00096
00097 inT16 height() const {
00098 if (!null_box ())
00099 return top_right.y () - bot_left.y ();
00100 else
00101 return 0;
00102 }
00103
00104 inT16 width() const {
00105 if (!null_box ())
00106 return top_right.x () - bot_left.x ();
00107 else
00108 return 0;
00109 }
00110
00111 inT32 area() const {
00112 if (!null_box ())
00113 return width () * height ();
00114 else
00115 return 0;
00116 }
00117
00118
00119
00120 void pad(int xpad, int ypad) {
00121 ICOORD pad(xpad, ypad);
00122 bot_left -= pad;
00123 top_right += pad;
00124 }
00125
00126 void move_bottom_edge(
00127 const inT16 y) {
00128 bot_left += ICOORD (0, y);
00129 }
00130
00131 void move_left_edge(
00132 const inT16 x) {
00133 bot_left += ICOORD (x, 0);
00134 }
00135
00136 void move_right_edge(
00137 const inT16 x) {
00138 top_right += ICOORD (x, 0);
00139 }
00140
00141 void move_top_edge(
00142 const inT16 y) {
00143 top_right += ICOORD (0, y);
00144 }
00145
00146 void move(
00147 const ICOORD vec) {
00148 bot_left += vec;
00149 top_right += vec;
00150 }
00151
00152 void move(
00153 const FCOORD vec) {
00154 bot_left.set_x ((inT16) floor (bot_left.x () + vec.x ()));
00155
00156 bot_left.set_y ((inT16) floor (bot_left.y () + vec.y ()));
00157
00158 top_right.set_x ((inT16) ceil (top_right.x () + vec.x ()));
00159
00160 top_right.set_y ((inT16) ceil (top_right.y () + vec.y ()));
00161
00162 }
00163
00164 void scale(
00165 const float f) {
00166 bot_left.set_x ((inT16) floor (bot_left.x () * f));
00167 bot_left.set_y ((inT16) floor (bot_left.y () * f));
00168 top_right.set_x ((inT16) ceil (top_right.x () * f));
00169 top_right.set_y ((inT16) ceil (top_right.y () * f));
00170 }
00171 void scale(
00172 const FCOORD vec) {
00173 bot_left.set_x ((inT16) floor (bot_left.x () * vec.x ()));
00174 bot_left.set_y ((inT16) floor (bot_left.y () * vec.y ()));
00175 top_right.set_x ((inT16) ceil (top_right.x () * vec.x ()));
00176 top_right.set_y ((inT16) ceil (top_right.y () * vec.y ()));
00177 }
00178
00179
00180
00181
00182 void rotate(const FCOORD& vec) {
00183 bot_left.rotate (vec);
00184 top_right.rotate (vec);
00185 *this = TBOX (bot_left, top_right);
00186 }
00187
00188
00189
00190 void rotate_large(const FCOORD& vec);
00191
00192 bool contains(
00193 const FCOORD pt) const;
00194
00195 bool contains(
00196 const TBOX &box) const;
00197
00198 bool overlap(
00199 const TBOX &box) const;
00200
00201 bool major_overlap(
00202 const TBOX &box) const;
00203
00204
00205 bool x_overlap(const TBOX &box) const;
00206
00207
00208
00209
00210 int x_gap(const TBOX& box) const {
00211 return MAX(bot_left.x(), box.bot_left.x()) -
00212 MIN(top_right.x(), box.top_right.x());
00213 }
00214
00215
00216
00217
00218 int y_gap(const TBOX& box) const {
00219 return MAX(bot_left.y(), box.bot_left.y()) -
00220 MIN(top_right.y(), box.top_right.y());
00221 }
00222
00223
00224
00225 bool major_x_overlap(const TBOX &box) const;
00226
00227
00228 bool y_overlap(const TBOX &box) const;
00229
00230
00231
00232 bool major_y_overlap(const TBOX &box) const;
00233
00234
00235 double overlap_fraction(const TBOX &box) const;
00236
00237
00238 double x_overlap_fraction(const TBOX& box) const;
00239
00240
00241 double y_overlap_fraction(const TBOX& box) const;
00242
00243
00244 bool x_almost_equal(const TBOX &box, int tolerance) const;
00245
00246
00247 bool almost_equal(const TBOX &box, int tolerance) const;
00248
00249 TBOX intersection(
00250 const TBOX &box) const;
00251
00252 TBOX bounding_union(
00253 const TBOX &box) const;
00254
00255
00256 void set_to_given_coords(int x_min, int y_min, int x_max, int y_max) {
00257 bot_left.set_x(x_min);
00258 bot_left.set_y(y_min);
00259 top_right.set_x(x_max);
00260 top_right.set_y(y_max);
00261 }
00262
00263 void print() const {
00264 tprintf("Bounding box=(%d,%d)->(%d,%d)\n",
00265 left(), bottom(), right(), top());
00266 }
00267
00268
00269
00270 void append_debug(STRING *str) const {
00271 char buffer[256];
00272 sprintf(buffer, "Bounding box=(%d,%d)->(%d,%d)\n",
00273 left(), bottom(), right(), top());
00274 *str += buffer;
00275 }
00276
00277 #ifndef GRAPHICS_DISABLED
00278 void plot(
00279 ScrollView* fd) const {
00280 fd->Rectangle(bot_left.x (), bot_left.y (), top_right.x (),
00281 top_right.y ());
00282 }
00283
00284 void plot(
00285 ScrollView* fd,
00286 ScrollView::Color fill_colour,
00287 ScrollView::Color border_colour) const;
00288 #endif
00289
00290 bool Serialize(FILE* fp) const;
00291
00292
00293 bool DeSerialize(bool swap, FILE* fp);
00294
00295 friend TBOX& operator+=(TBOX&, const TBOX&);
00296
00297 friend TBOX& operator&=(TBOX&, const TBOX&);
00298
00299
00300 private:
00301 ICOORD bot_left;
00302 ICOORD top_right;
00303 };
00304
00305
00306
00307
00308
00309
00310 inline TBOX::TBOX(
00311 const FCOORD pt
00312 ) {
00313 bot_left = ICOORD ((inT16) floor (pt.x ()), (inT16) floor (pt.y ()));
00314 top_right = ICOORD ((inT16) ceil (pt.x ()), (inT16) ceil (pt.y ()));
00315 }
00316
00317
00318
00319
00320
00321
00322
00323 inline bool TBOX::contains(const FCOORD pt) const {
00324 return ((pt.x () >= bot_left.x ()) &&
00325 (pt.x () <= top_right.x ()) &&
00326 (pt.y () >= bot_left.y ()) && (pt.y () <= top_right.y ()));
00327 }
00328
00329
00330
00331
00332
00333
00334
00335 inline bool TBOX::contains(const TBOX &box) const {
00336 return (contains (box.bot_left) && contains (box.top_right));
00337 }
00338
00339
00340
00341
00342
00343
00344
00345 inline bool TBOX::overlap(
00346 const TBOX &box) const {
00347 return ((box.bot_left.x () <= top_right.x ()) &&
00348 (box.top_right.x () >= bot_left.x ()) &&
00349 (box.bot_left.y () <= top_right.y ()) &&
00350 (box.top_right.y () >= bot_left.y ()));
00351 }
00352
00353
00354
00355
00356
00357
00358 inline bool TBOX::major_overlap(
00359 const TBOX &box) const {
00360 int overlap = MIN(box.top_right.x(), top_right.x());
00361 overlap -= MAX(box.bot_left.x(), bot_left.x());
00362 overlap += overlap;
00363 if (overlap < MIN(box.width(), width()))
00364 return false;
00365 overlap = MIN(box.top_right.y(), top_right.y());
00366 overlap -= MAX(box.bot_left.y(), bot_left.y());
00367 overlap += overlap;
00368 if (overlap < MIN(box.height(), height()))
00369 return false;
00370 return true;
00371 }
00372
00373
00374
00375
00376
00377
00378 inline double TBOX::overlap_fraction(const TBOX &box) const {
00379 double fraction = 0.0;
00380 if (this->area()) {
00381 fraction = this->intersection(box).area() * 1.0 / this->area();
00382 }
00383 return fraction;
00384 }
00385
00386
00387
00388
00389
00390
00391 inline bool TBOX::x_overlap(const TBOX &box) const {
00392 return ((box.bot_left.x() <= top_right.x()) &&
00393 (box.top_right.x() >= bot_left.x()));
00394 }
00395
00396
00397
00398
00399
00400
00401
00402 inline bool TBOX::major_x_overlap(const TBOX &box) const {
00403 inT16 overlap = box.width();
00404 if (this->left() > box.left()) {
00405 overlap -= this->left() - box.left();
00406 }
00407 if (this->right() < box.right()) {
00408 overlap -= box.right() - this->right();
00409 }
00410 return (overlap >= box.width() / 2 || overlap >= this->width() / 2);
00411 }
00412
00413
00414
00415
00416
00417
00418 inline bool TBOX::y_overlap(const TBOX &box) const {
00419 return ((box.bot_left.y() <= top_right.y()) &&
00420 (box.top_right.y() >= bot_left.y()));
00421 }
00422
00423
00424
00425
00426
00427
00428
00429 inline bool TBOX::major_y_overlap(const TBOX &box) const {
00430 inT16 overlap = box.height();
00431 if (this->bottom() > box.bottom()) {
00432 overlap -= this->bottom() - box.bottom();
00433 }
00434 if (this->top() < box.top()) {
00435 overlap -= box.top() - this->top();
00436 }
00437 return (overlap >= box.height() / 2 || overlap >= this->height() / 2);
00438 }
00439
00440
00441
00442
00443
00444
00445
00446
00447 inline double TBOX::x_overlap_fraction(const TBOX& other) const {
00448 int low = MAX(left(), other.left());
00449 int high = MIN(right(), other.right());
00450 int width = right() - left();
00451 if (width == 0) {
00452 int x = left();
00453 if (other.left() <= x && x <= other.right())
00454 return 1.0;
00455 else
00456 return 0.0;
00457 } else {
00458 return MAX(0, static_cast<double>(high - low) / width);
00459 }
00460 }
00461
00462
00463
00464
00465
00466
00467
00468
00469 inline double TBOX::y_overlap_fraction(const TBOX& other) const {
00470 int low = MAX(bottom(), other.bottom());
00471 int high = MIN(top(), other.top());
00472 int height = top() - bottom();
00473 if (height == 0) {
00474 int y = bottom();
00475 if (other.bottom() <= y && y <= other.top())
00476 return 1.0;
00477 else
00478 return 0.0;
00479 } else {
00480 return MAX(0, static_cast<double>(high - low) / height);
00481 }
00482 }
00483
00484 #endif