summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--basegfx/source/polygon/b2dpolygontools.cxx36
-rw-r--r--basegfx/source/polygon/b3dpolygontools.cxx255
-rw-r--r--include/basegfx/polygon/b2dpolygontools.hxx2
-rw-r--r--include/basegfx/polygon/b3dpolygontools.hxx12
4 files changed, 216 insertions, 89 deletions
diff --git a/basegfx/source/polygon/b2dpolygontools.cxx b/basegfx/source/polygon/b2dpolygontools.cxx
index 68d1120bc2cb..c194a38dc9d2 100644
--- a/basegfx/source/polygon/b2dpolygontools.cxx
+++ b/basegfx/source/polygon/b2dpolygontools.cxx
@@ -16,6 +16,8 @@
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
+#include <numeric>
+#include <algorithm>
#include <basegfx/numeric/ftools.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
@@ -32,8 +34,6 @@
#include <basegfx/curve/b2dbeziertools.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
-#include <numeric>
-
// #i37443#
#define ANGLE_BOUND_START_VALUE (2.25)
#define ANGLE_BOUND_MINIMUM_VALUE (0.1)
@@ -1231,6 +1231,32 @@ namespace basegfx::utils
return;
}
+ // precalculate maximal acceptable length of candidate polygon assuming
+ // we want to create a maximum of fNumberOfAllowedSnippets. For
+ // fNumberOfAllowedSnippets use ca. 65536, double due to line & gap.
+ static double fNumberOfAllowedSnippets(65535.0 * 2.0);
+ const double fAllowedLength((fNumberOfAllowedSnippets * fDotDashLength) / double(rDotDashArray.size()));
+ const double fCandidateLength(basegfx::utils::getLength(rCandidate));
+ std::vector<double> aDotDashArray(rDotDashArray);
+
+ if(fCandidateLength > fAllowedLength)
+ {
+ // we would produce more than fNumberOfAllowedSnippets, so
+ // adapt aDotDashArray to exactly produce assumed number. Also
+ // assert this to let the caller know about it.
+ // If this asserts: Please think about checking your DotDashArray
+ // before calling this function or evtl. use the callback version
+ // to *not* produce that much of data. Even then, you may still
+ // think about producing too much runtime (!)
+ assert(true && "applyLineDashing: potentially too expensive to do the requested dismantle - please consider stretched LineDash pattern (!)");
+
+ // calculate correcting factor, apply to aDotDashArray and fDotDashLength
+ // 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
B2DCubicBezier aCurrentEdge;
const bool bIsClosed(rCandidate.isClosed());
@@ -1240,7 +1266,7 @@ namespace basegfx::utils
// prepare DotDashArray iteration and the line/gap switching bool
sal_uInt32 nDotDashIndex(0);
bool bIsLine(true);
- double fDotDashMovingLength(rDotDashArray[0]);
+ double fDotDashMovingLength(aDotDashArray[0]);
B2DPolygon aSnippet;
// remember 1st and last snippets to try to merge after execution
@@ -1303,7 +1329,7 @@ namespace basegfx::utils
// prepare next DotDashArray step and flip line/gap flag
fLastDotDashMovingLength = fDotDashMovingLength;
- fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount];
+ fDotDashMovingLength += aDotDashArray[(++nDotDashIndex) % nDotDashCount];
bIsLine = !bIsLine;
}
@@ -1367,7 +1393,7 @@ namespace basegfx::utils
// prepare next DotDashArray step and flip line/gap flag
fLastDotDashMovingLength = fDotDashMovingLength;
- fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount];
+ fDotDashMovingLength += aDotDashArray[(++nDotDashIndex) % nDotDashCount];
bIsLine = !bIsLine;
}
diff --git a/basegfx/source/polygon/b3dpolygontools.cxx b/basegfx/source/polygon/b3dpolygontools.cxx
index 1d97d4d43f0e..a0349a156626 100644
--- a/basegfx/source/polygon/b3dpolygontools.cxx
+++ b/basegfx/source/polygon/b3dpolygontools.cxx
@@ -90,7 +90,90 @@ namespace basegfx::utils
return fRetval;
}
- void applyLineDashing(const B3DPolygon& rCandidate, const std::vector<double>& rDotDashArray, B3DPolyPolygon* pLineTarget, double fDotDashLength)
+ void applyLineDashing(
+ const B3DPolygon& rCandidate,
+ const std::vector<double>& rDotDashArray,
+ B3DPolyPolygon* pLineTarget,
+ double fDotDashLength)
+ {
+ // clear targets in any case
+ if(pLineTarget)
+ {
+ pLineTarget->clear();
+ }
+
+ // provide callback as lambda
+ auto aLineCallback(
+ nullptr == pLineTarget
+ ? std::function<void(const basegfx::B3DPolygon&)>()
+ : [&pLineTarget](const basegfx::B3DPolygon& rSnippet){ pLineTarget->append(rSnippet); });
+
+ // call version that uses callbacks
+ applyLineDashing(
+ rCandidate,
+ rDotDashArray,
+ aLineCallback,
+ fDotDashLength);
+ }
+
+ static void implHandleSnippet(
+ const B3DPolygon& rSnippet,
+ std::function<void(const basegfx::B3DPolygon& rSnippet)>& rTargetCallback,
+ B3DPolygon& rFirst,
+ B3DPolygon& rLast)
+ {
+ if(rSnippet.isClosed())
+ {
+ if(!rFirst.count())
+ {
+ rFirst = rSnippet;
+ }
+ else
+ {
+ if(rLast.count())
+ {
+ rTargetCallback(rLast);
+ }
+
+ rLast = rSnippet;
+ }
+ }
+ else
+ {
+ rTargetCallback(rSnippet);
+ }
+ }
+
+ static void implHandleFirstLast(
+ std::function<void(const basegfx::B3DPolygon& rSnippet)>& rTargetCallback,
+ B3DPolygon& rFirst,
+ B3DPolygon& rLast)
+ {
+ if(rFirst.count() && rLast.count()
+ && rFirst.getB3DPoint(0).equal(rLast.getB3DPoint(rLast.count() - 1)))
+ {
+ // start of first and end of last are the same -> merge them
+ rLast.append(rFirst);
+ rLast.removeDoublePoints();
+ rFirst.clear();
+ }
+
+ if(rLast.count())
+ {
+ rTargetCallback(rLast);
+ }
+
+ if(rFirst.count())
+ {
+ rTargetCallback(rFirst);
+ }
+ }
+
+ void applyLineDashing(
+ const B3DPolygon& rCandidate,
+ const std::vector<double>& rDotDashArray,
+ std::function<void(const basegfx::B3DPolygon& rSnippet)> aLineTargetCallback,
+ double fDotDashLength)
{
const sal_uInt32 nPointCount(rCandidate.count());
const sal_uInt32 nDotDashCount(rDotDashArray.size());
@@ -100,62 +183,74 @@ namespace basegfx::utils
fDotDashLength = std::accumulate(rDotDashArray.begin(), rDotDashArray.end(), 0.0);
}
- if(fTools::more(fDotDashLength, 0.0) && pLineTarget && nPointCount)
+ if(fTools::lessOrEqual(fDotDashLength, 0.0) || !aLineTargetCallback || !nPointCount)
{
- // clear targets
- if(pLineTarget)
+ // parameters make no sense, just add source to targets
+ if(aLineTargetCallback)
{
- pLineTarget->clear();
+ aLineTargetCallback(rCandidate);
}
- // prepare current edge's start
- B3DPoint aCurrentPoint(rCandidate.getB3DPoint(0));
- const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
-
- // prepare DotDashArray iteration and the line/gap switching bool
- sal_uInt32 nDotDashIndex(0);
- bool bIsLine(true);
- double fDotDashMovingLength(rDotDashArray[0]);
- B3DPolygon aSnippet;
-
- // iterate over all edges
- for(sal_uInt32 a(0); a < nEdgeCount; a++)
- {
- // update current edge
- const sal_uInt32 nNextIndex((a + 1) % nPointCount);
- const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex));
- const double fEdgeLength(B3DVector(aNextPoint - aCurrentPoint).getLength());
+ return;
+ }
- if(!fTools::equalZero(fEdgeLength))
- {
- double fLastDotDashMovingLength(0.0);
- while(fTools::less(fDotDashMovingLength, fEdgeLength))
- {
- // new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength]
- const bool bHandleLine(bIsLine && pLineTarget);
+ // precalculate maximal acceptable length of candidate polygon assuming
+ // we want to create a maximum of fNumberOfAllowedSnippets. In 3D
+ // use less for fNumberOfAllowedSnippets, ca. 6553.6, double due to line & gap.
+ // Less in 3D due to potentially blowing up to rounded line segments.
+ static double fNumberOfAllowedSnippets(6553.5 * 2.0);
+ const double fAllowedLength((fNumberOfAllowedSnippets * fDotDashLength) / double(rDotDashArray.size()));
+ const double fCandidateLength(basegfx::utils::getLength(rCandidate));
+ std::vector<double> aDotDashArray(rDotDashArray);
- if(bHandleLine)
- {
- if(!aSnippet.count())
- {
- aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fLastDotDashMovingLength / fEdgeLength));
- }
+ if(fCandidateLength > fAllowedLength)
+ {
+ // we would produce more than fNumberOfAllowedSnippets, so
+ // adapt aDotDashArray to exactly produce assumed number. Also
+ // assert this to let the caller know about it.
+ // If this asserts: Please think about checking your DotDashArray
+ // before calling this function or evtl. use the callback version
+ // to *not* produce that much of data. Even then, you may still
+ // think about producing too much runtime (!)
+ assert(true && "applyLineDashing: potentially too expensive to do the requested dismantle - please consider stretched LineDash pattern (!)");
+
+ // calculate correcting factor, apply to aDotDashArray and fDotDashLength
+ // to enlarge these as needed
+ const double fFactor(fCandidateLength / fAllowedLength);
+ std::for_each(aDotDashArray.begin(), aDotDashArray.end(), [&fFactor](double &f){ f *= fFactor; });
+ fDotDashLength *= fFactor;
+ }
- aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fDotDashMovingLength / fEdgeLength));
+ // prepare current edge's start
+ B3DPoint aCurrentPoint(rCandidate.getB3DPoint(0));
+ const bool bIsClosed(rCandidate.isClosed());
+ const sal_uInt32 nEdgeCount(bIsClosed ? nPointCount : nPointCount - 1);
- pLineTarget->append(aSnippet);
+ // prepare DotDashArray iteration and the line/gap switching bool
+ sal_uInt32 nDotDashIndex(0);
+ bool bIsLine(true);
+ double fDotDashMovingLength(aDotDashArray[0]);
+ B3DPolygon aSnippet;
- aSnippet.clear();
- }
+ // remember 1st and last snippets to try to merge after execution
+ // is complete and hand to callback
+ B3DPolygon aFirstLine, aLastLine;
- // prepare next DotDashArray step and flip line/gap flag
- fLastDotDashMovingLength = fDotDashMovingLength;
- fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount];
- bIsLine = !bIsLine;
- }
+ // iterate over all edges
+ for(sal_uInt32 a(0); a < nEdgeCount; a++)
+ {
+ // update current edge
+ const sal_uInt32 nNextIndex((a + 1) % nPointCount);
+ const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex));
+ const double fEdgeLength(B3DVector(aNextPoint - aCurrentPoint).getLength());
- // append snippet [fLastDotDashMovingLength, fEdgeLength]
- const bool bHandleLine(bIsLine && pLineTarget);
+ if(!fTools::equalZero(fEdgeLength))
+ {
+ double fLastDotDashMovingLength(0.0);
+ while(fTools::less(fDotDashMovingLength, fEdgeLength))
+ {
+ // new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength]
+ const bool bHandleLine(bIsLine && aLineTargetCallback);
if(bHandleLine)
{
@@ -164,57 +259,55 @@ namespace basegfx::utils
aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fLastDotDashMovingLength / fEdgeLength));
}
- aSnippet.append(aNextPoint);
- }
+ aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fDotDashMovingLength / fEdgeLength));
- // prepare move to next edge
- fDotDashMovingLength -= fEdgeLength;
- }
+ implHandleSnippet(aSnippet, aLineTargetCallback, aFirstLine, aLastLine);
- // prepare next edge step (end point gets new start point)
- aCurrentPoint = aNextPoint;
- }
+ aSnippet.clear();
+ }
- // append last intermediate results (if exists)
- if(aSnippet.count())
- {
- if(bIsLine && pLineTarget)
- {
- pLineTarget->append(aSnippet);
+ // prepare next DotDashArray step and flip line/gap flag
+ fLastDotDashMovingLength = fDotDashMovingLength;
+ fDotDashMovingLength += aDotDashArray[(++nDotDashIndex) % nDotDashCount];
+ bIsLine = !bIsLine;
}
- }
- // check if start and end polygon may be merged
- if(pLineTarget)
- {
- const sal_uInt32 nCount(pLineTarget->count());
+ // append snippet [fLastDotDashMovingLength, fEdgeLength]
+ const bool bHandleLine(bIsLine && aLineTargetCallback);
- if(nCount > 1)
+ if(bHandleLine)
{
- // these polygons were created above, there exists none with less than two points,
- // thus direct point access below is allowed
- const B3DPolygon aFirst(pLineTarget->getB3DPolygon(0));
- B3DPolygon aLast(pLineTarget->getB3DPolygon(nCount - 1));
-
- if(aFirst.getB3DPoint(0).equal(aLast.getB3DPoint(aLast.count() - 1)))
+ if(!aSnippet.count())
{
- // start of first and end of last are the same -> merge them
- aLast.append(aFirst);
- aLast.removeDoublePoints();
- pLineTarget->setB3DPolygon(0, aLast);
- pLineTarget->remove(nCount - 1);
+ aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fLastDotDashMovingLength / fEdgeLength));
}
+
+ aSnippet.append(aNextPoint);
}
+
+ // prepare move to next edge
+ fDotDashMovingLength -= fEdgeLength;
}
+
+ // prepare next edge step (end point gets new start point)
+ aCurrentPoint = aNextPoint;
}
- else
+
+ // append last intermediate results (if exists)
+ if(aSnippet.count())
{
- // parameters make no sense, just add source to targets
- if(pLineTarget)
+ const bool bHandleLine(bIsLine && aLineTargetCallback);
+
+ if(bHandleLine)
{
- pLineTarget->append(rCandidate);
+ implHandleSnippet(aSnippet, aLineTargetCallback, aFirstLine, aLastLine);
}
}
+
+ if(bIsClosed && aLineTargetCallback)
+ {
+ implHandleFirstLast(aLineTargetCallback, aFirstLine, aLastLine);
+ }
}
B3DPolygon applyDefaultNormalsSphere( const B3DPolygon& rCandidate, const B3DPoint& rCenter)
diff --git a/include/basegfx/polygon/b2dpolygontools.hxx b/include/basegfx/polygon/b2dpolygontools.hxx
index 2ec15714088b..90001bae7131 100644
--- a/include/basegfx/polygon/b2dpolygontools.hxx
+++ b/include/basegfx/polygon/b2dpolygontools.hxx
@@ -216,7 +216,7 @@ namespace basegfx
const ::std::vector<double>& rDotDashArray,
B2DPolyPolygon* pLineTarget,
B2DPolyPolygon* pGapTarget = nullptr,
- double fFullDashDotLen = 0.0);
+ double fDotDashLength = 0.0);
// test if point is inside epsilon-range around an edge defined
// by the two given points. Can be used for HitTesting. The epsilon-range
diff --git a/include/basegfx/polygon/b3dpolygontools.hxx b/include/basegfx/polygon/b3dpolygontools.hxx
index 2e37b64e2516..80383c29625e 100644
--- a/include/basegfx/polygon/b3dpolygontools.hxx
+++ b/include/basegfx/polygon/b3dpolygontools.hxx
@@ -20,9 +20,11 @@
#ifndef INCLUDED_BASEGFX_POLYGON_B3DPOLYGONTOOLS_HXX
#define INCLUDED_BASEGFX_POLYGON_B3DPOLYGONTOOLS_HXX
+#include <vector>
+#include <functional>
+
#include <basegfx/point/b3dpoint.hxx>
#include <basegfx/vector/b3dvector.hxx>
-#include <vector>
#include <basegfx/basegfxdllapi.h>
@@ -60,12 +62,18 @@ namespace basegfx
/** Apply given LineDashing to given polygon
For a description see applyLineDashing in b2dpolygontoos.hxx
+ Also 2nd version with callbacks, see comments in 2D version
*/
BASEGFX_DLLPUBLIC void applyLineDashing(
const B3DPolygon& rCandidate,
+ const std::vector<double>& rDotDashArray,
+ std::function<void(const basegfx::B3DPolygon& rSnippet)> aLineTargetCallback,
+ double fDotDashLength = 0.0);
+ BASEGFX_DLLPUBLIC void applyLineDashing(
+ const B3DPolygon& rCandidate,
const ::std::vector<double>& rDotDashArray,
B3DPolyPolygon* pLineTarget,
- double fFullDashDotLen);
+ double fDotDashLength = 0.0);
/** Create/replace normals for given 3d geometry with default normals from given center to outside.
rCandidate: the 3d geometry to change