diff options
Diffstat (limited to 'basegfx/source')
41 files changed, 2397 insertions, 1548 deletions
diff --git a/basegfx/source/color/bcolormodifier.cxx b/basegfx/source/color/bcolormodifier.cxx index 8620a94fe2c7..3b9d1ce158c3 100644 --- a/basegfx/source/color/bcolormodifier.cxx +++ b/basegfx/source/color/bcolormodifier.cxx @@ -18,10 +18,10 @@ */ #include <sal/config.h> - #include <algorithm> - +#include <float.h> #include <basegfx/color/bcolormodifier.hxx> +#include <comphelper/random.hxx> namespace basegfx { @@ -45,6 +45,11 @@ namespace basegfx return ::basegfx::BColor(fLuminance, fLuminance, fLuminance); } + OUString BColorModifier_gray::getModifierName() const + { + return "gray"; + } + BColorModifier_invert::~BColorModifier_invert() { } @@ -59,6 +64,11 @@ namespace basegfx return ::basegfx::BColor(1.0 - aSourceColor.getRed(), 1.0 - aSourceColor.getGreen(), 1.0 - aSourceColor.getBlue()); } + OUString BColorModifier_invert::getModifierName() const + { + return "invert"; + } + BColorModifier_luminance_to_alpha::~BColorModifier_luminance_to_alpha() { } @@ -75,6 +85,11 @@ namespace basegfx return ::basegfx::BColor(fAlpha, fAlpha, fAlpha); } + OUString BColorModifier_luminance_to_alpha::getModifierName() const + { + return "luminance_to_alpha"; + } + BColorModifier_replace::~BColorModifier_replace() { } @@ -96,6 +111,11 @@ namespace basegfx return maBColor; } + OUString BColorModifier_replace::getModifierName() const + { + return "replace"; + } + BColorModifier_interpolate::~BColorModifier_interpolate() { } @@ -117,6 +137,162 @@ namespace basegfx return interpolate(maBColor, aSourceColor, mfValue); } + OUString BColorModifier_interpolate::getModifierName() const + { + return "interpolate"; + } + + BColorModifier_matrix::~BColorModifier_matrix() + { + } + + bool BColorModifier_matrix::operator==(const BColorModifier& rCompare) const + { + const BColorModifier_matrix* pCompare = dynamic_cast< const BColorModifier_matrix* >(&rCompare); + + if(!pCompare) + { + return false; + } + + return maVector == pCompare->maVector; + } + + ::basegfx::BColor BColorModifier_matrix::getModifiedColor(const ::basegfx::BColor& aSourceColor) const + { + if (maVector.size() != 20) + return aSourceColor; + + const double aRed = maVector[0] * aSourceColor.getRed() + + maVector[1] * aSourceColor.getGreen() + + maVector[2] * aSourceColor.getBlue() + + maVector[3] * 1.0 + + maVector[4]; + const double aGreen = maVector[5] * aSourceColor.getRed() + + maVector[6] * aSourceColor.getGreen() + + maVector[7] * aSourceColor.getBlue() + + maVector[8] * 1.0 + + maVector[9]; + const double aBlue = maVector[10] * aSourceColor.getRed() + + maVector[11] * aSourceColor.getGreen() + + maVector[12] * aSourceColor.getBlue() + + maVector[13] * 1.0 + + maVector[14]; + /*TODO: add support for alpha + const double aAlpha = maVector[15] * aSourceColor.getRed() + + maVector[16] * aSourceColor.getGreen() + + maVector[17] * aSourceColor.getBlue() + + maVector[18] * 1.0 + + maVector[19]); + */ + + return ::basegfx::BColor( + std::clamp(aRed, 0.0, 1.0), + std::clamp(aGreen, 0.0, 1.0), + std::clamp(aBlue, 0.0, 1.0)); + } + + OUString BColorModifier_matrix::getModifierName() const + { + return "matrix"; + } + + BColorModifier_saturate::BColorModifier_saturate(double fValue) + { + maSatMatrix.set(0, 0, 0.213 + 0.787 * fValue); + maSatMatrix.set(0, 1, 0.715 - 0.715 * fValue); + maSatMatrix.set(0, 2, 0.072 - 0.072 * fValue); + maSatMatrix.set(1, 0, 0.213 - 0.213 * fValue); + maSatMatrix.set(1, 1, 0.715 + 0.285 * fValue); + maSatMatrix.set(1, 2, 0.072 - 0.072 * fValue); + maSatMatrix.set(2, 0, 0.213 - 0.213 * fValue); + maSatMatrix.set(2, 1, 0.715 - 0.715 * fValue); + maSatMatrix.set(2, 2, 0.072 + 0.928 * fValue); + } + + BColorModifier_saturate::~BColorModifier_saturate() + { + } + + bool BColorModifier_saturate::operator==(const BColorModifier& rCompare) const + { + const BColorModifier_saturate* pCompare = dynamic_cast< const BColorModifier_saturate* >(&rCompare); + + if(!pCompare) + { + return false; + } + + return maSatMatrix == pCompare->maSatMatrix; + } + + ::basegfx::BColor BColorModifier_saturate::getModifiedColor(const ::basegfx::BColor& aSourceColor) const + { + basegfx::B3DHomMatrix aColorMatrix; + aColorMatrix.set(0, 0, aSourceColor.getRed()); + aColorMatrix.set(1, 0, aSourceColor.getGreen()); + aColorMatrix.set(2, 0, aSourceColor.getBlue()); + + aColorMatrix = maSatMatrix * aColorMatrix; + return ::basegfx::BColor(aColorMatrix.get(0, 0), aColorMatrix.get(1, 0), aColorMatrix.get(2, 0)); + } + + OUString BColorModifier_saturate::getModifierName() const + { + return "saturate"; + } + + BColorModifier_hueRotate::BColorModifier_hueRotate(double fRad) + { + const double fCos = cos(fRad); + const double fSin = sin(fRad); + + maHueMatrix.set(0, 0, 0.213 + fCos * 0.787 - fSin * 0.213); + maHueMatrix.set(0, 1, 0.715 - fCos * 0.715 - fSin * 0.715); + maHueMatrix.set(0, 2, 0.072 - fCos * 0.072 + fSin * 0.928); + maHueMatrix.set(1, 0, 0.213 - fCos * 0.213 + fSin * 0.143); + maHueMatrix.set(1, 1, 0.715 + fCos * 0.285 + fSin * 0.140); + maHueMatrix.set(1, 2, 0.072 - fCos * 0.072 - fSin * 0.283); + maHueMatrix.set(2, 0, 0.213 - fCos * 0.213 - fSin * 0.787); + maHueMatrix.set(2, 1, 0.715 - fCos * 0.715 + fSin * 0.715); + maHueMatrix.set(2, 2, 0.072 + fCos * 0.928 + fSin * 0.072); + } + + BColorModifier_hueRotate::~BColorModifier_hueRotate() + { + } + + bool BColorModifier_hueRotate::operator==(const BColorModifier& rCompare) const + { + const BColorModifier_hueRotate* pCompare = dynamic_cast< const BColorModifier_hueRotate* >(&rCompare); + + if(!pCompare) + { + return false; + } + + return maHueMatrix == pCompare->maHueMatrix; + } + + ::basegfx::BColor BColorModifier_hueRotate::getModifiedColor(const ::basegfx::BColor& aSourceColor) const + { + basegfx::B3DHomMatrix aColorMatrix; + aColorMatrix.set(0, 0, aSourceColor.getRed()); + aColorMatrix.set(1, 0, aSourceColor.getGreen()); + aColorMatrix.set(2, 0, aSourceColor.getBlue()); + + aColorMatrix = maHueMatrix * aColorMatrix; + return ::basegfx::BColor( + std::clamp(aColorMatrix.get(0, 0), 0.0, 1.0), + std::clamp(aColorMatrix.get(1, 0), 0.0, 1.0), + std::clamp(aColorMatrix.get(2, 0), 0.0, 1.0)); + } + + OUString BColorModifier_hueRotate::getModifierName() const + { + return "hueRotate"; + } + BColorModifier_black_and_white::~BColorModifier_black_and_white() { } @@ -147,10 +323,15 @@ namespace basegfx } } + OUString BColorModifier_black_and_white::getModifierName() const + { + return "black_and_white"; + } + BColorModifier_gamma::BColorModifier_gamma(double fValue) : mfValue(fValue), mfInvValue(fValue), - mbUseIt(!basegfx::fTools::equal(fValue, 1.0) && basegfx::fTools::more(fValue, 0.0) && basegfx::fTools::lessOrEqual(fValue, 10.0)) + mbUseIt(!basegfx::fTools::equal(fValue, 1.0) && fValue > 0.0 && basegfx::fTools::lessOrEqual(fValue, 10.0)) { if(mbUseIt) { @@ -193,6 +374,11 @@ namespace basegfx } } + OUString BColorModifier_gamma::getModifierName() const + { + return "gamma"; + } + BColorModifier_RGBLuminanceContrast::BColorModifier_RGBLuminanceContrast(double fRed, double fGreen, double fBlue, double fLuminance, double fContrast) : mfRed(std::clamp(fRed, -1.0, 1.0)), mfGreen(std::clamp(fGreen, -1.0, 1.0)), @@ -270,6 +456,67 @@ namespace basegfx } } + OUString BColorModifier_RGBLuminanceContrast::getModifierName() const + { + return "RGBLuminanceContrast"; + } + + BColorModifier_randomize::BColorModifier_randomize(double fRandomPart) + : mfRandomPart(fRandomPart) + { + } + + BColorModifier_randomize::~BColorModifier_randomize() + { + } + + // compare operator + bool BColorModifier_randomize::operator==(const BColorModifier& rCompare) const + { + const BColorModifier_randomize* pCompare = dynamic_cast< const BColorModifier_randomize* >(&rCompare); + + if(!pCompare) + { + return false; + } + + return mfRandomPart == pCompare->mfRandomPart; + } + + // compute modified color + ::basegfx::BColor BColorModifier_randomize::getModifiedColor(const ::basegfx::BColor& aSourceColor) const + { + if(0.0 >= mfRandomPart) + { + // no randomizing, use orig color + return aSourceColor; + } + + if(1.0 <= mfRandomPart) + { + // full randomized color + return basegfx::BColor( + comphelper::rng::uniform_real_distribution(0.0, nextafter(1.0, DBL_MAX)), + comphelper::rng::uniform_real_distribution(0.0, nextafter(1.0, DBL_MAX)), + comphelper::rng::uniform_real_distribution(0.0, nextafter(1.0, DBL_MAX))); + } + + // mixed color + const double fMulA(1.0 - mfRandomPart); + return basegfx::BColor( + aSourceColor.getRed() * fMulA + + comphelper::rng::uniform_real_distribution(0.0, nextafter(mfRandomPart, DBL_MAX)), + aSourceColor.getGreen() * fMulA + + comphelper::rng::uniform_real_distribution(0.0, nextafter(mfRandomPart, DBL_MAX)), + aSourceColor.getBlue() * fMulA + + comphelper::rng::uniform_real_distribution(0.0, nextafter(mfRandomPart, DBL_MAX))); + } + + OUString BColorModifier_randomize::getModifierName() const + { + return "randomize"; + } + ::basegfx::BColor BColorModifierStack::getModifiedColor(const ::basegfx::BColor& rSource) const { if(maBColorModifiers.empty()) diff --git a/basegfx/source/curve/b2dcubicbezier.cxx b/basegfx/source/curve/b2dcubicbezier.cxx index a04c17568b38..3f5d87aa79f6 100644 --- a/basegfx/source/curve/b2dcubicbezier.cxx +++ b/basegfx/source/curve/b2dcubicbezier.cxx @@ -337,8 +337,6 @@ namespace basegfx { } - B2DCubicBezier::~B2DCubicBezier() = default; - // assignment operator B2DCubicBezier& B2DCubicBezier::operator=(const B2DCubicBezier&) = default; @@ -353,16 +351,6 @@ namespace basegfx ); } - bool B2DCubicBezier::operator!=(const B2DCubicBezier& rBezier) const - { - return ( - maStartPoint != rBezier.maStartPoint - || maEndPoint != rBezier.maEndPoint - || maControlPointA != rBezier.maControlPointA - || maControlPointB != rBezier.maControlPointB - ); - } - bool B2DCubicBezier::equal(const B2DCubicBezier& rBezier) const { return ( @@ -543,7 +531,7 @@ namespace basegfx B2DVector B2DCubicBezier::getTangent(double t) const { - if(fTools::lessOrEqual(t, 0.0)) + if(t <= 0.0) { // tangent in start point B2DVector aTangent(getControlPointA() - getStartPoint()); @@ -612,12 +600,12 @@ namespace basegfx } // adaptive subdivide by distance - void B2DCubicBezier::adaptiveSubdivideByDistance(B2DPolygon& rTarget, double fDistanceBound) const + void B2DCubicBezier::adaptiveSubdivideByDistance(B2DPolygon& rTarget, double fDistanceBound, int nRecurseLimit) const { if(isBezier()) { ImpSubDivDistance(maStartPoint, maControlPointA, maControlPointB, maEndPoint, rTarget, - fDistanceBound * fDistanceBound, std::numeric_limits<double>::max(), 30); + fDistanceBound * fDistanceBound, std::numeric_limits<double>::max(), nRecurseLimit); } else { @@ -1023,33 +1011,33 @@ namespace basegfx if(maControlPointA == maStartPoint) { maControlPointA = maStartPoint = basegfx::B2DPoint( - basegfx::fround(maStartPoint.getX()), - basegfx::fround(maStartPoint.getY())); + std::round(maStartPoint.getX()), + std::round(maStartPoint.getY())); } else { maStartPoint = basegfx::B2DPoint( - basegfx::fround(maStartPoint.getX()), - basegfx::fround(maStartPoint.getY())); + std::round(maStartPoint.getX()), + std::round(maStartPoint.getY())); maControlPointA = basegfx::B2DPoint( - basegfx::fround(maControlPointA.getX()), - basegfx::fround(maControlPointA.getY())); + std::round(maControlPointA.getX()), + std::round(maControlPointA.getY())); } if(maControlPointB == maEndPoint) { maControlPointB = maEndPoint = basegfx::B2DPoint( - basegfx::fround(maEndPoint.getX()), - basegfx::fround(maEndPoint.getY())); + std::round(maEndPoint.getX()), + std::round(maEndPoint.getY())); } else { maEndPoint = basegfx::B2DPoint( - basegfx::fround(maEndPoint.getX()), - basegfx::fround(maEndPoint.getY())); + std::round(maEndPoint.getX()), + std::round(maEndPoint.getY())); maControlPointB = basegfx::B2DPoint( - basegfx::fround(maControlPointB.getX()), - basegfx::fround(maControlPointB.getY())); + std::round(maControlPointB.getX()), + std::round(maControlPointB.getY())); } } } // end of namespace basegfx diff --git a/basegfx/source/inc/hommatrixtemplate.hxx b/basegfx/source/inc/hommatrixtemplate.hxx deleted file mode 100644 index a80df114c3e3..000000000000 --- a/basegfx/source/inc/hommatrixtemplate.hxx +++ /dev/null @@ -1,525 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you 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 . - */ - -#pragma once - -#include <sal/types.h> -#include <basegfx/numeric/ftools.hxx> -#include <cmath> -#include <string.h> - -#include <memory> - -namespace basegfx::internal - { - - inline double implGetDefaultValue(sal_uInt16 nRow, sal_uInt16 nColumn) - { - if(nRow == nColumn) - return 1.0; - return 0.0; - } - - template < sal_uInt16 RowSize > class ImplMatLine - { - double mfValue[RowSize]; - - public: - ImplMatLine() - { - } - - explicit ImplMatLine(sal_uInt16 nRow, ImplMatLine< RowSize >* pToBeCopied) - { - if(pToBeCopied) - { - memcpy(&mfValue, pToBeCopied, sizeof(double) * RowSize); - } - else - { - for(sal_uInt16 a(0); a < RowSize; a++) - { - mfValue[a] = implGetDefaultValue(nRow, a); - } - } - } - - double get(sal_uInt16 nColumn) const - { - return mfValue[nColumn]; - } - - void set(sal_uInt16 nColumn, const double& rValue) - { - mfValue[nColumn] = rValue; - } - }; - - template < sal_uInt16 RowSize > class ImplHomMatrixTemplate - { - ImplMatLine< RowSize > maLine[RowSize - 1]; - std::unique_ptr<ImplMatLine< RowSize >> mutable mpLine; - - public: - // Is last line used? - bool isLastLineDefault() const - { - if(!mpLine) - return true; - - for(sal_uInt16 a(0); a < RowSize; a++) - { - const double fDefault(implGetDefaultValue((RowSize - 1), a)); - const double fLineValue(mpLine->get(a)); - - if(!::basegfx::fTools::equal(fDefault, fLineValue)) - { - return false; - } - } - - // reset last line, it equals default - mpLine.reset(); - - return true; - } - - ImplHomMatrixTemplate() - { - // complete initialization with identity matrix, all lines - // were initialized with a trailing 1 followed by 0's. - for(sal_uInt16 a(0); a < RowSize-1; a++) - { - for(sal_uInt16 b(0); b < RowSize; b++) - maLine[a].set(b, implGetDefaultValue(a, b) ); - } - } - - ImplHomMatrixTemplate(const ImplHomMatrixTemplate& rToBeCopied) - { - operator=(rToBeCopied); - } - - ImplHomMatrixTemplate& operator=(const ImplHomMatrixTemplate& rToBeCopied) - { - if (this != &rToBeCopied) - { - // complete initialization using copy - for(sal_uInt16 a(0); a < (RowSize - 1); a++) - { - memcpy(&maLine[a], &rToBeCopied.maLine[a], sizeof(ImplMatLine< RowSize >)); - } - if(rToBeCopied.mpLine) - { - mpLine.reset( new ImplMatLine< RowSize >((RowSize - 1), rToBeCopied.mpLine.get()) ); - } - } - return *this; - } - - static sal_uInt16 getEdgeLength() { return RowSize; } - - double get(sal_uInt16 nRow, sal_uInt16 nColumn) const - { - if(nRow < (RowSize - 1)) - { - return maLine[nRow].get(nColumn); - } - - if(mpLine) - { - return mpLine->get(nColumn); - } - - return implGetDefaultValue((RowSize - 1), nColumn); - } - - void set(sal_uInt16 nRow, sal_uInt16 nColumn, const double& rValue) - { - if(nRow < (RowSize - 1)) - { - maLine[nRow].set(nColumn, rValue); - } - else if(mpLine) - { - mpLine->set(nColumn, rValue); - } - else - { - const double fDefault(implGetDefaultValue((RowSize - 1), nColumn)); - - if(!::basegfx::fTools::equal(fDefault, rValue)) - { - mpLine.reset(new ImplMatLine< RowSize >((RowSize - 1), nullptr)); - mpLine->set(nColumn, rValue); - } - } - } - - void testLastLine() - { - if(!mpLine) - return; - - bool bNecessary(false); - - for(sal_uInt16 a(0);!bNecessary && a < RowSize; a++) - { - const double fDefault(implGetDefaultValue((RowSize - 1), a)); - const double fLineValue(mpLine->get(a)); - - if(!::basegfx::fTools::equal(fDefault, fLineValue)) - { - bNecessary = true; - } - } - - if(!bNecessary) - { - mpLine.reset(); - } - } - - // Left-upper decomposition - bool ludcmp(sal_uInt16 nIndex[], sal_Int16& nParity) - { - double fBig, fSum, fDum; - double fStorage[RowSize]; - sal_uInt16 a, b, c; - - // #i30874# Initialize nAMax (compiler warns) - sal_uInt16 nAMax = 0; - - nParity = 1; - - // Calc the max of each line. If a line is empty, - // stop immediately since matrix is not invertible then. - for(a = 0; a < RowSize; a++) - { - fBig = 0.0; - - for(b = 0; b < RowSize; b++) - { - double fTemp(fabs(get(a, b))); - - if(::basegfx::fTools::more(fTemp, fBig)) - { - fBig = fTemp; - } - } - - if(::basegfx::fTools::equalZero(fBig)) - { - return false; - } - - fStorage[a] = 1.0 / fBig; - } - - // start normalizing - for(b = 0; b < RowSize; b++) - { - for(a = 0; a < b; a++) - { - fSum = get(a, b); - - for(c = 0; c < a; c++) - { - fSum -= get(a, c) * get(c, b); - } - - set(a, b, fSum); - } - - fBig = 0.0; - - for(a = b; a < RowSize; a++) - { - fSum = get(a, b); - - for(c = 0; c < b; c++) - { - fSum -= get(a, c) * get(c, b); - } - - set(a, b, fSum); - fDum = fStorage[a] * fabs(fSum); - - if(::basegfx::fTools::moreOrEqual(fDum, fBig)) - { - fBig = fDum; - nAMax = a; - } - } - - if(b != nAMax) - { - for(c = 0; c < RowSize; c++) - { - fDum = get(nAMax, c); - set(nAMax, c, get(b, c)); - set(b, c, fDum); - } - - nParity = -nParity; - fStorage[nAMax] = fStorage[b]; - } - - nIndex[b] = nAMax; - - // here the failure of precision occurs - const double fValBB(fabs(get(b, b))); - - if(::basegfx::fTools::equalZero(fValBB)) - { - return false; - } - - if(b != (RowSize - 1)) - { - fDum = 1.0 / get(b, b); - - for(a = b + 1; a < RowSize; a++) - { - set(a, b, get(a, b) * fDum); - } - } - } - - return true; - } - - void lubksb(const sal_uInt16 nIndex[], double fRow[]) const - { - sal_uInt16 b, ip; - sal_Int16 a, a2 = -1; - double fSum; - - for(a = 0; a < RowSize; a++) - { - ip = nIndex[a]; - fSum = fRow[ip]; - fRow[ip] = fRow[a]; - - if(a2 >= 0) - { - for(b = a2; b < a; b++) - { - fSum -= get(a, b) * fRow[b]; - } - } - else if(!::basegfx::fTools::equalZero(fSum)) - { - a2 = a; - } - - fRow[a] = fSum; - } - - for(a = (RowSize - 1); a >= 0; a--) - { - fSum = fRow[a]; - - for(b = a + 1; b < RowSize; b++) - { - fSum -= get(a, b) * fRow[b]; - } - - const double fValueAA(get(a, a)); - - if(!::basegfx::fTools::equalZero(fValueAA)) - { - fRow[a] = fSum / get(a, a); - } - } - } - - bool isIdentity() const - { - // last line needs no testing if not existing - const sal_uInt16 nMaxLine( - sal::static_int_cast<sal_uInt16>(mpLine ? RowSize : (RowSize - 1)) ); - - for(sal_uInt16 a(0); a < nMaxLine; a++) - { - for(sal_uInt16 b(0); b < RowSize; b++) - { - const double fDefault(implGetDefaultValue(a, b)); - const double fValueAB(get(a, b)); - - if(!::basegfx::fTools::equal(fDefault, fValueAB)) - { - return false; - } - } - } - - return true; - } - - bool isInvertible() const - { - ImplHomMatrixTemplate aWork(*this); - sal_uInt16 nIndex[RowSize]; - sal_Int16 nParity; - - return aWork.ludcmp(nIndex, nParity); - } - - void doInvert(const ImplHomMatrixTemplate& rWork, const sal_uInt16 nIndex[]) - { - double fArray[RowSize]; - - for(sal_uInt16 a(0); a < RowSize; a++) - { - // prepare line - sal_uInt16 b; - for( b = 0; b < RowSize; b++) - { - fArray[b] = implGetDefaultValue(a, b); - } - - // expand line - rWork.lubksb(nIndex, fArray); - - // copy line transposed to this matrix - for( b = 0; b < RowSize; b++) - { - set(b, a, fArray[b]); - } - } - - // evtl. get rid of last matrix line - testLastLine(); - } - - double doDeterminant() const - { - ImplHomMatrixTemplate aWork(*this); - sal_uInt16 nIndex[RowSize]; - sal_Int16 nParity; - double fRetval(0.0); - - if(aWork.ludcmp(nIndex, nParity)) - { - fRetval = static_cast<double>(nParity); - - // last line needs no multiply if not existing; default value would be 1. - const sal_uInt16 nMaxLine( - sal::static_int_cast<sal_uInt16>(aWork.mpLine ? RowSize : (RowSize - 1)) ); - - for(sal_uInt16 a(0); a < nMaxLine; a++) - { - fRetval *= aWork.get(a, a); - } - } - - return fRetval; - } - - void doAddMatrix(const ImplHomMatrixTemplate& rMat) - { - for(sal_uInt16 a(0); a < RowSize; a++) - { - for(sal_uInt16 b(0); b < RowSize; b++) - { - set(a, b, get(a, b) + rMat.get(a, b)); - } - } - - testLastLine(); - } - - void doSubMatrix(const ImplHomMatrixTemplate& rMat) - { - for(sal_uInt16 a(0); a < RowSize; a++) - { - for(sal_uInt16 b(0); b < RowSize; b++) - { - set(a, b, get(a, b) - rMat.get(a, b)); - } - } - - testLastLine(); - } - - void doMulMatrix(const double& rfValue) - { - for(sal_uInt16 a(0); a < RowSize; a++) - { - for(sal_uInt16 b(0); b < RowSize; b++) - { - set(a, b, get(a, b) * rfValue); - } - } - - testLastLine(); - } - - void doMulMatrix(const ImplHomMatrixTemplate& rMat) - { - // create a copy as source for the original values - const ImplHomMatrixTemplate aCopy(*this); - - // TODO: maybe optimize cases where last line is [0 0 1]. - - double fValue(0.0); - - for(sal_uInt16 a(0); a < RowSize; ++a) - { - for(sal_uInt16 b(0); b < RowSize; ++b) - { - fValue = 0.0; - - for(sal_uInt16 c(0); c < RowSize; ++c) - fValue += aCopy.get(c, b) * rMat.get(a, c); - - set(a, b, fValue); - } - } - - testLastLine(); - } - - bool isEqual(const ImplHomMatrixTemplate& rMat) const - { - const sal_uInt16 nMaxLine( - sal::static_int_cast<sal_uInt16>((mpLine || rMat.mpLine) ? RowSize : (RowSize - 1)) ); - - for(sal_uInt16 a(0); a < nMaxLine; a++) - { - for(sal_uInt16 b(0); b < RowSize; b++) - { - const double fValueA(get(a, b)); - const double fValueB(rMat.get(a, b)); - - if(!::basegfx::fTools::equal(fValueA, fValueB)) - { - return false; - } - } - } - - return true; - } - }; - -} // namespace basegfx::internal - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basegfx/source/inc/stringconversiontools.hxx b/basegfx/source/inc/stringconversiontools.hxx index fdf2f83e0f4e..797697d203ac 100644 --- a/basegfx/source/inc/stringconversiontools.hxx +++ b/basegfx/source/inc/stringconversiontools.hxx @@ -51,7 +51,7 @@ namespace basegfx::internal bool importDoubleAndSpaces(double& o_fRetval, sal_Int32& io_rPos, - const OUString& rStr, + std::u16string_view rStr, const sal_Int32 nLen ); bool importFlagAndSpaces(sal_Int32& o_nRetval, diff --git a/basegfx/source/matrix/b2dhommatrix.cxx b/basegfx/source/matrix/b2dhommatrix.cxx index f3d2622db27a..dc5c02b0e33f 100644 --- a/basegfx/source/matrix/b2dhommatrix.cxx +++ b/basegfx/source/matrix/b2dhommatrix.cxx @@ -18,7 +18,7 @@ */ #include <basegfx/matrix/b2dhommatrix.hxx> -#include <hommatrixtemplate.hxx> +#include <basegfx/matrix/hommatrixtemplate.hxx> #include <basegfx/tuple/b2dtuple.hxx> #include <basegfx/vector/b2dvector.hxx> #include <basegfx/matrix/b2dhommatrixtools.hxx> @@ -26,125 +26,100 @@ namespace basegfx { - typedef ::basegfx::internal::ImplHomMatrixTemplate< 3 > Impl2DHomMatrix_Base; - class Impl2DHomMatrix : public Impl2DHomMatrix_Base - { - }; - - static o3tl::cow_wrapper<Impl2DHomMatrix> DEFAULT; - - B2DHomMatrix::B2DHomMatrix() : mpImpl(DEFAULT) {} - - B2DHomMatrix::B2DHomMatrix(const B2DHomMatrix&) = default; - - B2DHomMatrix::B2DHomMatrix(B2DHomMatrix&&) = default; - - B2DHomMatrix::~B2DHomMatrix() = default; - - B2DHomMatrix::B2DHomMatrix(double f_0x0, double f_0x1, double f_0x2, double f_1x0, double f_1x1, double f_1x2) - { - mpImpl->set(0, 0, f_0x0); - mpImpl->set(0, 1, f_0x1); - mpImpl->set(0, 2, f_0x2); - mpImpl->set(1, 0, f_1x0); - mpImpl->set(1, 1, f_1x1); - mpImpl->set(1, 2, f_1x2); - } - - B2DHomMatrix& B2DHomMatrix::operator=(const B2DHomMatrix&) = default; - - B2DHomMatrix& B2DHomMatrix::operator=(B2DHomMatrix&&) = default; - - double B2DHomMatrix::get(sal_uInt16 nRow, sal_uInt16 nColumn) const - { - return mpImpl->get(nRow, nColumn); - } - - void B2DHomMatrix::set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue) - { - mpImpl->set(nRow, nColumn, fValue); - } + constexpr int RowSize = 3; void B2DHomMatrix::set3x2(double f_0x0, double f_0x1, double f_0x2, double f_1x0, double f_1x1, double f_1x2) { - mpImpl->set(0, 0, f_0x0); - mpImpl->set(0, 1, f_0x1); - mpImpl->set(0, 2, f_0x2); - mpImpl->set(1, 0, f_1x0); - mpImpl->set(1, 1, f_1x1); - mpImpl->set(1, 2, f_1x2); - } - - bool B2DHomMatrix::isLastLineDefault() const - { - return mpImpl->isLastLineDefault(); + mfValues[0][0] = f_0x0; + mfValues[0][1] = f_0x1; + mfValues[0][2] = f_0x2; + mfValues[1][0] = f_1x0; + mfValues[1][1] = f_1x1; + mfValues[1][2] = f_1x2; } bool B2DHomMatrix::isIdentity() const { - return mpImpl->isIdentity(); + for(sal_uInt16 a(0); a < RowSize - 1; a++) + { + for(sal_uInt16 b(0); b < RowSize; b++) + { + const double fDefault(internal::implGetDefaultValue(a, b)); + const double fValueAB(get(a, b)); + + if(!::basegfx::fTools::equal(fDefault, fValueAB)) + { + return false; + } + } + } + + return true; } void B2DHomMatrix::identity() { - *mpImpl = Impl2DHomMatrix(); + for(sal_uInt16 a(0); a < RowSize - 1; a++) + { + for(sal_uInt16 b(0); b < RowSize; b++) + mfValues[a][b] = internal::implGetDefaultValue(a, b); + } } bool B2DHomMatrix::isInvertible() const { - return mpImpl->isInvertible(); + double dst[6]; + /* Compute adjoint: */ + computeAdjoint(dst); + /* Compute determinant: */ + double det = computeDeterminant(dst); + if (fTools::equalZero(det)) + return false; + return true; } bool B2DHomMatrix::invert() { if(isIdentity()) - { return true; - } - Impl2DHomMatrix aWork(*mpImpl); - std::unique_ptr<sal_uInt16[]> pIndex( new sal_uInt16[Impl2DHomMatrix_Base::getEdgeLength()] ); - sal_Int16 nParity; + double dst[6]; - if(aWork.ludcmp(pIndex.get(), nParity)) - { - mpImpl->doInvert(aWork, pIndex.get()); - return true; - } + /* Compute adjoint: */ + computeAdjoint(dst); - return false; - } + /* Compute determinant: */ + double det = computeDeterminant(dst); + if (fTools::equalZero(det)) + return false; - B2DHomMatrix& B2DHomMatrix::operator+=(const B2DHomMatrix& rMat) - { - mpImpl->doAddMatrix(*rMat.mpImpl); - return *this; - } + /* Multiply adjoint with reciprocal of determinant: */ + det = 1.0 / det; + mfValues[0][0] = dst[0] * det; + mfValues[0][1] = dst[1] * det; + mfValues[0][2] = dst[2] * det; + mfValues[1][0] = dst[3] * det; + mfValues[1][1] = dst[4] * det; + mfValues[1][2] = dst[5] * det; - B2DHomMatrix& B2DHomMatrix::operator-=(const B2DHomMatrix& rMat) - { - mpImpl->doSubMatrix(*rMat.mpImpl); - return *this; + return true; } - B2DHomMatrix& B2DHomMatrix::operator*=(double fValue) + /* Compute adjoint, optimised for the case where the last (not stored) row is { 0, 0, 1 } */ + void B2DHomMatrix::computeAdjoint(double (&dst)[6]) const { - const double fOne(1.0); - - if(!fTools::equal(fOne, fValue)) - mpImpl->doMulMatrix(fValue); - - return *this; + dst[0] = + get(1, 1); + dst[1] = - get(0, 1); + dst[2] = + get(0, 1) * get(1, 2) - get(0, 2) * get(1, 1); + dst[3] = - get(1, 0); + dst[4] = + get(0, 0); + dst[5] = - get(0, 0) * get(1, 2) + get(0, 2) * get(1, 0); } - B2DHomMatrix& B2DHomMatrix::operator/=(double fValue) + /* Compute the determinant, given the adjoint matrix */ + double B2DHomMatrix::computeDeterminant(double (&dst)[6]) const { - const double fOne(1.0); - - if(!fTools::equal(fOne, fValue)) - mpImpl->doMulMatrix(1.0 / fValue); - - return *this; + return mfValues[0][0] * dst[0] + mfValues[0][1] * dst[3]; } B2DHomMatrix& B2DHomMatrix::operator*=(const B2DHomMatrix& rMat) @@ -161,23 +136,50 @@ namespace basegfx else { // multiply - mpImpl->doMulMatrix(*rMat.mpImpl); + doMulMatrix(rMat); } return *this; } - bool B2DHomMatrix::operator==(const B2DHomMatrix& rMat) const + void B2DHomMatrix::doMulMatrix(const B2DHomMatrix& rMat) { - if(mpImpl.same_object(rMat.mpImpl)) - return true; + // create a copy as source for the original values + const B2DHomMatrix aCopy(*this); - return mpImpl->isEqual(*rMat.mpImpl); + for(sal_uInt16 a(0); a < 2; ++a) + { + for(sal_uInt16 b(0); b < 3; ++b) + { + double fValue = 0.0; + + for(sal_uInt16 c(0); c < 2; ++c) + fValue += aCopy.mfValues[c][b] * rMat.mfValues[a][c]; + + mfValues[a][b] = fValue; + } + mfValues[a][2] += rMat.mfValues[a][2]; + } } - bool B2DHomMatrix::operator!=(const B2DHomMatrix& rMat) const + bool B2DHomMatrix::operator==(const B2DHomMatrix& rMat) const { - return !(*this == rMat); + if (&rMat == this) + return true; + for(sal_uInt16 a(0); a < 2; a++) + { + for(sal_uInt16 b(0); b < 3; b++) + { + const double fValueA(mfValues[a][b]); + const double fValueB(rMat.mfValues[a][b]); + + if(!::basegfx::fTools::equal(fValueA, fValueB)) + { + return false; + } + } + } + return true; } void B2DHomMatrix::rotate(double fRadiant) @@ -189,26 +191,26 @@ namespace basegfx double fCos(1.0); utils::createSinCosOrthogonal(fSin, fCos, fRadiant); - Impl2DHomMatrix aRotMat; + B2DHomMatrix aRotMat; aRotMat.set(0, 0, fCos); aRotMat.set(1, 1, fCos); aRotMat.set(1, 0, fSin); aRotMat.set(0, 1, -fSin); - mpImpl->doMulMatrix(aRotMat); + doMulMatrix(aRotMat); } void B2DHomMatrix::translate(double fX, double fY) { if(!fTools::equalZero(fX) || !fTools::equalZero(fY)) { - Impl2DHomMatrix aTransMat; + B2DHomMatrix aTransMat; aTransMat.set(0, 2, fX); aTransMat.set(1, 2, fY); - mpImpl->doMulMatrix(aTransMat); + doMulMatrix(aTransMat); } } @@ -223,12 +225,12 @@ namespace basegfx if(!fTools::equal(fOne, fX) || !fTools::equal(fOne, fY)) { - Impl2DHomMatrix aScaleMat; + B2DHomMatrix aScaleMat; aScaleMat.set(0, 0, fX); aScaleMat.set(1, 1, fY); - mpImpl->doMulMatrix(aScaleMat); + doMulMatrix(aScaleMat); } } @@ -242,11 +244,11 @@ namespace basegfx // #i76239# do not test against 1.0, but against 0.0. We are talking about a value not on the diagonal (!) if(!fTools::equalZero(fSx)) { - Impl2DHomMatrix aShearXMat; + B2DHomMatrix aShearXMat; aShearXMat.set(0, 1, fSx); - mpImpl->doMulMatrix(aShearXMat); + doMulMatrix(aShearXMat); } } @@ -255,11 +257,11 @@ namespace basegfx // #i76239# do not test against 1.0, but against 0.0. We are talking about a value not on the diagonal (!) if(!fTools::equalZero(fSy)) { - Impl2DHomMatrix aShearYMat; + B2DHomMatrix aShearYMat; aShearYMat.set(1, 0, fSy); - mpImpl->doMulMatrix(aShearYMat); + doMulMatrix(aShearYMat); } } @@ -272,12 +274,6 @@ namespace basegfx */ bool B2DHomMatrix::decompose(B2DTuple& rScale, B2DTuple& rTranslate, double& rRotate, double& rShearX) const { - // when perspective is used, decompose is not made here - if(!mpImpl->isLastLineDefault()) - { - return false; - } - // reset rotate and shear and copy translation values in every case rRotate = rShearX = 0.0; rTranslate.setX(get(0, 2)); diff --git a/basegfx/source/matrix/b3dhommatrix.cxx b/basegfx/source/matrix/b3dhommatrix.cxx index 3605767d681d..96edab9158b6 100644 --- a/basegfx/source/matrix/b3dhommatrix.cxx +++ b/basegfx/source/matrix/b3dhommatrix.cxx @@ -18,7 +18,7 @@ */ #include <basegfx/matrix/b3dhommatrix.hxx> -#include <hommatrixtemplate.hxx> +#include <basegfx/matrix/hommatrixtemplate.hxx> #include <basegfx/vector/b3dvector.hxx> #include <memory> @@ -142,11 +142,6 @@ namespace basegfx return mpImpl->isEqual(*rMat.mpImpl); } - bool B3DHomMatrix::operator!=(const B3DHomMatrix& rMat) const - { - return !(*this == rMat); - } - void B3DHomMatrix::rotate(double fAngleX,double fAngleY,double fAngleZ) { if(fTools::equalZero(fAngleX) && fTools::equalZero(fAngleY) && fTools::equalZero(fAngleZ)) diff --git a/basegfx/source/numeric/ftools.cxx b/basegfx/source/numeric/ftools.cxx index 246d8d548aac..4a01a4c0eca0 100644 --- a/basegfx/source/numeric/ftools.cxx +++ b/basegfx/source/numeric/ftools.cxx @@ -99,7 +99,7 @@ namespace basegfx double normalizeToRange(double v, const double fRange) { - if(fTools::lessOrEqual(fRange, 0.0)) + if(fRange <= 0.0) { // with a zero (or less) range, all normalizes to 0.0 return 0.0; diff --git a/basegfx/source/point/b2dpoint.cxx b/basegfx/source/point/b2dpoint.cxx index 0dc18b513db1..d12c3dd04c4f 100644 --- a/basegfx/source/point/b2dpoint.cxx +++ b/basegfx/source/point/b2dpoint.cxx @@ -23,41 +23,19 @@ namespace basegfx { - B2DPoint& B2DPoint::operator=( const ::basegfx::B2DTuple& rPoint ) - { - mfX = rPoint.getX(); - mfY = rPoint.getY(); - return *this; - } - B2DPoint& B2DPoint::operator*=( const ::basegfx::B2DHomMatrix& rMat ) { double fTempX( - rMat.get(0, 0) * mfX + - rMat.get(0, 1) * mfY + + rMat.get(0, 0) * mnX + + rMat.get(0, 1) * mnY + rMat.get(0, 2)); double fTempY( - rMat.get(1, 0) * mfX + - rMat.get(1, 1) * mfY + + rMat.get(1, 0) * mnX + + rMat.get(1, 1) * mnY + rMat.get(1, 2)); - if(!rMat.isLastLineDefault()) - { - const double fOne(1.0); - const double fTempM( - rMat.get(2, 0) * mfX + - rMat.get(2, 1) * mfY + - rMat.get(2, 2)); - - if(!fTools::equalZero(fTempM) && !fTools::equal(fOne, fTempM)) - { - fTempX /= fTempM; - fTempY /= fTempM; - } - } - - mfX = fTempX; - mfY = fTempY; + mnX = fTempX; + mnY = fTempY; return *this; } diff --git a/basegfx/source/point/b2ipoint.cxx b/basegfx/source/point/b2ipoint.cxx index 7b43ebc860e2..2790fe3a18a8 100644 --- a/basegfx/source/point/b2ipoint.cxx +++ b/basegfx/source/point/b2ipoint.cxx @@ -41,21 +41,6 @@ namespace basegfx rMat.get(1, 1) * mnY + rMat.get(1, 2)); - if(!rMat.isLastLineDefault()) - { - const double fOne(1.0); - const double fTempM( - rMat.get(2, 0) * mnX + - rMat.get(2, 1) * mnY + - rMat.get(2, 2)); - - if(!fTools::equalZero(fTempM) && !fTools::equal(fOne, fTempM)) - { - fTempX /= fTempM; - fTempY /= fTempM; - } - } - mnX = fround(fTempX); mnY = fround(fTempY); diff --git a/basegfx/source/point/b3dpoint.cxx b/basegfx/source/point/b3dpoint.cxx index ff70b501ed7a..7d2d4cf4a22b 100644 --- a/basegfx/source/point/b3dpoint.cxx +++ b/basegfx/source/point/b3dpoint.cxx @@ -26,28 +26,28 @@ namespace basegfx B3DPoint& B3DPoint::operator*=( const ::basegfx::B3DHomMatrix& rMat ) { double fTempX( - rMat.get(0, 0) * mfX + - rMat.get(0, 1) * mfY + - rMat.get(0, 2) * mfZ + + rMat.get(0, 0) * mnX + + rMat.get(0, 1) * mnY + + rMat.get(0, 2) * mnZ + rMat.get(0, 3)); double fTempY( - rMat.get(1, 0) * mfX + - rMat.get(1, 1) * mfY + - rMat.get(1, 2) * mfZ + + rMat.get(1, 0) * mnX + + rMat.get(1, 1) * mnY + + rMat.get(1, 2) * mnZ + rMat.get(1, 3)); double fTempZ( - rMat.get(2, 0) * mfX + - rMat.get(2, 1) * mfY + - rMat.get(2, 2) * mfZ + + rMat.get(2, 0) * mnX + + rMat.get(2, 1) * mnY + + rMat.get(2, 2) * mnZ + rMat.get(2, 3)); if(!rMat.isLastLineDefault()) { const double fOne(1.0); const double fTempM( - rMat.get(3, 0) * mfX + - rMat.get(3, 1) * mfY + - rMat.get(3, 2) * mfZ + + rMat.get(3, 0) * mnX + + rMat.get(3, 1) * mnY + + rMat.get(3, 2) * mnZ + rMat.get(3, 3)); if(!fTools::equalZero(fTempM) && !fTools::equal(fOne, fTempM)) @@ -58,9 +58,9 @@ namespace basegfx } } - mfX = fTempX; - mfY = fTempY; - mfZ = fTempZ; + mnX = fTempX; + mnY = fTempY; + mnZ = fTempZ; return *this; } diff --git a/basegfx/source/polygon/b2dlinegeometry.cxx b/basegfx/source/polygon/b2dlinegeometry.cxx index 6dda8f9e7e1f..a6a88c557ee8 100644 --- a/basegfx/source/polygon/b2dlinegeometry.cxx +++ b/basegfx/source/polygon/b2dlinegeometry.cxx @@ -147,7 +147,7 @@ namespace basegfx const B2DVector aTangentA(rCandidate.getTangent(0.0)); const double fScalarAE(aEdge.scalar(aTangentA)); - if(fTools::lessOrEqual(fScalarAE, 0.0)) + if(fScalarAE <= 0.0) { // angle between TangentA and Edge is bigger or equal 90 degrees return false; @@ -174,7 +174,7 @@ namespace basegfx const B2DVector aTangentB(rCandidate.getTangent(1.0)); const double fScalarBE(aEdge.scalar(aTangentB)); - if(fTools::lessOrEqual(fScalarBE, 0.0)) + if(fScalarBE <= 0.0) { // angle between TangentB and Edge is bigger or equal 90 degrees return false; @@ -335,8 +335,7 @@ namespace basegfx bool bStartRound, bool bEndRound, bool bStartSquare, - bool bEndSquare, - basegfx::triangulator::B2DTriangleVector* pTriangles) + bool bEndSquare) { // create polygon for edge // Unfortunately, while it would be geometrically correct to not add @@ -565,15 +564,6 @@ namespace basegfx } } - if(nullptr != pTriangles) - { - const basegfx::triangulator::B2DTriangleVector aResult( - basegfx::triangulator::triangulate( - aBezierPolygon)); - pTriangles->insert(pTriangles->end(), aResult.begin(), aResult.end()); - aBezierPolygon.clear(); - } - // return return aBezierPolygon; } @@ -672,15 +662,6 @@ namespace basegfx // close and return aEdgePolygon.setClosed(true); - if(nullptr != pTriangles) - { - const basegfx::triangulator::B2DTriangleVector aResult( - basegfx::triangulator::triangulate( - aEdgePolygon)); - pTriangles->insert(pTriangles->end(), aResult.begin(), aResult.end()); - aEdgePolygon.clear(); - } - return aEdgePolygon; } } @@ -693,8 +674,7 @@ namespace basegfx const B2DPoint& rPoint, double fHalfLineWidth, B2DLineJoin eJoin, - double fMiterMinimumAngle, - basegfx::triangulator::B2DTriangleVector* pTriangles) + double fMiterMinimumAngle) { SAL_WARN_IF(fHalfLineWidth <= 0.0,"basegfx","createAreaGeometryForJoin: LineWidth too small (!)"); assert((eJoin != B2DLineJoin::NONE) && "createAreaGeometryForJoin: B2DLineJoin::NONE not allowed (!)"); @@ -721,19 +701,9 @@ namespace basegfx { case B2DLineJoin::Miter : { - if(nullptr != pTriangles) - { - pTriangles->emplace_back( - aEndPoint, - rPoint, - aStartPoint); - } - else - { - aEdgePolygon.append(aEndPoint); - aEdgePolygon.append(rPoint); - aEdgePolygon.append(aStartPoint); - } + aEdgePolygon.append(aEndPoint); + aEdgePolygon.append(rPoint); + aEdgePolygon.append(aStartPoint); // Look for the cut point between start point along rTangentPrev and // end point along rTangentEdge. -rTangentEdge should be used, but since @@ -746,18 +716,7 @@ namespace basegfx if(fCutPos != 0.0) { const B2DPoint aCutPoint(aStartPoint + (rTangentPrev * fCutPos)); - - if(nullptr != pTriangles) - { - pTriangles->emplace_back( - aStartPoint, - aCutPoint, - aEndPoint); - } - else - { - aEdgePolygon.append(aCutPoint); - } + aEdgePolygon.append(aCutPoint); } break; @@ -783,27 +742,14 @@ namespace basegfx if(aBow.count() > 1) { - if(nullptr != pTriangles) - { - for(sal_uInt32 a(0); a < aBow.count() - 1; a++) - { - pTriangles->emplace_back( - 0 == a ? aStartPoint : aBow.getB2DPoint(a), - rPoint, - aBow.count() - 1 == a + 1 ? aEndPoint : aBow.getB2DPoint(a + 1)); - } - } - else - { - // #i101491# - // use the original start/end positions; the ones from bow creation may be numerically - // different due to their different creation. To guarantee good merging quality with edges - // and edge roundings (and to reduce point count) - aEdgePolygon = aBow; - aEdgePolygon.setB2DPoint(0, aStartPoint); - aEdgePolygon.setB2DPoint(aEdgePolygon.count() - 1, aEndPoint); - aEdgePolygon.append(rPoint); - } + // #i101491# + // use the original start/end positions; the ones from bow creation may be numerically + // different due to their different creation. To guarantee good merging quality with edges + // and edge roundings (and to reduce point count) + aEdgePolygon = aBow; + aEdgePolygon.setB2DPoint(0, aStartPoint); + aEdgePolygon.setB2DPoint(aEdgePolygon.count() - 1, aEndPoint); + aEdgePolygon.append(rPoint); break; } @@ -814,19 +760,9 @@ namespace basegfx } default: // B2DLineJoin::Bevel { - if(nullptr != pTriangles) - { - pTriangles->emplace_back( - aEndPoint, - rPoint, - aStartPoint); - } - else - { - aEdgePolygon.append(aEndPoint); - aEdgePolygon.append(rPoint); - aEdgePolygon.append(aStartPoint); - } + aEdgePolygon.append(aEndPoint); + aEdgePolygon.append(rPoint); + aEdgePolygon.append(aStartPoint); break; } @@ -848,8 +784,7 @@ namespace basegfx css::drawing::LineCap eCap, double fMaxAllowedAngle, double fMaxPartOfEdge, - double fMiterMinimumAngle, - basegfx::triangulator::B2DTriangleVector* pTriangles) + double fMiterMinimumAngle) { if(fMaxAllowedAngle > M_PI_2) { @@ -958,8 +893,7 @@ namespace basegfx aEdge.getStartPoint(), fHalfLineWidth, eJoin, - fMiterMinimumAngle, - pTriangles)); + fMiterMinimumAngle)); } else if(aOrientation == B2VectorOrientation::Negative) { @@ -975,8 +909,7 @@ namespace basegfx aEdge.getStartPoint(), fHalfLineWidth, eJoin, - fMiterMinimumAngle, - pTriangles)); + fMiterMinimumAngle)); } } @@ -994,8 +927,7 @@ namespace basegfx bFirst && eCap == css::drawing::LineCap_ROUND, bLast && eCap == css::drawing::LineCap_ROUND, bFirst && eCap == css::drawing::LineCap_SQUARE, - bLast && eCap == css::drawing::LineCap_SQUARE, - pTriangles)); + bLast && eCap == css::drawing::LineCap_SQUARE)); } else { @@ -1006,8 +938,7 @@ namespace basegfx false, false, false, - false, - pTriangles)); + false)); } // prepare next step @@ -1030,17 +961,7 @@ namespace basegfx aCandidate.getB2DPoint(0), fHalfLineWidth)); - if(nullptr != pTriangles) - { - const basegfx::triangulator::B2DTriangleVector aResult( - basegfx::triangulator::triangulate( - aCircle)); - pTriangles->insert(pTriangles->end(), aResult.begin(), aResult.end()); - } - else - { - aRetval.append(aCircle); - } + aRetval.append(aCircle); } return aRetval; diff --git a/basegfx/source/polygon/b2dpolygon.cxx b/basegfx/source/polygon/b2dpolygon.cxx index 3c85a2666d25..cf7309d20dd3 100644 --- a/basegfx/source/polygon/b2dpolygon.cxx +++ b/basegfx/source/polygon/b2dpolygon.cxx @@ -17,7 +17,8 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ -#include <osl/diagnose.h> +#include <sal/config.h> + #include <basegfx/polygon/b2dpolygon.hxx> #include <basegfx/point/b2dpoint.hxx> #include <basegfx/vector/b2dvector.hxx> @@ -28,34 +29,13 @@ #include <memory> #include <vector> -namespace { - -struct CoordinateData2D : public basegfx::B2DPoint +namespace { -public: - CoordinateData2D() {} - - explicit CoordinateData2D(const basegfx::B2DPoint& rData) - : B2DPoint(rData) - {} - - CoordinateData2D& operator=(const basegfx::B2DPoint& rData) - { - B2DPoint::operator=(rData); - return *this; - } - - void transform(const basegfx::B2DHomMatrix& rMatrix) - { - *this *= rMatrix; - } -}; class CoordinateDataArray2D { - typedef std::vector< CoordinateData2D > CoordinateData2DVector; - - CoordinateData2DVector maVector; +private: + std::vector<basegfx::B2DPoint> maVector; public: explicit CoordinateDataArray2D(sal_uInt32 nCount) @@ -80,11 +60,13 @@ public: const basegfx::B2DPoint& getCoordinate(sal_uInt32 nIndex) const { + assert(nIndex < maVector.size()); return maVector[nIndex]; } void setCoordinate(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue) { + assert(nIndex < maVector.size()); maVector[nIndex] = rValue; } @@ -93,59 +75,50 @@ public: maVector.reserve(nCount); } - void append(const CoordinateData2D& rValue) + void append(const basegfx::B2DPoint& rValue) { maVector.push_back(rValue); } - void insert(sal_uInt32 nIndex, const CoordinateData2D& rValue, sal_uInt32 nCount) + void insert(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue, sal_uInt32 nCount) { - if(nCount) - { - // add nCount copies of rValue - CoordinateData2DVector::iterator aIndex(maVector.begin()); - aIndex += nIndex; - maVector.insert(aIndex, nCount, rValue); - } + assert(nCount > 0); + assert(nIndex <= maVector.size()); + // add nCount copies of rValue + maVector.insert(maVector.begin() + nIndex, nCount, rValue); } void insert(sal_uInt32 nIndex, const CoordinateDataArray2D& rSource) { - const sal_uInt32 nCount(rSource.maVector.size()); - - if(nCount) - { - // insert data - CoordinateData2DVector::iterator aIndex(maVector.begin()); - aIndex += nIndex; - CoordinateData2DVector::const_iterator aStart(rSource.maVector.begin()); - CoordinateData2DVector::const_iterator aEnd(rSource.maVector.end()); - maVector.insert(aIndex, aStart, aEnd); - } + assert(rSource.maVector.size() > 0); + assert(nIndex <= maVector.size()); + // insert data + auto aIndex = maVector.begin(); + aIndex += nIndex; + auto aStart = rSource.maVector.cbegin(); + auto aEnd = rSource.maVector.cend(); + maVector.insert(aIndex, aStart, aEnd); } void remove(sal_uInt32 nIndex, sal_uInt32 nCount) { - if(nCount) - { - // remove point data - CoordinateData2DVector::iterator aStart(maVector.begin()); - aStart += nIndex; - const CoordinateData2DVector::iterator aEnd(aStart + nCount); - maVector.erase(aStart, aEnd); - } + assert(nCount > 0); + assert(nIndex + nCount <= maVector.size()); + // remove point data + const auto aStart = maVector.begin() + nIndex; + const auto aEnd = aStart + nCount; + maVector.erase(aStart, aEnd); } void flip(bool bIsClosed) { - if(maVector.size() <= 1) - return; + assert(maVector.size() > 1); // to keep the same point at index 0, just flip all points except the // first one when closed const sal_uInt32 nHalfSize(bIsClosed ? (maVector.size() - 1) >> 1 : maVector.size() >> 1); - CoordinateData2DVector::iterator aStart(bIsClosed ? maVector.begin() + 1 : maVector.begin()); - CoordinateData2DVector::iterator aEnd(maVector.end() - 1); + auto aStart = bIsClosed ? maVector.begin() + 1 : maVector.begin(); + auto aEnd = maVector.end() - 1; for(sal_uInt32 a(0); a < nHalfSize; a++) { @@ -188,9 +161,9 @@ public: void transform(const basegfx::B2DHomMatrix& rMatrix) { - for (auto & elem : maVector) + for (auto& point : maVector) { - elem.transform(rMatrix); + point *= rMatrix; } } }; @@ -252,10 +225,9 @@ public: ControlVectorArray2D(const ControlVectorArray2D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount) : mnUsedVectors(0) { - ControlVectorPair2DVector::const_iterator aStart(rOriginal.maVector.begin()); - aStart += nIndex; - ControlVectorPair2DVector::const_iterator aEnd(aStart); - aEnd += nCount; + assert(nIndex + nCount <= rOriginal.maVector.size()); + auto aStart(rOriginal.maVector.begin() + nIndex); + auto aEnd(aStart + nCount); maVector.reserve(nCount); for(; aStart != aEnd; ++aStart) @@ -282,6 +254,7 @@ public: const basegfx::B2DVector& getPrevVector(sal_uInt32 nIndex) const { + assert(nIndex < maVector.size()); return maVector[nIndex].getPrevVector(); } @@ -314,6 +287,7 @@ public: const basegfx::B2DVector& getNextVector(sal_uInt32 nIndex) const { + assert(nIndex < maVector.size()); return maVector[nIndex].getNextVector(); } @@ -357,13 +331,11 @@ public: void insert(sal_uInt32 nIndex, const ControlVectorPair2D& rValue, sal_uInt32 nCount) { - if(!nCount) - return; + assert(nCount > 0); + assert(nIndex <= maVector.size()); // add nCount copies of rValue - ControlVectorPair2DVector::iterator aIndex(maVector.begin()); - aIndex += nIndex; - maVector.insert(aIndex, nCount, rValue); + maVector.insert(maVector.begin() + nIndex, nCount, rValue); if(!rValue.getPrevVector().equalZero()) mnUsedVectors += nCount; @@ -374,14 +346,11 @@ public: void insert(sal_uInt32 nIndex, const ControlVectorArray2D& rSource) { - const sal_uInt32 nCount(rSource.maVector.size()); - - if(!nCount) - return; + assert(rSource.maVector.size() > 0); + assert(nIndex <= maVector.size()); // insert data - ControlVectorPair2DVector::iterator aIndex(maVector.begin()); - aIndex += nIndex; + ControlVectorPair2DVector::iterator aIndex(maVector.begin() + nIndex); ControlVectorPair2DVector::const_iterator aStart(rSource.maVector.begin()); ControlVectorPair2DVector::const_iterator aEnd(rSource.maVector.end()); maVector.insert(aIndex, aStart, aEnd); @@ -398,8 +367,8 @@ public: void remove(sal_uInt32 nIndex, sal_uInt32 nCount) { - if(!nCount) - return; + assert(nCount > 0); + assert(nIndex + nCount <= maVector.size()); const ControlVectorPair2DVector::iterator aDeleteStart(maVector.begin() + nIndex); const ControlVectorPair2DVector::iterator aDeleteEnd(aDeleteStart + nCount); @@ -420,8 +389,7 @@ public: void flip(bool bIsClosed) { - if(maVector.size() <= 1) - return; + assert(maVector.size() > 1); // to keep the same point at index 0, just flip all points except the // first one when closed @@ -460,7 +428,7 @@ class ImplBufferedData : public basegfx::SystemDependentDataHolder { private: // Possibility to hold the last subdivision - std::optional< basegfx::B2DPolygon > mpDefaultSubdivision; + mutable std::optional< basegfx::B2DPolygon > mpDefaultSubdivision; // Possibility to hold the last B2DRange calculation mutable std::optional< basegfx::B2DRange > moB2DRange; @@ -474,7 +442,7 @@ public: { if(!mpDefaultSubdivision) { - const_cast< ImplBufferedData* >(this)->mpDefaultSubdivision = basegfx::utils::adaptiveSubdivideByAngle(rSource); + mpDefaultSubdivision = basegfx::utils::adaptiveSubdivideByAngle(rSource); } return *mpDefaultSubdivision; @@ -563,7 +531,9 @@ private: std::optional< ControlVectorArray2D > moControlVector; // buffered data for e.g. default subdivision and range - std::unique_ptr< ImplBufferedData > mpBufferedData; + // we do not want to 'modify' the ImplB2DPolygon, + // but add buffered data that is valid for all referencing instances + mutable std::unique_ptr<ImplBufferedData> mpBufferedData; // flag which decides if this polygon is opened or closed bool mbIsClosed; @@ -578,7 +548,7 @@ public: if(!mpBufferedData) { - const_cast< ImplB2DPolygon* >(this)->mpBufferedData.reset(new ImplBufferedData); + mpBufferedData.reset(new ImplBufferedData); } return mpBufferedData->getDefaultAdaptiveSubdivision(rSource); @@ -588,7 +558,7 @@ public: { if(!mpBufferedData) { - const_cast< ImplB2DPolygon* >(this)->mpBufferedData.reset(new ImplBufferedData); + mpBufferedData.reset(new ImplBufferedData); } return mpBufferedData->getB2DRange(rSource); @@ -713,7 +683,7 @@ public: void append(const basegfx::B2DPoint& rPoint) { mpBufferedData.reset(); // TODO: is this needed? - const CoordinateData2D aCoordinate(rPoint); + const auto aCoordinate = rPoint; maPoints.append(aCoordinate); if(moControlVector) @@ -725,20 +695,23 @@ public: void insert(sal_uInt32 nIndex, const basegfx::B2DPoint& rPoint, sal_uInt32 nCount) { - if(nCount) - { - mpBufferedData.reset(); - CoordinateData2D aCoordinate(rPoint); - maPoints.insert(nIndex, aCoordinate, nCount); + assert(nCount > 0); + mpBufferedData.reset(); + auto aCoordinate = rPoint; + maPoints.insert(nIndex, aCoordinate, nCount); - if(moControlVector) - { - ControlVectorPair2D aVectorPair; - moControlVector->insert(nIndex, aVectorPair, nCount); - } + if(moControlVector) + { + ControlVectorPair2D aVectorPair; + moControlVector->insert(nIndex, aVectorPair, nCount); } } + void append(const basegfx::B2DPoint& rPoint, sal_uInt32 nCount) + { + insert(count(), rPoint, nCount); + } + const basegfx::B2DVector& getPrevControlVector(sal_uInt32 nIndex) const { if(moControlVector) @@ -836,24 +809,19 @@ public: setPrevControlVector(nCount, rPrev); } - void insert(sal_uInt32 nIndex, const ImplB2DPolygon& rSource) + void append(const ImplB2DPolygon& rSource) { - const sal_uInt32 nCount(rSource.maPoints.count()); - - if(!nCount) - return; + assert(rSource.maPoints.count() > 0); + const sal_uInt32 nIndex = count(); mpBufferedData.reset(); - if(rSource.moControlVector && rSource.moControlVector->isUsed() && !moControlVector) - { - moControlVector.emplace(maPoints.count()); - } - maPoints.insert(nIndex, rSource.maPoints); if(rSource.moControlVector) { + if (!moControlVector) + moControlVector.emplace(nIndex); moControlVector->insert(nIndex, *rSource.moControlVector); if(!moControlVector->isUsed()) @@ -862,15 +830,13 @@ public: else if(moControlVector) { ControlVectorPair2D aVectorPair; - moControlVector->insert(nIndex, aVectorPair, nCount); + moControlVector->insert(nIndex, aVectorPair, rSource.count()); } } void remove(sal_uInt32 nIndex, sal_uInt32 nCount) { - if(!nCount) - return; - + assert(nCount > 0); mpBufferedData.reset(); maPoints.remove(nIndex, nCount); @@ -885,8 +851,7 @@ public: void flip() { - if(maPoints.count() <= 1) - return; + assert(maPoints.count() > 1); mpBufferedData.reset(); @@ -1087,7 +1052,7 @@ public: } } - void addOrReplaceSystemDependentData(basegfx::SystemDependentData_SharedPtr& rData) + void addOrReplaceSystemDependentData(basegfx::SystemDependentData_SharedPtr& rData) const { if(!mpBufferedData) { @@ -1110,7 +1075,10 @@ public: namespace basegfx { - B2DPolygon::B2DPolygon() = default; + static o3tl::cow_wrapper<ImplB2DPolygon> DEFAULT; + + B2DPolygon::B2DPolygon() + : mpPolygon(DEFAULT) {} B2DPolygon::B2DPolygon(std::initializer_list<basegfx::B2DPoint> aPoints) { @@ -1127,9 +1095,6 @@ namespace basegfx B2DPolygon::B2DPolygon(const B2DPolygon& rPolygon, sal_uInt32 nIndex, sal_uInt32 nCount) : mpPolygon(ImplB2DPolygon(*rPolygon.mpPolygon, nIndex, nCount)) { - // TODO(P2): one extra temporary here (cow_wrapper copies - // given ImplB2DPolygon into its internal impl_t wrapper type) - OSL_ENSURE(nIndex + nCount <= rPolygon.mpPolygon->count(), "B2DPolygon constructor outside range (!)"); } B2DPolygon::~B2DPolygon() = default; @@ -1151,11 +1116,6 @@ namespace basegfx return ((*mpPolygon) == (*rPolygon.mpPolygon)); } - bool B2DPolygon::operator!=(const B2DPolygon& rPolygon) const - { - return !(*this == rPolygon); - } - sal_uInt32 B2DPolygon::count() const { return mpPolygon->count(); @@ -1163,16 +1123,12 @@ namespace basegfx B2DPoint const & B2DPolygon::getB2DPoint(sal_uInt32 nIndex) const { - OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)"); - return mpPolygon->getPoint(nIndex); } void B2DPolygon::setB2DPoint(sal_uInt32 nIndex, const B2DPoint& rValue) { - OSL_ENSURE(nIndex < std::as_const(mpPolygon)->count(), "B2DPolygon access outside range (!)"); - - if(std::as_const(mpPolygon)->getPoint(nIndex) != rValue) + if(getB2DPoint(nIndex) != rValue) { mpPolygon->setPoint(nIndex, rValue); } @@ -1185,8 +1141,6 @@ namespace basegfx void B2DPolygon::insert(sal_uInt32 nIndex, const B2DPoint& rPoint, sal_uInt32 nCount) { - OSL_ENSURE(nIndex <= std::as_const(mpPolygon)->count(), "B2DPolygon Insert outside range (!)"); - if(nCount) { mpPolygon->insert(nIndex, rPoint, nCount); @@ -1197,7 +1151,7 @@ namespace basegfx { if(nCount) { - mpPolygon->insert(std::as_const(mpPolygon)->count(), rPoint, nCount); + mpPolygon->append(rPoint, nCount); } } @@ -1206,40 +1160,45 @@ namespace basegfx mpPolygon->append(rPoint); } - B2DPoint B2DPolygon::getPrevControlPoint(sal_uInt32 nIndex) const + const basegfx::B2DVector& B2DPolygon::getPrevControlVector(sal_uInt32 nIndex) const + { + return mpPolygon->getPrevControlVector(nIndex); + } + + const basegfx::B2DVector& B2DPolygon::getNextControlVector(sal_uInt32 nIndex) const { - OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)"); + return mpPolygon->getNextControlVector(nIndex); + } - if(mpPolygon->areControlPointsUsed()) + B2DPoint B2DPolygon::getPrevControlPoint(sal_uInt32 nIndex) const + { + if(areControlPointsUsed()) { - return mpPolygon->getPoint(nIndex) + mpPolygon->getPrevControlVector(nIndex); + return getB2DPoint(nIndex) + getPrevControlVector(nIndex); } else { - return mpPolygon->getPoint(nIndex); + return getB2DPoint(nIndex); } } B2DPoint B2DPolygon::getNextControlPoint(sal_uInt32 nIndex) const { - OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)"); - - if(mpPolygon->areControlPointsUsed()) + if(areControlPointsUsed()) { - return mpPolygon->getPoint(nIndex) + mpPolygon->getNextControlVector(nIndex); + return getB2DPoint(nIndex) + getNextControlVector(nIndex); } else { - return mpPolygon->getPoint(nIndex); + return getB2DPoint(nIndex); } } void B2DPolygon::setPrevControlPoint(sal_uInt32 nIndex, const B2DPoint& rValue) { - OSL_ENSURE(nIndex < std::as_const(mpPolygon)->count(), "B2DPolygon access outside range (!)"); - const basegfx::B2DVector aNewVector(rValue - std::as_const(mpPolygon)->getPoint(nIndex)); + const basegfx::B2DVector aNewVector(rValue - getB2DPoint(nIndex)); - if(std::as_const(mpPolygon)->getPrevControlVector(nIndex) != aNewVector) + if(getPrevControlVector(nIndex) != aNewVector) { mpPolygon->setPrevControlVector(nIndex, aNewVector); } @@ -1247,10 +1206,9 @@ namespace basegfx void B2DPolygon::setNextControlPoint(sal_uInt32 nIndex, const B2DPoint& rValue) { - OSL_ENSURE(nIndex < std::as_const(mpPolygon)->count(), "B2DPolygon access outside range (!)"); - const basegfx::B2DVector aNewVector(rValue - std::as_const(mpPolygon)->getPoint(nIndex)); + const basegfx::B2DVector aNewVector(rValue - getB2DPoint(nIndex)); - if(std::as_const(mpPolygon)->getNextControlVector(nIndex) != aNewVector) + if(getNextControlVector(nIndex) != aNewVector) { mpPolygon->setNextControlVector(nIndex, aNewVector); } @@ -1258,12 +1216,11 @@ namespace basegfx void B2DPolygon::setControlPoints(sal_uInt32 nIndex, const basegfx::B2DPoint& rPrev, const basegfx::B2DPoint& rNext) { - OSL_ENSURE(nIndex < std::as_const(mpPolygon)->count(), "B2DPolygon access outside range (!)"); - const B2DPoint aPoint(std::as_const(mpPolygon)->getPoint(nIndex)); + const B2DPoint aPoint(getB2DPoint(nIndex)); const basegfx::B2DVector aNewPrev(rPrev - aPoint); const basegfx::B2DVector aNewNext(rNext - aPoint); - if(std::as_const(mpPolygon)->getPrevControlVector(nIndex) != aNewPrev || std::as_const(mpPolygon)->getNextControlVector(nIndex) != aNewNext) + if(getPrevControlVector(nIndex) != aNewPrev || getNextControlVector(nIndex) != aNewNext) { mpPolygon->setControlVectors(nIndex, aNewPrev, aNewNext); } @@ -1271,9 +1228,7 @@ namespace basegfx void B2DPolygon::resetPrevControlPoint(sal_uInt32 nIndex) { - OSL_ENSURE(nIndex < std::as_const(mpPolygon)->count(), "B2DPolygon access outside range (!)"); - - if(std::as_const(mpPolygon)->areControlPointsUsed() && !std::as_const(mpPolygon)->getPrevControlVector(nIndex).equalZero()) + if(areControlPointsUsed() && !getPrevControlVector(nIndex).equalZero()) { mpPolygon->setPrevControlVector(nIndex, B2DVector::getEmptyVector()); } @@ -1281,9 +1236,7 @@ namespace basegfx void B2DPolygon::resetNextControlPoint(sal_uInt32 nIndex) { - OSL_ENSURE(nIndex < std::as_const(mpPolygon)->count(), "B2DPolygon access outside range (!)"); - - if(std::as_const(mpPolygon)->areControlPointsUsed() && !std::as_const(mpPolygon)->getNextControlVector(nIndex).equalZero()) + if(areControlPointsUsed() && !getNextControlVector(nIndex).equalZero()) { mpPolygon->setNextControlVector(nIndex, B2DVector::getEmptyVector()); } @@ -1291,7 +1244,7 @@ namespace basegfx void B2DPolygon::resetControlPoints() { - if(std::as_const(mpPolygon)->areControlPointsUsed()) + if(areControlPointsUsed()) { mpPolygon->resetControlVectors(); } @@ -1302,12 +1255,12 @@ namespace basegfx const B2DPoint& rPrevControlPoint, const B2DPoint& rPoint) { - const B2DVector aNewNextVector(std::as_const(mpPolygon)->count() ? B2DVector(rNextControlPoint - std::as_const(mpPolygon)->getPoint(std::as_const(mpPolygon)->count() - 1)) : B2DVector::getEmptyVector()); + const B2DVector aNewNextVector(count() ? B2DVector(rNextControlPoint - getB2DPoint(count() - 1)) : B2DVector::getEmptyVector()); const B2DVector aNewPrevVector(rPrevControlPoint - rPoint); if(aNewNextVector.equalZero() && aNewPrevVector.equalZero()) { - mpPolygon->insert(std::as_const(mpPolygon)->count(), rPoint, 1); + mpPolygon->append(rPoint); } else { @@ -1317,7 +1270,7 @@ namespace basegfx void B2DPolygon::appendQuadraticBezierSegment(const B2DPoint& rControlPoint, const B2DPoint& rPoint) { - if (std::as_const(mpPolygon)->count() == 0) + if (count() == 0) { mpPolygon->append(rPoint); const double nX((rControlPoint.getX() * 2.0 + rPoint.getX()) / 3.0); @@ -1326,7 +1279,7 @@ namespace basegfx } else { - const B2DPoint aPreviousPoint(std::as_const(mpPolygon)->getPoint(std::as_const(mpPolygon)->count() - 1)); + const B2DPoint aPreviousPoint(getB2DPoint(count() - 1)); const double nX1((rControlPoint.getX() * 2.0 + aPreviousPoint.getX()) / 3.0); const double nY1((rControlPoint.getY() * 2.0 + aPreviousPoint.getY()) / 3.0); @@ -1344,26 +1297,20 @@ namespace basegfx bool B2DPolygon::isPrevControlPointUsed(sal_uInt32 nIndex) const { - OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)"); - - return (mpPolygon->areControlPointsUsed() && !mpPolygon->getPrevControlVector(nIndex).equalZero()); + return (areControlPointsUsed() && !getPrevControlVector(nIndex).equalZero()); } bool B2DPolygon::isNextControlPointUsed(sal_uInt32 nIndex) const { - OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)"); - - return (mpPolygon->areControlPointsUsed() && !mpPolygon->getNextControlVector(nIndex).equalZero()); + return (areControlPointsUsed() && !getNextControlVector(nIndex).equalZero()); } B2VectorContinuity B2DPolygon::getContinuityInPoint(sal_uInt32 nIndex) const { - OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)"); - - if(mpPolygon->areControlPointsUsed()) + if(areControlPointsUsed()) { - const B2DVector& rPrev(mpPolygon->getPrevControlVector(nIndex)); - const B2DVector& rNext(mpPolygon->getNextControlVector(nIndex)); + const B2DVector& rPrev(getPrevControlVector(nIndex)); + const B2DVector& rNext(getNextControlVector(nIndex)); return getContinuity(rPrev, rNext); } @@ -1375,19 +1322,18 @@ namespace basegfx void B2DPolygon::getBezierSegment(sal_uInt32 nIndex, B2DCubicBezier& rTarget) const { - OSL_ENSURE(nIndex < mpPolygon->count(), "B2DPolygon access outside range (!)"); - const bool bNextIndexValidWithoutClose(nIndex + 1 < mpPolygon->count()); + const bool bNextIndexValidWithoutClose(nIndex + 1 < count()); - if(bNextIndexValidWithoutClose || mpPolygon->isClosed()) + if(bNextIndexValidWithoutClose || isClosed()) { const sal_uInt32 nNextIndex(bNextIndexValidWithoutClose ? nIndex + 1 : 0); - rTarget.setStartPoint(mpPolygon->getPoint(nIndex)); - rTarget.setEndPoint(mpPolygon->getPoint(nNextIndex)); + rTarget.setStartPoint(getB2DPoint(nIndex)); + rTarget.setEndPoint(getB2DPoint(nNextIndex)); - if(mpPolygon->areControlPointsUsed()) + if(areControlPointsUsed()) { - rTarget.setControlPointA(rTarget.getStartPoint() + mpPolygon->getNextControlVector(nIndex)); - rTarget.setControlPointB(rTarget.getEndPoint() + mpPolygon->getPrevControlVector(nNextIndex)); + rTarget.setControlPointA(rTarget.getStartPoint() + getNextControlVector(nIndex)); + rTarget.setControlPointB(rTarget.getEndPoint() + getPrevControlVector(nNextIndex)); } else { @@ -1399,7 +1345,7 @@ namespace basegfx else { // no valid edge at all, reset rTarget to current point - const B2DPoint aPoint(mpPolygon->getPoint(nIndex)); + const B2DPoint aPoint(getB2DPoint(nIndex)); rTarget.setStartPoint(aPoint); rTarget.setEndPoint(aPoint); rTarget.setControlPointA(aPoint); @@ -1419,30 +1365,27 @@ namespace basegfx void B2DPolygon::append(const B2DPolygon& rPoly, sal_uInt32 nIndex, sal_uInt32 nCount) { - if(!rPoly.count()) - return; + assert(nIndex + nCount <= rPoly.count()); if(!nCount) { - nCount = rPoly.count(); + nCount = rPoly.count() - nIndex; + if (!nCount) + return; } if(nIndex == 0 && nCount == rPoly.count()) { - mpPolygon->insert(std::as_const(mpPolygon)->count(), *rPoly.mpPolygon); + mpPolygon->append(*rPoly.mpPolygon); } else { - OSL_ENSURE(nIndex + nCount <= rPoly.mpPolygon->count(), "B2DPolygon Append outside range (!)"); - ImplB2DPolygon aTempPoly(*rPoly.mpPolygon, nIndex, nCount); - mpPolygon->insert(std::as_const(mpPolygon)->count(), aTempPoly); + mpPolygon->append(ImplB2DPolygon(*rPoly.mpPolygon, nIndex, nCount)); } } void B2DPolygon::remove(sal_uInt32 nIndex, sal_uInt32 nCount) { - OSL_ENSURE(nIndex + nCount <= std::as_const(mpPolygon)->count(), "B2DPolygon Remove outside range (!)"); - if(nCount) { mpPolygon->remove(nIndex, nCount); @@ -1477,7 +1420,7 @@ namespace basegfx bool B2DPolygon::hasDoublePoints() const { - return (mpPolygon->count() > 1 && mpPolygon->hasDoublePoints()); + return (count() > 1 && mpPolygon->hasDoublePoints()); } void B2DPolygon::removeDoublePoints() @@ -1491,7 +1434,7 @@ namespace basegfx void B2DPolygon::transform(const B2DHomMatrix& rMatrix) { - if(std::as_const(mpPolygon)->count() && !rMatrix.isIdentity()) + if(count() && !rMatrix.isIdentity()) { mpPolygon->transform(rMatrix); } @@ -1499,14 +1442,7 @@ namespace basegfx void B2DPolygon::addOrReplaceSystemDependentDataInternal(SystemDependentData_SharedPtr& rData) const { - // Need to get ImplB2DPolygon* from cow_wrapper *without* - // calling make_unique() here - we do not want to - // 'modify' the ImplB2DPolygon, but add buffered data that - // is valid for all referencing instances - const B2DPolygon* pMe(this); - const ImplB2DPolygon* pMyImpl(pMe->mpPolygon.get()); - - const_cast<ImplB2DPolygon*>(pMyImpl)->addOrReplaceSystemDependentData(rData); + mpPolygon->addOrReplaceSystemDependentData(rData); } SystemDependentData_SharedPtr B2DPolygon::getSystemDependantDataInternal(size_t hash_code) const diff --git a/basegfx/source/polygon/b2dpolygonclipper.cxx b/basegfx/source/polygon/b2dpolygonclipper.cxx index 246d5a10ab84..e2f1f060381e 100644 --- a/basegfx/source/polygon/b2dpolygonclipper.cxx +++ b/basegfx/source/polygon/b2dpolygonclipper.cxx @@ -25,6 +25,7 @@ #include <basegfx/polygon/b2dpolypolygontools.hxx> #include <basegfx/curve/b2dcubicbezier.hxx> #include <basegfx/utils/rectcliptools.hxx> +#include <sal/log.hxx> namespace basegfx::utils { @@ -161,12 +162,11 @@ namespace basegfx::utils B2DPolyPolygon clipPolyPolygonOnParallelAxis(const B2DPolyPolygon& rCandidate, bool bParallelToXAxis, bool bAboveAxis, double fValueOnOtherAxis, bool bStroke) { - const sal_uInt32 nPolygonCount(rCandidate.count()); B2DPolyPolygon aRetval; - for(sal_uInt32 a(0); a < nPolygonCount; a++) + for(const auto& rB2DPolygon : rCandidate ) { - const B2DPolyPolygon aClippedPolyPolygon(clipPolygonOnParallelAxis(rCandidate.getB2DPolygon(a), bParallelToXAxis, bAboveAxis, fValueOnOtherAxis, bStroke)); + const B2DPolyPolygon aClippedPolyPolygon(clipPolygonOnParallelAxis(rB2DPolygon, bParallelToXAxis, bAboveAxis, fValueOnOtherAxis, bStroke)); if(aClippedPolyPolygon.count()) { @@ -283,10 +283,9 @@ namespace basegfx::utils B2DPolyPolygon clipPolyPolygonOnRange(const B2DPolyPolygon& rCandidate, const B2DRange& rRange, bool bInside, bool bStroke) { - const sal_uInt32 nPolygonCount(rCandidate.count()); B2DPolyPolygon aRetval; - if(!nPolygonCount) + if(!rCandidate.count()) { // source is empty return aRetval; @@ -308,9 +307,9 @@ namespace basegfx::utils if(bInside) { - for(sal_uInt32 a(0); a < nPolygonCount; a++) + for( const auto& rClippedPoly : rCandidate) { - const B2DPolyPolygon aClippedPolyPolygon(clipPolygonOnRange(rCandidate.getB2DPolygon(a), rRange, bInside, bStroke)); + const B2DPolyPolygon aClippedPolyPolygon(clipPolygonOnRange(rClippedPoly , rRange, bInside, bStroke)); if(aClippedPolyPolygon.count()) { @@ -330,7 +329,8 @@ namespace basegfx::utils return aRetval; } - B2DPolyPolygon clipPolyPolygonOnPolyPolygon(const B2DPolyPolygon& rCandidate, const B2DPolyPolygon& rClip, bool bInside, bool bStroke) + B2DPolyPolygon clipPolyPolygonOnPolyPolygon(const B2DPolyPolygon& rCandidate, const B2DPolyPolygon& rClip, + bool bInside, bool bStroke, size_t* pPointLimit) { B2DPolyPolygon aRetval; @@ -343,10 +343,10 @@ namespace basegfx::utils // line clipping, create line snippets by first adding all cut points and // then marching along the edges and detecting if they are inside or outside // the clip polygon - for(sal_uInt32 a(0); a < rCandidate.count(); a++) + for(const auto& rPolygon : rCandidate) { // add cuts with clip to polygon, including bezier segments - const B2DPolygon aCandidate(addPointsAtCuts(rCandidate.getB2DPolygon(a), rClip)); + const B2DPolygon aCandidate(addPointsAtCuts(rPolygon, rClip)); const sal_uInt32 nPointCount(aCandidate.count()); const sal_uInt32 nEdgeCount(aCandidate.isClosed() ? nPointCount : nPointCount - 1); B2DCubicBezier aEdge; @@ -471,7 +471,14 @@ namespace basegfx::utils // prepare 2nd source polygon in same way - B2DPolyPolygon aMergePolyPolygonB = solveCrossovers(rCandidate); + B2DPolyPolygon aMergePolyPolygonB = solveCrossovers(rCandidate, pPointLimit); + + if (pPointLimit && !*pPointLimit) + { + SAL_WARN("basegfx", "clipPolyPolygonOnPolyPolygon hit point limit"); + return aRetval; + } + aMergePolyPolygonB = stripNeutralPolygons(aMergePolyPolygonB); aMergePolyPolygonB = correctOrientations(aMergePolyPolygonB); @@ -480,7 +487,7 @@ namespace basegfx::utils // be solved again, they were solved in the preparation. aRetval.append(aMergePolyPolygonA); aRetval.append(aMergePolyPolygonB); - aRetval = solveCrossovers(aRetval); + aRetval = solveCrossovers(aRetval, pPointLimit); // now remove neutral polygons (closed, but no area). In a last // step throw away all polygons which have a depth of less than 1 diff --git a/basegfx/source/polygon/b2dpolygoncutandtouch.cxx b/basegfx/source/polygon/b2dpolygoncutandtouch.cxx index 99a73ca82bc3..c91f0ec48f7d 100644 --- a/basegfx/source/polygon/b2dpolygoncutandtouch.cxx +++ b/basegfx/source/polygon/b2dpolygoncutandtouch.cxx @@ -19,6 +19,7 @@ #include <basegfx/polygon/b2dpolygoncutandtouch.hxx> #include <osl/diagnose.h> +#include <sal/log.hxx> #include <basegfx/numeric/ftools.hxx> #include <basegfx/point/b2dpoint.hxx> #include <basegfx/vector/b2dvector.hxx> @@ -178,14 +179,12 @@ namespace basegfx // (as in adaptiveSubdivideByCount) it is now possible to calculate back the // cut positions in the polygon to relative cut positions on the original bezier // segment. - const sal_uInt32 nTempPointCount(rPointVector.size()); const sal_uInt32 nEdgeCount(rPolygon.count() ? rPolygon.count() - 1 : 0); - if(nTempPointCount && nEdgeCount) + if(!rPointVector.empty() && nEdgeCount) { - for(sal_uInt32 a(0); a < nTempPointCount; a++) + for( const auto& rTempPoint : rPointVector ) { - const temporaryPoint& rTempPoint = rPointVector[a]; const double fCutPosInPolygon(static_cast<double>(rTempPoint.getIndex()) + rTempPoint.getCut()); const double fRelativeCutPos(fCutPosInPolygon / static_cast<double>(nEdgeCount)); rTempPoints.emplace_back(rTempPoint.getPoint(), nInd, fRelativeCutPos); @@ -203,7 +202,7 @@ namespace basegfx // predefines for calls to this methods before method implementation - void findCuts(const B2DPolygon& rCandidate, temporaryPointVector& rTempPoints); + void findCuts(const B2DPolygon& rCandidate, temporaryPointVector& rTempPoints, size_t* pPointLimit = nullptr); void findTouches(const B2DPolygon& rEdgePolygon, const B2DPolygon& rPointPolygon, temporaryPointVector& rTempPoints); void findCuts(const B2DPolygon& rCandidateA, const B2DPolygon& rCandidateB, temporaryPointVector& rTempPointsA, temporaryPointVector& rTempPointsB); @@ -487,7 +486,7 @@ namespace basegfx } } - void findCuts(const B2DPolygon& rCandidate, temporaryPointVector& rTempPoints) + void findCuts(const B2DPolygon& rCandidate, temporaryPointVector& rTempPoints, size_t* pPointLimit) { // find out if there are edges with intersections (self-cuts). If yes, add // entries to rTempPoints accordingly @@ -588,6 +587,9 @@ namespace basegfx findEdgeCutsTwoEdges(aCurrA, aNextA, aCurrB, aNextB, a, b, rTempPoints, rTempPoints); } + if (pPointLimit && rTempPoints.size() > *pPointLimit) + break; + // prepare next step aCurrB = aNextB; } @@ -596,6 +598,14 @@ namespace basegfx aCurrA = aNextA; } } + + if (pPointLimit) + { + if (rTempPoints.size() > *pPointLimit) + *pPointLimit = 0; + else + *pPointLimit -= rTempPoints.size(); + } } } // end of anonymous namespace @@ -841,14 +851,19 @@ namespace basegfx namespace basegfx::utils { - B2DPolygon addPointsAtCutsAndTouches(const B2DPolygon& rCandidate) + B2DPolygon addPointsAtCutsAndTouches(const B2DPolygon& rCandidate, size_t* pPointLimit) { if(rCandidate.count()) { temporaryPointVector aTempPoints; findTouches(rCandidate, rCandidate, aTempPoints); - findCuts(rCandidate, aTempPoints); + findCuts(rCandidate, aTempPoints, pPointLimit); + if (pPointLimit && !*pPointLimit) + { + SAL_WARN("basegfx", "addPointsAtCutsAndTouches hit point limit"); + return rCandidate; + } return mergeTemporaryPointsAndPolygon(rCandidate, aTempPoints); } @@ -858,7 +873,7 @@ namespace basegfx::utils } } - B2DPolyPolygon addPointsAtCutsAndTouches(const B2DPolyPolygon& rCandidate) + B2DPolyPolygon addPointsAtCutsAndTouches(const B2DPolyPolygon& rCandidate, size_t* pPointLimit) { const sal_uInt32 nCount(rCandidate.count()); @@ -869,7 +884,7 @@ namespace basegfx::utils if(nCount == 1) { // remove self intersections - aRetval.append(addPointsAtCutsAndTouches(rCandidate.getB2DPolygon(0))); + aRetval.append(addPointsAtCutsAndTouches(rCandidate.getB2DPolygon(0), pPointLimit)); } else { @@ -880,7 +895,13 @@ namespace basegfx::utils for(a = 0; a < nCount; a++) { // use polygons with solved self intersections - pTempData[a].setPolygon(addPointsAtCutsAndTouches(rCandidate.getB2DPolygon(a))); + pTempData[a].setPolygon(addPointsAtCutsAndTouches(rCandidate.getB2DPolygon(a), pPointLimit)); + } + + if (pPointLimit && !*pPointLimit) + { + SAL_WARN("basegfx", "addPointsAtCutsAndTouches hit point limit"); + return rCandidate; } // now cuts and touches between the polygons diff --git a/basegfx/source/polygon/b2dpolygontools.cxx b/basegfx/source/polygon/b2dpolygontools.cxx index c6eb3cf5b28b..482d35d4df1d 100644 --- a/basegfx/source/polygon/b2dpolygontools.cxx +++ b/basegfx/source/polygon/b2dpolygontools.cxx @@ -18,6 +18,7 @@ */ #include <numeric> #include <algorithm> +#include <stack> #include <basegfx/numeric/ftools.hxx> #include <basegfx/polygon/b2dpolygontools.hxx> @@ -157,7 +158,7 @@ namespace basegfx::utils return rCandidate.getContinuityInPoint(nIndex); } - B2DPolygon adaptiveSubdivideByDistance(const B2DPolygon& rCandidate, double fDistanceBound) + B2DPolygon adaptiveSubdivideByDistance(const B2DPolygon& rCandidate, double fDistanceBound, int nRecurseLimit) { if(rCandidate.areControlPointsUsed()) { @@ -213,7 +214,7 @@ namespace basegfx::utils } // call adaptive subdivide which adds edges to aRetval accordingly - aBezier.adaptiveSubdivideByDistance(aRetval, fBound); + aBezier.adaptiveSubdivideByDistance(aRetval, fBound, nRecurseLimit); } else { @@ -1204,30 +1205,26 @@ namespace basegfx::utils void applyLineDashing( const B2DPolygon& rCandidate, const std::vector<double>& rDotDashArray, - std::function<void(const basegfx::B2DPolygon& rSnippet)> aLineTargetCallback, - std::function<void(const basegfx::B2DPolygon& rSnippet)> aGapTargetCallback, + const std::function<void(const basegfx::B2DPolygon& rSnippet)>& rLineTargetCallback, + const std::function<void(const basegfx::B2DPolygon& rSnippet)>& rGapTargetCallback, double fDotDashLength) { const sal_uInt32 nPointCount(rCandidate.count()); const sal_uInt32 nDotDashCount(rDotDashArray.size()); - if(fTools::lessOrEqual(fDotDashLength, 0.0)) + if(fDotDashLength <= 0.0) { fDotDashLength = std::accumulate(rDotDashArray.begin(), rDotDashArray.end(), 0.0); } - if(fTools::lessOrEqual(fDotDashLength, 0.0) || (!aLineTargetCallback && !aGapTargetCallback) || !nPointCount) + if(fDotDashLength <= 0.0 || (!rLineTargetCallback && !rGapTargetCallback) || !nPointCount) { // parameters make no sense, just add source to targets - if(aLineTargetCallback) - { - aLineTargetCallback(rCandidate); - } + if (rLineTargetCallback) + rLineTargetCallback(rCandidate); - if(aGapTargetCallback) - { - aGapTargetCallback(rCandidate); - } + if (rGapTargetCallback) + rGapTargetCallback(rCandidate); return; } @@ -1255,7 +1252,6 @@ namespace basegfx::utils // to enlarge these as needed const double fFactor(fCandidateLength / fAllowedLength); std::for_each(aDotDashArray.begin(), aDotDashArray.end(), [&fFactor](double &f){ f *= fFactor; }); - fDotDashLength *= fFactor; } // prepare current edge's start @@ -1299,8 +1295,8 @@ namespace basegfx::utils while(fTools::less(fDotDashMovingLength, fEdgeLength)) { // new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength] - const bool bHandleLine(bIsLine && aLineTargetCallback); - const bool bHandleGap(!bIsLine && aGapTargetCallback); + const bool bHandleLine(bIsLine && rLineTargetCallback); + const bool bHandleGap(!bIsLine && rGapTargetCallback); if(bHandleLine || bHandleGap) { @@ -1317,12 +1313,12 @@ namespace basegfx::utils if(bHandleLine) { - implHandleSnippet(aSnippet, aLineTargetCallback, aFirstLine, aLastLine); + implHandleSnippet(aSnippet, rLineTargetCallback, aFirstLine, aLastLine); } if(bHandleGap) { - implHandleSnippet(aSnippet, aGapTargetCallback, aFirstGap, aLastGap); + implHandleSnippet(aSnippet, rGapTargetCallback, aFirstGap, aLastGap); } aSnippet.clear(); @@ -1335,8 +1331,8 @@ namespace basegfx::utils } // append closing snippet [fLastDotDashMovingLength, fEdgeLength] - const bool bHandleLine(bIsLine && aLineTargetCallback); - const bool bHandleGap(!bIsLine && aGapTargetCallback); + const bool bHandleLine(bIsLine && rLineTargetCallback); + const bool bHandleGap(!bIsLine && rGapTargetCallback); if(bHandleLine || bHandleGap) { @@ -1367,8 +1363,8 @@ namespace basegfx::utils while(fTools::less(fDotDashMovingLength, fEdgeLength)) { // new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength] - const bool bHandleLine(bIsLine && aLineTargetCallback); - const bool bHandleGap(!bIsLine && aGapTargetCallback); + const bool bHandleLine(bIsLine && rLineTargetCallback); + const bool bHandleGap(!bIsLine && rGapTargetCallback); if(bHandleLine || bHandleGap) { @@ -1381,12 +1377,12 @@ namespace basegfx::utils if(bHandleLine) { - implHandleSnippet(aSnippet, aLineTargetCallback, aFirstLine, aLastLine); + implHandleSnippet(aSnippet, rLineTargetCallback, aFirstLine, aLastLine); } if(bHandleGap) { - implHandleSnippet(aSnippet, aGapTargetCallback, aFirstGap, aLastGap); + implHandleSnippet(aSnippet, rGapTargetCallback, aFirstGap, aLastGap); } aSnippet.clear(); @@ -1399,8 +1395,8 @@ namespace basegfx::utils } // append snippet [fLastDotDashMovingLength, fEdgeLength] - const bool bHandleLine(bIsLine && aLineTargetCallback); - const bool bHandleGap(!bIsLine && aGapTargetCallback); + const bool bHandleLine(bIsLine && rLineTargetCallback); + const bool bHandleGap(!bIsLine && rGapTargetCallback); if(bHandleLine || bHandleGap) { @@ -1424,28 +1420,28 @@ namespace basegfx::utils // append last intermediate results (if exists) if(aSnippet.count()) { - const bool bHandleLine(bIsLine && aLineTargetCallback); - const bool bHandleGap(!bIsLine && aGapTargetCallback); + const bool bHandleLine(bIsLine && rLineTargetCallback); + const bool bHandleGap(!bIsLine && rGapTargetCallback); if(bHandleLine) { - implHandleSnippet(aSnippet, aLineTargetCallback, aFirstLine, aLastLine); + implHandleSnippet(aSnippet, rLineTargetCallback, aFirstLine, aLastLine); } if(bHandleGap) { - implHandleSnippet(aSnippet, aGapTargetCallback, aFirstGap, aLastGap); + implHandleSnippet(aSnippet, rGapTargetCallback, aFirstGap, aLastGap); } } - if(bIsClosed && aLineTargetCallback) + if(bIsClosed && rLineTargetCallback) { - implHandleFirstLast(aLineTargetCallback, aFirstLine, aLastLine); + implHandleFirstLast(rLineTargetCallback, aFirstLine, aLastLine); } - if(bIsClosed && aGapTargetCallback) + if(bIsClosed && rGapTargetCallback) { - implHandleFirstLast(aGapTargetCallback, aFirstGap, aLastGap); + implHandleFirstLast(rGapTargetCallback, aFirstGap, aLastGap); } } @@ -2823,7 +2819,7 @@ namespace basegfx::utils { OSL_ENSURE(rOld1.count() == rOld2.count(), "B2DPolygon interpolate: Different geometry (!)"); - if(fTools::lessOrEqual(t, 0.0) || rOld1 == rOld2) + if(t <= 0.0 || rOld1 == rOld2) { return rOld1; } @@ -3330,6 +3326,8 @@ namespace basegfx::utils if(0 != nCount) { + aRetval.reserve(nCount); + const css::awt::Point* pPointSequence = rPointSequenceSource.getConstArray(); const css::drawing::PolygonFlags* pFlagSequence = rFlagSequenceSource.getConstArray(); @@ -3573,6 +3571,105 @@ namespace basegfx::utils } } +B2DPolygon createSimplifiedPolygon(const B2DPolygon& rCandidate, const double fTolerance) +{ + const sal_uInt32 nPointCount(rCandidate.count()); + if (nPointCount < 3 || rCandidate.areControlPointsUsed()) + return rCandidate; + + // The solution does not use recursion directly, since this could lead to a stack overflow if + // nPointCount is very large. Instead, an own stack is used. This does not contain points, but + // pairs of low and high index of a range in rCandidate. A parallel boolean vector is used to note + // whether a point of rCandidate belongs to the output polygon or not. + std::vector<bool> bIsKeptVec(nPointCount, false); + bIsKeptVec[0] = true; + bIsKeptVec[nPointCount - 1] = true; + sal_uInt32 nKept = 2; + std::stack<std::pair<sal_uInt32, sal_uInt32>> aUnfinishedRangesStack; + + // The RDP algorithm draws a straight line from the first point to the last point of a range. + // Then, from the inner points of the range, the point that has the largest distance to the line + // is determined. If the distance is greater than the tolerance, this point is kept and the lower + // and upper sub-segments of the range are treated in the same way. If the distance is smaller + // than the tolerance, none of the inner points will be kept. + sal_uInt32 nLowIndex = 0; + sal_uInt32 nHighIndex = nPointCount - 1; + bool bContinue = true; + do + { + bContinue = false; + if (nHighIndex - nLowIndex < 2) // maximal two points, range is finished. + { + // continue with sibling upper range if any + if (!aUnfinishedRangesStack.empty()) + { + std::pair<sal_uInt32, sal_uInt32> aIndexPair = aUnfinishedRangesStack.top(); + aUnfinishedRangesStack.pop(); + nLowIndex = aIndexPair.first; + nHighIndex = aIndexPair.second; + bContinue = true; + } + } + else // the range needs examine the max distance + { + // Get maximal distance of inner points of the range to the straight line from start to + // end point of the range. + // For calculation of the distance we use the Hesse normal form of the straight line. + B2DPoint aLowPoint = rCandidate.getB2DPoint(nLowIndex); + B2DPoint aHighPoint = rCandidate.getB2DPoint(nHighIndex); + B2DVector aNormalVec + = basegfx::getNormalizedPerpendicular(B2DVector(aHighPoint) - B2DVector(aLowPoint)); + double fLineOriginDistance = aNormalVec.scalar(B2DVector(aLowPoint)); + double fMaxDist = 0; + sal_uInt32 nMaxPointIndex = nLowIndex; + for (sal_uInt32 i = nLowIndex + 1; i < nHighIndex; i++) + { + double fDistance + = aNormalVec.scalar(B2DVector(rCandidate.getB2DPoint(i))) - fLineOriginDistance; + if (std::fabs(fDistance) > fMaxDist) + { + fMaxDist = std::fabs(fDistance); + nMaxPointIndex = i; + } + } + + if (fMaxDist >= fTolerance) + { + // We need to divide the current range into two sub ranges. + bIsKeptVec[nMaxPointIndex] = true; + nKept++; + // continue with lower sub range and push upper sub range to stack + aUnfinishedRangesStack.push(std::make_pair(nMaxPointIndex, nHighIndex)); + nHighIndex = nMaxPointIndex; + bContinue = true; + } + else + { + // We do not keep any of the inner points of the current range. + // continue with sibling upper range if any + if (!aUnfinishedRangesStack.empty()) + { + std::pair<sal_uInt32, sal_uInt32> aIndexPair = aUnfinishedRangesStack.top(); + aUnfinishedRangesStack.pop(); + nLowIndex = aIndexPair.first; + nHighIndex = aIndexPair.second; + bContinue = true; + } + } + } + } while (bContinue); + + // Put all points which are marked as "keep" into the result polygon + B2DPolygon aResultPolygon; + aResultPolygon.reserve(nKept); + for (sal_uInt32 i = 0; i < nPointCount; i++) + { + if (bIsKeptVec[i]) + aResultPolygon.append(rCandidate.getB2DPoint(i)); + } + return aResultPolygon; +} + } // end of namespace /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basegfx/source/polygon/b2dpolygontriangulator.cxx b/basegfx/source/polygon/b2dpolygontriangulator.cxx index 5fbd3960e585..b72e3da6039d 100644 --- a/basegfx/source/polygon/b2dpolygontriangulator.cxx +++ b/basegfx/source/polygon/b2dpolygontriangulator.cxx @@ -92,11 +92,6 @@ namespace basegfx return (maStart.equal(rComp.maStart) && maEnd.equal(rComp.maEnd)); } - bool operator!=(const EdgeEntry& rComp) const - { - return !(*this == rComp); - } - const B2DPoint& getStart() const { return maStart; } const B2DPoint& getEnd() const { return maEnd; } @@ -218,18 +213,17 @@ namespace basegfx // by Y,X,atan2 when adding nodes if(rCandidate.count()) { - for(sal_uInt32 a(0); a < rCandidate.count(); a++) + for(const auto& rPolygonCandidate : rCandidate) { - const B2DPolygon& aPolygonCandidate(rCandidate.getB2DPolygon(a)); - const sal_uInt32 nCount(aPolygonCandidate.count()); + const sal_uInt32 nCount {rPolygonCandidate.count()}; if(nCount > 2) { - B2DPoint aPrevPnt(aPolygonCandidate.getB2DPoint(nCount - 1)); + B2DPoint aPrevPnt(rPolygonCandidate.getB2DPoint(nCount - 1)); for(sal_uInt32 b(0); b < nCount; b++) { - B2DPoint aNextPnt(aPolygonCandidate.getB2DPoint(b)); + B2DPoint aNextPnt(rPolygonCandidate.getB2DPoint(b)); if( !aPrevPnt.equal(aNextPnt) ) { diff --git a/basegfx/source/polygon/b2dpolypolygon.cxx b/basegfx/source/polygon/b2dpolypolygon.cxx index 4fd12bde4a10..fe2a7c7f94c8 100644 --- a/basegfx/source/polygon/b2dpolypolygon.cxx +++ b/basegfx/source/polygon/b2dpolypolygon.cxx @@ -19,18 +19,23 @@ #include <sal/config.h> +#include <cassert> #include <utility> #include <basegfx/polygon/b2dpolypolygon.hxx> -#include <osl/diagnose.h> #include <basegfx/polygon/b2dpolygon.hxx> #include <basegfx/matrix/b2dhommatrix.hxx> #include <basegfx/utils/systemdependentdata.hxx> +namespace basegfx +{ + class ImplB2DPolyPolygon { basegfx::B2DPolygonVector maPolygons; - std::unique_ptr< basegfx::SystemDependentDataHolder > mpSystemDependentDataHolder; + // we do not want to 'modify' the ImplB2DPolyPolygon, + // but add buffered data that is valid for all referencing instances + mutable std::unique_ptr<basegfx::SystemDependentDataHolder> mpSystemDependentDataHolder; public: ImplB2DPolyPolygon() @@ -58,7 +63,7 @@ public: return *this; } - void addOrReplaceSystemDependentData(basegfx::SystemDependentData_SharedPtr& rData) + void addOrReplaceSystemDependentData(basegfx::SystemDependentData_SharedPtr& rData) const { if(!mpSystemDependentDataHolder) { @@ -85,46 +90,55 @@ public: const basegfx::B2DPolygon& getB2DPolygon(sal_uInt32 nIndex) const { + assert(nIndex < maPolygons.size()); return maPolygons[nIndex]; } void setB2DPolygon(sal_uInt32 nIndex, const basegfx::B2DPolygon& rPolygon) { + assert(nIndex < maPolygons.size()); maPolygons[nIndex] = rPolygon; } void insert(sal_uInt32 nIndex, const basegfx::B2DPolygon& rPolygon, sal_uInt32 nCount) { - if(nCount) - { - // add nCount copies of rPolygon - basegfx::B2DPolygonVector::iterator aIndex(maPolygons.begin()); - if( nIndex ) - aIndex += nIndex; - maPolygons.insert(aIndex, nCount, rPolygon); - } + assert(nCount > 0); + assert(nIndex <= maPolygons.size()); + // add nCount copies of rPolygon + maPolygons.insert(maPolygons.begin() + nIndex, nCount, rPolygon); + } + + void append(const basegfx::B2DPolygon& rPolygon, sal_uInt32 nCount) + { + insert(maPolygons.size(), rPolygon, nCount); + } + + void reserve(sal_uInt32 nCount) + { + maPolygons.reserve(nCount); } void insert(sal_uInt32 nIndex, const basegfx::B2DPolyPolygon& rPolyPolygon) { + assert(nIndex <= maPolygons.size()); // add nCount polygons from rPolyPolygon - basegfx::B2DPolygonVector::iterator aIndex(maPolygons.begin()); - if( nIndex ) - aIndex += nIndex; - maPolygons.insert(aIndex, rPolyPolygon.begin(), rPolyPolygon.end()); + maPolygons.insert(maPolygons.begin() + nIndex, rPolyPolygon.begin(), rPolyPolygon.end()); + } + + void append(const basegfx::B2DPolyPolygon& rPolyPolygon) + { + insert(maPolygons.size(), rPolyPolygon); } void remove(sal_uInt32 nIndex, sal_uInt32 nCount) { - if(nCount) - { - // remove polygon data - basegfx::B2DPolygonVector::iterator aStart(maPolygons.begin()); - aStart += nIndex; - const basegfx::B2DPolygonVector::iterator aEnd(aStart + nCount); + assert(nCount > 0); + assert(nIndex + nCount <= maPolygons.size()); + // remove polygon data + auto aStart(maPolygons.begin() + nIndex); + auto aEnd(aStart + nCount); - maPolygons.erase(aStart, aEnd); - } + maPolygons.erase(aStart, aEnd); } sal_uInt32 count() const @@ -197,13 +211,7 @@ public: } }; -namespace basegfx -{ - - static o3tl::cow_wrapper<ImplB2DPolyPolygon> DEFAULT; - - B2DPolyPolygon::B2DPolyPolygon() : - mpPolyPolygon(DEFAULT) {} + B2DPolyPolygon::B2DPolyPolygon() = default; B2DPolyPolygon::B2DPolyPolygon(const B2DPolyPolygon&) = default; @@ -222,8 +230,7 @@ namespace basegfx void B2DPolyPolygon::makeUnique() { - mpPolyPolygon.make_unique(); - mpPolyPolygon->makeUnique(); + mpPolyPolygon->makeUnique(); // non-const cow_wrapper::operator-> calls make_unique } bool B2DPolyPolygon::operator==(const B2DPolyPolygon& rPolyPolygon) const @@ -234,11 +241,6 @@ namespace basegfx return ((*mpPolyPolygon) == (*rPolyPolygon.mpPolyPolygon)); } - bool B2DPolyPolygon::operator!=(const B2DPolyPolygon& rPolyPolygon) const - { - return !((*this) == rPolyPolygon); - } - sal_uInt32 B2DPolyPolygon::count() const { return mpPolyPolygon->count(); @@ -246,26 +248,20 @@ namespace basegfx B2DPolygon const & B2DPolyPolygon::getB2DPolygon(sal_uInt32 nIndex) const { - OSL_ENSURE(nIndex < mpPolyPolygon->count(), "B2DPolyPolygon access outside range (!)"); - return mpPolyPolygon->getB2DPolygon(nIndex); } void B2DPolyPolygon::setB2DPolygon(sal_uInt32 nIndex, const B2DPolygon& rPolygon) { - OSL_ENSURE(nIndex < std::as_const(mpPolyPolygon)->count(), "B2DPolyPolygon access outside range (!)"); - if(getB2DPolygon(nIndex) != rPolygon) mpPolyPolygon->setB2DPolygon(nIndex, rPolygon); } bool B2DPolyPolygon::areControlPointsUsed() const { - for(sal_uInt32 a(0); a < mpPolyPolygon->count(); a++) + for(sal_uInt32 a(0); a < count(); a++) { - const B2DPolygon& rPolygon = mpPolyPolygon->getB2DPolygon(a); - - if(rPolygon.areControlPointsUsed()) + if(getB2DPolygon(a).areControlPointsUsed()) { return true; } @@ -276,8 +272,6 @@ namespace basegfx void B2DPolyPolygon::insert(sal_uInt32 nIndex, const B2DPolygon& rPolygon, sal_uInt32 nCount) { - OSL_ENSURE(nIndex <= std::as_const(mpPolyPolygon)->count(), "B2DPolyPolygon Insert outside range (!)"); - if(nCount) mpPolyPolygon->insert(nIndex, rPolygon, nCount); } @@ -285,16 +279,27 @@ namespace basegfx void B2DPolyPolygon::append(const B2DPolygon& rPolygon, sal_uInt32 nCount) { if(nCount) - mpPolyPolygon->insert(std::as_const(mpPolyPolygon)->count(), rPolygon, nCount); + mpPolyPolygon->append(rPolygon, nCount); + } + + void B2DPolyPolygon::reserve(sal_uInt32 nCount) + { + if(nCount) + mpPolyPolygon->reserve(nCount); } B2DPolyPolygon B2DPolyPolygon::getDefaultAdaptiveSubdivision() const { B2DPolyPolygon aRetval; - - for(sal_uInt32 a(0); a < mpPolyPolygon->count(); a++) + if (count()) { - aRetval.append(mpPolyPolygon->getB2DPolygon(a).getDefaultAdaptiveSubdivision()); + ImplB2DPolyPolygon& dest = *aRetval.mpPolyPolygon; + dest.reserve(count()); + + for (sal_uInt32 a(0); a < count(); a++) + { + dest.append(getB2DPolygon(a).getDefaultAdaptiveSubdivision(), 1); + } } return aRetval; @@ -304,9 +309,9 @@ namespace basegfx { B2DRange aRetval; - for(sal_uInt32 a(0); a < mpPolyPolygon->count(); a++) + for(sal_uInt32 a(0); a < count(); a++) { - aRetval.expand(mpPolyPolygon->getB2DPolygon(a).getB2DRange()); + aRetval.expand(getB2DPolygon(a).getB2DRange()); } return aRetval; @@ -314,8 +319,6 @@ namespace basegfx void B2DPolyPolygon::insert(sal_uInt32 nIndex, const B2DPolyPolygon& rPolyPolygon) { - OSL_ENSURE(nIndex <= std::as_const(mpPolyPolygon)->count(), "B2DPolyPolygon Insert outside range (!)"); - if(rPolyPolygon.count()) mpPolyPolygon->insert(nIndex, rPolyPolygon); } @@ -323,13 +326,11 @@ namespace basegfx void B2DPolyPolygon::append(const B2DPolyPolygon& rPolyPolygon) { if(rPolyPolygon.count()) - mpPolyPolygon->insert(std::as_const(mpPolyPolygon)->count(), rPolyPolygon); + mpPolyPolygon->append(rPolyPolygon); } void B2DPolyPolygon::remove(sal_uInt32 nIndex, sal_uInt32 nCount) { - OSL_ENSURE(nIndex + nCount <= std::as_const(mpPolyPolygon)->count(), "B2DPolyPolygon Remove outside range (!)"); - if(nCount) mpPolyPolygon->remove(nIndex, nCount); } @@ -341,19 +342,15 @@ namespace basegfx bool B2DPolyPolygon::isClosed() const { - bool bRetval(true); - // PolyPOlygon is closed when all contained Polygons are closed or // no Polygon exists. - for(sal_uInt32 a(0); bRetval && a < mpPolyPolygon->count(); a++) + for(sal_uInt32 a(0); a < count(); a++) { - if(!mpPolyPolygon->getB2DPolygon(a).isClosed()) - { - bRetval = false; - } + if(!getB2DPolygon(a).isClosed()) + return false; } - return bRetval; + return true; } void B2DPolyPolygon::setClosed(bool bNew) @@ -364,7 +361,7 @@ namespace basegfx void B2DPolyPolygon::flip() { - if(std::as_const(mpPolyPolygon)->count()) + if(count()) { mpPolyPolygon->flip(); } @@ -372,17 +369,13 @@ namespace basegfx bool B2DPolyPolygon::hasDoublePoints() const { - bool bRetval(false); - - for(sal_uInt32 a(0); !bRetval && a < mpPolyPolygon->count(); a++) + for(sal_uInt32 a(0); a < count(); a++) { - if(mpPolyPolygon->getB2DPolygon(a).hasDoublePoints()) - { - bRetval = true; - } + if(getB2DPolygon(a).hasDoublePoints()) + return true; } - return bRetval; + return false; } void B2DPolyPolygon::removeDoublePoints() @@ -393,7 +386,7 @@ namespace basegfx void B2DPolyPolygon::transform(const B2DHomMatrix& rMatrix) { - if(std::as_const(mpPolyPolygon)->count() && !rMatrix.isIdentity()) + if(count() && !rMatrix.isIdentity()) { mpPolyPolygon->transform(rMatrix); } @@ -421,14 +414,7 @@ namespace basegfx void B2DPolyPolygon::addOrReplaceSystemDependentDataInternal(SystemDependentData_SharedPtr& rData) const { - // Need to get ImplB2DPolyPolygon* from cow_wrapper *without* - // calling make_unique() here - we do not want to - // 'modify' the ImplB2DPolyPolygon, but add buffered data that - // is valid for all referencing instances - const B2DPolyPolygon* pMe(this); - const ImplB2DPolyPolygon* pMyImpl(pMe->mpPolyPolygon.get()); - - const_cast<ImplB2DPolyPolygon*>(pMyImpl)->addOrReplaceSystemDependentData(rData); + mpPolyPolygon->addOrReplaceSystemDependentData(rData); } SystemDependentData_SharedPtr B2DPolyPolygon::getSystemDependantDataInternal(size_t hash_code) const diff --git a/basegfx/source/polygon/b2dpolypolygoncutter.cxx b/basegfx/source/polygon/b2dpolypolygoncutter.cxx index ac1e10660607..4ad6eb5b219d 100644 --- a/basegfx/source/polygon/b2dpolypolygoncutter.cxx +++ b/basegfx/source/polygon/b2dpolypolygoncutter.cxx @@ -28,8 +28,10 @@ #include <basegfx/polygon/b2dpolypolygontools.hxx> #include <basegfx/curve/b2dcubicbezier.hxx> #include <sal/log.hxx> +#include <utility> #include <vector> #include <algorithm> +#include <numeric> namespace basegfx { @@ -144,16 +146,16 @@ namespace basegfx if(rVecA.cross(rVecB) > 0.0) { // b is left turn seen from a, test if Test is left of both and so inside (left is seen as inside) - const bool bBoolA(fTools::moreOrEqual(rVecA.cross(rTest), 0.0)); - const bool bBoolB(fTools::lessOrEqual(rVecB.cross(rTest), 0.0)); + const bool bBoolA(rVecA.cross(rTest) >= 0.0); + const bool bBoolB(rVecB.cross(rTest) <= 0.0); return (bBoolA && bBoolB); } else { // b is right turn seen from a, test if Test is right of both and so outside (left is seen as inside) - const bool bBoolA(fTools::lessOrEqual(rVecA.cross(rTest), 0.0)); - const bool bBoolB(fTools::moreOrEqual(rVecB.cross(rTest), 0.0)); + const bool bBoolA(rVecA.cross(rTest) <= 0.0); + const bool bBoolB(rVecB.cross(rTest) >= 0.0); return (!(bBoolA && bBoolB)); } @@ -440,9 +442,9 @@ namespace basegfx { basegfx::B2DPoint* pLast(&maSNV[0].mpPN->maPoint); - for(a = 1; a < nNodeCount; a++) + for(const auto& rSN : maSNV) { - basegfx::B2DPoint* pCurrent(&maSNV[a].mpPN->maPoint); + basegfx::B2DPoint* pCurrent(&rSN.mpPN->maPoint); if(pLast->equal(*pCurrent) && (pLast->getX() != pCurrent->getX() || pLast->getY() != pCurrent->getY())) { @@ -513,8 +515,8 @@ namespace basegfx impSolve(); } - explicit solver(const B2DPolyPolygon& rOriginal) - : maOriginal(rOriginal), + explicit solver(B2DPolyPolygon aOriginal, size_t* pPointLimit = nullptr) + : maOriginal(std::move(aOriginal)), mbIsCurve(false), mbChanged(false) { @@ -523,7 +525,7 @@ namespace basegfx if(!nOriginalCount) return; - B2DPolyPolygon aGeometry(utils::addPointsAtCutsAndTouches(maOriginal)); + B2DPolyPolygon aGeometry(utils::addPointsAtCutsAndTouches(maOriginal, pPointLimit)); aGeometry.removeDoublePoints(); aGeometry = utils::simplifyCurveSegments(aGeometry); mbIsCurve = aGeometry.areControlPointsUsed(); @@ -532,25 +534,13 @@ namespace basegfx if(!nOriginalCount) return; - sal_uInt32 nPointCount(0); - sal_uInt32 a(0); - - // count points - for(a = 0; a < nOriginalCount; a++) - { - const B2DPolygon& aCandidate(aGeometry.getB2DPolygon(a)); - const sal_uInt32 nCandCount(aCandidate.count()); - - // If it's not a bezier curve, at least three points would be needed to have a - // topological relevant (not empty) polygon. Since it's not known here if trivial - // edges (dead ends) will be kept or sorted out, add non-bezier polygons with - // more than one point. - // For bezier curves, the minimum for defining an area is also one. - if(nCandCount) - { - nPointCount += nCandCount; - } - } + // If it's not a bezier curve, at least three points would be needed to have a + // topological relevant (not empty) polygon. Since it's not known here if trivial + // edges (dead ends) will be kept or sorted out, add non-bezier polygons with + // more than one point. + // For bezier curves, the minimum for defining an area is also one. + sal_uInt32 nPointCount = std::accumulate( aGeometry.begin(), aGeometry.end(), sal_uInt32(0), + [](sal_uInt32 a, const basegfx::B2DPolygon& b){return a + b.count();}); if(!nPointCount) return; @@ -563,16 +553,15 @@ namespace basegfx // fill data sal_uInt32 nInsertIndex(0); - for(a = 0; a < nOriginalCount; a++) + for(const auto& rCandidate : aGeometry ) { - const B2DPolygon& aCandidate(aGeometry.getB2DPolygon(a)); - const sal_uInt32 nCandCount(aCandidate.count()); + const sal_uInt32 nCandCount(rCandidate.count()); // use same condition as above, the data vector is // pre-allocated if(nCandCount) { - impAddPolygon(nInsertIndex, aCandidate); + impAddPolygon(nInsertIndex, rCandidate); nInsertIndex += nCandCount; } } @@ -684,11 +673,11 @@ namespace basegfx namespace basegfx::utils { - B2DPolyPolygon solveCrossovers(const B2DPolyPolygon& rCandidate) + B2DPolyPolygon solveCrossovers(const B2DPolyPolygon& rCandidate, size_t* pPointLimit) { if(rCandidate.count() > 0) { - solver aSolver(rCandidate); + solver aSolver(rCandidate, pPointLimit); return aSolver.getB2DPolyPolygon(); } else @@ -707,13 +696,11 @@ namespace basegfx::utils { B2DPolyPolygon aRetval; - for(sal_uInt32 a(0); a < rCandidate.count(); a++) + for(const auto& rPolygon : rCandidate) { - const B2DPolygon& aCandidate(rCandidate.getB2DPolygon(a)); - - if(utils::getOrientation(aCandidate) != B2VectorOrientation::Neutral) + if(utils::getOrientation(rPolygon) != B2VectorOrientation::Neutral) { - aRetval.append(aCandidate); + aRetval.append(rPolygon); } } diff --git a/basegfx/source/polygon/b2dpolypolygontools.cxx b/basegfx/source/polygon/b2dpolypolygontools.cxx index 74cdf23241d3..faf734f6e79e 100644 --- a/basegfx/source/polygon/b2dpolypolygontools.cxx +++ b/basegfx/source/polygon/b2dpolypolygontools.cxx @@ -113,7 +113,7 @@ namespace basegfx::utils return rCandidate; } - B2DPolyPolygon adaptiveSubdivideByDistance(const B2DPolyPolygon& rCandidate, double fDistanceBound) + B2DPolyPolygon adaptiveSubdivideByDistance(const B2DPolyPolygon& rCandidate, double fDistanceBound, int nRecurseLimit) { if(rCandidate.areControlPointsUsed()) { @@ -123,7 +123,7 @@ namespace basegfx::utils { if(rPolygon.areControlPointsUsed()) { - aRetval.append(utils::adaptiveSubdivideByDistance(rPolygon, fDistanceBound)); + aRetval.append(utils::adaptiveSubdivideByDistance(rPolygon, fDistanceBound, nRecurseLimit)); } else { @@ -514,7 +514,7 @@ namespace basegfx::utils } B2DPolygon aCurrSegment; - const size_t sliceSize=SAL_N_ELEMENTS(numbers)/12; + const size_t sliceSize=std::size(numbers)/12; const int* pCurrSegment=numbers + nNumber*sliceSize; for( size_t i=0; i<sliceSize; i++, pCurrSegment++) { @@ -553,6 +553,7 @@ namespace basegfx::utils const css::drawing::PointSequenceSequence& rPointSequenceSequenceSource) { B2DPolyPolygon aRetval; + aRetval.reserve(rPointSequenceSequenceSource.getLength()); const css::drawing::PointSequence* pPointSequence = rPointSequenceSequenceSource.getConstArray(); const css::drawing::PointSequence* pPointSeqEnd = pPointSequence + rPointSequenceSequenceSource.getLength(); diff --git a/basegfx/source/polygon/b2dsvgpolypolygon.cxx b/basegfx/source/polygon/b2dsvgpolypolygon.cxx index 323fff14c024..fe4f646eb3ba 100644 --- a/basegfx/source/polygon/b2dsvgpolypolygon.cxx +++ b/basegfx/source/polygon/b2dsvgpolypolygon.cxx @@ -74,12 +74,12 @@ namespace basegfx::utils bool importFromSvgD( B2DPolyPolygon& o_rPolyPolygon, - const OUString& rSvgDStatement, + std::u16string_view rSvgDStatement, bool bHandleRelativeNextPointCompatible, PointIndexSet* pHelpPointIndexSet) { o_rPolyPolygon.clear(); - const sal_Int32 nLen(rSvgDStatement.getLength()); + const sal_Int32 nLen(rSvgDStatement.size()); sal_Int32 nPos(0); double nLastX( 0.0 ); double nLastY( 0.0 ); @@ -272,7 +272,7 @@ namespace basegfx::utils // get first control point. It's the reflection of the PrevControlPoint // of the last point. If not existent, use current point (see SVG) - B2DPoint aPrevControl(B2DPoint(nLastX, nLastY)); + B2DPoint aPrevControl(nLastX, nLastY); const sal_uInt32 nIndex(aCurrPoly.count() - 1); if(aCurrPoly.areControlPointsUsed() && aCurrPoly.isPrevControlPointUsed(nIndex)) @@ -421,7 +421,7 @@ namespace basegfx::utils // get first control point. It's the reflection of the PrevControlPoint // of the last point. If not existent, use current point (see SVG) - B2DPoint aPrevControl(B2DPoint(nLastX, nLastY)); + B2DPoint aPrevControl(nLastX, nLastY); const sal_uInt32 nIndex(aCurrPoly.count() - 1); const B2DPoint aPrevPoint(aCurrPoly.getB2DPoint(nIndex)); @@ -664,10 +664,10 @@ namespace basegfx::utils } bool importFromSvgPoints( B2DPolygon& o_rPoly, - const OUString& rSvgPointsAttribute ) + std::u16string_view rSvgPointsAttribute ) { o_rPoly.clear(); - const sal_Int32 nLen(rSvgPointsAttribute.getLength()); + const sal_Int32 nLen(rSvgPointsAttribute.size()); sal_Int32 nPos(0); double nX, nY; @@ -704,9 +704,9 @@ namespace basegfx::utils aResult.append(' '); } - aResult.append(aPoint.getX()); - aResult.append(','); - aResult.append(aPoint.getY()); + aResult.append(OUString::number(aPoint.getX()) + + "," + + OUString::number(aPoint.getY())); } return aResult.makeStringAndClear(); diff --git a/basegfx/source/polygon/b2dtrapezoid.cxx b/basegfx/source/polygon/b2dtrapezoid.cxx index b7991dbf55d4..654adc094ef9 100644 --- a/basegfx/source/polygon/b2dtrapezoid.cxx +++ b/basegfx/source/polygon/b2dtrapezoid.cxx @@ -174,6 +174,9 @@ namespace basegfx::trapezoidhelper // method for cut support B2DPoint getCutPointForGivenY(double fGivenY) const { + // avoid div/0 + if (getDeltaY() == 0) + return B2DPoint(getStart().getX(), fGivenY); // Calculate cut point locally (do not use interpolate) since it is numerically // necessary to guarantee the new, equal Y-coordinate const double fFactor((fGivenY - getStart().getY()) / getDeltaY()); @@ -290,7 +293,7 @@ namespace basegfx::trapezoidhelper const double fOldDeltaYStart(rCutPoint.getY() - aEdge.getStart().getY()); - if(fTools::lessOrEqual(fOldDeltaYStart, 0.0)) + if(fOldDeltaYStart <= 0.0) { // do not split: the resulting edge would be horizontal // correct it to new start point @@ -300,7 +303,7 @@ namespace basegfx::trapezoidhelper const double fNewDeltaYStart(aEdge.getEnd().getY() - rCutPoint.getY()); - if(fTools::lessOrEqual(fNewDeltaYStart, 0.0)) + if(fNewDeltaYStart <= 0.0) { // do not split: the resulting edge would be horizontal // correct it to new end point @@ -946,7 +949,7 @@ namespace basegfx::utils const B2DPoint& rPointB, double fLineWidth) { - if(fTools::lessOrEqual(fLineWidth, 0.0)) + if(fLineWidth <= 0.0) { // no line width return; @@ -1118,7 +1121,7 @@ namespace basegfx::utils const B2DPolygon& rPolygon, double fLineWidth) { - if(fTools::lessOrEqual(fLineWidth, 0.0)) + if(fLineWidth <= 0.0) { return; } diff --git a/basegfx/source/polygon/b3dpolygon.cxx b/basegfx/source/polygon/b3dpolygon.cxx index c1ee4b08345a..ebd9e3f4f7ea 100644 --- a/basegfx/source/polygon/b3dpolygon.cxx +++ b/basegfx/source/polygon/b3dpolygon.cxx @@ -1413,11 +1413,6 @@ namespace basegfx return (*mpPolygon == *rPolygon.mpPolygon); } - bool B3DPolygon::operator!=(const B3DPolygon& rPolygon) const - { - return !(*this == rPolygon); - } - sal_uInt32 B3DPolygon::count() const { return mpPolygon->count(); diff --git a/basegfx/source/polygon/b3dpolygontools.cxx b/basegfx/source/polygon/b3dpolygontools.cxx index a1f65bef2f48..968624e0f28b 100644 --- a/basegfx/source/polygon/b3dpolygontools.cxx +++ b/basegfx/source/polygon/b3dpolygontools.cxx @@ -173,25 +173,22 @@ namespace basegfx::utils void applyLineDashing( const B3DPolygon& rCandidate, const std::vector<double>& rDotDashArray, - std::function<void(const basegfx::B3DPolygon& rSnippet)> aLineTargetCallback, + const std::function<void(const basegfx::B3DPolygon& rSnippet)>& rLineTargetCallback, double fDotDashLength) { const sal_uInt32 nPointCount(rCandidate.count()); const sal_uInt32 nDotDashCount(rDotDashArray.size()); - if(fTools::lessOrEqual(fDotDashLength, 0.0)) + if(fDotDashLength <= 0.0) { fDotDashLength = std::accumulate(rDotDashArray.begin(), rDotDashArray.end(), 0.0); } - if(fTools::lessOrEqual(fDotDashLength, 0.0) || !aLineTargetCallback || !nPointCount) + if(fDotDashLength <= 0.0 || !rLineTargetCallback || !nPointCount) { // parameters make no sense, just add source to targets - if(aLineTargetCallback) - { - aLineTargetCallback(rCandidate); - } - + if (rLineTargetCallback) + rLineTargetCallback(rCandidate); return; } @@ -219,7 +216,6 @@ namespace basegfx::utils // to enlarge these as needed const double fFactor(fCandidateLength / fAllowedLength); std::for_each(aDotDashArray.begin(), aDotDashArray.end(), [&fFactor](double &f){ f *= fFactor; }); - fDotDashLength *= fFactor; } // prepare current edge's start @@ -260,7 +256,7 @@ namespace basegfx::utils aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fDotDashMovingLength / fEdgeLength)); - implHandleSnippet(aSnippet, aLineTargetCallback, aFirstLine, aLastLine); + implHandleSnippet(aSnippet, rLineTargetCallback, aFirstLine, aLastLine); aSnippet.clear(); } @@ -295,13 +291,13 @@ namespace basegfx::utils { if(bIsLine) { - implHandleSnippet(aSnippet, aLineTargetCallback, aFirstLine, aLastLine); + implHandleSnippet(aSnippet, rLineTargetCallback, aFirstLine, aLastLine); } } if(bIsClosed) { - implHandleFirstLast(aLineTargetCallback, aFirstLine, aLastLine); + implHandleFirstLast(rLineTargetCallback, aFirstLine, aLastLine); } } diff --git a/basegfx/source/polygon/b3dpolypolygon.cxx b/basegfx/source/polygon/b3dpolypolygon.cxx index 017906eef5b8..5a43cb876be6 100644 --- a/basegfx/source/polygon/b3dpolypolygon.cxx +++ b/basegfx/source/polygon/b3dpolypolygon.cxx @@ -223,11 +223,6 @@ namespace basegfx return ((*mpPolyPolygon) == (*rPolyPolygon.mpPolyPolygon)); } - bool B3DPolyPolygon::operator!=(const B3DPolyPolygon& rPolyPolygon) const - { - return !(*this == rPolyPolygon); - } - sal_uInt32 B3DPolyPolygon::count() const { return mpPolyPolygon->count(); diff --git a/basegfx/source/polygon/b3dpolypolygontools.cxx b/basegfx/source/polygon/b3dpolypolygontools.cxx index 62ddd3ae771f..ffd8bded4d59 100644 --- a/basegfx/source/polygon/b3dpolypolygontools.cxx +++ b/basegfx/source/polygon/b3dpolypolygontools.cxx @@ -37,12 +37,10 @@ namespace basegfx::utils B3DRange getRange(const B3DPolyPolygon& rCandidate) { B3DRange aRetval; - const sal_uInt32 nPolygonCount(rCandidate.count()); - for(sal_uInt32 a(0); a < nPolygonCount; a++) + for(const auto& rPolygon : rCandidate ) { - const B3DPolygon& aCandidate = rCandidate.getB3DPolygon(a); - aRetval.expand(getRange(aCandidate)); + aRetval.expand(getRange(rPolygon)); } return aRetval; @@ -389,9 +387,9 @@ namespace basegfx::utils { B3DPolyPolygon aRetval; - for(sal_uInt32 a(0); a < rCandidate.count(); a++) + for( const auto& rB3DPolygon : rCandidate) { - aRetval.append(applyDefaultNormalsSphere(rCandidate.getB3DPolygon(a), rCenter)); + aRetval.append(applyDefaultNormalsSphere(rB3DPolygon, rCenter)); } return aRetval; @@ -401,9 +399,9 @@ namespace basegfx::utils { B3DPolyPolygon aRetval; - for(sal_uInt32 a(0); a < rCandidate.count(); a++) + for( const auto& rB3DPolygon : rCandidate ) { - aRetval.append(invertNormals(rCandidate.getB3DPolygon(a))); + aRetval.append(invertNormals(rB3DPolygon)); } return aRetval; @@ -413,9 +411,9 @@ namespace basegfx::utils { B3DPolyPolygon aRetval; - for(sal_uInt32 a(0); a < rCandidate.count(); a++) + for( const auto& rB3DPolygon : rCandidate) { - aRetval.append(applyDefaultTextureCoordinatesParallel(rCandidate.getB3DPolygon(a), rRange, bChangeX, bChangeY)); + aRetval.append(applyDefaultTextureCoordinatesParallel(rB3DPolygon, rRange, bChangeX, bChangeY)); } return aRetval; @@ -425,9 +423,9 @@ namespace basegfx::utils { B3DPolyPolygon aRetval; - for(sal_uInt32 a(0); a < rCandidate.count(); a++) + for( const auto& rB3DPolygon : rCandidate ) { - aRetval.append(applyDefaultTextureCoordinatesSphere(rCandidate.getB3DPolygon(a), rCenter, bChangeX, bChangeY)); + aRetval.append(applyDefaultTextureCoordinatesSphere(rB3DPolygon, rCenter, bChangeX, bChangeY)); } return aRetval; @@ -445,10 +443,9 @@ namespace basegfx::utils { sal_Int32 nInsideCount(0); - for(sal_uInt32 a(0); a < nPolygonCount; a++) + for(const auto& rPolygon : rCandidate ) { - const B3DPolygon& aPolygon(rCandidate.getB3DPolygon(a)); - const bool bInside(isInside(aPolygon, rPoint, false/*bWithBorder*/)); + const bool bInside(isInside(rPolygon, rPoint, false/*bWithBorder*/)); if(bInside) { diff --git a/basegfx/source/range/b2dpolyrange.cxx b/basegfx/source/range/b2dpolyrange.cxx index beb506fc8e4d..42ee21ec0d64 100644 --- a/basegfx/source/range/b2dpolyrange.cxx +++ b/basegfx/source/range/b2dpolyrange.cxx @@ -109,11 +109,6 @@ namespace basegfx return ((*mpImpl) == (*rRange.mpImpl)); } - bool B2DPolyRange::operator!=(const B2DPolyRange& rRange) const - { - return !(*this == rRange); - } - sal_uInt32 B2DPolyRange::count() const { return mpImpl->count(); diff --git a/basegfx/source/range/b2drange.cxx b/basegfx/source/range/b2drange.cxx index be025cc64b1d..1f20cce90a48 100644 --- a/basegfx/source/range/b2drange.cxx +++ b/basegfx/source/range/b2drange.cxx @@ -23,12 +23,12 @@ namespace basegfx { - B2DRange::B2DRange( const B2IRange& rRange ) + B2DRange::B2DRange(const B2IRange& rRange) { - if( !rRange.isEmpty() ) + if (!rRange.isEmpty()) { - maRangeX = MyBasicRange(rRange.getMinX()); - maRangeY = MyBasicRange(rRange.getMinY()); + maRangeX = basegfx::BasicRange<ValueType, TraitsType>(rRange.getMinX()); + maRangeY = basegfx::BasicRange<ValueType, TraitsType>(rRange.getMinY()); maRangeX.expand(rRange.getMaxX()); maRangeY.expand(rRange.getMaxY()); @@ -48,9 +48,9 @@ namespace basegfx } } - B2DRange& B2DRange::operator*=( const ::basegfx::B2DHomMatrix& rMat ) + B2DRange& B2DRange::operator*=(const basegfx::B2DHomMatrix& rMatrix) { - transform(rMat); + transform(rMatrix); return *this; } diff --git a/basegfx/source/tools/b2dclipstate.cxx b/basegfx/source/tools/b2dclipstate.cxx index 7b8309e0de1c..3eefdd8c5f12 100644 --- a/basegfx/source/tools/b2dclipstate.cxx +++ b/basegfx/source/tools/b2dclipstate.cxx @@ -26,6 +26,7 @@ #include <basegfx/polygon/b2dpolypolygon.hxx> #include <basegfx/polygon/b2dpolypolygontools.hxx> #include <basegfx/polygon/b2dpolypolygoncutter.hxx> +#include <utility> namespace basegfx::utils @@ -39,8 +40,8 @@ namespace basegfx::utils mePendingOps(UNION) {} - explicit ImplB2DClipState( const B2DPolyPolygon& rPoly ) : - maClipPoly(rPoly), + explicit ImplB2DClipState( B2DPolyPolygon aPoly ) : + maClipPoly(std::move(aPoly)), mePendingOps(UNION) {} @@ -414,11 +415,6 @@ namespace basegfx::utils return ((*mpImpl) == (*rRHS.mpImpl)); } - bool B2DClipState::operator!=(const B2DClipState& rRHS) const - { - return !(*this == rRHS); - } - void B2DClipState::unionRange(const B2DRange& rRange) { mpImpl->unionRange(rRange); diff --git a/basegfx/source/tools/bgradient.cxx b/basegfx/source/tools/bgradient.cxx new file mode 100644 index 000000000000..9f98c54cfc1c --- /dev/null +++ b/basegfx/source/tools/bgradient.cxx @@ -0,0 +1,996 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <basegfx/utils/bgradient.hxx> +#include <basegfx/utils/gradienttools.hxx> +#include <com/sun/star/awt/Gradient2.hpp> +#include <boost/property_tree/json_parser.hpp> +#include <map> + +typedef std::map<OUString, OUString> StringMap; + +namespace +{ +css::awt::GradientStyle lcl_getStyleFromString(std::u16string_view rStyle) +{ + if (rStyle == u"LINEAR") + return css::awt::GradientStyle_LINEAR; + else if (rStyle == u"AXIAL") + return css::awt::GradientStyle_AXIAL; + else if (rStyle == u"RADIAL") + return css::awt::GradientStyle_RADIAL; + else if (rStyle == u"ELLIPTICAL") + return css::awt::GradientStyle_ELLIPTICAL; + else if (rStyle == u"SQUARE") + return css::awt::GradientStyle_SQUARE; + else if (rStyle == u"RECT") + return css::awt::GradientStyle_RECT; + + return css::awt::GradientStyle_LINEAR; +} + +StringMap lcl_jsonToStringMap(std::u16string_view rJSON) +{ + StringMap aArgs; + if (rJSON.size() && rJSON[0] != '\0') + { + std::stringstream aStream(std::string(OUStringToOString(rJSON, RTL_TEXTENCODING_ASCII_US))); + boost::property_tree::ptree aTree; + boost::property_tree::read_json(aStream, aTree); + + for (const auto& rPair : aTree) + { + aArgs[OUString::fromUtf8(rPair.first)] + = OUString::fromUtf8(rPair.second.get_value<std::string>(".")); + } + } + return aArgs; +} + +basegfx::BGradient lcl_buildGradientFromStringMap(StringMap& rMap) +{ + basegfx::BGradient aGradient( + basegfx::BColorStops(ColorToBColorConverter(rMap["startcolor"].toInt32(16)).getBColor(), + ColorToBColorConverter(rMap["endcolor"].toInt32(16)).getBColor())); + + aGradient.SetGradientStyle(lcl_getStyleFromString(rMap["style"])); + aGradient.SetAngle(Degree10(rMap["angle"].toInt32())); + + return aGradient; +} +} + +namespace basegfx +{ +// constructor with two colors to explicitly create a +// BColorStops for a single StartColor @0.0 & EndColor @1.0 +BColorStops::BColorStops(const BColor& rStart, const BColor& rEnd) +{ + emplace_back(0.0, rStart); + emplace_back(1.0, rEnd); +} + +/* Helper to grep the correct ColorStop out of + ColorStops and interpolate as needed for given + relative value in fPosition in the range of [0.0 .. 1.0]. + It also takes care of evtl. given RequestedSteps. + */ +BColor BColorStops::getInterpolatedBColor(double fPosition, sal_uInt32 nRequestedSteps, + BColorStopRange& rLastColorStopRange) const +{ + // no color at all, done + if (empty()) + return BColor(); + + // outside range -> at start + const double fMin(front().getStopOffset()); + if (fPosition < fMin) + return front().getStopColor(); + + // outside range -> at end + const double fMax(back().getStopOffset()); + if (fPosition > fMax) + return back().getStopColor(); + + // special case for the 'classic' case with just two colors: + // we can optimize that and keep the speed/resources low + // by avoiding some calculations and an O(log(N)) array access + if (2 == size()) + { + // if same StopOffset use front color + if (fTools::equal(fMin, fMax)) + return front().getStopColor(); + + const basegfx::BColor aCStart(front().getStopColor()); + const basegfx::BColor aCEnd(back().getStopColor()); + + // if colors are equal just return one + if (aCStart == aCEnd) + return aCStart; + + // calculate Steps + const sal_uInt32 nSteps( + basegfx::utils::calculateNumberOfSteps(nRequestedSteps, aCStart, aCEnd)); + + // we need to extend the interpolation to the local + // range of ColorStops. Despite having two ColorStops + // these are not necessarily at 0.0 and 1.0, so may be + // not the classical Start/EndColor (what is allowed) + fPosition = (fPosition - fMin) / (fMax - fMin); + return basegfx::interpolate(aCStart, aCEnd, + nSteps > 1 ? floor(fPosition * nSteps) / double(nSteps - 1) + : fPosition); + } + + // check if we need to newly populate the needed interpolation data + // or if we can re-use from last time. + // If this scope is not entered, we do not need the binary search. It's + // only a single buffered entry, and only used when more than three + // ColorStops exist, but makes a huge difference compared with accessing + // the sorted ColorStop vector each time. + // NOTE: with this simple change I get very high hit rates, e.g. rotating + // a donut with gradient test '1' hit rate is at 0.99909440357755486 + if (rLastColorStopRange.mfOffsetStart == rLastColorStopRange.mfOffsetEnd + || fPosition < rLastColorStopRange.mfOffsetStart + || fPosition > rLastColorStopRange.mfOffsetEnd) + { + // access needed spot in sorted array using binary search + // NOTE: This *seems* slow(er) when developing compared to just + // looping/accessing, but that's just due to the extensive + // debug test code created by the stl. In a pro version, + // all is good/fast as expected + const auto upperBound(std::upper_bound(begin(), end(), BColorStop(fPosition), + [](const BColorStop& x, const BColorStop& y) { + return x.getStopOffset() < y.getStopOffset(); + })); + + // no upper bound, done + if (end() == upperBound) + return back().getStopColor(); + + // lower bound is one entry back, access that + const auto lowerBound(upperBound - 1); + + // no lower bound, done + if (end() == lowerBound) + return back().getStopColor(); + + // we have lower and upper bound, get colors and offsets + rLastColorStopRange.maColorStart = lowerBound->getStopColor(); + rLastColorStopRange.maColorEnd = upperBound->getStopColor(); + rLastColorStopRange.mfOffsetStart = lowerBound->getStopOffset(); + rLastColorStopRange.mfOffsetEnd = upperBound->getStopOffset(); + } + + // when there are just two color steps this cannot happen, but when using + // a range of colors this *may* be used inside the range to represent + // single-colored regions inside a ColorRange. Use that color & done + if (rLastColorStopRange.maColorStart == rLastColorStopRange.maColorEnd) + return rLastColorStopRange.maColorStart; + + // calculate number of steps and adapted proportional + // range for scaler in [0.0 .. 1.0] + const double fAdaptedScaler( + (fPosition - rLastColorStopRange.mfOffsetStart) + / (rLastColorStopRange.mfOffsetEnd - rLastColorStopRange.mfOffsetStart)); + const sal_uInt32 nSteps(basegfx::utils::calculateNumberOfSteps( + nRequestedSteps, rLastColorStopRange.maColorStart, rLastColorStopRange.maColorEnd)); + + // interpolate & evtl. apply steps + return interpolate(rLastColorStopRange.maColorStart, rLastColorStopRange.maColorEnd, + nSteps > 1 ? floor(fAdaptedScaler * nSteps) / double(nSteps - 1) + : fAdaptedScaler); +} + +/* Tooling method that allows to replace the StartColor in a + vector of ColorStops. A vector in 'ordered state' is expected, + so you may use/have used sortAndCorrect. + This method is for convenience & backwards compatibility, please + think about handling multi-colored gradients directly. + */ +void BColorStops::replaceStartColor(const BColor& rStart) +{ + BColorStops::iterator a1stNonStartColor(begin()); + + // search for highest existing non-StartColor - CAUTION, + // there might be none, one or multiple with StopOffset 0.0 + while (a1stNonStartColor != end() && a1stNonStartColor->getStopOffset() <= 0.0) + a1stNonStartColor++; + + // create new ColorStops by 1st adding new one and then all + // non-StartColor entries + BColorStops aNewColorStops; + + aNewColorStops.reserve(size() + 1); + aNewColorStops.emplace_back(0.0, rStart); + aNewColorStops.insert(aNewColorStops.end(), a1stNonStartColor, end()); + + // assign & done + *this = aNewColorStops; +} + +/* Tooling method that allows to replace the EndColor in a + vector of ColorStops. A vector in 'ordered state' is expected, + so you may use/have used sortAndCorrectColorStops. + This method is for convenience & backwards compatibility, please + think about handling multi-colored gradients directly. + */ +void BColorStops::replaceEndColor(const BColor& rEnd) +{ + // erase all evtl. existing EndColor(s) + while (!empty() && basegfx::fTools::moreOrEqual(back().getStopOffset(), 1.0)) + pop_back(); + + // add at the end of existing ColorStops + emplace_back(1.0, rEnd); +} + +/* Tooling method to linearly blend the Colors contained in + a given ColorStop vector against a given Color using the + given intensity values. + The intensity values fStartIntensity, fEndIntensity are + in the range of [0.0 .. 1.0] and describe how much the + blend is supposed to be done at the start color position + and the end color position respectively, where 0.0 means + to fully use the given BlendColor, 1.0 means to not change + the existing color in the ColorStop. + Every color entry in the given ColorStop is blended + relative to it's StopPosition, interpolating the + given intensities with the range [0.0 .. 1.0] to do so. + */ +void BColorStops::blendToIntensity(double fStartIntensity, double fEndIntensity, + const BColor& rBlendColor) +{ + // no entries, done + if (empty()) + return; + + // correct intensities (maybe assert when input was wrong) + fStartIntensity = std::max(std::min(1.0, fStartIntensity), 0.0); + fEndIntensity = std::max(std::min(1.0, fEndIntensity), 0.0); + + // all 100%, no real blend, done + if (basegfx::fTools::equal(fStartIntensity, 1.0) && basegfx::fTools::equal(fEndIntensity, 1.0)) + return; + + // blend relative to StopOffset position + for (auto& candidate : *this) + { + const double fOffset(candidate.getStopOffset()); + const double fIntensity((fStartIntensity * (1.0 - fOffset)) + (fEndIntensity * fOffset)); + candidate = basegfx::BColorStop( + fOffset, basegfx::interpolate(rBlendColor, candidate.getStopColor(), fIntensity)); + } +} + +/* Tooling method to guarantee sort and correctness for + the given ColorStops vector. + A vector fulfilling these conditions is called to be + in 'ordered state'. + + At return, the following conditions are guaranteed: + - contains no ColorStops with offset < 0.0 (will + be removed) + - contains no ColorStops with offset > 1.0 (will + be removed) + - ColorStops with identical offsets are now allowed + - will be sorted from lowest offset to highest + + Some more notes: + - It can happen that the result is empty + - It is allowed to have consecutive entries with + the same color, this represents single-color + regions inside the gradient + - A entry with 0.0 is not required or forced, so + no 'StartColor' is technically required + - A entry with 1.0 is not required or forced, so + no 'EndColor' is technically required + + All this is done in one run (sort + O(N)) without + creating a copy of the data in any form + */ +void BColorStops::sortAndCorrect() +{ + // no content, we are done + if (empty()) + return; + + if (1 == size()) + { + // no gradient at all, but preserve given color + // evtl. correct offset to be in valid range [0.0 .. 1.0] + // NOTE: This does not move it to 0.0 or 1.0, it *can* still + // be somewhere in-between what is allowed + const BColorStop aEntry(front()); + clear(); + emplace_back(std::max(0.0, std::min(1.0, aEntry.getStopOffset())), aEntry.getStopColor()); + + // done + return; + } + + // start with sorting the input data. Remember that + // this preserves the order of equal entries, where + // equal is defined here by offset (see use operator==) + std::sort(begin(), end()); + + // prepare status values + size_t write(0); + + // use the paradigm of a band machine with two heads, read + // and write with write <= read all the time. Step over the + // data using read and check for valid entry. If valid, decide + // how to keep it + for (size_t read(0); read < size(); read++) + { + // get offset of entry at read position + double fOff((*this)[read].getStopOffset()); + + if (fOff < 0.0 && read + 1 < size()) + { + // value < 0.0 and we have a next entry. check for gradient snippet + // containing 0.0 resp. StartColor + const double fOff2((*this)[read + 1].getStopOffset()); + + if (fOff2 > 0.0) + { + // read is the start of a gradient snippet containing 0.0. Correct + // entry to StartColor, interpolate to correct StartColor + (*this)[read] + = BColorStop(0.0, basegfx::interpolate((*this)[read].getStopColor(), + (*this)[read + 1].getStopColor(), + (0.0 - fOff) / (fOff2 - fOff))); + + // adapt fOff + fOff = 0.0; + } + } + + // step over < 0 values, these are outside and will be removed + if (fOff < 0.0) + { + continue; + } + + if (basegfx::fTools::less(fOff, 1.0) && read + 1 < size()) + { + // value < 1.0 and we have a next entry. check for gradient snippet + // containing 1.0 resp. EndColor + const double fOff2((*this)[read + 1].getStopOffset()); + + if (basegfx::fTools::more(fOff2, 1.0)) + { + // read is the start of a gradient snippet containing 1.0. Correct + // next entry to EndColor, interpolate to correct EndColor + (*this)[read + 1] + = BColorStop(1.0, basegfx::interpolate((*this)[read].getStopColor(), + (*this)[read + 1].getStopColor(), + (1.0 - fOff) / (fOff2 - fOff))); + + // adapt fOff + fOff = 1.0; + } + } + + // step over > 1 values; even break, since all following + // entries will also be bigger due to being sorted, so done + if (basegfx::fTools::more(fOff, 1.0)) + { + break; + } + + // entry is valid value at read position + // copy if write target is empty (write at start) or when + // write target is different to read in color or offset + if (0 == write || !((*this)[read] == (*this)[write - 1])) + { + if (write != read) + { + // copy read to write backwards to close gaps + (*this)[write] = (*this)[read]; + } + + // always forward write position + write++; + } + } + + // correct size when length is reduced. write is always at + // last used position + 1 + if (size() > write) + { + if (0 == write) + { + // no valid entries at all, but not empty. This can only happen + // when all entries are below 0.0 or above 1.0 (else a gradient + // snippet spawning over both would have been detected) + if (back().getStopOffset() < 0.0) + { + // all outside too low, rescue last due to being closest to content + const BColor aBackColor(back().getStopColor()); + clear(); + emplace_back(0.0, aBackColor); + } + else // if (basegfx::fTools::more(front().getStopOffset(), 1.0)) + { + // all outside too high, rescue first due to being closest to content + const BColor aFrontColor(front().getStopColor()); + clear(); + emplace_back(1.0, aFrontColor); + } + } + else + { + resize(write); + } + } +} + +bool BColorStops::checkPenultimate() const +{ + // not needed when no ColorStops + if (empty()) + return false; + + // not needed when last ColorStop at the end or outside + if (basegfx::fTools::moreOrEqual(back().getStopOffset(), 1.0)) + return false; + + // get penultimate entry + const auto penultimate(rbegin() + 1); + + // if there is none, we need no correction and are done + if (penultimate == rend()) + return false; + + // not needed when the last two ColorStops have different offset, then + // a visible range will be processed already + if (!basegfx::fTools::equal(back().getStopOffset(), penultimate->getStopOffset())) + return false; + + // not needed when the last two ColorStops have the same Color, then the + // range before solves the problem + if (back().getStopColor() == penultimate->getStopColor()) + return false; + + return true; +} + +/* Tooling method to check if a ColorStop vector is defined + by a single color. It returns true if this is the case. + If true is returned, rSingleColor contains that single + color for convenience. + NOTE: If no ColorStop is defined, a fallback to BColor-default + (which is black) and true will be returned + */ +bool BColorStops::isSingleColor(BColor& rSingleColor) const +{ + if (empty()) + { + rSingleColor = BColor(); + return true; + } + + if (1 == size()) + { + rSingleColor = front().getStopColor(); + return true; + } + + rSingleColor = front().getStopColor(); + + for (auto const& rCandidate : *this) + { + if (rCandidate.getStopColor() != rSingleColor) + return false; + } + + return true; +} + +/* Tooling method to reverse ColorStops, including offsets. + When also mirroring offsets a valid sort keeps valid. + */ +void BColorStops::reverseColorStops() +{ + // can use std::reverse, but also need to adapt offset(s) + std::reverse(begin(), end()); + for (auto& candidate : *this) + candidate = BColorStop(1.0 - candidate.getStopOffset(), candidate.getStopColor()); +} + +// createSpaceAtStart creates fOffset space at start by +// translating/scaling all entries to the right +void BColorStops::createSpaceAtStart(double fOffset) +{ + // nothing to do if empty + if (empty()) + return; + + // correct offset to [0.0 .. 1.0] + fOffset = std::max(std::min(1.0, fOffset), 0.0); + + // nothing to do if 0.0 == offset + if (basegfx::fTools::equalZero(fOffset)) + return; + + BColorStops aNewStops; + + for (const auto& candidate : *this) + { + aNewStops.emplace_back(fOffset + (candidate.getStopOffset() * (1.0 - fOffset)), + candidate.getStopColor()); + } + + *this = aNewStops; +} + +// removeSpaceAtStart removes fOffset space from start by +// translating/scaling entries more or equal to fOffset +// to the left. Entries less than fOffset will be removed +void BColorStops::removeSpaceAtStart(double fOffset) +{ + // nothing to do if empty + if (empty()) + return; + + // correct factor to [0.0 .. 1.0] + fOffset = std::max(std::min(1.0, fOffset), 0.0); + + // nothing to do if fOffset == 0.0 + if (basegfx::fTools::equalZero(fOffset)) + return; + + BColorStops aNewStops; + const double fMul(basegfx::fTools::equal(fOffset, 1.0) ? 1.0 : 1.0 / (1.0 - fOffset)); + + for (const auto& candidate : *this) + { + if (basegfx::fTools::moreOrEqual(candidate.getStopOffset(), fOffset)) + { + aNewStops.emplace_back((candidate.getStopOffset() - fOffset) * fMul, + candidate.getStopColor()); + } + } + + *this = aNewStops; +} + +// try to detect if an empty/no-color-change area exists +// at the start and return offset to it. Returns 0.0 if not. +double BColorStops::detectPossibleOffsetAtStart() const +{ + BColor aSingleColor; + const bool bSingleColor(isSingleColor(aSingleColor)); + + // no useful offset for single color + if (bSingleColor) + return 0.0; + + // here we know that we have at least two colors, so we have a + // color change. Find colors left and right of that first color change + BColorStops::const_iterator aColorR(begin()); + BColorStops::const_iterator aColorL(aColorR++); + + // aColorR would 1st get equal to end(), so no need to also check aColorL + // for end(). Loop as long as same color. Since we *have* a color change + // not even aColorR can get equal to end() before color inequality, but + // keep for safety + while (aColorR != end() && aColorL->getStopColor() == aColorR->getStopColor()) + { + aColorL++; + aColorR++; + } + + // also for safety: access values at aColorL below *only* + // if not equal to end(), but can theoretically not happen + if (aColorL == end()) + { + return 0.0; + } + + // return offset (maybe 0.0 what is OK) + return aColorL->getStopOffset(); +} + +// checks whether the color stops are symmetrical in color and offset. +bool BColorStops::isSymmetrical() const +{ + if (empty()) + return false; + if (1 == size()) + return basegfx::fTools::equal(0.5, front().getStopOffset()); + + BColorStops::const_iterator aIter(begin()); // for going forward + BColorStops::const_iterator aRIter(end()); // for going backward + --aRIter; + // We have at least two elements, so aIter <= aRIter fails before iterators no longer point to + // an element. + while (aIter <= aRIter && aIter->getStopColor().equal(aRIter->getStopColor()) + && basegfx::fTools::equal(aIter->getStopOffset(), 1.0 - aRIter->getStopOffset())) + { + ++aIter; + --aRIter; + } + return aIter > aRIter; +} + +void BColorStops::doApplyAxial() +{ + // prepare new ColorStops + basegfx::BColorStops aNewColorStops; + + // add gradient stops in reverse order, scaled to [0.0 .. 0.5] + basegfx::BColorStops::const_reverse_iterator aRevCurrColor(rbegin()); + + while (aRevCurrColor != rend()) + { + aNewColorStops.emplace_back((1.0 - aRevCurrColor->getStopOffset()) * 0.5, + aRevCurrColor->getStopColor()); + aRevCurrColor++; + } + + // prepare non-reverse run + basegfx::BColorStops::const_iterator aCurrColor(begin()); + + if (basegfx::fTools::equalZero(aCurrColor->getStopOffset())) + { + // Caution: do not add 1st entry again, that would be double since it was + // already added as last element of the inverse run above. But only if + // the gradient has a start entry for 0.0 aka StartColor, else it is correct. + aCurrColor++; + } + + // add gradient stops in non-reverse order, translated and scaled to [0.5 .. 1.0] + while (aCurrColor != end()) + { + aNewColorStops.emplace_back((aCurrColor->getStopOffset() * 0.5) + 0.5, + aCurrColor->getStopColor()); + aCurrColor++; + } + + // apply color stops + *this = aNewColorStops; +} + +void BColorStops::doApplySteps(sal_uInt16 nStepCount) +{ + // check for zero or invalid steps setting -> done + if (0 == nStepCount || nStepCount > 100) + return; + + // no change needed if single color + BColor aSingleColor; + if (isSingleColor(aSingleColor)) + return; + + // prepare new color stops, get L/R iterators for segments + basegfx::BColorStops aNewColorStops; + basegfx::BColorStops::const_iterator aColorR(begin()); + basegfx::BColorStops::const_iterator aColorL(aColorR++); + + while (aColorR != end()) + { + // get start/end color for segment + const double fStart(aColorL->getStopOffset()); + const double fDelta(aColorR->getStopOffset() - fStart); + + if (aNewColorStops.empty() || aNewColorStops.back() != *aColorL) + { + // add start color, but check if it is already there - which is the + // case from the 2nd segment on due to a new segment starting with + // the same color as the previous one ended + aNewColorStops.push_back(*aColorL); + } + if (!basegfx::fTools::equalZero(fDelta)) + { + // create in-between steps, always two at the same position to + // define a 'hard' color stop. Get start/end color for the segment + const basegfx::BColor& rStartColor(aColorL->getStopColor()); + const basegfx::BColor& rEndColor(aColorR->getStopColor()); + + if (rStartColor != rEndColor) + { + // get relative single-step width + // tdf155852 Use same method for the color as in rendering. + const double fSingleStep(1.0 / static_cast<double>(nStepCount - 1)); + const double fOffsetStep(fDelta / static_cast<double>(nStepCount)); + + for (sal_uInt16 a(1); a < nStepCount; a++) + { + // calculate stop position since being used twice + const double fPosition(fStart + fOffsetStep * static_cast<double>(a)); + + // add end color of previous sub-segment + aNewColorStops.emplace_back( + fPosition, basegfx::interpolate(rStartColor, rEndColor, + static_cast<double>(a - 1) * fSingleStep)); + + // add start color of current sub-segment + aNewColorStops.emplace_back( + fPosition, basegfx::interpolate(rStartColor, rEndColor, + static_cast<double>(a) * fSingleStep)); + } + } + } + + // always add end color of segment + aNewColorStops.push_back(*aColorR); + + // next segment + aColorL++; + aColorR++; + } + + // apply the change to color stops + *this = aNewColorStops; +} + +std::string BGradient::GradientStyleToString(css::awt::GradientStyle eStyle) +{ + switch (eStyle) + { + case css::awt::GradientStyle::GradientStyle_LINEAR: + return "LINEAR"; + + case css::awt::GradientStyle::GradientStyle_AXIAL: + return "AXIAL"; + + case css::awt::GradientStyle::GradientStyle_RADIAL: + return "RADIAL"; + + case css::awt::GradientStyle::GradientStyle_ELLIPTICAL: + return "ELLIPTICAL"; + + case css::awt::GradientStyle::GradientStyle_SQUARE: + return "SQUARE"; + + case css::awt::GradientStyle::GradientStyle_RECT: + return "RECT"; + + case css::awt::GradientStyle::GradientStyle_MAKE_FIXED_SIZE: + return "MAKE_FIXED_SIZE"; + } + + return ""; +} + +BGradient BGradient::fromJSON(std::u16string_view rJSON) +{ + StringMap aMap(lcl_jsonToStringMap(rJSON)); + return lcl_buildGradientFromStringMap(aMap); +} + +BGradient::BGradient() + : eStyle(css::awt::GradientStyle_LINEAR) + , aColorStops() + , nAngle(0) + , nBorder(0) + , nOfsX(50) + , nOfsY(50) + , nIntensStart(100) + , nIntensEnd(100) + , nStepCount(0) +{ + aColorStops.emplace_back(0.0, BColor(0.0, 0.0, 0.0)); // COL_BLACK + aColorStops.emplace_back(1.0, BColor(1.0, 1.0, 1.0)); // COL_WHITE +} + +BGradient::BGradient(const basegfx::BColorStops& rColorStops, css::awt::GradientStyle eTheStyle, + Degree10 nTheAngle, sal_uInt16 nXOfs, sal_uInt16 nYOfs, sal_uInt16 nTheBorder, + sal_uInt16 nStartIntens, sal_uInt16 nEndIntens, sal_uInt16 nSteps) + : eStyle(eTheStyle) + , aColorStops(rColorStops) + , nAngle(nTheAngle) + , nBorder(nTheBorder) + , nOfsX(nXOfs) + , nOfsY(nYOfs) + , nIntensStart(nStartIntens) + , nIntensEnd(nEndIntens) + , nStepCount(nSteps) +{ + SetColorStops(aColorStops); +} + +bool BGradient::operator==(const BGradient& rGradient) const +{ + return (eStyle == rGradient.eStyle && aColorStops == rGradient.aColorStops + && nAngle == rGradient.nAngle && nBorder == rGradient.nBorder + && nOfsX == rGradient.nOfsX && nOfsY == rGradient.nOfsY + && nIntensStart == rGradient.nIntensStart && nIntensEnd == rGradient.nIntensEnd + && nStepCount == rGradient.nStepCount); +} + +void BGradient::SetColorStops(const basegfx::BColorStops& rSteps) +{ + aColorStops = rSteps; + aColorStops.sortAndCorrect(); + if (aColorStops.empty()) + aColorStops.emplace_back(0.0, basegfx::BColor()); +} + +namespace +{ +OUString AsRGBHexString(const ColorToBColorConverter& rVal) +{ + std::stringstream ss; + ss << std::hex << std::setfill('0') << std::setw(6) << sal_uInt32(rVal); + return OUString::createFromAscii(ss.str()); +} +} + +boost::property_tree::ptree BGradient::dumpAsJSON() const +{ + boost::property_tree::ptree aTree; + + aTree.put("style", BGradient::GradientStyleToString(eStyle)); + const ColorToBColorConverter aStart(GetColorStops().front().getStopColor()); + aTree.put("startcolor", AsRGBHexString(aStart.GetRGBColor())); + const ColorToBColorConverter aEnd(GetColorStops().back().getStopColor()); + aTree.put("endcolor", AsRGBHexString(aEnd.GetRGBColor())); + aTree.put("angle", std::to_string(nAngle.get())); + aTree.put("border", std::to_string(nBorder)); + aTree.put("x", std::to_string(nOfsX)); + aTree.put("y", std::to_string(nOfsY)); + aTree.put("intensstart", std::to_string(nIntensStart)); + aTree.put("intensend", std::to_string(nIntensEnd)); + aTree.put("stepcount", std::to_string(nStepCount)); + + return aTree; +} + +void BGradient::tryToRecreateBorder(basegfx::BColorStops* pAssociatedTransparencyStops) +{ + // border already set, do not try to recreate + if (0 != GetBorder()) + return; + + BColor aSingleColor; + const bool bSingleColor(GetColorStops().isSingleColor(aSingleColor)); + + // no need to recreate with single color + if (bSingleColor) + return; + + const bool bIsAxial(css::awt::GradientStyle_AXIAL == GetGradientStyle()); + + if (bIsAxial) + { + // for axial due to reverse used gradient work reversed + aColorStops.reverseColorStops(); + if (nullptr != pAssociatedTransparencyStops) + pAssociatedTransparencyStops->reverseColorStops(); + } + + // check if we have space at start of range [0.0 .. 1.0] that + // may be interpreted as 'border' -> same color. That may involve + // different scenarios, e.g. 1st index > 0.0, but also a non-zero + // number of same color entries, or a combination of both + const double fOffset(aColorStops.detectPossibleOffsetAtStart()); + + if (!basegfx::fTools::equalZero(fOffset)) + { + // we have a border area, indeed re-create + aColorStops.removeSpaceAtStart(fOffset); + if (nullptr != pAssociatedTransparencyStops) + pAssociatedTransparencyStops->removeSpaceAtStart(fOffset); + + // ...and create border value + SetBorder(static_cast<sal_uInt16>(std::lround(fOffset * 100.0))); + } + + if (bIsAxial) + { + // take back reverse + aColorStops.reverseColorStops(); + if (nullptr != pAssociatedTransparencyStops) + pAssociatedTransparencyStops->reverseColorStops(); + } +} + +void BGradient::tryToApplyBorder() +{ + // no border to apply, done + if (0 == GetBorder()) + return; + + // NOTE: no new start node is added. The new ColorStop + // mechanism does not need entries at 0.0 and 1.0. + // In case this is needed, do that in the caller + const double fOffset(GetBorder() * 0.01); + + if (css::awt::GradientStyle_AXIAL == GetGradientStyle()) + { + // for axial due to reverse used gradient work reversed + aColorStops.reverseColorStops(); + aColorStops.createSpaceAtStart(fOffset); + aColorStops.reverseColorStops(); + } + else + { + // apply border to GradientStops + aColorStops.createSpaceAtStart(fOffset); + } + + // set changed values + SetBorder(0); +} + +void BGradient::tryToApplyStartEndIntensity() +{ + // already on default, nothing to apply + if (100 == GetStartIntens() && 100 == GetEndIntens()) + return; + + // apply 'old' blend stuff, blend against black + aColorStops.blendToIntensity(GetStartIntens() * 0.01, GetEndIntens() * 0.01, + BColor()); // COL_BLACK + + // set values to default + SetStartIntens(100); + SetEndIntens(100); +} + +void BGradient::tryToConvertToAxial() +{ + if (css::awt::GradientStyle_LINEAR != GetGradientStyle() || 0 != GetBorder() + || GetColorStops().empty()) + return; + + if (!GetColorStops().isSymmetrical()) + return; + + SetGradientStyle(css::awt::GradientStyle_AXIAL); + + // Stretch the first half of the color stops to double width + // and collect them in a new color stops vector. + BColorStops aAxialColorStops; + aAxialColorStops.reserve(std::ceil(GetColorStops().size() / 2.0)); + BColorStops::const_iterator aIter(GetColorStops().begin()); + while (basegfx::fTools::lessOrEqual(aIter->getStopOffset(), 0.5)) + { + BColorStop aNextStop(std::clamp((*aIter).getStopOffset() * 2.0, 0.0, 1.0), + (*aIter).getStopColor()); + aAxialColorStops.push_back(aNextStop); + ++aIter; + } + // Axial gradients have outmost color as last color stop. + aAxialColorStops.reverseColorStops(); + + SetColorStops(aAxialColorStops); +} + +void BGradient::tryToApplyAxial() +{ + // only need to do something if css::awt::GradientStyle_AXIAL, else done + if (GetGradientStyle() != css::awt::GradientStyle_AXIAL) + return; + + // apply the change to color stops + aColorStops.doApplyAxial(); + + // set style to GradientStyle_LINEAR + SetGradientStyle(css::awt::GradientStyle_LINEAR); +} + +void BGradient::tryToApplySteps() +{ + // check for zero or invalid steps setting -> done + if (0 == GetSteps() || GetSteps() > 100) + return; + + // do the action + aColorStops.doApplySteps(GetSteps()); + + // set value to default + SetSteps(0); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basegfx/source/tools/canvastools.cxx b/basegfx/source/tools/canvastools.cxx index 11ebe70dec28..70f4787710ad 100644 --- a/basegfx/source/tools/canvastools.cxx +++ b/basegfx/source/tools/canvastools.cxx @@ -34,6 +34,8 @@ #include <basegfx/matrix/b2dhommatrix.hxx> #include <basegfx/matrix/b3dhommatrix.hxx> #include <basegfx/point/b2dpoint.hxx> +#include <basegfx/vector/b2dsize.hxx> +#include <basegfx/vector/b2ivector.hxx> #include <basegfx/range/b3drange.hxx> #include <basegfx/range/b2irange.hxx> #include <basegfx/polygon/b2dpolygon.hxx> @@ -373,10 +375,9 @@ namespace basegfx::unotools return output; } - geometry::RealSize2D size2DFromB2DSize( const ::basegfx::B2DVector& rVec ) + geometry::RealSize2D size2DFromB2DSize(const ::basegfx::B2DSize& rSize) { - return geometry::RealSize2D( rVec.getX(), - rVec.getY() ); + return geometry::RealSize2D(rSize.getWidth(), rSize.getHeight()); } geometry::RealPoint2D point2DFromB2DPoint( const ::basegfx::B2DPoint& rPoint ) @@ -427,16 +428,15 @@ namespace basegfx::unotools rRect.Z2); } - geometry::IntegerSize2D integerSize2DFromB2ISize( const ::basegfx::B2IVector& rSize ) + geometry::IntegerSize2D integerSize2DFromB2ISize( const ::basegfx::B2ISize& rSize ) { - return geometry::IntegerSize2D( rSize.getX(), - rSize.getY() ); + return geometry::IntegerSize2D( rSize.getWidth(), + rSize.getHeight() ); } - ::basegfx::B2IVector b2ISizeFromIntegerSize2D( const geometry::IntegerSize2D& rSize ) + basegfx::B2ISize b2ISizeFromIntegerSize2D( const geometry::IntegerSize2D& rSize ) { - return ::basegfx::B2IVector( rSize.Width, - rSize.Height ); + return basegfx::B2ISize(rSize.Width, rSize.Height); } ::basegfx::B2IRange b2IRectangleFromIntegerRectangle2D( const geometry::IntegerRectangle2D& rRectangle ) diff --git a/basegfx/source/tools/gradienttools.cxx b/basegfx/source/tools/gradienttools.cxx index 3605d8fe0be0..8f3e8ae83c06 100644 --- a/basegfx/source/tools/gradienttools.cxx +++ b/basegfx/source/tools/gradienttools.cxx @@ -21,6 +21,11 @@ #include <basegfx/point/b2dpoint.hxx> #include <basegfx/range/b2drange.hxx> #include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <com/sun/star/awt/Gradient2.hpp> +#include <osl/endian.h> + +#include <algorithm> +#include <cmath> namespace basegfx { @@ -28,7 +33,7 @@ namespace basegfx { return getTextureTransform() == rODFGradientInfo.getTextureTransform() && getAspectRatio() == rODFGradientInfo.getAspectRatio() - && getSteps() == rODFGradientInfo.getSteps(); + && getRequestedSteps() == rODFGradientInfo.getRequestedSteps(); } const B2DHomMatrix& ODFGradientInfo::getBackTextureTransform() const @@ -135,7 +140,7 @@ namespace basegfx // add object expansion if(bCircular) { - const double fOriginalDiag(sqrt((fTargetSizeX * fTargetSizeX) + (fTargetSizeY * fTargetSizeY))); + const double fOriginalDiag(std::hypot(fTargetSizeX, fTargetSizeY)); fTargetOffsetX -= (fOriginalDiag - fTargetSizeX) / 2.0; fTargetOffsetY -= (fOriginalDiag - fTargetSizeY) / 2.0; @@ -144,10 +149,10 @@ namespace basegfx } else { - fTargetOffsetX -= (0.4142 / 2.0 ) * fTargetSizeX; - fTargetOffsetY -= (0.4142 / 2.0 ) * fTargetSizeY; - fTargetSizeX = 1.4142 * fTargetSizeX; - fTargetSizeY = 1.4142 * fTargetSizeY; + fTargetOffsetX -= ((M_SQRT2 - 1) / 2.0 ) * fTargetSizeX; + fTargetOffsetY -= ((M_SQRT2 - 1) / 2.0 ) * fTargetSizeY; + fTargetSizeX = M_SQRT2 * fTargetSizeX; + fTargetSizeY = M_SQRT2 * fTargetSizeY; } const double fHalfBorder((1.0 - fBorder) * 0.5); @@ -260,6 +265,233 @@ namespace basegfx namespace utils { + /* Tooling method to extract data from given BGradient + to ColorStops, doing some corrections, partially based + on given SingleColor */ + void prepareColorStops( + const basegfx::BGradient& rGradient, + BColorStops& rColorStops, + BColor& rSingleColor) + { + if (rGradient.GetColorStops().isSingleColor(rSingleColor)) + { + // when single color, preserve value in rSingleColor + // and clear the ColorStops, done. + rColorStops.clear(); + return; + } + + const bool bAdaptStartEndIntensity(100 != rGradient.GetStartIntens() || 100 != rGradient.GetEndIntens()); + const bool bAdaptBorder(0 != rGradient.GetBorder()); + + if (!bAdaptStartEndIntensity && !bAdaptBorder) + { + // copy unchanged ColorStops & done + rColorStops = rGradient.GetColorStops(); + return; + } + + // prepare a copy to work on + basegfx::BGradient aWorkCopy(rGradient); + + if (bAdaptStartEndIntensity) + { + aWorkCopy.tryToApplyStartEndIntensity(); + + // this can again lead to single color (e.g. both zero, so + // all black), so check again for it + if (aWorkCopy.GetColorStops().isSingleColor(rSingleColor)) + { + rColorStops.clear(); + return; + } + } + + if (bAdaptBorder) + { + aWorkCopy.tryToApplyBorder(); + } + + // extract ColorStops, that's all we need here + rColorStops = aWorkCopy.GetColorStops(); + } + + /* Tooling method to synchronize the given ColorStops. + The intention is that a color GradientStops and an + alpha/transparence GradientStops gets synchronized + for export. */ + void synchronizeColorStops( + BColorStops& rColorStops, + BColorStops& rAlphaStops, + const BColor& rSingleColor, + const BColor& rSingleAlpha) + { + if (rColorStops.empty()) + { + if (rAlphaStops.empty()) + { + // no AlphaStops and no ColorStops + // create two-stop fallbacks for both + rColorStops = BColorStops { + BColorStop(0.0, rSingleColor), + BColorStop(1.0, rSingleColor) }; + rAlphaStops = BColorStops { + BColorStop(0.0, rSingleAlpha), + BColorStop(1.0, rSingleAlpha) }; + } + else + { + // AlphaStops but no ColorStops + // create fallback synched with existing AlphaStops + for (const auto& cand : rAlphaStops) + { + rColorStops.emplace_back(cand.getStopOffset(), rSingleColor); + } + } + + // preparations complete, we are done + return; + } + else if (rAlphaStops.empty()) + { + // ColorStops but no AlphaStops + // create fallback AlphaStops synched with existing ColorStops using SingleAlpha + for (const auto& cand : rColorStops) + { + rAlphaStops.emplace_back(cand.getStopOffset(), rSingleAlpha); + } + + // preparations complete, we are done + return; + } + + // here we have ColorStops and AlphaStops not empty. Check if we need to + // synchronize both or if they are already usable/in a synched state so + // that they have same count and same StopOffsets + bool bNeedToSyncronize(rColorStops.size() != rAlphaStops.size()); + + if (!bNeedToSyncronize) + { + // check for same StopOffsets + BColorStops::const_iterator aCurrColor(rColorStops.begin()); + BColorStops::const_iterator aCurrAlpha(rAlphaStops.begin()); + + while (!bNeedToSyncronize && + aCurrColor != rColorStops.end() && + aCurrAlpha != rAlphaStops.end()) + { + if (fTools::equal(aCurrColor->getStopOffset(), aCurrAlpha->getStopOffset())) + { + aCurrColor++; + aCurrAlpha++; + } + else + { + bNeedToSyncronize = true; + } + } + } + + if (bNeedToSyncronize) + { + // synchronize sizes & StopOffsets + BColorStops::const_iterator aCurrColor(rColorStops.begin()); + BColorStops::const_iterator aCurrAlpha(rAlphaStops.begin()); + BColorStops aNewColor; + BColorStops aNewAlpha; + BColorStops::BColorStopRange aColorStopRange; + BColorStops::BColorStopRange aAlphaStopRange; + bool bRealChange(false); + + do { + const bool bColor(aCurrColor != rColorStops.end()); + const bool bAlpha(aCurrAlpha != rAlphaStops.end()); + + if (bColor && bAlpha) + { + const double fColorOff(aCurrColor->getStopOffset()); + const double fAlphaOff(aCurrAlpha->getStopOffset()); + + if (fTools::less(fColorOff, fAlphaOff)) + { + // copy color, create alpha + aNewColor.emplace_back(fColorOff, aCurrColor->getStopColor()); + aNewAlpha.emplace_back(fColorOff, rAlphaStops.getInterpolatedBColor(fColorOff, 0, aAlphaStopRange)); + bRealChange = true; + aCurrColor++; + } + else if (fTools::more(fColorOff, fAlphaOff)) + { + // copy alpha, create color + aNewColor.emplace_back(fAlphaOff, rColorStops.getInterpolatedBColor(fAlphaOff, 0, aColorStopRange)); + aNewAlpha.emplace_back(fAlphaOff, aCurrAlpha->getStopColor()); + bRealChange = true; + aCurrAlpha++; + } + else + { + // equal: copy both, advance + aNewColor.emplace_back(fColorOff, aCurrColor->getStopColor()); + aNewAlpha.emplace_back(fAlphaOff, aCurrAlpha->getStopColor()); + aCurrColor++; + aCurrAlpha++; + } + } + else if (bColor) + { + const double fColorOff(aCurrColor->getStopOffset()); + aNewAlpha.emplace_back(fColorOff, rAlphaStops.getInterpolatedBColor(fColorOff, 0, aAlphaStopRange)); + aNewColor.emplace_back(fColorOff, aCurrColor->getStopColor()); + bRealChange = true; + aCurrColor++; + } + else if (bAlpha) + { + const double fAlphaOff(aCurrAlpha->getStopOffset()); + aNewColor.emplace_back(fAlphaOff, rColorStops.getInterpolatedBColor(fAlphaOff, 0, aColorStopRange)); + aNewAlpha.emplace_back(fAlphaOff, aCurrAlpha->getStopColor()); + bRealChange = true; + aCurrAlpha++; + } + else + { + // no more input, break do..while loop + break; + } + } + while(true); + + if (bRealChange) + { + // copy on 'real' change, that means data was added. + // This should always be the cease and should have been + // detected as such above, see bNeedToSyncronize + rColorStops = aNewColor; + rAlphaStops = aNewAlpha; // MCGR: tdf#155537 used wrong result here + } + } + } + + sal_uInt32 calculateNumberOfSteps( + sal_uInt32 nRequestedSteps, + const BColor& rStart, + const BColor& rEnd) + { + const sal_uInt32 nMaxSteps(sal_uInt32((rStart.getMaximumDistance(rEnd) * 127.5) + 0.5)); + + if (0 == nRequestedSteps) + { + nRequestedSteps = nMaxSteps; + } + + if(nRequestedSteps > nMaxSteps) + { + nRequestedSteps = nMaxSteps; + } + + return std::max(sal_uInt32(1), nRequestedSteps); + } + ODFGradientInfo createLinearODFGradientInfo( const B2DRange& rTargetArea, sal_uInt32 nSteps, @@ -355,7 +587,7 @@ namespace basegfx { const B2DPoint aCoor(rGradInfo.getBackTextureTransform() * rUV); - // Ignore Y, this is not needed at all for Y-Oriented gradients + // Ignore X, this is not needed at all for Y-Oriented gradients // if(aCoor.getX() < 0.0 || aCoor.getX() > 1.0) // { // return 0.0; @@ -371,13 +603,6 @@ namespace basegfx return 1.0; // end value for outside } - const sal_uInt32 nSteps(rGradInfo.getSteps()); - - if(nSteps) - { - return floor(aCoor.getY() * nSteps) / double(nSteps - 1); - } - return aCoor.getY(); } @@ -385,7 +610,7 @@ namespace basegfx { const B2DPoint aCoor(rGradInfo.getBackTextureTransform() * rUV); - // Ignore Y, this is not needed at all for Y-Oriented gradients + // Ignore X, this is not needed at all for Y-Oriented gradients //if(aCoor.getX() < 0.0 || aCoor.getX() > 1.0) //{ // return 0.0; @@ -398,17 +623,22 @@ namespace basegfx return 1.0; // use end value when outside in Y } - const sal_uInt32 nSteps(rGradInfo.getSteps()); + return fAbsY; + } - if(nSteps) + double getRadialGradientAlpha(const B2DPoint& rUV, const ODFGradientInfo& rGradInfo) + { + const B2DPoint aCoor(rGradInfo.getBackTextureTransform() * rUV); + + if(aCoor.getX() < -1.0 || aCoor.getX() > 1.0 || aCoor.getY() < -1.0 || aCoor.getY() > 1.0) { - return floor(fAbsY * nSteps) / double(nSteps - 1); + return 0.0; } - return fAbsY; + return 1.0 - std::hypot(aCoor.getX(), aCoor.getY()); } - double getRadialGradientAlpha(const B2DPoint& rUV, const ODFGradientInfo& rGradInfo) + double getEllipticalGradientAlpha(const B2DPoint& rUV, const ODFGradientInfo& rGradInfo) { const B2DPoint aCoor(rGradInfo.getBackTextureTransform() * rUV); @@ -417,22 +647,26 @@ namespace basegfx return 0.0; } - const double t(1.0 - sqrt(aCoor.getX() * aCoor.getX() + aCoor.getY() * aCoor.getY())); - const sal_uInt32 nSteps(rGradInfo.getSteps()); + double fAspectRatio(rGradInfo.getAspectRatio()); + double t(1.0); - if(nSteps && t < 1.0) + // MCGR: Similar to getRectangularGradientAlpha (please + // see there) we need to use aspect ratio here. Due to + // initEllipticalGradientInfo using M_SQRT2 to make this + // gradient look 'nicer' this correction seems not 100% + // correct, but is close enough for now + if(fAspectRatio > 1.0) + { + t = 1.0 - std::hypot(aCoor.getX() / fAspectRatio, aCoor.getY()); + } + else if(fAspectRatio > 0.0) { - return floor(t * nSteps) / double(nSteps - 1); + t = 1.0 - std::hypot(aCoor.getX(), aCoor.getY() * fAspectRatio); } return t; } - double getEllipticalGradientAlpha(const B2DPoint& rUV, const ODFGradientInfo& rGradInfo) - { - return getRadialGradientAlpha(rUV, rGradInfo); // only matrix setup differs - } - double getSquareGradientAlpha(const B2DPoint& rUV, const ODFGradientInfo& rGradInfo) { const B2DPoint aCoor(rGradInfo.getBackTextureTransform() * rUV); @@ -450,20 +684,71 @@ namespace basegfx return 0.0; } - const double t(1.0 - std::max(fAbsX, fAbsY)); - const sal_uInt32 nSteps(rGradInfo.getSteps()); + return 1.0 - std::max(fAbsX, fAbsY); + } + + double getRectangularGradientAlpha(const B2DPoint& rUV, const ODFGradientInfo& rGradInfo) + { + const B2DPoint aCoor(rGradInfo.getBackTextureTransform() * rUV); + double fAbsX(fabs(aCoor.getX())); - if(nSteps && t < 1.0) + if(fAbsX >= 1.0) { - return floor(t * nSteps) / double(nSteps - 1); + return 0.0; } - return t; - } + double fAbsY(fabs(aCoor.getY())); - double getRectangularGradientAlpha(const B2DPoint& rUV, const ODFGradientInfo& rGradInfo) - { - return getSquareGradientAlpha(rUV, rGradInfo); // only matrix setup differs + if(fAbsY >= 1.0) + { + return 0.0; + } + + // MCGR: Visualizations using the texturing method for + // displaying gradients (getBackTextureTransform is + // involved) show wrong results for GradientElliptical + // and GradientRect, this can be best seen when using + // less steps, e.g. just four. This thus has influence + // on cppcanvas (slideshow) and 3D textures, so needs + // to be corrected. + // Missing is to use the aspect ratio of the object + // in this [-1, -1, 1, 1] unified coordinate space + // after getBackTextureTransform is applied. Optically + // in the larger direction of the texturing the color + // step distances are too big *because* we are in that + // unit range now. + // To correct that, a kind of 'limo stretching' needs to + // be applied, adding space around the center + // proportional to the aspect ratio, so the intuitive + // idea would be to do + // + // fAbsX' = ((fAspectRatio - 1) + fAbsX) / fAspectRatio + // + // which scales from the center. This does not work, and + // after some thoughts it's clear why: It's not the + // position that needs to be moved (this cannot be + // changed), but the position *before* that scale has + // to be determined to get the correct, shifted color + // for the already 'new' position. Thus, turn around + // the expression as + // + // fAbsX' * fAspectRatio = fAspectRatio - 1 + fAbsX + // fAbsX' * fAspectRatio - fAspectRatio + 1 = fAbsX + // fAbsX = (fAbsX' - 1) * fAspectRatio + 1 + // + // This works and can even be simply adapted for + // fAspectRatio < 1.0 aka vertical is bigger. + double fAspectRatio(rGradInfo.getAspectRatio()); + if(fAspectRatio > 1.0) + { + fAbsX = ((fAbsX - 1) * fAspectRatio) + 1; + } + else if(fAspectRatio > 0.0) + { + fAbsY = ((fAbsY - 1) / fAspectRatio) + 1; + } + + return 1.0 - std::max(fAbsX, fAbsY); } } // namespace utils } // namespace basegfx diff --git a/basegfx/source/tools/stringconversiontools.cxx b/basegfx/source/tools/stringconversiontools.cxx index d9f7df14cf50..79b6d604662e 100644 --- a/basegfx/source/tools/stringconversiontools.cxx +++ b/basegfx/source/tools/stringconversiontools.cxx @@ -46,70 +46,66 @@ namespace basegfx::internal static bool getDoubleChar(double& o_fRetval, sal_Int32& io_rPos, - const OUString& rStr) + std::u16string_view rStr) { - sal_Unicode aChar = io_rPos < rStr.getLength() ? rStr[io_rPos] : 0; - OUStringBuffer sNumberString; + const sal_Int64 nStrSize = rStr.size(); + sal_Unicode aChar = io_rPos < nStrSize ? rStr[io_rPos] : 0; + const sal_Int32 nStartPos = io_rPos; // sign if(aChar == '+' || aChar == '-') { - sNumberString.append(rStr[io_rPos]); aChar = rStr[++io_rPos]; } // numbers before point while('0' <= aChar && '9' >= aChar) { - sNumberString.append(rStr[io_rPos]); io_rPos++; - aChar = io_rPos < rStr.getLength() ? rStr[io_rPos] : 0; + aChar = io_rPos < nStrSize ? rStr[io_rPos] : 0; } // point if(aChar == '.') { - sNumberString.append(rStr[io_rPos]); io_rPos++; - aChar = io_rPos < rStr.getLength() ? rStr[io_rPos] : 0; + aChar = io_rPos < nStrSize ? rStr[io_rPos] : 0; } // numbers after point while ('0' <= aChar && '9' >= aChar) { - sNumberString.append(rStr[io_rPos]); io_rPos++; - aChar = io_rPos < rStr.getLength() ? rStr[io_rPos] : 0; + aChar = io_rPos < nStrSize ? rStr[io_rPos] : 0; } // 'e' if(aChar == 'e' || aChar == 'E') { - sNumberString.append(rStr[io_rPos]); io_rPos++; - aChar = io_rPos < rStr.getLength() ? rStr[io_rPos] : 0; + aChar = io_rPos < nStrSize ? rStr[io_rPos] : 0; // sign for 'e' if(aChar == '+' || aChar == '-') { - sNumberString.append(rStr[io_rPos]); io_rPos++; - aChar = io_rPos < rStr.getLength() ? rStr[io_rPos] : 0; + aChar = io_rPos < nStrSize ? rStr[io_rPos] : 0; } // number for 'e' while('0' <= aChar && '9' >= aChar) { - sNumberString.append(rStr[io_rPos]); io_rPos++; - aChar = io_rPos < rStr.getLength() ? rStr[io_rPos] : 0; + aChar = io_rPos < nStrSize ? rStr[io_rPos] : 0; } } - if(sNumberString.getLength()) + const sal_Int32 nLen = io_rPos - nStartPos; + if(nLen) { + rStr = rStr.substr(nStartPos, nLen); rtl_math_ConversionStatus eStatus; - o_fRetval = ::rtl::math::stringToDouble( sNumberString.makeStringAndClear(), + o_fRetval = ::rtl::math::stringToDouble( rStr, '.', ',', &eStatus ); @@ -121,7 +117,7 @@ namespace basegfx::internal bool importDoubleAndSpaces(double& o_fRetval, sal_Int32& io_rPos, - const OUString& rStr, + std::u16string_view rStr, const sal_Int32 nLen ) { if( !getDoubleChar(o_fRetval, io_rPos, rStr) ) diff --git a/basegfx/source/tools/systemdependentdata.cxx b/basegfx/source/tools/systemdependentdata.cxx index 106124f57389..0d64d9982cef 100644 --- a/basegfx/source/tools/systemdependentdata.cxx +++ b/basegfx/source/tools/systemdependentdata.cxx @@ -8,6 +8,7 @@ */ #include <basegfx/utils/systemdependentdata.hxx> +#include <config_fuzzers.h> #include <math.h> namespace basegfx @@ -36,6 +37,10 @@ namespace basegfx sal_uInt32 SystemDependentData::calculateCombinedHoldCyclesInSeconds() const { +#if ENABLE_FUZZERS + return 0; +#endif + if(0 == mnCalculatedCycles) { const sal_Int64 nBytes(estimateUsageInBytes()); @@ -47,7 +52,8 @@ namespace basegfx // For the future, a more sophisticated differentiation may be added if(nBytes > 450) { - const sal_uInt32 nSeconds = 60; // HoldCyclesInSeconds + // HoldCyclesInSeconds + const sal_uInt32 nSeconds = 60; // default is Seconds (minimal is one) sal_uInt32 nResult(0 == nSeconds ? 1 : nSeconds); diff --git a/basegfx/source/tools/unopolypolygon.cxx b/basegfx/source/tools/unopolypolygon.cxx index 48b3372d5526..323e06a96f18 100644 --- a/basegfx/source/tools/unopolypolygon.cxx +++ b/basegfx/source/tools/unopolypolygon.cxx @@ -28,17 +28,16 @@ #include <basegfx/utils/unopolypolygon.hxx> #include <basegfx/matrix/b2dhommatrixtools.hxx> #include <cppuhelper/supportsservice.hxx> +#include <utility> using namespace ::com::sun::star; namespace basegfx::unotools { - UnoPolyPolygon::UnoPolyPolygon( const B2DPolyPolygon& rPolyPoly ) : - maPolyPoly( rPolyPoly ), + UnoPolyPolygon::UnoPolyPolygon( B2DPolyPolygon aPolyPoly ) : + maPolyPoly(std::move( aPolyPoly )), meFillRule( rendering::FillRule_EVEN_ODD ) { - // or else races will haunt us. - maPolyPoly.makeUnique(); } void SAL_CALL UnoPolyPolygon::addPolyPolygon( @@ -98,7 +97,7 @@ namespace basegfx::unotools throw lang::IllegalArgumentException( "UnoPolyPolygon::addPolyPolygon(): Invalid input " "poly-polygon, cannot retrieve vertex data", - static_cast<cppu::OWeakObject*>(this), 1); + getXWeak(), 1); aSrcPoly = unotools::polyPolygonFromPoint2DSequenceSequence( xLinePoly->getPoints( 0, @@ -229,7 +228,7 @@ namespace basegfx::unotools const B2DPolygon& rPoly( maPolyPoly.getB2DPolygon( nPolygonIndex ) ); - if( nPointIndex < 0 || nPointIndex >= static_cast<sal_Int32>(rPoly.count()) ) + if( nPointIndex < 0 || o3tl::make_unsigned(nPointIndex) >= rPoly.count() ) throw lang::IndexOutOfBoundsException(); return unotools::point2DFromB2DPoint( rPoly.getB2DPoint( nPointIndex ) ); @@ -246,7 +245,7 @@ namespace basegfx::unotools B2DPolygon aPoly( maPolyPoly.getB2DPolygon( nPolygonIndex ) ); - if( nPointIndex < 0 || nPointIndex >= static_cast<sal_Int32>(aPoly.count()) ) + if( nPointIndex < 0 || o3tl::make_unsigned(nPointIndex) >= aPoly.count() ) throw lang::IndexOutOfBoundsException(); aPoly.setB2DPoint( nPointIndex, @@ -297,7 +296,7 @@ namespace basegfx::unotools const B2DPolygon& rPoly( maPolyPoly.getB2DPolygon( nPolygonIndex ) ); const sal_uInt32 nPointCount(rPoly.count()); - if( nPointIndex < 0 || nPointIndex >= static_cast<sal_Int32>(nPointCount) ) + if( nPointIndex < 0 || o3tl::make_unsigned(nPointIndex) >= nPointCount ) throw lang::IndexOutOfBoundsException(); const B2DPoint& rPt( rPoly.getB2DPoint( nPointIndex ) ); @@ -323,7 +322,7 @@ namespace basegfx::unotools B2DPolygon aPoly( maPolyPoly.getB2DPolygon( nPolygonIndex ) ); const sal_uInt32 nPointCount(aPoly.count()); - if( nPointIndex < 0 || nPointIndex >= static_cast<sal_Int32>(nPointCount) ) + if( nPointIndex < 0 || o3tl::make_unsigned(nPointIndex) >= nPointCount ) throw lang::IndexOutOfBoundsException(); aPoly.setB2DPoint( nPointIndex, @@ -422,7 +421,7 @@ namespace basegfx::unotools OUString SAL_CALL UnoPolyPolygon::getImplementationName() { - return "gfx::internal::UnoPolyPolygon"; + return u"gfx::internal::UnoPolyPolygon"_ustr; } sal_Bool SAL_CALL UnoPolyPolygon::supportsService( const OUString& ServiceName ) @@ -432,17 +431,14 @@ namespace basegfx::unotools uno::Sequence< OUString > SAL_CALL UnoPolyPolygon::getSupportedServiceNames() { - return { "com.sun.star.rendering.PolyPolygon2D" }; + return { u"com.sun.star.rendering.PolyPolygon2D"_ustr }; } B2DPolyPolygon UnoPolyPolygon::getPolyPolygon() const { std::unique_lock const guard( m_aMutex ); - // detach result from us - B2DPolyPolygon aRet( maPolyPoly ); - aRet.makeUnique(); - return aRet; + return maPolyPoly; } } diff --git a/basegfx/source/tools/zoomtools.cxx b/basegfx/source/tools/zoomtools.cxx index 4fedb8ee848c..dd4c7a6cbbd3 100644 --- a/basegfx/source/tools/zoomtools.cxx +++ b/basegfx/source/tools/zoomtools.cxx @@ -26,7 +26,7 @@ const double ZOOM_FACTOR = 1.12246205; * @param nCurrent current value * @param nMultiple multiple against which the current value is rounded */ -static tools::Long roundMultiple(tools::Long nCurrent, int nMultiple) +static sal_uInt16 roundMultiple(sal_uInt16 nCurrent, int nMultiple) { // round zoom to a multiple of nMultiple return (( nCurrent + nMultiple / 2 ) - ( nCurrent + nMultiple / 2 ) % nMultiple); @@ -39,10 +39,10 @@ static tools::Long roundMultiple(tools::Long nCurrent, int nMultiple) * * @param nCurrent current zoom factor */ -static tools::Long roundZoom(double nCurrent) +static sal_uInt16 roundZoom(double nCurrent) { // convert nCurrent properly to int - tools::Long nNew = nCurrent + 0.5; + sal_uInt16 nNew = nCurrent + 0.5; // round to more common numbers above 50 if (nNew > 1000) { @@ -66,7 +66,7 @@ static tools::Long roundZoom(double nCurrent) * @param nPrevious previous zoom factor * @param nStep step which shouldn't be skipped */ -static tools::Long enforceStep(tools::Long nCurrent, tools::Long nPrevious, int nStep) +static sal_uInt16 enforceStep(sal_uInt16 nCurrent, sal_uInt16 nPrevious, unsigned int nStep) { if ((( nCurrent > nStep ) && ( nPrevious < nStep )) || (( nCurrent < nStep ) && ( nPrevious > nStep ))) @@ -80,9 +80,9 @@ static tools::Long enforceStep(tools::Long nCurrent, tools::Long nPrevious, int * * @param nCurrent current zoom factor */ -tools::Long zoomIn(tools::Long nCurrent) +sal_uInt16 zoomIn(sal_uInt16 nCurrent) { - tools::Long nNew = roundZoom( nCurrent * ZOOM_FACTOR ); + sal_uInt16 nNew = roundZoom( nCurrent * ZOOM_FACTOR ); // make sure some values are not skipped nNew = enforceStep(nNew, nCurrent, 200); nNew = enforceStep(nNew, nCurrent, 100); @@ -97,9 +97,9 @@ tools::Long zoomIn(tools::Long nCurrent) * * @param nCurrent current zoom factor */ -tools::Long zoomOut(tools::Long nCurrent) +sal_uInt16 zoomOut(sal_uInt16 nCurrent) { - tools::Long nNew = roundZoom( nCurrent / ZOOM_FACTOR ); + sal_uInt16 nNew = roundZoom( nCurrent / ZOOM_FACTOR ); // make sure some values are not skipped nNew = enforceStep(nNew, nCurrent, 200); nNew = enforceStep(nNew, nCurrent, 100); diff --git a/basegfx/source/vector/b2dvector.cxx b/basegfx/source/vector/b2dvector.cxx index 1ad51a9b5a4c..1f696237fecf 100644 --- a/basegfx/source/vector/b2dvector.cxx +++ b/basegfx/source/vector/b2dvector.cxx @@ -25,57 +25,45 @@ namespace basegfx { B2DVector& B2DVector::normalize() { - double fLen(scalar(*this)); + double fLen(std::hypot(mnX, mnY)); - if(fTools::equalZero(fLen)) - { - mfX = 0.0; - mfY = 0.0; - } - else + if(!fTools::equalZero(fLen)) { const double fOne(1.0); if(!fTools::equal(fOne, fLen)) { - fLen = sqrt(fLen); - - if(!fTools::equalZero(fLen)) - { - mfX /= fLen; - mfY /= fLen; - } + mnX /= fLen; + mnY /= fLen; } } + else + { + mnX = 0.0; + mnY = 0.0; + } return *this; } - B2DVector& B2DVector::operator=( const B2DTuple& rVec ) - { - mfX = rVec.getX(); - mfY = rVec.getY(); - return *this; - } - double B2DVector::getLength() const { - if(fTools::equalZero(mfX)) + if(fTools::equalZero(mnX)) { - return fabs(mfY); + return fabs(mnY); } - else if(fTools::equalZero(mfY)) + else if(fTools::equalZero(mnY)) { - return fabs(mfX); + return fabs(mnX); } - return hypot( mfX, mfY ); + return hypot( mnX, mnY ); } double B2DVector::angle( const B2DVector& rVec ) const { - return atan2(mfX * rVec.getY() - mfY * rVec.getX(), - mfX * rVec.getX() + mfY * rVec.getY()); + return atan2(mnX * rVec.getY() - mnY * rVec.getX(), + mnX * rVec.getX() + mnY * rVec.getY()); } const B2DVector& B2DVector::getEmptyVector() @@ -85,19 +73,19 @@ namespace basegfx B2DVector& B2DVector::operator*=( const B2DHomMatrix& rMat ) { - const double fTempX( rMat.get(0,0)*mfX + - rMat.get(0,1)*mfY ); - const double fTempY( rMat.get(1,0)*mfX + - rMat.get(1,1)*mfY ); - mfX = fTempX; - mfY = fTempY; + const double fTempX( rMat.get(0,0)*mnX + + rMat.get(0,1)*mnY ); + const double fTempY( rMat.get(1,0)*mnX + + rMat.get(1,1)*mnY ); + mnX = fTempX; + mnY = fTempY; return *this; } B2DVector& B2DVector::setLength(double fLen) { - double fLenNow(scalar(*this)); + double fLenNow(std::hypot(mnX, mnY)); if(!fTools::equalZero(fLenNow)) { @@ -105,11 +93,11 @@ namespace basegfx if(!fTools::equal(fOne, fLenNow)) { - fLen /= sqrt(fLenNow); + fLen /= fLenNow; } - mfX *= fLen; - mfY *= fLen; + mnX *= fLen; + mnY *= fLen; } return *this; diff --git a/basegfx/source/vector/b2ivector.cxx b/basegfx/source/vector/b2ivector.cxx index 5b45871a39cf..6d618facf48f 100644 --- a/basegfx/source/vector/b2ivector.cxx +++ b/basegfx/source/vector/b2ivector.cxx @@ -42,7 +42,7 @@ namespace basegfx B2IVector& B2IVector::setLength(double fLen) { - double fLenNow(scalar(*this)); + double fLenNow(std::hypot(mnX, mnY)); if(!::basegfx::fTools::equalZero(fLenNow)) { @@ -50,7 +50,7 @@ namespace basegfx if(!::basegfx::fTools::equal(fOne, fLenNow)) { - fLen /= sqrt(fLenNow); + fLen /= fLenNow; } mnX = fround( mnX*fLen ); diff --git a/basegfx/source/vector/b3dvector.cxx b/basegfx/source/vector/b3dvector.cxx index 002ee330f9f4..68e3fcf205c4 100644 --- a/basegfx/source/vector/b3dvector.cxx +++ b/basegfx/source/vector/b3dvector.cxx @@ -24,7 +24,7 @@ namespace basegfx { B3DVector& B3DVector::normalize() { - double fLen(scalar(*this)); + double fLen(std::hypot(mnX, mnY, mnZ)); if(!::basegfx::fTools::equalZero(fLen)) { @@ -32,13 +32,17 @@ namespace basegfx if(!::basegfx::fTools::equal(fOne, fLen)) { - fLen = sqrt(fLen); - - mfX /= fLen; - mfY /= fLen; - mfZ /= fLen; + mnX /= fLen; + mnY /= fLen; + mnZ /= fLen; } } + else + { + mnX = 0.0; + mnY = 0.0; + mnZ = 0.0; + } return *this; } @@ -52,12 +56,12 @@ namespace basegfx B3DVector& B3DVector::operator*=( const ::basegfx::B3DHomMatrix& rMat ) { - const double fTempX( rMat.get(0,0)*mfX + rMat.get(0,1)*mfY + rMat.get(0,2)*mfZ ); - const double fTempY( rMat.get(1,0)*mfX + rMat.get(1,1)*mfY + rMat.get(1,2)*mfZ ); - const double fTempZ( rMat.get(2,0)*mfX + rMat.get(2,1)*mfY + rMat.get(2,2)*mfZ ); - mfX = fTempX; - mfY = fTempY; - mfZ = fTempZ; + const double fTempX( rMat.get(0,0)*mnX + rMat.get(0,1)*mnY + rMat.get(0,2)*mnZ ); + const double fTempY( rMat.get(1,0)*mnX + rMat.get(1,1)*mnY + rMat.get(1,2)*mnZ ); + const double fTempZ( rMat.get(2,0)*mnX + rMat.get(2,1)*mnY + rMat.get(2,2)*mnZ ); + mnX = fTempX; + mnY = fTempY; + mnZ = fTempZ; return *this; } diff --git a/basegfx/source/workbench/Makefile b/basegfx/source/workbench/Makefile index 21dfc1400d11..6218141da1c8 100644 --- a/basegfx/source/workbench/Makefile +++ b/basegfx/source/workbench/Makefile @@ -16,19 +16,8 @@ # the License at http://www.apache.org/licenses/LICENSE-2.0 . # -# Testbuild - -#test : bezierclip.cxx convexhull.cxx -# g++ -Wall -g \ -# -I. -I. -I../inc -I./inc -I./unx/inc -I./unxlngi4/inc -I. -I/develop4/update/SRX644/unxlngi4/inc.m4/stl -I/develop4/update/SRX644/unxlngi4/inc.m4/external -I/develop4/update/SRX644/unxlngi4/inc.m4 -I/develop4/update/SRX644/src.m4/solenv/unxlngi4/inc -I/net/grande/develop6/update/dev/gcc_3.0.1_linux_libc2.11_turbolinux/include -I/develop4/update/SRX644/src.m4/solenv/inc -I/develop4/update/SRX644/unxlngi4/inc.m4/stl -I/net/grande.germany/develop6/update/dev/gcc_3.0.1_linux_libc2.11_turbolinux/redhat60/usr/include -I/net/grande.germany/develop6/update/dev/gcc_3.0.1_linux_libc2.11_turbolinux/redhat60/usr/include/X11 -I/develop4/update/SRX644/src.m4/res -I/net/grande/develop6/update/dev/Linux_JDK_1.4.0/include -I/net/grande/develop6/update/dev/Linux_JDK_1.4.0/include/linux -I. -I./res -I. \ -# -include preinclude.h -D_USE_NAMESPACE -DGLIBC=2 -D_USE_NAMESPACE=1 -D_DEBUG_RUNTIME \ -# bezierclip.cxx convexhull.cxx -o bezierclip - prog : bezierclip.cxx convexhull.cxx - g++ -Wall -g bezierclip.cxx convexhull.cxx -o bezierclip - -test : testconvexhull.cxx - g++ -Wall -g testconvexhull.cxx -o testhull + g++ -I. -Wall -g bezierclip.cxx convexhull.cxx -o bezierclip .cxx.o: g++ -c $(LOCALDEFINES) $(CCFLAGS) $< diff --git a/basegfx/source/workbench/bezierclip.cxx b/basegfx/source/workbench/bezierclip.cxx index 1f16ed37c05c..676f239efd10 100644 --- a/basegfx/source/workbench/bezierclip.cxx +++ b/basegfx/source/workbench/bezierclip.cxx @@ -17,6 +17,8 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include <iostream> +#include <cassert> #include <algorithm> #include <iterator> #include <vector> @@ -85,7 +87,7 @@ void Impl_calcFatLine( FatLine& line, const Bezier& c ) line.b = (c.p0.x - c.p3.x); // normalize - const double len( sqrt( line.a*line.a + line.b*line.b ) ); + const double len(std::hypot(line.a, line.b)); if( !tolZero(len) ) { line.a /= len; @@ -287,9 +289,9 @@ bool Impl_calcSafeParams_clip( double& t1, Polygon2D convHull( convexHull( poly ) ); - cout << "# convex hull testing" << endl + std::cout << "# convex hull testing" << std::endl << "plot [t=0:1] "; - cout << " bez(" + std::cout << " bez(" << poly[0].x << "," << poly[1].x << "," << poly[2].x << "," @@ -303,22 +305,22 @@ bool Impl_calcSafeParams_clip( double& t1, << t1 << ", t, " << t2 << ", t, " << "'-' using ($1):($2) title \"control polygon\" with lp, " - << "'-' using ($1):($2) title \"convex hull\" with lp" << endl; + << "'-' using ($1):($2) title \"convex hull\" with lp" << std::endl; unsigned int k; for( k=0; k<poly.size(); ++k ) { - cout << poly[k].x << " " << poly[k].y << endl; + std::cout << poly[k].x << " " << poly[k].y << std::endl; } - cout << poly[0].x << " " << poly[0].y << endl; - cout << "e" << endl; + std::cout << poly[0].x << " " << poly[0].y << std::endl; + std::cout << "e" << std::endl; for( k=0; k<convHull.size(); ++k ) { - cout << convHull[k].x << " " << convHull[k].y << endl; + std::cout << convHull[k].x << " " << convHull[k].y << std::endl; } - cout << convHull[0].x << " " << convHull[0].y << endl; - cout << "e" << endl; + std::cout << convHull[0].x << " " << convHull[0].y << std::endl; + std::cout << "e" << std::endl; return bRet; #endif @@ -376,7 +378,7 @@ void printCurvesWithSafeRange( const Bezier& c1, const Bezier& c2, double t1_c1, { static int offset = 0; - cout << "# safe param range testing" << endl + std::cout << "# safe param range testing" << std::endl << "plot [t=0.0:1.0] "; // clip safe ranges off c1 @@ -391,7 +393,7 @@ void printCurvesWithSafeRange( const Bezier& c1, const Bezier& c2, double t1_c1, // output remaining segment (c1_part1) - cout << "bez(" + std::cout << "bez(" << c1.p0.x+offset << "," << c1.p1.x+offset << "," << c1.p2.x+offset << "," @@ -448,7 +450,7 @@ void printCurvesWithSafeRange( const Bezier& c1, const Bezier& c2, double t1_c1, << bounds_c2.c-bounds_c2.dMax << ",t)+" << offset << ", liney(" << bounds_c2.a << "," << bounds_c2.b << "," - << bounds_c2.c-bounds_c2.dMax << ",t) title \"fat line (max) \"" << endl; + << bounds_c2.c-bounds_c2.dMax << ",t) title \"fat line (max) \"" << std::endl; offset += 1; } @@ -459,10 +461,10 @@ void printResultWithFinalCurves( const Bezier& c1, const Bezier& c1_part, { static int offset = 0; - cout << "# final result" << endl + std::cout << "# final result" << std::endl << "plot [t=0.0:1.0] "; - cout << "bez(" + std::cout << "bez(" << c1.p0.x+offset << "," << c1.p1.x+offset << "," << c1.p2.x+offset << "," @@ -521,7 +523,7 @@ void printResultWithFinalCurves( const Bezier& c1, const Bezier& c1_part, << c2_part.p0.y << "," << c2_part.p1.y << "," << c2_part.p2.y << "," - << c2_part.p3.y << ",t)" << endl; + << c2_part.p3.y << ",t)" << std::endl; offset += 1; } @@ -682,7 +684,7 @@ void Impl_calcFocus( Bezier& res, const Bezier& c ) fRes[0] = 0.0; fRes[1] = 1.0; - cerr << "Matrix singular!" << endl; + std::cerr << "Matrix singular!" << std::endl; } // now, the reordered and per-coefficient collected focus curve is @@ -842,25 +844,25 @@ bool Impl_calcSafeParams_focus( double& t1, Polygon2D convHull( convexHull( controlPolygon ) ); - cout << "# convex hull testing (focus)" << endl + std::cout << "# convex hull testing (focus)" << std::endl << "plot [t=0:1] "; - cout << "'-' using ($1):($2) title \"control polygon\" with lp, " - << "'-' using ($1):($2) title \"convex hull\" with lp" << endl; + std::cout << "'-' using ($1):($2) title \"control polygon\" with lp, " + << "'-' using ($1):($2) title \"convex hull\" with lp" << std::endl; unsigned int count; for( count=0; count<controlPolygon.size(); ++count ) { - cout << controlPolygon[count].x << " " << controlPolygon[count].y << endl; + std::cout << controlPolygon[count].x << " " << controlPolygon[count].y << std::endl; } - cout << controlPolygon[0].x << " " << controlPolygon[0].y << endl; - cout << "e" << endl; + std::cout << controlPolygon[0].x << " " << controlPolygon[0].y << std::endl; + std::cout << "e" << std::endl; for( count=0; count<convHull.size(); ++count ) { - cout << convHull[count].x << " " << convHull[count].y << endl; + std::cout << convHull[count].x << " " << convHull[count].y << std::endl; } - cout << convHull[0].x << " " << convHull[0].y << endl; - cout << "e" << endl; + std::cout << convHull[0].x << " " << convHull[0].y << std::endl; + std::cout << "e" << std::endl; return bRet; #endif @@ -922,24 +924,24 @@ template <class Functor> void Impl_applySafeRanges_rec( std::back_insert_iterato // tangency, and justifies to return a single intersection // point. Otherwise, inside/outside test might fail here. - for( int i=0; i<recursionLevel; ++i ) cerr << " "; + for( int i=0; i<recursionLevel; ++i ) std::cerr << " "; if( recursionLevel % 2 ) { - cerr << "level: " << recursionLevel + std::cerr << std::endl << "level: " << recursionLevel << " t: " << last_t1_c2 + (last_t2_c2 - last_t1_c2)/2.0 << ", c1: " << last_t1_c2 << " " << last_t2_c2 << ", c2: " << last_t1_c1 << " " << last_t2_c1 - << endl; + << std::endl; } else { - cerr << "level: " << recursionLevel + std::cerr << std::endl << "level: " << recursionLevel << " t: " << last_t1_c1 + (last_t2_c1 - last_t1_c1)/2.0 << ", c1: " << last_t1_c1 << " " << last_t2_c1 << ", c2: " << last_t1_c2 << " " << last_t2_c2 - << endl; + << std::endl; } // refine solution @@ -1141,7 +1143,7 @@ struct BezierTangencyFunctor c1_orig, // use orig curve here, need t's on original curve focus ) ); - cerr << "range: " << t2_c1 - t1_c1 << ", ret: " << bRet << endl; + std::cerr << "range: " << t2_c1 - t1_c1 << ", ret: " << bRet << std::endl; return bRet; } @@ -1299,24 +1301,24 @@ int main(int argc, const char *argv[]) }; // output gnuplot setup - cout << "#!/usr/bin/gnuplot -persist" << endl - << "#" << endl - << "# automatically generated by bezierclip, don't change!" << endl - << "#" << endl - << "set parametric" << endl - << "bez(p,q,r,s,t) = p*(1-t)**3+q*3*(1-t)**2*t+r*3*(1-t)*t**2+s*t**3" << endl - << "bezd(p,q,r,s,t) = 3*(q-p)*(1-t)**2+6*(r-q)*(1-t)*t+3*(s-r)*t**2" << endl - << "pointmarkx(c,t) = c-0.03*t" << endl - << "pointmarky(c,t) = c+0.03*t" << endl - << "linex(a,b,c,t) = a*-c + t*-b" << endl - << "liney(a,b,c,t) = b*-c + t*a" << endl << endl - << "# end of setup" << endl << endl; + std::cout << "#!/usr/bin/gnuplot -persist" << std::endl + << "#" << std::endl + << "# automatically generated by bezierclip, don't change!" << std::endl + << "#" << std::endl + << "set parametric" << std::endl + << "bez(p,q,r,s,t) = p*(1-t)**3+q*3*(1-t)**2*t+r*3*(1-t)*t**2+s*t**3" << std::endl + << "bezd(p,q,r,s,t) = 3*(q-p)*(1-t)**2+6*(r-q)*(1-t)*t+3*(s-r)*t**2" << std::endl + << "pointmarkx(c,t) = c-0.03*t" << std::endl + << "pointmarky(c,t) = c+0.03*t" << std::endl + << "linex(a,b,c,t) = a*-c + t*-b" << std::endl + << "liney(a,b,c,t) = b*-c + t*a" << std::endl << std::endl + << "# end of setup" << std::endl << std::endl; #ifdef WITH_CONVEXHULL_TEST // test convex hull algorithm const double convHull_xOffset( curr_Offset ); curr_Offset += 20; - cout << "# convex hull testing" << endl + std::cout << "# convex hull testing" << std::endl << "plot [t=0:1] "; for( i=0; i<sizeof(someCurves)/sizeof(Bezier); ++i ) { @@ -1331,7 +1333,7 @@ int main(int argc, const char *argv[]) aTestPoly[2].x += convHull_xOffset; aTestPoly[3].x += convHull_xOffset; - cout << " bez(" + std::cout << " bez(" << aTestPoly[0].x << "," << aTestPoly[1].x << "," << aTestPoly[2].x << "," @@ -1342,9 +1344,9 @@ int main(int argc, const char *argv[]) << aTestPoly[3].y << ",t), '-' using ($1):($2) title \"convex hull " << i << "\" with lp"; if( i+1<sizeof(someCurves)/sizeof(Bezier) ) - cout << ",\\" << endl; + std::cout << ",\\" << std::endl; else - cout << endl; + std::cout << std::endl; } for( i=0; i<sizeof(someCurves)/sizeof(Bezier); ++i ) { @@ -1363,10 +1365,10 @@ int main(int argc, const char *argv[]) for( k=0; k<convHull.size(); ++k ) { - cout << convHull[k].x << " " << convHull[k].y << endl; + std::cout << convHull[k].x << " " << convHull[k].y << std::endl; } - cout << convHull[0].x << " " << convHull[0].y << endl; - cout << "e" << endl; + std::cout << convHull[0].x << " " << convHull[0].y << std::endl; + std::cout << "e" << std::endl; } #endif @@ -1374,7 +1376,7 @@ int main(int argc, const char *argv[]) // test convex hull algorithm const double multiSubdivide_xOffset( curr_Offset ); curr_Offset += 20; - cout << "# multi subdivide testing" << endl + std::cout << "# multi subdivide testing" << std::endl << "plot [t=0:1] "; for( i=0; i<sizeof(someCurves)/sizeof(Bezier); ++i ) { @@ -1406,7 +1408,7 @@ int main(int argc, const char *argv[]) // subdivide at t2 Impl_deCasteljauAt( c1_part3, c1_part2, c, t2 ); - cout << " bez(" + std::cout << " bez(" << c1_part1.p0.x << "," << c1_part1.p1.x << "," << c1_part1.p2.x << "," @@ -1435,9 +1437,9 @@ int main(int argc, const char *argv[]) << c1_part3.p3.y << ",t) title \"left " << i << "\""; if( i+1<sizeof(someCurves)/sizeof(Bezier) ) - cout << ",\\" << endl; + std::cout << ",\\" << std::endl; else - cout << endl; + std::cout << std::endl; } #endif @@ -1445,7 +1447,7 @@ int main(int argc, const char *argv[]) // test fatline algorithm const double fatLine_xOffset( curr_Offset ); curr_Offset += 20; - cout << "# fat line testing" << endl + std::cout << "# fat line testing" << std::endl << "plot [t=0:1] "; for( i=0; i<sizeof(someCurves)/sizeof(Bezier); ++i ) { @@ -1460,7 +1462,7 @@ int main(int argc, const char *argv[]) Impl_calcFatLine(line, c); - cout << " bez(" + std::cout << " bez(" << c.p0.x << "," << c.p1.x << "," << c.p2.x << "," @@ -1489,9 +1491,9 @@ int main(int argc, const char *argv[]) << line.c-line.dMax << ",t) title \"fat line (max) on " << i << "\""; if( i+1<sizeof(someCurves)/sizeof(Bezier) ) - cout << ",\\" << endl; + std::cout << ",\\" << std::endl; else - cout << endl; + std::cout << std::endl; } #endif @@ -1499,7 +1501,7 @@ int main(int argc, const char *argv[]) // test focus curve algorithm const double focus_xOffset( curr_Offset ); curr_Offset += 20; - cout << "# focus line testing" << endl + std::cout << "# focus line testing" << std::endl << "plot [t=0:1] "; for( i=0; i<sizeof(someCurves)/sizeof(Bezier); ++i ) { @@ -1514,7 +1516,7 @@ int main(int argc, const char *argv[]) Bezier focus; Impl_calcFocus(focus, c); - cout << " bez(" + std::cout << " bez(" << c.p0.x << "," << c.p1.x << "," << c.p2.x << "," @@ -1533,16 +1535,16 @@ int main(int argc, const char *argv[]) << focus.p3.y << ",t) title \"focus " << i << "\""; if( i+1<sizeof(someCurves)/sizeof(Bezier) ) - cout << ",\\" << endl; + std::cout << ",\\" << std::endl; else - cout << endl; + std::cout << std::endl; } #endif #ifdef WITH_SAFEPARAMBASE_TEST // test safe params base method double safeParamsBase_xOffset( curr_Offset ); - cout << "# safe param base method testing" << endl + std::cout << "# safe param base method testing" << std::endl << "plot [t=0:1] "; for( i=0; i<sizeof(someCurves)/sizeof(Bezier); ++i ) { @@ -1565,7 +1567,7 @@ int main(int argc, const char *argv[]) Polygon2D convHull( convexHull( poly ) ); - cout << " bez(" + std::cout << " bez(" << poly[0].x << "," << poly[1].x << "," << poly[2].x << "," @@ -1578,16 +1580,16 @@ int main(int argc, const char *argv[]) << "t+" << safeParamsBase_xOffset << ", 1, "; if( bRet ) { - cout << t1+safeParamsBase_xOffset << ", t, " + std::cout << t1+safeParamsBase_xOffset << ", t, " << t2+safeParamsBase_xOffset << ", t, "; } - cout << "'-' using ($1):($2) title \"control polygon\" with lp, " + std::cout << "'-' using ($1):($2) title \"control polygon\" with lp, " << "'-' using ($1):($2) title \"convex hull\" with lp"; if( i+1<sizeof(someCurves)/sizeof(Bezier) ) - cout << ",\\" << endl; + std::cout << ",\\" << std::endl; else - cout << endl; + std::cout << std::endl; safeParamsBase_xOffset += 2; } @@ -1617,17 +1619,17 @@ int main(int argc, const char *argv[]) unsigned int k; for( k=0; k<poly.size(); ++k ) { - cout << poly[k].x << " " << poly[k].y << endl; + std::cout << poly[k].x << " " << poly[k].y << std::endl; } - cout << poly[0].x << " " << poly[0].y << endl; - cout << "e" << endl; + std::cout << poly[0].x << " " << poly[0].y << std::endl; + std::cout << "e" << std::endl; for( k=0; k<convHull.size(); ++k ) { - cout << convHull[k].x << " " << convHull[k].y << endl; + std::cout << convHull[k].x << " " << convHull[k].y << std::endl; } - cout << convHull[0].x << " " << convHull[0].y << endl; - cout << "e" << endl; + std::cout << convHull[0].x << " " << convHull[0].y << std::endl; + std::cout << "e" << std::endl; safeParamsBase_xOffset += 2; } @@ -1638,7 +1640,7 @@ int main(int argc, const char *argv[]) // test safe parameter range algorithm const double safeParams_xOffset( curr_Offset ); curr_Offset += 20; - cout << "# safe param range testing" << endl + std::cout << "# safe param range testing" << std::endl << "plot [t=0.0:1.0] "; for( i=0; i<sizeof(someCurves)/sizeof(Bezier); ++i ) { @@ -1672,7 +1674,7 @@ int main(int argc, const char *argv[]) // output remaining segment (c1_part1) - cout << " bez(" + std::cout << " bez(" << c1.p0.x << "," << c1.p1.x << "," << c1.p2.x << "," @@ -1699,9 +1701,9 @@ int main(int argc, const char *argv[]) << c1_part1.p3.y << ",t)"; if( i+2<sizeof(someCurves)/sizeof(Bezier) ) - cout << ",\\" << endl; + std::cout << ",\\" << std::endl; else - cout << endl; + std::cout << std::endl; } } } @@ -1736,7 +1738,7 @@ int main(int argc, const char *argv[]) // test safe parameter range from focus algorithm const double safeParamsFocus_xOffset( curr_Offset ); curr_Offset += 20; - cout << "# safe param range from focus testing" << endl + std::cout << "# safe param range from focus testing" << std::endl << "plot [t=0.0:1.0] "; for( i=0; i<sizeof(someCurves)/sizeof(Bezier); ++i ) { @@ -1790,7 +1792,7 @@ int main(int argc, const char *argv[]) bool bRet( Impl_calcSafeParams_focus( t1, t2, c1, focus ) ); - cerr << "t1: " << t1 << ", t2: " << t2 << endl; + std::cerr << "t1: " << t1 << ", t2: " << t2 << std::endl; // clip safe ranges off c1 Bezier c1_part1; @@ -1804,7 +1806,7 @@ int main(int argc, const char *argv[]) // output remaining segment (c1_part1) - cout << " bez(" + std::cout << " bez(" << c1.p0.x << "," << c1.p1.x << "," << c1.p2.x << "," @@ -1845,7 +1847,7 @@ int main(int argc, const char *argv[]) #endif if( bRet ) { - cout << ", bez(" + std::cout << ", bez(" << c1_part1.p0.x << "," << c1_part1.p1.x << "," << c1_part1.p2.x << "," @@ -1857,9 +1859,9 @@ int main(int argc, const char *argv[]) } if( i+2<sizeof(someCurves)/sizeof(Bezier) ) - cout << ",\\" << endl; + std::cout << ",\\" << std::endl; else - cout << endl; + std::cout << std::endl; } } #endif @@ -1903,7 +1905,7 @@ int main(int argc, const char *argv[]) // test full bezier clipping const double bezierClip_xOffset( curr_Offset ); - cout << endl << endl << "# bezier clip testing" << endl + std::cout << std::endl << std::endl << "# bezier clip testing" << std::endl << "plot [t=0:1] "; for( i=0; i<sizeof(someCurves)/sizeof(Bezier); ++i ) { @@ -1921,7 +1923,7 @@ int main(int argc, const char *argv[]) c2.p2.x += bezierClip_xOffset; c2.p3.x += bezierClip_xOffset; - cout << " bez(" + std::cout << " bez(" << c1.p0.x << "," << c1.p1.x << "," << c1.p2.x << "," @@ -1959,9 +1961,9 @@ int main(int argc, const char *argv[]) << c2.p3.y << ",$1)) title \"bezier " << i << " clipped against " << j << " (t on " << j << ")\""; if( i+2<sizeof(someCurves)/sizeof(Bezier) ) - cout << ",\\" << endl; + std::cout << ",\\" << std::endl; else - cout << endl; + std::cout << std::endl; } } for( i=0; i<sizeof(someCurves)/sizeof(Bezier); ++i ) @@ -1985,15 +1987,15 @@ int main(int argc, const char *argv[]) for( k=0; k<result.size(); ++k ) { - cout << result[k].first << endl; + std::cout << result[k].first << std::endl; } - cout << "e" << endl; + std::cout << "e" << std::endl; for( k=0; k<result.size(); ++k ) { - cout << result[k].second << endl; + std::cout << result[k].second << std::endl; } - cout << "e" << endl; + std::cout << "e" << std::endl; } } #endif diff --git a/basegfx/source/workbench/gauss.hxx b/basegfx/source/workbench/gauss.hxx index 3605c1cac9bd..4ef050ccbc52 100644 --- a/basegfx/source/workbench/gauss.hxx +++ b/basegfx/source/workbench/gauss.hxx @@ -47,8 +47,6 @@ bool eliminate( Matrix& matrix, int cols, const BaseType& minPivot ) { - BaseType temp; - /* i, j, k *must* be signed, when looping like: j>=0 ! */ /* eliminate below main diagonal */ for(int i=0; i<cols-1; ++i) @@ -66,9 +64,7 @@ bool eliminate( Matrix& matrix, /* interchange rows 'max' and 'i' */ for(int k=0; k<cols; ++k) { - temp = matrix[ i*cols + k ]; - matrix[ i*cols + k ] = matrix[ max*cols + k ]; - matrix[ max*cols + k ] = temp; + std::swap(matrix[ i*cols + k ], matrix[ max*cols + k ]); } /* eliminate column */ |