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