Mercurial > hgrepos > Python2 > PyMuPDF
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/thirdparty/tesseract/src/ccstruct/rect.h Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,504 @@ +/********************************************************************** + * File: rect.h (Formerly box.h) + * Description: Bounding box class definition. + * Author: Phil Cheatle + * + * (C) Copyright 1991, Hewlett-Packard Ltd. + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** http://www.apache.org/licenses/LICENSE-2.0 + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + * + **********************************************************************/ + +#ifndef RECT_H +#define RECT_H + +#include "points.h" // for ICOORD, FCOORD +#include "scrollview.h" // for ScrollView, ScrollView::Color +#include "tesstypes.h" // for TDimension +#include "tprintf.h" // for tprintf + +#include <tesseract/export.h> // for DLLSYM + +#include <algorithm> // for std::max, std::min +#include <cmath> // for std::ceil, std::floor +#include <cstdint> // for INT16_MAX +#include <cstdio> // for FILE +#include <string> // for std::string + +namespace tesseract { + +class TESS_API TBOX { // bounding box +public: + TBOX() + : // empty constructor making a null box + bot_left(INT16_MAX, INT16_MAX) + , top_right(-INT16_MAX, -INT16_MAX) {} + + TBOX( // constructor + const ICOORD pt1, // one corner + const ICOORD pt2); // the other corner + + //********************************************************************* + // TBOX::TBOX() Constructor from 4 integer values. + // Note: It is caller's responsibility to provide values + // in the right order. + //********************************************************************* + TBOX( // constructor + TDimension left, TDimension bottom, TDimension right, TDimension top) + : bot_left(left, bottom), top_right(right, top) {} + + TBOX( // box around FCOORD + const FCOORD pt); + + bool null_box() const { // Is box null + return ((left() >= right()) || (top() <= bottom())); + } + + bool operator==(const TBOX &other) const { + return bot_left == other.bot_left && top_right == other.top_right; + } + + TDimension top() const { // coord of top + return top_right.y(); + } + void set_top(int y) { + top_right.set_y(y); + } + + TDimension bottom() const { // coord of bottom + return bot_left.y(); + } + void set_bottom(int y) { + bot_left.set_y(y); + } + + TDimension left() const { // coord of left + return bot_left.x(); + } + void set_left(int x) { + bot_left.set_x(x); + } + + TDimension right() const { // coord of right + return top_right.x(); + } + void set_right(int x) { + top_right.set_x(x); + } + int x_middle() const { + return (bot_left.x() + top_right.x()) / 2; + } + int y_middle() const { + return (bot_left.y() + top_right.y()) / 2; + } + + const ICOORD &botleft() const { // access function + return bot_left; + } + + ICOORD botright() const { // ~ access function + return ICOORD(top_right.x(), bot_left.y()); + } + + ICOORD topleft() const { // ~ access function + return ICOORD(bot_left.x(), top_right.y()); + } + + const ICOORD &topright() const { // access function + return top_right; + } + + TDimension height() const { // how high is it? + if (!null_box()) { + return top_right.y() - bot_left.y(); + } else { + return 0; + } + } + + TDimension width() const { // how wide is it? + if (!null_box()) { + return top_right.x() - bot_left.x(); + } else { + return 0; + } + } + + int32_t area() const { // what is the area? + if (!null_box()) { + return width() * height(); + } else { + return 0; + } + } + + // Pads the box on either side by the supplied x,y pad amounts. + // NO checks for exceeding any bounds like 0 or an image size. + void pad(int xpad, int ypad) { + ICOORD pad(xpad, ypad); + bot_left -= pad; + top_right += pad; + } + + void move_bottom_edge( // move one edge + const TDimension y) { // by +/- y + bot_left += ICOORD(0, y); + } + + void move_left_edge( // move one edge + const TDimension x) { // by +/- x + bot_left += ICOORD(x, 0); + } + + void move_right_edge( // move one edge + const TDimension x) { // by +/- x + top_right += ICOORD(x, 0); + } + + void move_top_edge( // move one edge + const TDimension y) { // by +/- y + top_right += ICOORD(0, y); + } + + void move( // move box + const ICOORD vec) { // by vector + bot_left += vec; + top_right += vec; + } + + void move( // move box + const FCOORD vec) { // by float vector + bot_left.set_x(static_cast<TDimension>(std::floor(bot_left.x() + vec.x()))); + // round left + bot_left.set_y(static_cast<TDimension>(std::floor(bot_left.y() + vec.y()))); + // round down + top_right.set_x(static_cast<TDimension>(std::ceil(top_right.x() + vec.x()))); + // round right + top_right.set_y(static_cast<TDimension>(std::ceil(top_right.y() + vec.y()))); + // round up + } + + void scale( // scale box + const float f) { // by multiplier + // round left + bot_left.set_x(static_cast<TDimension>(std::floor(bot_left.x() * f))); + // round down + bot_left.set_y(static_cast<TDimension>(std::floor(bot_left.y() * f))); + // round right + top_right.set_x(static_cast<TDimension>(std::ceil(top_right.x() * f))); + // round up + top_right.set_y(static_cast<TDimension>(std::ceil(top_right.y() * f))); + } + void scale( // scale box + const FCOORD vec) { // by float vector + bot_left.set_x(static_cast<TDimension>(std::floor(bot_left.x() * vec.x()))); + bot_left.set_y(static_cast<TDimension>(std::floor(bot_left.y() * vec.y()))); + top_right.set_x(static_cast<TDimension>(std::ceil(top_right.x() * vec.x()))); + top_right.set_y(static_cast<TDimension>(std::ceil(top_right.y() * vec.y()))); + } + + // rotate doesn't enlarge the box - it just rotates the bottom-left + // and top-right corners. Use rotate_large if you want to guarantee + // that all content is contained within the rotated box. + void rotate(const FCOORD &vec) { // by vector + bot_left.rotate(vec); + top_right.rotate(vec); + *this = TBOX(bot_left, top_right); + } + // rotate_large constructs the containing bounding box of all 4 + // corners after rotating them. It therefore guarantees that all + // original content is contained within, but also slightly enlarges the box. + void rotate_large(const FCOORD &vec); + + bool contains( // is pt inside box + const FCOORD pt) const; + + bool contains( // is box inside box + const TBOX &box) const; + + bool overlap( // do boxes overlap + const TBOX &box) const; + + bool major_overlap( // do boxes overlap more than half + const TBOX &box) const; + + // Do boxes overlap on x axis. + bool x_overlap(const TBOX &box) const; + + // Return the horizontal gap between the boxes. If the boxes + // overlap horizontally then the return value is negative, indicating + // the amount of the overlap. + int x_gap(const TBOX &box) const { + return std::max(bot_left.x(), box.bot_left.x()) - std::min(top_right.x(), box.top_right.x()); + } + + // Return the vertical gap between the boxes. If the boxes + // overlap vertically then the return value is negative, indicating + // the amount of the overlap. + int y_gap(const TBOX &box) const { + return std::max(bot_left.y(), box.bot_left.y()) - std::min(top_right.y(), box.top_right.y()); + } + + // Do boxes overlap on x axis by more than + // half of the width of the narrower box. + bool major_x_overlap(const TBOX &box) const; + + // Do boxes overlap on y axis. + bool y_overlap(const TBOX &box) const; + + // Do boxes overlap on y axis by more than + // half of the height of the shorter box. + bool major_y_overlap(const TBOX &box) const; + + // fraction of current box's area covered by other + double overlap_fraction(const TBOX &box) const; + + // fraction of the current box's projected area covered by the other's + double x_overlap_fraction(const TBOX &box) const; + + // fraction of the current box's projected area covered by the other's + double y_overlap_fraction(const TBOX &box) const; + + // Returns true if the boxes are almost equal on x axis. + bool x_almost_equal(const TBOX &box, int tolerance) const; + + // Returns true if the boxes are almost equal + bool almost_equal(const TBOX &box, int tolerance) const; + + TBOX intersection( // shared area box + const TBOX &box) const; + + TBOX bounding_union( // box enclosing both + const TBOX &box) const; + + // Sets the box boundaries to the given coordinates. + void set_to_given_coords(int x_min, int y_min, int x_max, int y_max) { + bot_left.set_x(x_min); + bot_left.set_y(y_min); + top_right.set_x(x_max); + top_right.set_y(y_max); + } + + void print() const { // print + tprintf("Bounding box=(%d,%d)->(%d,%d)\n", left(), bottom(), right(), top()); + } + // Appends the bounding box as (%d,%d)->(%d,%d) to a string. + void print_to_str(std::string &str) const; + +#ifndef GRAPHICS_DISABLED + void plot( // use current settings + ScrollView *fd) const { // where to paint + fd->Rectangle(bot_left.x(), bot_left.y(), top_right.x(), top_right.y()); + } + + void plot( // paint box + ScrollView *fd, // where to paint + ScrollView::Color fill_colour, // colour for inside + ScrollView::Color border_colour) const; // colour for border +#endif + // Writes to the given file. Returns false in case of error. + bool Serialize(FILE *fp) const; + bool Serialize(TFile *fp) const; + + // Reads from the given file. Returns false in case of error. + // If swap is true, assumes a big/little-endian swap is needed. + bool DeSerialize(bool swap, FILE *fp); + bool DeSerialize(TFile *fp); + + friend TBOX &operator+=(TBOX &, const TBOX &); + // in place union + friend TBOX &operator&=(TBOX &, const TBOX &); + // in place intersection + +private: + ICOORD bot_left; // bottom left corner + ICOORD top_right; // top right corner +}; + +/********************************************************************** + * TBOX::TBOX() Constructor from 1 FCOORD + * + **********************************************************************/ + +inline TBOX::TBOX( // constructor + const FCOORD pt // floating centre +) { + bot_left = + ICOORD(static_cast<TDimension>(std::floor(pt.x())), static_cast<TDimension>(std::floor(pt.y()))); + top_right = + ICOORD(static_cast<TDimension>(std::ceil(pt.x())), static_cast<TDimension>(std::ceil(pt.y()))); +} + +/********************************************************************** + * TBOX::contains() Is point within box + * + **********************************************************************/ + +inline bool TBOX::contains(const FCOORD pt) const { + return ((pt.x() >= bot_left.x()) && (pt.x() <= top_right.x()) && (pt.y() >= bot_left.y()) && + (pt.y() <= top_right.y())); +} + +/********************************************************************** + * TBOX::contains() Is box within box + * + **********************************************************************/ + +inline bool TBOX::contains(const TBOX &box) const { + return (contains(box.bot_left) && contains(box.top_right)); +} + +/********************************************************************** + * TBOX::overlap() Do two boxes overlap? + * + **********************************************************************/ + +inline bool TBOX::overlap( // do boxes overlap + const TBOX &box) const { + return ((box.bot_left.x() <= top_right.x()) && (box.top_right.x() >= bot_left.x()) && + (box.bot_left.y() <= top_right.y()) && (box.top_right.y() >= bot_left.y())); +} + +/********************************************************************** + * TBOX::major_overlap() Do two boxes overlap by at least half of the smallest? + * + **********************************************************************/ + +inline bool TBOX::major_overlap( // Do boxes overlap more that half. + const TBOX &box) const { + int overlap = std::min(box.top_right.x(), top_right.x()); + overlap -= std::max(box.bot_left.x(), bot_left.x()); + overlap += overlap; + if (overlap < std::min(box.width(), width())) { + return false; + } + overlap = std::min(box.top_right.y(), top_right.y()); + overlap -= std::max(box.bot_left.y(), bot_left.y()); + overlap += overlap; + if (overlap < std::min(box.height(), height())) { + return false; + } + return true; +} + +/********************************************************************** + * TBOX::overlap_fraction() Fraction of area covered by the other box + * + **********************************************************************/ + +inline double TBOX::overlap_fraction(const TBOX &box) const { + double fraction = 0.0; + if (this->area()) { + fraction = this->intersection(box).area() * 1.0 / this->area(); + } + return fraction; +} + +/********************************************************************** + * TBOX::x_overlap() Do two boxes overlap on x-axis + * + **********************************************************************/ + +inline bool TBOX::x_overlap(const TBOX &box) const { + return ((box.bot_left.x() <= top_right.x()) && (box.top_right.x() >= bot_left.x())); +} + +/********************************************************************** + * TBOX::major_x_overlap() Do two boxes overlap by more than half the + * width of the narrower box on the x-axis + * + **********************************************************************/ + +inline bool TBOX::major_x_overlap(const TBOX &box) const { + TDimension overlap = box.width(); + if (this->left() > box.left()) { + overlap -= this->left() - box.left(); + } + if (this->right() < box.right()) { + overlap -= box.right() - this->right(); + } + return (overlap >= box.width() / 2 || overlap >= this->width() / 2); +} + +/********************************************************************** + * TBOX::y_overlap() Do two boxes overlap on y-axis + * + **********************************************************************/ + +inline bool TBOX::y_overlap(const TBOX &box) const { + return ((box.bot_left.y() <= top_right.y()) && (box.top_right.y() >= bot_left.y())); +} + +/********************************************************************** + * TBOX::major_y_overlap() Do two boxes overlap by more than half the + * height of the shorter box on the y-axis + * + **********************************************************************/ + +inline bool TBOX::major_y_overlap(const TBOX &box) const { + TDimension overlap = box.height(); + if (this->bottom() > box.bottom()) { + overlap -= this->bottom() - box.bottom(); + } + if (this->top() < box.top()) { + overlap -= box.top() - this->top(); + } + return (overlap >= box.height() / 2 || overlap >= this->height() / 2); +} + +/********************************************************************** + * TBOX::x_overlap_fraction() Calculates the horizontal overlap of the + * given boxes as a fraction of this boxes + * width. + * + **********************************************************************/ + +inline double TBOX::x_overlap_fraction(const TBOX &other) const { + int low = std::max(left(), other.left()); + int high = std::min(right(), other.right()); + int width = right() - left(); + if (width == 0) { + int x = left(); + if (other.left() <= x && x <= other.right()) { + return 1.0; + } else { + return 0.0; + } + } else { + return std::max(0.0, static_cast<double>(high - low) / width); + } +} + +/********************************************************************** + * TBOX::y_overlap_fraction() Calculates the vertical overlap of the + * given boxes as a fraction of this boxes + * height. + * + **********************************************************************/ + +inline double TBOX::y_overlap_fraction(const TBOX &other) const { + int low = std::max(bottom(), other.bottom()); + int high = std::min(top(), other.top()); + int height = top() - bottom(); + if (height == 0) { + int y = bottom(); + if (other.bottom() <= y && y <= other.top()) { + return 1.0; + } else { + return 0.0; + } + } else { + return std::max(0.0, static_cast<double>(high - low) / height); + } +} + +} // namespace tesseract + +#endif
