Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/thirdparty/tesseract/src/ccstruct/quspline.cpp @ 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/quspline.cpp Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,402 @@ +/********************************************************************** + * File: quspline.cpp (Formerly qspline.c) + * Description: Code for the QSPLINE class. + * Author: Ray Smith + * + * (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. + * + **********************************************************************/ + +// Include automatically generated configuration file if running autoconf. +#ifdef HAVE_CONFIG_H +# include "config_auto.h" +#endif + +#include "quspline.h" + +#include "points.h" // for ICOORD +#include "quadlsq.h" // for QLSQ +#include "quadratc.h" // for QUAD_COEFFS + +#include <allheaders.h> // for pixRenderPolyline, pixGetDepth, pixGetHeight +#include "pix.h" // for L_CLEAR_PIXELS, L_SET_PIXELS, Pix (ptr only) + +namespace tesseract { + +#define QSPLINE_PRECISION 16 // no of steps to draw + +/********************************************************************** + * QSPLINE::QSPLINE + * + * Constructor to build a QSPLINE given the components used in the old code. + **********************************************************************/ + +QSPLINE::QSPLINE( // constructor + int32_t count, // no of segments + int32_t *xstarts, // start coords + double *coeffs // coefficients +) { + int32_t index; // segment index + + // get memory + xcoords = new int32_t[count + 1]; + quadratics = new QUAD_COEFFS[count]; + segments = count; + for (index = 0; index < segments; index++) { + // copy them + xcoords[index] = xstarts[index]; + quadratics[index] = + QUAD_COEFFS(coeffs[index * 3], coeffs[index * 3 + 1], coeffs[index * 3 + 2]); + } + // right edge + xcoords[index] = xstarts[index]; +} + +/********************************************************************** + * QSPLINE::QSPLINE + * + * Constructor to build a QSPLINE by appproximation of points. + **********************************************************************/ + +QSPLINE::QSPLINE( // constructor + int xstarts[], // spline boundaries + int segcount, // no of segments + int xpts[], // points to fit + int ypts[], int pointcount, // no of pts + int degree // fit required +) { + int pointindex; /*no along text line */ + int segment; /*segment no */ + int32_t *ptcounts; // no in each segment + QLSQ qlsq; /*accumulator */ + + segments = segcount; + xcoords = new int32_t[segcount + 1]; + ptcounts = new int32_t[segcount + 1]; + quadratics = new QUAD_COEFFS[segcount]; + memmove(xcoords, xstarts, (segcount + 1) * sizeof(int32_t)); + ptcounts[0] = 0; /*none in any yet */ + for (segment = 0, pointindex = 0; pointindex < pointcount; pointindex++) { + while (segment < segcount && xpts[pointindex] >= xstarts[segment]) { + segment++; /*try next segment */ + /*cumulative counts */ + ptcounts[segment] = ptcounts[segment - 1]; + } + ptcounts[segment]++; /*no in previous partition */ + } + while (segment < segcount) { + segment++; + /*zero the rest */ + ptcounts[segment] = ptcounts[segment - 1]; + } + + for (segment = 0; segment < segcount; segment++) { + qlsq.clear(); + /*first blob */ + pointindex = ptcounts[segment]; + if (pointindex > 0 && xpts[pointindex] != xpts[pointindex - 1] && + xpts[pointindex] != xstarts[segment]) { + qlsq.add(xstarts[segment], + ypts[pointindex - 1] + (ypts[pointindex] - ypts[pointindex - 1]) * + (xstarts[segment] - xpts[pointindex - 1]) / + (xpts[pointindex] - xpts[pointindex - 1])); + } + for (; pointindex < ptcounts[segment + 1]; pointindex++) { + qlsq.add(xpts[pointindex], ypts[pointindex]); + } + if (pointindex > 0 && pointindex < pointcount && xpts[pointindex] != xstarts[segment + 1]) { + qlsq.add(xstarts[segment + 1], + ypts[pointindex - 1] + (ypts[pointindex] - ypts[pointindex - 1]) * + (xstarts[segment + 1] - xpts[pointindex - 1]) / + (xpts[pointindex] - xpts[pointindex - 1])); + } + qlsq.fit(degree); + quadratics[segment].a = qlsq.get_a(); + quadratics[segment].b = qlsq.get_b(); + quadratics[segment].c = qlsq.get_c(); + } + delete[] ptcounts; +} + +/********************************************************************** + * QSPLINE::QSPLINE + * + * Constructor to build a QSPLINE from another. + **********************************************************************/ + +QSPLINE::QSPLINE( // constructor + const QSPLINE &src) { + segments = 0; + xcoords = nullptr; + quadratics = nullptr; + *this = src; +} + +/********************************************************************** + * QSPLINE::~QSPLINE + * + * Destroy a QSPLINE. + **********************************************************************/ + +QSPLINE::~QSPLINE() { + delete[] xcoords; + delete[] quadratics; +} + +/********************************************************************** + * QSPLINE::operator= + * + * Copy a QSPLINE + **********************************************************************/ + +QSPLINE &QSPLINE::operator=( // assignment + const QSPLINE &source) { + delete[] xcoords; + delete[] quadratics; + + segments = source.segments; + xcoords = new int32_t[segments + 1]; + quadratics = new QUAD_COEFFS[segments]; + memmove(xcoords, source.xcoords, (segments + 1) * sizeof(int32_t)); + memmove(quadratics, source.quadratics, segments * sizeof(QUAD_COEFFS)); + return *this; +} + +/********************************************************************** + * QSPLINE::step + * + * Return the total of the step functions between the given coords. + **********************************************************************/ + +double QSPLINE::step( // find step functions + double x1, // between coords + double x2) { + int index1, index2; // indices of coords + double total; /*total steps */ + + index1 = spline_index(x1); + index2 = spline_index(x2); + total = 0; + while (index1 < index2) { + total += static_cast<double>(quadratics[index1 + 1].y(static_cast<float>(xcoords[index1 + 1]))); + total -= static_cast<double>(quadratics[index1].y(static_cast<float>(xcoords[index1 + 1]))); + index1++; /*next segment */ + } + return total; /*total steps */ +} + +/********************************************************************** + * QSPLINE::y + * + * Return the y value at the given x value. + **********************************************************************/ + +double QSPLINE::y( // evaluate + double x // coord to evaluate at + ) const { + int32_t index; // segment index + + index = spline_index(x); + return quadratics[index].y(x); // in correct segment +} + +/********************************************************************** + * QSPLINE::spline_index + * + * Return the index to the largest xcoord not greater than x. + **********************************************************************/ + +int32_t QSPLINE::spline_index( // evaluate + double x // coord to evaluate at + ) const { + int32_t index; // segment index + int32_t bottom; // bottom of range + int32_t top; // top of range + + bottom = 0; + top = segments; + while (top - bottom > 1) { + index = (top + bottom) / 2; // centre of range + if (x >= xcoords[index]) { + bottom = index; // new min + } else { + top = index; // new max + } + } + return bottom; +} + +/********************************************************************** + * QSPLINE::move + * + * Reposition spline by vector + **********************************************************************/ + +void QSPLINE::move( // reposition spline + ICOORD vec // by vector +) { + int32_t segment; // index of segment + int16_t x_shift = vec.x(); + + for (segment = 0; segment < segments; segment++) { + xcoords[segment] += x_shift; + quadratics[segment].move(vec); + } + xcoords[segment] += x_shift; +} + +/********************************************************************** + * QSPLINE::overlap + * + * Return true if spline2 overlaps this by no more than fraction less + * than the bounds of this. + **********************************************************************/ + +bool QSPLINE::overlap( // test overlap + QSPLINE *spline2, // 2 cannot be smaller + double fraction // by more than this +) { + int leftlimit = xcoords[1]; /*common left limit */ + int rightlimit = xcoords[segments - 1]; /*common right limit */ + /*or too non-overlap */ + return !(spline2->segments < 3 || + spline2->xcoords[1] > leftlimit + fraction * (rightlimit - leftlimit) || + spline2->xcoords[spline2->segments - 1] < + rightlimit - fraction * (rightlimit - leftlimit)); +} + +/********************************************************************** + * extrapolate_spline + * + * Extrapolates the spline linearly using the same gradient as the + * quadratic has at either end. + **********************************************************************/ + +void QSPLINE::extrapolate( // linear extrapolation + double gradient, // gradient to use + int xmin, // new left edge + int xmax // new right edge +) { + int segment; /*current segment of spline */ + int dest_segment; // dest index + int32_t *xstarts; // new boundaries + QUAD_COEFFS *quads; // new ones + int increment; // in size + + increment = xmin < xcoords[0] ? 1 : 0; + if (xmax > xcoords[segments]) { + increment++; + } + if (increment == 0) { + return; + } + xstarts = new int32_t[segments + 1 + increment]; + quads = new QUAD_COEFFS[segments + increment]; + if (xmin < xcoords[0]) { + xstarts[0] = xmin; + quads[0].a = 0; + quads[0].b = gradient; + quads[0].c = y(xcoords[0]) - quads[0].b * xcoords[0]; + dest_segment = 1; + } else { + dest_segment = 0; + } + for (segment = 0; segment < segments; segment++) { + xstarts[dest_segment] = xcoords[segment]; + quads[dest_segment] = quadratics[segment]; + dest_segment++; + } + xstarts[dest_segment] = xcoords[segment]; + if (xmax > xcoords[segments]) { + quads[dest_segment].a = 0; + quads[dest_segment].b = gradient; + quads[dest_segment].c = y(xcoords[segments]) - quads[dest_segment].b * xcoords[segments]; + dest_segment++; + xstarts[dest_segment] = xmax + 1; + } + segments = dest_segment; + delete[] xcoords; + delete[] quadratics; + xcoords = xstarts; + quadratics = quads; +} + +/********************************************************************** + * QSPLINE::plot + * + * Draw the QSPLINE in the given colour. + **********************************************************************/ + +#ifndef GRAPHICS_DISABLED +void QSPLINE::plot( // draw it + ScrollView *window, // window to draw in + ScrollView::Color colour // colour to draw in + ) const { + int32_t segment; // index of segment + int16_t step; // index of poly piece + double increment; // x increment + double x; // x coord + + window->Pen(colour); + for (segment = 0; segment < segments; segment++) { + increment = static_cast<double>(xcoords[segment + 1] - xcoords[segment]) / QSPLINE_PRECISION; + x = xcoords[segment]; + for (step = 0; step <= QSPLINE_PRECISION; step++) { + if (segment == 0 && step == 0) { + window->SetCursor(x, quadratics[segment].y(x)); + } else { + window->DrawTo(x, quadratics[segment].y(x)); + } + x += increment; + } + } +} +#endif + +void QSPLINE::plot(Image pix) const { + if (pix == nullptr) { + return; + } + + int32_t segment; // Index of segment + int16_t step; // Index of poly piece + double increment; // x increment + double x; // x coord + auto height = static_cast<double>(pixGetHeight(pix)); + Pta *points = ptaCreate(QSPLINE_PRECISION * segments); + const int kLineWidth = 5; + + for (segment = 0; segment < segments; segment++) { + increment = static_cast<double>((xcoords[segment + 1] - xcoords[segment])) / QSPLINE_PRECISION; + x = xcoords[segment]; + for (step = 0; step <= QSPLINE_PRECISION; step++) { + double y = height - quadratics[segment].y(x); + ptaAddPt(points, x, y); + x += increment; + } + } + + switch (pixGetDepth(pix)) { + case 1: + pixRenderPolyline(pix, points, kLineWidth, L_SET_PIXELS, 1); + break; + case 32: + pixRenderPolylineArb(pix, points, kLineWidth, 255, 0, 0, 1); + break; + default: + pixRenderPolyline(pix, points, kLineWidth, L_CLEAR_PIXELS, 1); + break; + } + ptaDestroy(&points); +} + +} // namespace tesseract
