tdf#130655 added callback interface to ::applyLineDashing
This version of the tooling method allows to avoid collecting line snippets in a return value PolyPolygon. Instead, offer lambda functions to get callbacks for created snippets. The original method using a B2DPolyPolygon return value is adapted to already use this, so serves as example of usage and ensures that only one identical algorithm is used. Change-Id: Ie306968a895ad280fc2425fb40b3244769216ba0 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/88684 Tested-by: Jenkins Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
This commit is contained in:
parent
75500a4161
commit
0dc4fddb9c
@ -1110,7 +1110,102 @@ namespace basegfx::utils
|
||||
return false;
|
||||
}
|
||||
|
||||
void applyLineDashing(const B2DPolygon& rCandidate, const std::vector<double>& rDotDashArray, B2DPolyPolygon* pLineTarget, B2DPolyPolygon* pGapTarget, double fDotDashLength)
|
||||
void applyLineDashing(
|
||||
const B2DPolygon& rCandidate,
|
||||
const std::vector<double>& rDotDashArray,
|
||||
B2DPolyPolygon* pLineTarget,
|
||||
B2DPolyPolygon* pGapTarget,
|
||||
double fDotDashLength)
|
||||
{
|
||||
// clear targets in any case
|
||||
if(pLineTarget)
|
||||
{
|
||||
pLineTarget->clear();
|
||||
}
|
||||
|
||||
if(pGapTarget)
|
||||
{
|
||||
pGapTarget->clear();
|
||||
}
|
||||
|
||||
// provide callbacks as lambdas
|
||||
auto aLineCallback(
|
||||
nullptr == pLineTarget
|
||||
? std::function<void(const basegfx::B2DPolygon&)>()
|
||||
: [&pLineTarget](const basegfx::B2DPolygon& rSnippet){ pLineTarget->append(rSnippet); });
|
||||
auto aGapCallback(
|
||||
nullptr == pGapTarget
|
||||
? std::function<void(const basegfx::B2DPolygon&)>()
|
||||
: [&pGapTarget](const basegfx::B2DPolygon& rSnippet){ pGapTarget->append(rSnippet); });
|
||||
|
||||
// call version that uses callbacks
|
||||
applyLineDashing(
|
||||
rCandidate,
|
||||
rDotDashArray,
|
||||
aLineCallback,
|
||||
aGapCallback,
|
||||
fDotDashLength);
|
||||
}
|
||||
|
||||
static void implHandleSnippet(
|
||||
const B2DPolygon& rSnippet,
|
||||
std::function<void(const basegfx::B2DPolygon& rSnippet)>& rTargetCallback,
|
||||
B2DPolygon& rFirst,
|
||||
B2DPolygon& 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::B2DPolygon& rSnippet)>& rTargetCallback,
|
||||
B2DPolygon& rFirst,
|
||||
B2DPolygon& rLast)
|
||||
{
|
||||
if(rFirst.count() && rLast.count()
|
||||
&& rFirst.getB2DPoint(0).equal(rLast.getB2DPoint(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 B2DPolygon& rCandidate,
|
||||
const std::vector<double>& rDotDashArray,
|
||||
std::function<void(const basegfx::B2DPolygon& rSnippet)> aLineTargetCallback,
|
||||
std::function<void(const basegfx::B2DPolygon& rSnippet)> aGapTargetCallback,
|
||||
double fDotDashLength)
|
||||
{
|
||||
const sal_uInt32 nPointCount(rCandidate.count());
|
||||
const sal_uInt32 nDotDashCount(rDotDashArray.size());
|
||||
@ -1120,154 +1215,133 @@ namespace basegfx::utils
|
||||
fDotDashLength = std::accumulate(rDotDashArray.begin(), rDotDashArray.end(), 0.0);
|
||||
}
|
||||
|
||||
if(fTools::more(fDotDashLength, 0.0) && (pLineTarget || pGapTarget) && nPointCount)
|
||||
if(fTools::lessOrEqual(fDotDashLength, 0.0) || (!aLineTargetCallback && !aGapTargetCallback) || !nPointCount)
|
||||
{
|
||||
// clear targets
|
||||
if(pLineTarget)
|
||||
// parameters make no sense, just add source to targets
|
||||
if(aLineTargetCallback)
|
||||
{
|
||||
pLineTarget->clear();
|
||||
aLineTargetCallback(rCandidate);
|
||||
}
|
||||
|
||||
if(pGapTarget)
|
||||
if(aGapTargetCallback)
|
||||
{
|
||||
pGapTarget->clear();
|
||||
aGapTargetCallback(rCandidate);
|
||||
}
|
||||
|
||||
// prepare current edge's start
|
||||
B2DCubicBezier aCurrentEdge;
|
||||
const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
|
||||
aCurrentEdge.setStartPoint(rCandidate.getB2DPoint(0));
|
||||
return;
|
||||
}
|
||||
|
||||
// prepare DotDashArray iteration and the line/gap switching bool
|
||||
sal_uInt32 nDotDashIndex(0);
|
||||
bool bIsLine(true);
|
||||
double fDotDashMovingLength(rDotDashArray[0]);
|
||||
B2DPolygon aSnippet;
|
||||
// prepare current edge's start
|
||||
B2DCubicBezier aCurrentEdge;
|
||||
const bool bIsClosed(rCandidate.isClosed());
|
||||
const sal_uInt32 nEdgeCount(bIsClosed ? nPointCount : nPointCount - 1);
|
||||
aCurrentEdge.setStartPoint(rCandidate.getB2DPoint(0));
|
||||
|
||||
// iterate over all edges
|
||||
for(sal_uInt32 a(0); a < nEdgeCount; a++)
|
||||
// prepare DotDashArray iteration and the line/gap switching bool
|
||||
sal_uInt32 nDotDashIndex(0);
|
||||
bool bIsLine(true);
|
||||
double fDotDashMovingLength(rDotDashArray[0]);
|
||||
B2DPolygon aSnippet;
|
||||
|
||||
// remember 1st and last snippets to try to merge after execution
|
||||
// is complete and hand to callback
|
||||
B2DPolygon aFirstLine, aLastLine;
|
||||
B2DPolygon aFirstGap, aLastGap;
|
||||
|
||||
// iterate over all edges
|
||||
for(sal_uInt32 a(0); a < nEdgeCount; a++)
|
||||
{
|
||||
// update current edge (fill in C1, C2 and end point)
|
||||
double fLastDotDashMovingLength(0.0);
|
||||
const sal_uInt32 nNextIndex((a + 1) % nPointCount);
|
||||
aCurrentEdge.setControlPointA(rCandidate.getNextControlPoint(a));
|
||||
aCurrentEdge.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
|
||||
aCurrentEdge.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
|
||||
|
||||
// check if we have a trivial bezier segment -> possible fallback to edge
|
||||
aCurrentEdge.testAndSolveTrivialBezier();
|
||||
|
||||
if(aCurrentEdge.isBezier())
|
||||
{
|
||||
// update current edge (fill in C1, C2 and end point)
|
||||
double fLastDotDashMovingLength(0.0);
|
||||
const sal_uInt32 nNextIndex((a + 1) % nPointCount);
|
||||
aCurrentEdge.setControlPointA(rCandidate.getNextControlPoint(a));
|
||||
aCurrentEdge.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
|
||||
aCurrentEdge.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
|
||||
// bezier segment
|
||||
const B2DCubicBezierHelper aCubicBezierHelper(aCurrentEdge);
|
||||
const double fEdgeLength(aCubicBezierHelper.getLength());
|
||||
|
||||
// check if we have a trivial bezier segment -> possible fallback to edge
|
||||
aCurrentEdge.testAndSolveTrivialBezier();
|
||||
|
||||
if(aCurrentEdge.isBezier())
|
||||
if(!fTools::equalZero(fEdgeLength))
|
||||
{
|
||||
// bezier segment
|
||||
const B2DCubicBezierHelper aCubicBezierHelper(aCurrentEdge);
|
||||
const double fEdgeLength(aCubicBezierHelper.getLength());
|
||||
|
||||
if(!fTools::equalZero(fEdgeLength))
|
||||
while(fTools::less(fDotDashMovingLength, fEdgeLength))
|
||||
{
|
||||
while(fTools::less(fDotDashMovingLength, fEdgeLength))
|
||||
{
|
||||
// new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength]
|
||||
const bool bHandleLine(bIsLine && pLineTarget);
|
||||
const bool bHandleGap(!bIsLine && pGapTarget);
|
||||
|
||||
if(bHandleLine || bHandleGap)
|
||||
{
|
||||
const double fBezierSplitStart(aCubicBezierHelper.distanceToRelative(fLastDotDashMovingLength));
|
||||
const double fBezierSplitEnd(aCubicBezierHelper.distanceToRelative(fDotDashMovingLength));
|
||||
B2DCubicBezier aBezierSnippet(aCurrentEdge.snippet(fBezierSplitStart, fBezierSplitEnd));
|
||||
|
||||
if(!aSnippet.count())
|
||||
{
|
||||
aSnippet.append(aBezierSnippet.getStartPoint());
|
||||
}
|
||||
|
||||
aSnippet.appendBezierSegment(aBezierSnippet.getControlPointA(), aBezierSnippet.getControlPointB(), aBezierSnippet.getEndPoint());
|
||||
|
||||
if(bHandleLine)
|
||||
{
|
||||
pLineTarget->append(aSnippet);
|
||||
}
|
||||
else
|
||||
{
|
||||
pGapTarget->append(aSnippet);
|
||||
}
|
||||
|
||||
aSnippet.clear();
|
||||
}
|
||||
|
||||
// prepare next DotDashArray step and flip line/gap flag
|
||||
fLastDotDashMovingLength = fDotDashMovingLength;
|
||||
fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount];
|
||||
bIsLine = !bIsLine;
|
||||
}
|
||||
|
||||
// append closing snippet [fLastDotDashMovingLength, fEdgeLength]
|
||||
const bool bHandleLine(bIsLine && pLineTarget);
|
||||
const bool bHandleGap(!bIsLine && pGapTarget);
|
||||
// new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength]
|
||||
const bool bHandleLine(bIsLine && aLineTargetCallback);
|
||||
const bool bHandleGap(!bIsLine && aGapTargetCallback);
|
||||
|
||||
if(bHandleLine || bHandleGap)
|
||||
{
|
||||
B2DCubicBezier aRight;
|
||||
const double fBezierSplit(aCubicBezierHelper.distanceToRelative(fLastDotDashMovingLength));
|
||||
|
||||
aCurrentEdge.split(fBezierSplit, nullptr, &aRight);
|
||||
const double fBezierSplitStart(aCubicBezierHelper.distanceToRelative(fLastDotDashMovingLength));
|
||||
const double fBezierSplitEnd(aCubicBezierHelper.distanceToRelative(fDotDashMovingLength));
|
||||
B2DCubicBezier aBezierSnippet(aCurrentEdge.snippet(fBezierSplitStart, fBezierSplitEnd));
|
||||
|
||||
if(!aSnippet.count())
|
||||
{
|
||||
aSnippet.append(aRight.getStartPoint());
|
||||
aSnippet.append(aBezierSnippet.getStartPoint());
|
||||
}
|
||||
|
||||
aSnippet.appendBezierSegment(aRight.getControlPointA(), aRight.getControlPointB(), aRight.getEndPoint());
|
||||
}
|
||||
aSnippet.appendBezierSegment(aBezierSnippet.getControlPointA(), aBezierSnippet.getControlPointB(), aBezierSnippet.getEndPoint());
|
||||
|
||||
// prepare move to next edge
|
||||
fDotDashMovingLength -= fEdgeLength;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// simple edge
|
||||
const double fEdgeLength(aCurrentEdge.getEdgeLength());
|
||||
|
||||
if(!fTools::equalZero(fEdgeLength))
|
||||
{
|
||||
while(fTools::less(fDotDashMovingLength, fEdgeLength))
|
||||
{
|
||||
// new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength]
|
||||
const bool bHandleLine(bIsLine && pLineTarget);
|
||||
const bool bHandleGap(!bIsLine && pGapTarget);
|
||||
|
||||
if(bHandleLine || bHandleGap)
|
||||
if(bHandleLine)
|
||||
{
|
||||
if(!aSnippet.count())
|
||||
{
|
||||
aSnippet.append(interpolate(aCurrentEdge.getStartPoint(), aCurrentEdge.getEndPoint(), fLastDotDashMovingLength / fEdgeLength));
|
||||
}
|
||||
|
||||
aSnippet.append(interpolate(aCurrentEdge.getStartPoint(), aCurrentEdge.getEndPoint(), fDotDashMovingLength / fEdgeLength));
|
||||
|
||||
if(bHandleLine)
|
||||
{
|
||||
pLineTarget->append(aSnippet);
|
||||
}
|
||||
else
|
||||
{
|
||||
pGapTarget->append(aSnippet);
|
||||
}
|
||||
|
||||
aSnippet.clear();
|
||||
implHandleSnippet(aSnippet, aLineTargetCallback, aFirstLine, aLastLine);
|
||||
}
|
||||
|
||||
// prepare next DotDashArray step and flip line/gap flag
|
||||
fLastDotDashMovingLength = fDotDashMovingLength;
|
||||
fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount];
|
||||
bIsLine = !bIsLine;
|
||||
if(bHandleGap)
|
||||
{
|
||||
implHandleSnippet(aSnippet, aGapTargetCallback, aFirstGap, aLastGap);
|
||||
}
|
||||
|
||||
aSnippet.clear();
|
||||
}
|
||||
|
||||
// append snippet [fLastDotDashMovingLength, fEdgeLength]
|
||||
const bool bHandleLine(bIsLine && pLineTarget);
|
||||
const bool bHandleGap(!bIsLine && pGapTarget);
|
||||
// prepare next DotDashArray step and flip line/gap flag
|
||||
fLastDotDashMovingLength = fDotDashMovingLength;
|
||||
fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount];
|
||||
bIsLine = !bIsLine;
|
||||
}
|
||||
|
||||
// append closing snippet [fLastDotDashMovingLength, fEdgeLength]
|
||||
const bool bHandleLine(bIsLine && aLineTargetCallback);
|
||||
const bool bHandleGap(!bIsLine && aGapTargetCallback);
|
||||
|
||||
if(bHandleLine || bHandleGap)
|
||||
{
|
||||
B2DCubicBezier aRight;
|
||||
const double fBezierSplit(aCubicBezierHelper.distanceToRelative(fLastDotDashMovingLength));
|
||||
|
||||
aCurrentEdge.split(fBezierSplit, nullptr, &aRight);
|
||||
|
||||
if(!aSnippet.count())
|
||||
{
|
||||
aSnippet.append(aRight.getStartPoint());
|
||||
}
|
||||
|
||||
aSnippet.appendBezierSegment(aRight.getControlPointA(), aRight.getControlPointB(), aRight.getEndPoint());
|
||||
}
|
||||
|
||||
// prepare move to next edge
|
||||
fDotDashMovingLength -= fEdgeLength;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// simple edge
|
||||
const double fEdgeLength(aCurrentEdge.getEdgeLength());
|
||||
|
||||
if(!fTools::equalZero(fEdgeLength))
|
||||
{
|
||||
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);
|
||||
|
||||
if(bHandleLine || bHandleGap)
|
||||
{
|
||||
@ -1276,88 +1350,75 @@ namespace basegfx::utils
|
||||
aSnippet.append(interpolate(aCurrentEdge.getStartPoint(), aCurrentEdge.getEndPoint(), fLastDotDashMovingLength / fEdgeLength));
|
||||
}
|
||||
|
||||
aSnippet.append(aCurrentEdge.getEndPoint());
|
||||
aSnippet.append(interpolate(aCurrentEdge.getStartPoint(), aCurrentEdge.getEndPoint(), fDotDashMovingLength / fEdgeLength));
|
||||
|
||||
if(bHandleLine)
|
||||
{
|
||||
implHandleSnippet(aSnippet, aLineTargetCallback, aFirstLine, aLastLine);
|
||||
}
|
||||
|
||||
if(bHandleGap)
|
||||
{
|
||||
implHandleSnippet(aSnippet, aGapTargetCallback, aFirstGap, aLastGap);
|
||||
}
|
||||
|
||||
aSnippet.clear();
|
||||
}
|
||||
|
||||
// prepare move to next edge
|
||||
fDotDashMovingLength -= fEdgeLength;
|
||||
// prepare next DotDashArray step and flip line/gap flag
|
||||
fLastDotDashMovingLength = fDotDashMovingLength;
|
||||
fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount];
|
||||
bIsLine = !bIsLine;
|
||||
}
|
||||
}
|
||||
|
||||
// prepare next edge step (end point gets new start point)
|
||||
aCurrentEdge.setStartPoint(aCurrentEdge.getEndPoint());
|
||||
}
|
||||
// append snippet [fLastDotDashMovingLength, fEdgeLength]
|
||||
const bool bHandleLine(bIsLine && aLineTargetCallback);
|
||||
const bool bHandleGap(!bIsLine && aGapTargetCallback);
|
||||
|
||||
// append last intermediate results (if exists)
|
||||
if(aSnippet.count())
|
||||
{
|
||||
if(bIsLine && pLineTarget)
|
||||
{
|
||||
pLineTarget->append(aSnippet);
|
||||
}
|
||||
else if(!bIsLine && pGapTarget)
|
||||
{
|
||||
pGapTarget->append(aSnippet);
|
||||
}
|
||||
}
|
||||
|
||||
// check if start and end polygon may be merged
|
||||
if(pLineTarget)
|
||||
{
|
||||
const sal_uInt32 nCount(pLineTarget->count());
|
||||
|
||||
if(nCount > 1)
|
||||
{
|
||||
// these polygons were created above, there exists none with less than two points,
|
||||
// thus direct point access below is allowed
|
||||
const B2DPolygon aFirst(pLineTarget->getB2DPolygon(0));
|
||||
B2DPolygon aLast(pLineTarget->getB2DPolygon(nCount - 1));
|
||||
|
||||
if(aFirst.getB2DPoint(0).equal(aLast.getB2DPoint(aLast.count() - 1)))
|
||||
if(bHandleLine || bHandleGap)
|
||||
{
|
||||
// start of first and end of last are the same -> merge them
|
||||
aLast.append(aFirst);
|
||||
aLast.removeDoublePoints();
|
||||
pLineTarget->setB2DPolygon(0, aLast);
|
||||
pLineTarget->remove(nCount - 1);
|
||||
if(!aSnippet.count())
|
||||
{
|
||||
aSnippet.append(interpolate(aCurrentEdge.getStartPoint(), aCurrentEdge.getEndPoint(), fLastDotDashMovingLength / fEdgeLength));
|
||||
}
|
||||
|
||||
aSnippet.append(aCurrentEdge.getEndPoint());
|
||||
}
|
||||
|
||||
// prepare move to next edge
|
||||
fDotDashMovingLength -= fEdgeLength;
|
||||
}
|
||||
}
|
||||
|
||||
if(pGapTarget)
|
||||
// prepare next edge step (end point gets new start point)
|
||||
aCurrentEdge.setStartPoint(aCurrentEdge.getEndPoint());
|
||||
}
|
||||
|
||||
// append last intermediate results (if exists)
|
||||
if(aSnippet.count())
|
||||
{
|
||||
const bool bHandleLine(bIsLine && aLineTargetCallback);
|
||||
const bool bHandleGap(!bIsLine && aGapTargetCallback);
|
||||
|
||||
if(bHandleLine)
|
||||
{
|
||||
const sal_uInt32 nCount(pGapTarget->count());
|
||||
implHandleSnippet(aSnippet, aLineTargetCallback, aFirstLine, aLastLine);
|
||||
}
|
||||
|
||||
if(nCount > 1)
|
||||
{
|
||||
// these polygons were created above, there exists none with less than two points,
|
||||
// thus direct point access below is allowed
|
||||
const B2DPolygon aFirst(pGapTarget->getB2DPolygon(0));
|
||||
B2DPolygon aLast(pGapTarget->getB2DPolygon(nCount - 1));
|
||||
|
||||
if(aFirst.getB2DPoint(0).equal(aLast.getB2DPoint(aLast.count() - 1)))
|
||||
{
|
||||
// start of first and end of last are the same -> merge them
|
||||
aLast.append(aFirst);
|
||||
aLast.removeDoublePoints();
|
||||
pGapTarget->setB2DPolygon(0, aLast);
|
||||
pGapTarget->remove(nCount - 1);
|
||||
}
|
||||
}
|
||||
if(bHandleGap)
|
||||
{
|
||||
implHandleSnippet(aSnippet, aGapTargetCallback, aFirstGap, aLastGap);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// parameters make no sense, just add source to targets
|
||||
if(pLineTarget)
|
||||
{
|
||||
pLineTarget->append(rCandidate);
|
||||
}
|
||||
|
||||
if(pGapTarget)
|
||||
{
|
||||
pGapTarget->append(rCandidate);
|
||||
}
|
||||
if(bIsClosed && aLineTargetCallback)
|
||||
{
|
||||
implHandleFirstLast(aLineTargetCallback, aFirstLine, aLastLine);
|
||||
}
|
||||
|
||||
if(bIsClosed && aGapTargetCallback)
|
||||
{
|
||||
implHandleFirstLast(aGapTargetCallback, aFirstGap, aLastGap);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,9 @@
|
||||
#ifndef INCLUDED_BASEGFX_POLYGON_B2DPOLYGONTOOLS_HXX
|
||||
#define INCLUDED_BASEGFX_POLYGON_B2DPOLYGONTOOLS_HXX
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
#include <basegfx/point/b2dpoint.hxx>
|
||||
#include <basegfx/vector/b2dvector.hxx>
|
||||
#include <basegfx/range/b2drectangle.hxx>
|
||||
@ -27,7 +30,6 @@
|
||||
#include <basegfx/polygon/b2dpolygontriangulator.hxx>
|
||||
#include <com/sun/star/drawing/PointSequence.hpp>
|
||||
#include <com/sun/star/drawing/FlagSequence.hpp>
|
||||
#include <vector>
|
||||
#include <basegfx/basegfxdllapi.h>
|
||||
#include <o3tl/typed_flags_set.hxx>
|
||||
|
||||
@ -188,7 +190,27 @@ namespace basegfx
|
||||
@param fFullDashDotLen
|
||||
The summed-up length of the rDotDashArray. If zero, it will
|
||||
be calculated internally.
|
||||
|
||||
There is now a 2nd version that allows to provide callback
|
||||
functions that get called when a snippet of a line/gap is
|
||||
produced and needs to be added. This allows to use it like
|
||||
a 'pipeline'. When using this (e.g. the 1st version uses
|
||||
this internally to guarantee the same algorithm is used)
|
||||
it is not needed to accumulate a potentially huge number
|
||||
of polygons in the result-polyPolygons, but e.g. consume
|
||||
them directly in the caller. Example is renderinmg a
|
||||
dashed line but without creating the potentially huge amount
|
||||
of polygons.
|
||||
The 2nd version will also merge first/last line/gap snippets
|
||||
if the input polygon is closed and the start/end-points match
|
||||
accordingly - at the cost that this will be delivered last.
|
||||
*/
|
||||
BASEGFX_DLLPUBLIC 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 = std::function<void(const basegfx::B2DPolygon&)>(),
|
||||
double fDotDashLength = 0.0);
|
||||
BASEGFX_DLLPUBLIC void applyLineDashing(
|
||||
const B2DPolygon& rCandidate,
|
||||
const ::std::vector<double>& rDotDashArray,
|
||||
|
Loading…
x
Reference in New Issue
Block a user