diff options
Diffstat (limited to 'Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.cpp')
-rw-r--r-- | Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.cpp | 548 |
1 files changed, 0 insertions, 548 deletions
diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.cpp b/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.cpp deleted file mode 100644 index 8c5d7448966..00000000000 --- a/Build/source/texk/dvisvgm/dvisvgm-src/src/TensorProductPatch.cpp +++ /dev/null @@ -1,548 +0,0 @@ -/************************************************************************* -** TensorProductPatch.cpp ** -** ** -** This file is part of dvisvgm -- a fast DVI to SVG converter ** -** Copyright (C) 2005-2021 Martin Gieseking <martin.gieseking@uos.de> ** -** ** -** This program is free software; you can redistribute it and/or ** -** modify it under the terms of the GNU General Public License as ** -** published by the Free Software Foundation; either version 3 of ** -** the License, or (at your option) any later version. ** -** ** -** This program is distributed in the hope that it will be useful, but ** -** WITHOUT ANY WARRANTY; without even the implied warranty of ** -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** -** GNU General Public License for more details. ** -** ** -** You should have received a copy of the GNU General Public License ** -** along with this program; if not, see <http://www.gnu.org/licenses/>. ** -*************************************************************************/ - -#include <valarray> -#include "TensorProductPatch.hpp" - -using namespace std; - - -TensorProductPatch::TensorProductPatch (const PointVec &points, const ColorVec &colors, Color::ColorSpace cspace, int edgeflag, TensorProductPatch *patch) - : ShadingPatch(cspace) -{ - setPoints(points, edgeflag, patch); - setColors(colors, edgeflag, patch); -} - - -void TensorProductPatch::setFirstMatrixColumn (const DPair source[4], bool reverse) { - for (int i=0; i < 4; i++) - _points[i][0] = source[reverse ? 3-i : i]; -} - - -void TensorProductPatch::setFirstMatrixColumn (DPair source[4][4], int col, bool reverse) { - for (int i=0; i < 4; i++) - _points[i][0] = source[reverse ? 3-i : i][col]; -} - - -/*void TensorProductPatch::setPoints (const DPair points[4][4]) { - for (int i=0; i < 4; i++) - for (int j=0; j < 4; j++) - _points[i][j] = points[i][j]; -}*/ - - -/** Sets the control points defining the structure of the patch. If the edge flag is 0, - * the point vector must contain all 16 control points of the 4x4 matrix in "spiral" order: - * 0 11 10 9 - * 1 12 15 8 - * 2 13 14 7 - * 3 4 5 6 - * If the edge flag is 1,2, or 3, the points of the first matrix collumn - * are omitted, and taken from a reference patch instead. - * @param[in] points the control points in "spiral" order as described in the PS reference, p. 286 - * @param[in] edgeflag defines how to connect this patch with another one - * @param[in] patch reference patch required if edgeflag > 0 */ -void TensorProductPatch::setPoints (const PointVec &points, int edgeflag, ShadingPatch *patch) { - auto tpPatch = dynamic_cast<TensorProductPatch*>(patch); - if (edgeflag > 0 && !tpPatch) - throw ShadingException("missing preceding data in definition of tensor-product patch"); - if ((edgeflag == 0 && points.size() != 16) || (edgeflag > 0 && points.size() != 12)) - throw ShadingException("invalid number of control points in tensor-product patch definition"); - - // assign the 12 control points that are invariant for all edge flag values - int i = (edgeflag == 0 ? 4 : 0); - _points[3][1] = points[i++]; - _points[3][2] = points[i++]; - _points[3][3] = points[i++]; - _points[2][3] = points[i++]; - _points[1][3] = points[i++]; - _points[0][3] = points[i++]; - _points[0][2] = points[i++]; - _points[0][1] = points[i++]; - _points[1][1] = points[i++]; - _points[2][1] = points[i++]; - _points[2][2] = points[i++]; - _points[1][2] = points[i]; - // populate the first column of the control point matrix - switch (edgeflag) { - case 0: setFirstMatrixColumn(&points[0], false); break; - case 1: setFirstMatrixColumn(tpPatch->_points[3], false); break; - case 2: setFirstMatrixColumn(tpPatch->_points, 3, true); break; - case 3: setFirstMatrixColumn(tpPatch->_points[0], true); break; - } -} - - -/** Sets the vertex colors of the patch. If the edge flag is 0, - * the color vector must contain all 4 colors in the following order: - * c00, c30, c33, c03, where cXY belongs to the vertex pXY of the control - * point matrix. - * c00 ---- c03 - * | | - * | | - * c30 ---- c33 - * If the edge flag is 1,2, or 3, the colors c00 and c30 are omitted, - * and taken from a reference patch instead. - * @param[in] points the color values in the order c00, c30, c33, c03 - * @param[in] edgeflag defines how to connect this patch with another one - * @param[in] patch reference patch required if edgeflag > 0 */ -void TensorProductPatch::setColors(const ColorVec &colors, int edgeflag, ShadingPatch* patch) { - auto tpPatch = dynamic_cast<TensorProductPatch*>(patch); - if (edgeflag > 0 && !tpPatch) - throw ShadingException("missing preceding data in definition of tensor-product patch"); - if ((edgeflag == 0 && colors.size() != 4) || (edgeflag > 0 && colors.size() != 2)) - throw ShadingException("invalid number of colors in tensor-product patch definition"); - - int i = (edgeflag == 0 ? 2 : 0); - _colors[3] = colors[i]; - _colors[1] = colors[i+1]; - switch (edgeflag) { - case 0: _colors[0] = colors[0]; _colors[2] = colors[1]; break; - case 1: _colors[0] = tpPatch->_colors[2]; _colors[2] = tpPatch->_colors[3]; break; - case 2: _colors[0] = tpPatch->_colors[3]; _colors[2] = tpPatch->_colors[1]; break; - case 3: _colors[0] = tpPatch->_colors[1]; _colors[2] = tpPatch->_colors[0]; break; - } -} - - -/** Returns the point P(u,v) of the patch. */ -DPair TensorProductPatch::valueAt (double u, double v) const { - // check if we can return one of the vertices - if (u == 0) { - if (v == 0) - return _points[0][0]; - else if (v == 1) - return _points[3][0]; - } - else if (u == 1) { - if (v == 0) - return _points[0][3]; - else if (v == 1) - return _points[3][3]; - } - // compute tensor product - DPair p[4]; - for (int i=0; i < 4; i++) { - Bezier bezier(_points[i][0], _points[i][1], _points[i][2], _points[i][3]); - p[i] = bezier.valueAt(u); - } - Bezier bezier(p[0], p[1], p[2], p[3]); - return bezier.valueAt(v); -} - - -/** Returns the color at point P(u,v) which is bilinearly interpolated from - * the colors assigned to vertices of the patch. */ -Color TensorProductPatch::colorAt (double u, double v) const { - // check if we can return one of the vertex colors - if (u == 0) { - if (v == 0) - return _colors[0]; - else if (v == 1) - return _colors[2]; - } - else if (u == 1) { - if (v == 0) - return _colors[1]; - else if (v == 1) - return _colors[3]; - } - // interpolate color - ColorGetter getComponents; - ColorSetter setComponents; - colorQueryFuncs(getComponents, setComponents); - valarray<double> comp[4]; - for (int i=0; i < 4; i++) - (_colors[i].*getComponents)(comp[i]); - Color color; - (color.*setComponents)((1-u)*(1-v)*comp[0] + u*(1-v)*comp[1] + (1-u)*v*comp[2] + u*v*comp[3]); - return color; -} - - -Color TensorProductPatch::averageColor () const { - return averageColor(_colors[0], _colors[1], _colors[2], _colors[3]); -} - - -/** Compute the average of four given colors depending on the assigned color space. */ -Color TensorProductPatch::averageColor (const Color &c1, const Color &c2, const Color &c3, const Color &c4) const { - ColorGetter getComponents; - ColorSetter setComponents; - colorQueryFuncs(getComponents, setComponents); - valarray<double> va1, va2, va3, va4; - (c1.*getComponents)(va1); - (c2.*getComponents)(va2); - (c3.*getComponents)(va3); - (c4.*getComponents)(va4); - Color averageColor; - (averageColor.*setComponents)((va1+va2+va3+va4)/4.0); - return averageColor; -} - - -GraphicsPath<double> TensorProductPatch::getBoundaryPath () const { - // Simple approach: Use the outer curves as boundary path. This doesn't always lead - // to correct results since, depending on the control points, P(u,v) might exceed - // the simple boundary. - GraphicsPath<double> path; - path.moveto(_points[0][0]); - path.cubicto(_points[0][1], _points[0][2], _points[0][3]); - path.cubicto(_points[1][3], _points[2][3], _points[3][3]); - path.cubicto(_points[3][2], _points[3][1], _points[3][0]); - path.cubicto(_points[2][0], _points[1][0], _points[0][0]); - path.closepath(); - return path; -} - - -/** Computes the bicubically interpolated isoparametric Bézier curve P(u,t) that - * runs "vertically" from P(u,0) to P(u,1) through the patch P. - * @param[in] u "horizontal" parameter in the range from 0 to 1 - * @param[out] bezier the resulting Bézier curve */ -void TensorProductPatch::verticalCurve (double u, Bezier &bezier) const { - // check for simple cases (boundary curves) first - if (u == 0) - bezier.setPoints(_points[0][0], _points[1][0], _points[2][0], _points[3][0]); - else if (u == 1) - bezier.setPoints(_points[0][3], _points[1][3], _points[2][3], _points[3][3]); - else { - // compute "inner" curve - DPair p[4]; - for (int i=0; i < 4; i++) { - Bezier bezier(_points[i][0], _points[i][1], _points[i][2], _points[i][3]); - p[i] = bezier.valueAt(u); - } - bezier.setPoints(p[0], p[1], p[2], p[3]); - } -} - - -/** Computes the bicubically interpolated isoparametric Bézier curve P(t,v) that - * runs "horizontally" from P(0,v) to P(1,v) through the patch P. - * @param[in] v "vertical" parameter in the range from 0 to 1 - * @param[out] bezier the resulting Bézier curve */ -void TensorProductPatch::horizontalCurve (double v, Bezier &bezier) const { - // check for simple cases (boundary curves) first - if (v == 0) - bezier.setPoints(_points[0][0], _points[0][1], _points[0][2], _points[0][3]); - else if (v == 1) - bezier.setPoints(_points[3][0], _points[3][1], _points[3][2], _points[3][3]); - else { - // compute "inner" curve - DPair p[4]; - for (int i=0; i < 4; i++) { - Bezier bezier(_points[0][i], _points[1][i], _points[2][i], _points[3][i]); - p[i] = bezier.valueAt(v); - } - bezier.setPoints(p[0], p[1], p[2], p[3]); - } -} - - -/** Computes the sub-patch that maps the unit square [0,1]x[0,1] to - * the area P([u1,u2],[v1,v2]) of patch P. The control points of the sub-patch - * can easily be calculated using the tensor product blossom of patch P. - * See G. Farin: Curves and Surfaces for CAGD, p. 259 for example. */ -void TensorProductPatch::subpatch (double u1, double u2, double v1, double v2, TensorProductPatch &patch) const { - if (u1 > u2) swap(u1, u2); - if (v1 > v2) swap(v1, v2); - // compute control points - double u[] = {u1, u1, u1, 0}; // blossom parameters of the "horizontal" domain (plus dummy value 0) - for (int i=0; i < 4; i++) { - u[3-i] = u2; - double v[] = {v1, v1, v1, 0}; // blossom parameters of the "vertical" domain (plus dummy value 0) - for (int j=0; j < 4; j++) { - v[3-j] = v2; - patch._points[i][j] = blossomValue(u, v); - } - } - // assign color values - patch._colors[0] = colorAt(u1, v1); - patch._colors[1] = colorAt(u2, v1); - patch._colors[2] = colorAt(u1, v2); - patch._colors[3] = colorAt(u2, v2); -} - - -/** Computes the value b(u1,u2,u3;v1,v2,v3) where b is tensor product blossom of the patch. */ -DPair TensorProductPatch::blossomValue (double u1, double u2, double u3, double v1, double v2, double v3) const { - DPair p[4]; - for (int i=0; i < 4; i++) { - Bezier bezier(_points[i][0], _points[i][1], _points[i][2], _points[i][3]); - p[i] = bezier.blossomValue(u1, u2, u3); - } - Bezier bezier(p[0], p[1], p[2], p[3]); - return bezier.blossomValue(v1, v2, v3); -} - - -/** Snaps value x to the interval [0,1]. Values lesser than or near 0 are mapped to 0, values - * greater than or near 1 are mapped to 1. */ -static inline double snap (double x) { - if (abs(x) < 0.001) - return 0; - if (abs(1-x) < 0.001) - return 1; - return x; -} - - -/** Computes a single row of segments approximating the patch region between v1 and v1+inc. */ -void TensorProductPatch::approximateRow (double v1, double inc, bool overlap, double delta, const vector<Bezier> &vbeziers, Callback &callback) const { - double v2 = snap(v1+inc); - double ov2 = (overlap && v2 < 1) ? snap(v2+inc) : v2; - Bezier hbezier1, hbezier2; - horizontalCurve(v1, hbezier1); - horizontalCurve(ov2, hbezier2); - double u1 = 0; - for (size_t i=1; i < vbeziers.size(); i++) { - double u2 = snap(u1+inc); - double ou2 = (overlap && u2 < 1) ? snap(u2+inc) : u2; - // compute segment boundaries - Bezier b1(hbezier1, u1, ou2); - Bezier b2(vbeziers[i + (overlap && i < vbeziers.size()-1 ? 1 : 0)], v1, ov2); - Bezier b3(hbezier2, u1, ou2); - Bezier b4(vbeziers[i-1], v1, ov2); - GraphicsPath<double> path; - path.moveto(b1.point(0)); - if (inc > delta) { - path.cubicto(b1.point(1), b1.point(2), b1.point(3)); - path.cubicto(b2.point(1), b2.point(2), b2.point(3)); - path.cubicto(b3.point(2), b3.point(1), b3.point(0)); - path.cubicto(b4.point(2), b4.point(1), b4.point(0)); - } - else { - path.lineto(b1.point(3)); - path.lineto(b2.point(3)); - path.lineto(b3.point(0)); - } - path.closepath(); - callback.patchSegment(path, averageColor(colorAt(u1, v1), colorAt(u2, v1), colorAt(u1, v2), colorAt(u2, v2))); - u1 = u2; - } -} - - -/** Approximate the patch by dividing it into a grid of segments that are filled with the - * average color of the corresponding region. The boundary of each segment consists of - * four Bézier curves, too. In order to prevent visual gaps between neighbored segments due - * to anti-aliasing, the flag 'overlap' can be set. It enlarges the segments so that they overlap - * with their right and bottom neighbors (which are drawn on top of the overlapping regions). - * @param[in] gridsize number of segments per row/column - * @param[in] overlap if true, enlarge each segment to overlap with its right and bottom neighbors - * @param[in] delta reduce level of detail if the segment size is smaller than the given value - * @param[in] callback object notified */ -void TensorProductPatch::approximate (int gridsize, bool overlap, double delta, Callback &callback) const { - if (_colors[0] == _colors[1] && _colors[1] == _colors[2] && _colors[2] == _colors[3]) { - // simple case: monochromatic patch - GraphicsPath<double> path = getBoundaryPath(); - callback.patchSegment(path, _colors[0]); - } - else { - const double inc = 1.0/gridsize; - // collect curves dividing the patch into several columns (curved vertical stripes) - vector<Bezier> vbeziers(gridsize+1); - double u=0; - for (int i=0; i <= gridsize; i++) { - verticalCurve(u, vbeziers[i]); - u = snap(u+inc); - } - // compute the segments row by row - double v=0; - for (int i=0; i < gridsize; i++) { - approximateRow(v, inc, overlap, delta, vbeziers, callback); - v = snap(v+inc); - } - } -} - - -BoundingBox TensorProductPatch::getBBox () const { - BoundingBox bbox; - Bezier bezier; - for (int i=0; i <= 1; i++) { - horizontalCurve(i, bezier); - bbox.embed(bezier.getBBox()); - verticalCurve(i, bezier); - bbox.embed(bezier.getBBox()); - } - return bbox; -} - - -#if 0 -void TensorProductPatch::approximate (int gridsize, Callback &callback) const { - const double inc = 1.0/gridsize; - Bezier ubezier0; verticalCurve(0, ubezier0); - Bezier ubezier1; verticalCurve(1, ubezier1); - Bezier vbezier0; horizontalCurve(0, vbezier0); - Bezier vbezier1; horizontalCurve(1, vbezier1); - for (double v1=0; v1 < 1; v1=snap(v1+inc)) { - double v2 = snap(v1+inc); - DPair p0 = valueAt(0, v1); - DPair p2 = valueAt(0, v2); - Color c0 = colorAt(0, v1); - Color c2 = colorAt(0, v2); - double u1 = 0; - for (double u2=inc; u2 <= 1; u2=snap(u2+inc)) { - DPair p1 = valueAt(u2, v1); - DPair p3 = valueAt(u2, v2); - Color c1 = colorAt(u2, v1); - Color c3 = colorAt(u2, v2); - // Compute a single patch segment. Only those segment edges that lay on the - // patch boundary are drawn as Bézier curves, all other edges are approximated - // with straight lines. This ensures a smooth outline and reduces the number of - // time consuming computations. - GraphicsPath<double> path; - path.moveto(p0); - if (v1 > 0) - path.lineto(p1); - else { - Bezier bezier(vbezier0, u1, u2); - path.cubicto(bezier.point(1), bezier.point(2), bezier.point(3)); - } - if (u2 < 1) - path.lineto(p3); - else { - Bezier bezier(ubezier1, v1, v2); - path.cubicto(bezier.point(1), bezier.point(2), bezier.point(3)); - } - if (v2 < 1) - path.lineto(p2); - else { - Bezier bezier(vbezier1, u1, u2); - path.cubicto(bezier.point(2), bezier.point(1), bezier.point(0)); - } - if (u1 > 0) - path.closepath(); - else { - Bezier bezier(ubezier0, v1, v2); - path.cubicto(bezier.point(2), bezier.point(1), bezier.point(0)); - path.closepath(); - } - callback.patchSegment(path, averageColor(c0, c1, c2, c3)); - p0 = p1; - p2 = p3; - c0 = c1; - c2 = c3; - u1 = u2; - } - } -} -#endif - - -///////////////////////////////////////////////////////////////////////////////////// - - -CoonsPatch::CoonsPatch (const PointVec &points, const ColorVec &colors, Color::ColorSpace cspace, int edgeflag, CoonsPatch *patch) - : TensorProductPatch(cspace) -{ - setPoints(points, edgeflag, patch); - setColors(colors, edgeflag, patch); -} - - -DPair CoonsPatch::valueAt (double u, double v) const { - // Compute the value of P(u,v) using the Coons equation rather than the - // tensor product since the "inner" control points of the tensor matrix - // might not be set yet. - Bezier bezier1(_points[3][0], _points[3][1], _points[3][2], _points[3][3]); - Bezier bezier2(_points[0][0], _points[0][1], _points[0][2], _points[0][3]); - Bezier bezier3(_points[3][0], _points[2][0], _points[1][0], _points[0][0]); - Bezier bezier4(_points[3][3], _points[2][3], _points[1][3], _points[0][3]); - DPair ph = bezier1.valueAt(u)*(1-v) + bezier2.valueAt(u)*v; - DPair pv = bezier3.valueAt(v)*(1-u) + bezier4.valueAt(v)*u; - DPair pc = (_points[3][0]*(1-u) + _points[3][3]*u)*(1-v) + (_points[0][0]*(1-u) + _points[0][3]*u)*v; - return ph+pv-pc; -} - - -/** Sets the 12 control points defining the geometry of the coons patch. The points - * must be given in the following order: - * 3 4 5 6 - * 2 7 - * 1 8 - * 0 11 10 9 - * where each edge of the square represents the four control points of a cubic Bézier curve. - * If the edge flag is 1, 2, or 3, the points 0 to 3 are omitted, and taken from a reference - * patch instead. - * @param[in] points the control points in cyclic order as described in the PS reference, p. 281 - * @param[in] edgeflag defines how to connect this patch to another one - * @param[in] patch reference patch required if edgeflag > 0 */ -void CoonsPatch::setPoints (const PointVec &points, int edgeflag, ShadingPatch *patch) { - auto coonsPatch = dynamic_cast<CoonsPatch*>(patch); - if (edgeflag > 0 && !coonsPatch) - throw ShadingException("missing preceding data in definition of relative Coons patch"); - if ((edgeflag == 0 && points.size() != 12) || (edgeflag > 0 && points.size() != 8)) - throw ShadingException("invalid number of control points in Coons patch definition"); - - // Since a Coons patch is a special tensor product patch, we only have to reorder the - // control points and compute the additional "inner" points of the 4x4 point tensor matrix. - - // set outer control points of the tensor matrix except those of the first column - // because these points depend on the edge flag - int i = (edgeflag == 0 ? 4 : 0); - _points[3][1] = points[i++]; - _points[3][2] = points[i++]; - _points[3][3] = points[i++]; - _points[2][3] = points[i++]; - _points[1][3] = points[i++]; - _points[0][3] = points[i++]; - _points[0][2] = points[i++]; - _points[0][1] = points[i]; - - // set control points of first matrix column - switch (edgeflag) { - case 0: setFirstMatrixColumn(&points[0], false); break; - case 1: setFirstMatrixColumn(coonsPatch->_points[3], false); break; - case 2: setFirstMatrixColumn(coonsPatch->_points, 3, true); break; - case 3: setFirstMatrixColumn(coonsPatch->_points[0], true); break; - } - // compute inner control points of the tensor matrix - _points[1][1] = valueAt(1.0/3.0, 2.0/3.0); - _points[1][2] = valueAt(2.0/3.0, 2.0/3.0); - _points[2][1] = valueAt(1.0/3.0, 1.0/3.0); - _points[2][2] = valueAt(2.0/3.0, 1.0/3.0); -} - - -void CoonsPatch::setColors (const ColorVec &colors, int edgeflag, ShadingPatch *patch) { - auto coonsPatch = dynamic_cast<CoonsPatch*>(patch); - if (edgeflag > 0 && !coonsPatch) - throw ShadingException("missing preceding data in definition of relative Coons patch"); - if ((edgeflag == 0 && colors.size() != 4) || (edgeflag > 0 && colors.size() != 2)) - throw ShadingException("invalid number of colors in Coons patch definition"); - - int i = (edgeflag == 0 ? 2 : 0); - _colors[3] = colors[i]; - _colors[1] = colors[i+1]; - switch (edgeflag) { - case 0: _colors[0] = colors[0]; _colors[2] = colors[1]; break; - case 1: _colors[0] = coonsPatch->_colors[2]; _colors[2] = coonsPatch->_colors[3]; break; - case 2: _colors[0] = coonsPatch->_colors[3]; _colors[2] = coonsPatch->_colors[1]; break; - case 3: _colors[0] = coonsPatch->_colors[1]; _colors[2] = coonsPatch->_colors[0]; break; - } -} - |