Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/tesseract/src/ccstruct/rect.h @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /********************************************************************** | |
| 2 * File: rect.h (Formerly box.h) | |
| 3 * Description: Bounding box class definition. | |
| 4 * Author: Phil Cheatle | |
| 5 * | |
| 6 * (C) Copyright 1991, Hewlett-Packard Ltd. | |
| 7 ** Licensed under the Apache License, Version 2.0 (the "License"); | |
| 8 ** you may not use this file except in compliance with the License. | |
| 9 ** You may obtain a copy of the License at | |
| 10 ** http://www.apache.org/licenses/LICENSE-2.0 | |
| 11 ** Unless required by applicable law or agreed to in writing, software | |
| 12 ** distributed under the License is distributed on an "AS IS" BASIS, | |
| 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 14 ** See the License for the specific language governing permissions and | |
| 15 ** limitations under the License. | |
| 16 * | |
| 17 **********************************************************************/ | |
| 18 | |
| 19 #ifndef RECT_H | |
| 20 #define RECT_H | |
| 21 | |
| 22 #include "points.h" // for ICOORD, FCOORD | |
| 23 #include "scrollview.h" // for ScrollView, ScrollView::Color | |
| 24 #include "tesstypes.h" // for TDimension | |
| 25 #include "tprintf.h" // for tprintf | |
| 26 | |
| 27 #include <tesseract/export.h> // for DLLSYM | |
| 28 | |
| 29 #include <algorithm> // for std::max, std::min | |
| 30 #include <cmath> // for std::ceil, std::floor | |
| 31 #include <cstdint> // for INT16_MAX | |
| 32 #include <cstdio> // for FILE | |
| 33 #include <string> // for std::string | |
| 34 | |
| 35 namespace tesseract { | |
| 36 | |
| 37 class TESS_API TBOX { // bounding box | |
| 38 public: | |
| 39 TBOX() | |
| 40 : // empty constructor making a null box | |
| 41 bot_left(INT16_MAX, INT16_MAX) | |
| 42 , top_right(-INT16_MAX, -INT16_MAX) {} | |
| 43 | |
| 44 TBOX( // constructor | |
| 45 const ICOORD pt1, // one corner | |
| 46 const ICOORD pt2); // the other corner | |
| 47 | |
| 48 //********************************************************************* | |
| 49 // TBOX::TBOX() Constructor from 4 integer values. | |
| 50 // Note: It is caller's responsibility to provide values | |
| 51 // in the right order. | |
| 52 //********************************************************************* | |
| 53 TBOX( // constructor | |
| 54 TDimension left, TDimension bottom, TDimension right, TDimension top) | |
| 55 : bot_left(left, bottom), top_right(right, top) {} | |
| 56 | |
| 57 TBOX( // box around FCOORD | |
| 58 const FCOORD pt); | |
| 59 | |
| 60 bool null_box() const { // Is box null | |
| 61 return ((left() >= right()) || (top() <= bottom())); | |
| 62 } | |
| 63 | |
| 64 bool operator==(const TBOX &other) const { | |
| 65 return bot_left == other.bot_left && top_right == other.top_right; | |
| 66 } | |
| 67 | |
| 68 TDimension top() const { // coord of top | |
| 69 return top_right.y(); | |
| 70 } | |
| 71 void set_top(int y) { | |
| 72 top_right.set_y(y); | |
| 73 } | |
| 74 | |
| 75 TDimension bottom() const { // coord of bottom | |
| 76 return bot_left.y(); | |
| 77 } | |
| 78 void set_bottom(int y) { | |
| 79 bot_left.set_y(y); | |
| 80 } | |
| 81 | |
| 82 TDimension left() const { // coord of left | |
| 83 return bot_left.x(); | |
| 84 } | |
| 85 void set_left(int x) { | |
| 86 bot_left.set_x(x); | |
| 87 } | |
| 88 | |
| 89 TDimension right() const { // coord of right | |
| 90 return top_right.x(); | |
| 91 } | |
| 92 void set_right(int x) { | |
| 93 top_right.set_x(x); | |
| 94 } | |
| 95 int x_middle() const { | |
| 96 return (bot_left.x() + top_right.x()) / 2; | |
| 97 } | |
| 98 int y_middle() const { | |
| 99 return (bot_left.y() + top_right.y()) / 2; | |
| 100 } | |
| 101 | |
| 102 const ICOORD &botleft() const { // access function | |
| 103 return bot_left; | |
| 104 } | |
| 105 | |
| 106 ICOORD botright() const { // ~ access function | |
| 107 return ICOORD(top_right.x(), bot_left.y()); | |
| 108 } | |
| 109 | |
| 110 ICOORD topleft() const { // ~ access function | |
| 111 return ICOORD(bot_left.x(), top_right.y()); | |
| 112 } | |
| 113 | |
| 114 const ICOORD &topright() const { // access function | |
| 115 return top_right; | |
| 116 } | |
| 117 | |
| 118 TDimension height() const { // how high is it? | |
| 119 if (!null_box()) { | |
| 120 return top_right.y() - bot_left.y(); | |
| 121 } else { | |
| 122 return 0; | |
| 123 } | |
| 124 } | |
| 125 | |
| 126 TDimension width() const { // how wide is it? | |
| 127 if (!null_box()) { | |
| 128 return top_right.x() - bot_left.x(); | |
| 129 } else { | |
| 130 return 0; | |
| 131 } | |
| 132 } | |
| 133 | |
| 134 int32_t area() const { // what is the area? | |
| 135 if (!null_box()) { | |
| 136 return width() * height(); | |
| 137 } else { | |
| 138 return 0; | |
| 139 } | |
| 140 } | |
| 141 | |
| 142 // Pads the box on either side by the supplied x,y pad amounts. | |
| 143 // NO checks for exceeding any bounds like 0 or an image size. | |
| 144 void pad(int xpad, int ypad) { | |
| 145 ICOORD pad(xpad, ypad); | |
| 146 bot_left -= pad; | |
| 147 top_right += pad; | |
| 148 } | |
| 149 | |
| 150 void move_bottom_edge( // move one edge | |
| 151 const TDimension y) { // by +/- y | |
| 152 bot_left += ICOORD(0, y); | |
| 153 } | |
| 154 | |
| 155 void move_left_edge( // move one edge | |
| 156 const TDimension x) { // by +/- x | |
| 157 bot_left += ICOORD(x, 0); | |
| 158 } | |
| 159 | |
| 160 void move_right_edge( // move one edge | |
| 161 const TDimension x) { // by +/- x | |
| 162 top_right += ICOORD(x, 0); | |
| 163 } | |
| 164 | |
| 165 void move_top_edge( // move one edge | |
| 166 const TDimension y) { // by +/- y | |
| 167 top_right += ICOORD(0, y); | |
| 168 } | |
| 169 | |
| 170 void move( // move box | |
| 171 const ICOORD vec) { // by vector | |
| 172 bot_left += vec; | |
| 173 top_right += vec; | |
| 174 } | |
| 175 | |
| 176 void move( // move box | |
| 177 const FCOORD vec) { // by float vector | |
| 178 bot_left.set_x(static_cast<TDimension>(std::floor(bot_left.x() + vec.x()))); | |
| 179 // round left | |
| 180 bot_left.set_y(static_cast<TDimension>(std::floor(bot_left.y() + vec.y()))); | |
| 181 // round down | |
| 182 top_right.set_x(static_cast<TDimension>(std::ceil(top_right.x() + vec.x()))); | |
| 183 // round right | |
| 184 top_right.set_y(static_cast<TDimension>(std::ceil(top_right.y() + vec.y()))); | |
| 185 // round up | |
| 186 } | |
| 187 | |
| 188 void scale( // scale box | |
| 189 const float f) { // by multiplier | |
| 190 // round left | |
| 191 bot_left.set_x(static_cast<TDimension>(std::floor(bot_left.x() * f))); | |
| 192 // round down | |
| 193 bot_left.set_y(static_cast<TDimension>(std::floor(bot_left.y() * f))); | |
| 194 // round right | |
| 195 top_right.set_x(static_cast<TDimension>(std::ceil(top_right.x() * f))); | |
| 196 // round up | |
| 197 top_right.set_y(static_cast<TDimension>(std::ceil(top_right.y() * f))); | |
| 198 } | |
| 199 void scale( // scale box | |
| 200 const FCOORD vec) { // by float vector | |
| 201 bot_left.set_x(static_cast<TDimension>(std::floor(bot_left.x() * vec.x()))); | |
| 202 bot_left.set_y(static_cast<TDimension>(std::floor(bot_left.y() * vec.y()))); | |
| 203 top_right.set_x(static_cast<TDimension>(std::ceil(top_right.x() * vec.x()))); | |
| 204 top_right.set_y(static_cast<TDimension>(std::ceil(top_right.y() * vec.y()))); | |
| 205 } | |
| 206 | |
| 207 // rotate doesn't enlarge the box - it just rotates the bottom-left | |
| 208 // and top-right corners. Use rotate_large if you want to guarantee | |
| 209 // that all content is contained within the rotated box. | |
| 210 void rotate(const FCOORD &vec) { // by vector | |
| 211 bot_left.rotate(vec); | |
| 212 top_right.rotate(vec); | |
| 213 *this = TBOX(bot_left, top_right); | |
| 214 } | |
| 215 // rotate_large constructs the containing bounding box of all 4 | |
| 216 // corners after rotating them. It therefore guarantees that all | |
| 217 // original content is contained within, but also slightly enlarges the box. | |
| 218 void rotate_large(const FCOORD &vec); | |
| 219 | |
| 220 bool contains( // is pt inside box | |
| 221 const FCOORD pt) const; | |
| 222 | |
| 223 bool contains( // is box inside box | |
| 224 const TBOX &box) const; | |
| 225 | |
| 226 bool overlap( // do boxes overlap | |
| 227 const TBOX &box) const; | |
| 228 | |
| 229 bool major_overlap( // do boxes overlap more than half | |
| 230 const TBOX &box) const; | |
| 231 | |
| 232 // Do boxes overlap on x axis. | |
| 233 bool x_overlap(const TBOX &box) const; | |
| 234 | |
| 235 // Return the horizontal gap between the boxes. If the boxes | |
| 236 // overlap horizontally then the return value is negative, indicating | |
| 237 // the amount of the overlap. | |
| 238 int x_gap(const TBOX &box) const { | |
| 239 return std::max(bot_left.x(), box.bot_left.x()) - std::min(top_right.x(), box.top_right.x()); | |
| 240 } | |
| 241 | |
| 242 // Return the vertical gap between the boxes. If the boxes | |
| 243 // overlap vertically then the return value is negative, indicating | |
| 244 // the amount of the overlap. | |
| 245 int y_gap(const TBOX &box) const { | |
| 246 return std::max(bot_left.y(), box.bot_left.y()) - std::min(top_right.y(), box.top_right.y()); | |
| 247 } | |
| 248 | |
| 249 // Do boxes overlap on x axis by more than | |
| 250 // half of the width of the narrower box. | |
| 251 bool major_x_overlap(const TBOX &box) const; | |
| 252 | |
| 253 // Do boxes overlap on y axis. | |
| 254 bool y_overlap(const TBOX &box) const; | |
| 255 | |
| 256 // Do boxes overlap on y axis by more than | |
| 257 // half of the height of the shorter box. | |
| 258 bool major_y_overlap(const TBOX &box) const; | |
| 259 | |
| 260 // fraction of current box's area covered by other | |
| 261 double overlap_fraction(const TBOX &box) const; | |
| 262 | |
| 263 // fraction of the current box's projected area covered by the other's | |
| 264 double x_overlap_fraction(const TBOX &box) const; | |
| 265 | |
| 266 // fraction of the current box's projected area covered by the other's | |
| 267 double y_overlap_fraction(const TBOX &box) const; | |
| 268 | |
| 269 // Returns true if the boxes are almost equal on x axis. | |
| 270 bool x_almost_equal(const TBOX &box, int tolerance) const; | |
| 271 | |
| 272 // Returns true if the boxes are almost equal | |
| 273 bool almost_equal(const TBOX &box, int tolerance) const; | |
| 274 | |
| 275 TBOX intersection( // shared area box | |
| 276 const TBOX &box) const; | |
| 277 | |
| 278 TBOX bounding_union( // box enclosing both | |
| 279 const TBOX &box) const; | |
| 280 | |
| 281 // Sets the box boundaries to the given coordinates. | |
| 282 void set_to_given_coords(int x_min, int y_min, int x_max, int y_max) { | |
| 283 bot_left.set_x(x_min); | |
| 284 bot_left.set_y(y_min); | |
| 285 top_right.set_x(x_max); | |
| 286 top_right.set_y(y_max); | |
| 287 } | |
| 288 | |
| 289 void print() const { // print | |
| 290 tprintf("Bounding box=(%d,%d)->(%d,%d)\n", left(), bottom(), right(), top()); | |
| 291 } | |
| 292 // Appends the bounding box as (%d,%d)->(%d,%d) to a string. | |
| 293 void print_to_str(std::string &str) const; | |
| 294 | |
| 295 #ifndef GRAPHICS_DISABLED | |
| 296 void plot( // use current settings | |
| 297 ScrollView *fd) const { // where to paint | |
| 298 fd->Rectangle(bot_left.x(), bot_left.y(), top_right.x(), top_right.y()); | |
| 299 } | |
| 300 | |
| 301 void plot( // paint box | |
| 302 ScrollView *fd, // where to paint | |
| 303 ScrollView::Color fill_colour, // colour for inside | |
| 304 ScrollView::Color border_colour) const; // colour for border | |
| 305 #endif | |
| 306 // Writes to the given file. Returns false in case of error. | |
| 307 bool Serialize(FILE *fp) const; | |
| 308 bool Serialize(TFile *fp) const; | |
| 309 | |
| 310 // Reads from the given file. Returns false in case of error. | |
| 311 // If swap is true, assumes a big/little-endian swap is needed. | |
| 312 bool DeSerialize(bool swap, FILE *fp); | |
| 313 bool DeSerialize(TFile *fp); | |
| 314 | |
| 315 friend TBOX &operator+=(TBOX &, const TBOX &); | |
| 316 // in place union | |
| 317 friend TBOX &operator&=(TBOX &, const TBOX &); | |
| 318 // in place intersection | |
| 319 | |
| 320 private: | |
| 321 ICOORD bot_left; // bottom left corner | |
| 322 ICOORD top_right; // top right corner | |
| 323 }; | |
| 324 | |
| 325 /********************************************************************** | |
| 326 * TBOX::TBOX() Constructor from 1 FCOORD | |
| 327 * | |
| 328 **********************************************************************/ | |
| 329 | |
| 330 inline TBOX::TBOX( // constructor | |
| 331 const FCOORD pt // floating centre | |
| 332 ) { | |
| 333 bot_left = | |
| 334 ICOORD(static_cast<TDimension>(std::floor(pt.x())), static_cast<TDimension>(std::floor(pt.y()))); | |
| 335 top_right = | |
| 336 ICOORD(static_cast<TDimension>(std::ceil(pt.x())), static_cast<TDimension>(std::ceil(pt.y()))); | |
| 337 } | |
| 338 | |
| 339 /********************************************************************** | |
| 340 * TBOX::contains() Is point within box | |
| 341 * | |
| 342 **********************************************************************/ | |
| 343 | |
| 344 inline bool TBOX::contains(const FCOORD pt) const { | |
| 345 return ((pt.x() >= bot_left.x()) && (pt.x() <= top_right.x()) && (pt.y() >= bot_left.y()) && | |
| 346 (pt.y() <= top_right.y())); | |
| 347 } | |
| 348 | |
| 349 /********************************************************************** | |
| 350 * TBOX::contains() Is box within box | |
| 351 * | |
| 352 **********************************************************************/ | |
| 353 | |
| 354 inline bool TBOX::contains(const TBOX &box) const { | |
| 355 return (contains(box.bot_left) && contains(box.top_right)); | |
| 356 } | |
| 357 | |
| 358 /********************************************************************** | |
| 359 * TBOX::overlap() Do two boxes overlap? | |
| 360 * | |
| 361 **********************************************************************/ | |
| 362 | |
| 363 inline bool TBOX::overlap( // do boxes overlap | |
| 364 const TBOX &box) const { | |
| 365 return ((box.bot_left.x() <= top_right.x()) && (box.top_right.x() >= bot_left.x()) && | |
| 366 (box.bot_left.y() <= top_right.y()) && (box.top_right.y() >= bot_left.y())); | |
| 367 } | |
| 368 | |
| 369 /********************************************************************** | |
| 370 * TBOX::major_overlap() Do two boxes overlap by at least half of the smallest? | |
| 371 * | |
| 372 **********************************************************************/ | |
| 373 | |
| 374 inline bool TBOX::major_overlap( // Do boxes overlap more that half. | |
| 375 const TBOX &box) const { | |
| 376 int overlap = std::min(box.top_right.x(), top_right.x()); | |
| 377 overlap -= std::max(box.bot_left.x(), bot_left.x()); | |
| 378 overlap += overlap; | |
| 379 if (overlap < std::min(box.width(), width())) { | |
| 380 return false; | |
| 381 } | |
| 382 overlap = std::min(box.top_right.y(), top_right.y()); | |
| 383 overlap -= std::max(box.bot_left.y(), bot_left.y()); | |
| 384 overlap += overlap; | |
| 385 if (overlap < std::min(box.height(), height())) { | |
| 386 return false; | |
| 387 } | |
| 388 return true; | |
| 389 } | |
| 390 | |
| 391 /********************************************************************** | |
| 392 * TBOX::overlap_fraction() Fraction of area covered by the other box | |
| 393 * | |
| 394 **********************************************************************/ | |
| 395 | |
| 396 inline double TBOX::overlap_fraction(const TBOX &box) const { | |
| 397 double fraction = 0.0; | |
| 398 if (this->area()) { | |
| 399 fraction = this->intersection(box).area() * 1.0 / this->area(); | |
| 400 } | |
| 401 return fraction; | |
| 402 } | |
| 403 | |
| 404 /********************************************************************** | |
| 405 * TBOX::x_overlap() Do two boxes overlap on x-axis | |
| 406 * | |
| 407 **********************************************************************/ | |
| 408 | |
| 409 inline bool TBOX::x_overlap(const TBOX &box) const { | |
| 410 return ((box.bot_left.x() <= top_right.x()) && (box.top_right.x() >= bot_left.x())); | |
| 411 } | |
| 412 | |
| 413 /********************************************************************** | |
| 414 * TBOX::major_x_overlap() Do two boxes overlap by more than half the | |
| 415 * width of the narrower box on the x-axis | |
| 416 * | |
| 417 **********************************************************************/ | |
| 418 | |
| 419 inline bool TBOX::major_x_overlap(const TBOX &box) const { | |
| 420 TDimension overlap = box.width(); | |
| 421 if (this->left() > box.left()) { | |
| 422 overlap -= this->left() - box.left(); | |
| 423 } | |
| 424 if (this->right() < box.right()) { | |
| 425 overlap -= box.right() - this->right(); | |
| 426 } | |
| 427 return (overlap >= box.width() / 2 || overlap >= this->width() / 2); | |
| 428 } | |
| 429 | |
| 430 /********************************************************************** | |
| 431 * TBOX::y_overlap() Do two boxes overlap on y-axis | |
| 432 * | |
| 433 **********************************************************************/ | |
| 434 | |
| 435 inline bool TBOX::y_overlap(const TBOX &box) const { | |
| 436 return ((box.bot_left.y() <= top_right.y()) && (box.top_right.y() >= bot_left.y())); | |
| 437 } | |
| 438 | |
| 439 /********************************************************************** | |
| 440 * TBOX::major_y_overlap() Do two boxes overlap by more than half the | |
| 441 * height of the shorter box on the y-axis | |
| 442 * | |
| 443 **********************************************************************/ | |
| 444 | |
| 445 inline bool TBOX::major_y_overlap(const TBOX &box) const { | |
| 446 TDimension overlap = box.height(); | |
| 447 if (this->bottom() > box.bottom()) { | |
| 448 overlap -= this->bottom() - box.bottom(); | |
| 449 } | |
| 450 if (this->top() < box.top()) { | |
| 451 overlap -= box.top() - this->top(); | |
| 452 } | |
| 453 return (overlap >= box.height() / 2 || overlap >= this->height() / 2); | |
| 454 } | |
| 455 | |
| 456 /********************************************************************** | |
| 457 * TBOX::x_overlap_fraction() Calculates the horizontal overlap of the | |
| 458 * given boxes as a fraction of this boxes | |
| 459 * width. | |
| 460 * | |
| 461 **********************************************************************/ | |
| 462 | |
| 463 inline double TBOX::x_overlap_fraction(const TBOX &other) const { | |
| 464 int low = std::max(left(), other.left()); | |
| 465 int high = std::min(right(), other.right()); | |
| 466 int width = right() - left(); | |
| 467 if (width == 0) { | |
| 468 int x = left(); | |
| 469 if (other.left() <= x && x <= other.right()) { | |
| 470 return 1.0; | |
| 471 } else { | |
| 472 return 0.0; | |
| 473 } | |
| 474 } else { | |
| 475 return std::max(0.0, static_cast<double>(high - low) / width); | |
| 476 } | |
| 477 } | |
| 478 | |
| 479 /********************************************************************** | |
| 480 * TBOX::y_overlap_fraction() Calculates the vertical overlap of the | |
| 481 * given boxes as a fraction of this boxes | |
| 482 * height. | |
| 483 * | |
| 484 **********************************************************************/ | |
| 485 | |
| 486 inline double TBOX::y_overlap_fraction(const TBOX &other) const { | |
| 487 int low = std::max(bottom(), other.bottom()); | |
| 488 int high = std::min(top(), other.top()); | |
| 489 int height = top() - bottom(); | |
| 490 if (height == 0) { | |
| 491 int y = bottom(); | |
| 492 if (other.bottom() <= y && y <= other.top()) { | |
| 493 return 1.0; | |
| 494 } else { | |
| 495 return 0.0; | |
| 496 } | |
| 497 } else { | |
| 498 return std::max(0.0, static_cast<double>(high - low) / height); | |
| 499 } | |
| 500 } | |
| 501 | |
| 502 } // namespace tesseract | |
| 503 | |
| 504 #endif |
