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:
committed by
Armin Le Grand
parent
75500a4161
commit
0dc4fddb9c
@@ -1110,19 +1110,14 @@ 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)
|
||||
{
|
||||
const sal_uInt32 nPointCount(rCandidate.count());
|
||||
const sal_uInt32 nDotDashCount(rDotDashArray.size());
|
||||
|
||||
if(fTools::lessOrEqual(fDotDashLength, 0.0))
|
||||
{
|
||||
fDotDashLength = std::accumulate(rDotDashArray.begin(), rDotDashArray.end(), 0.0);
|
||||
}
|
||||
|
||||
if(fTools::more(fDotDashLength, 0.0) && (pLineTarget || pGapTarget) && nPointCount)
|
||||
{
|
||||
// clear targets
|
||||
// clear targets in any case
|
||||
if(pLineTarget)
|
||||
{
|
||||
pLineTarget->clear();
|
||||
@@ -1133,9 +1128,113 @@ namespace basegfx::utils
|
||||
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());
|
||||
|
||||
if(fTools::lessOrEqual(fDotDashLength, 0.0))
|
||||
{
|
||||
fDotDashLength = std::accumulate(rDotDashArray.begin(), rDotDashArray.end(), 0.0);
|
||||
}
|
||||
|
||||
if(fTools::lessOrEqual(fDotDashLength, 0.0) || (!aLineTargetCallback && !aGapTargetCallback) || !nPointCount)
|
||||
{
|
||||
// parameters make no sense, just add source to targets
|
||||
if(aLineTargetCallback)
|
||||
{
|
||||
aLineTargetCallback(rCandidate);
|
||||
}
|
||||
|
||||
if(aGapTargetCallback)
|
||||
{
|
||||
aGapTargetCallback(rCandidate);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// prepare current edge's start
|
||||
B2DCubicBezier aCurrentEdge;
|
||||
const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
|
||||
const bool bIsClosed(rCandidate.isClosed());
|
||||
const sal_uInt32 nEdgeCount(bIsClosed ? nPointCount : nPointCount - 1);
|
||||
aCurrentEdge.setStartPoint(rCandidate.getB2DPoint(0));
|
||||
|
||||
// prepare DotDashArray iteration and the line/gap switching bool
|
||||
@@ -1144,6 +1243,11 @@ namespace basegfx::utils
|
||||
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++)
|
||||
{
|
||||
@@ -1168,8 +1272,8 @@ namespace basegfx::utils
|
||||
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);
|
||||
const bool bHandleLine(bIsLine && aLineTargetCallback);
|
||||
const bool bHandleGap(!bIsLine && aGapTargetCallback);
|
||||
|
||||
if(bHandleLine || bHandleGap)
|
||||
{
|
||||
@@ -1186,11 +1290,12 @@ namespace basegfx::utils
|
||||
|
||||
if(bHandleLine)
|
||||
{
|
||||
pLineTarget->append(aSnippet);
|
||||
implHandleSnippet(aSnippet, aLineTargetCallback, aFirstLine, aLastLine);
|
||||
}
|
||||
else
|
||||
|
||||
if(bHandleGap)
|
||||
{
|
||||
pGapTarget->append(aSnippet);
|
||||
implHandleSnippet(aSnippet, aGapTargetCallback, aFirstGap, aLastGap);
|
||||
}
|
||||
|
||||
aSnippet.clear();
|
||||
@@ -1203,8 +1308,8 @@ namespace basegfx::utils
|
||||
}
|
||||
|
||||
// append closing snippet [fLastDotDashMovingLength, fEdgeLength]
|
||||
const bool bHandleLine(bIsLine && pLineTarget);
|
||||
const bool bHandleGap(!bIsLine && pGapTarget);
|
||||
const bool bHandleLine(bIsLine && aLineTargetCallback);
|
||||
const bool bHandleGap(!bIsLine && aGapTargetCallback);
|
||||
|
||||
if(bHandleLine || bHandleGap)
|
||||
{
|
||||
@@ -1235,8 +1340,8 @@ namespace basegfx::utils
|
||||
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);
|
||||
const bool bHandleLine(bIsLine && aLineTargetCallback);
|
||||
const bool bHandleGap(!bIsLine && aGapTargetCallback);
|
||||
|
||||
if(bHandleLine || bHandleGap)
|
||||
{
|
||||
@@ -1249,11 +1354,12 @@ namespace basegfx::utils
|
||||
|
||||
if(bHandleLine)
|
||||
{
|
||||
pLineTarget->append(aSnippet);
|
||||
implHandleSnippet(aSnippet, aLineTargetCallback, aFirstLine, aLastLine);
|
||||
}
|
||||
else
|
||||
|
||||
if(bHandleGap)
|
||||
{
|
||||
pGapTarget->append(aSnippet);
|
||||
implHandleSnippet(aSnippet, aGapTargetCallback, aFirstGap, aLastGap);
|
||||
}
|
||||
|
||||
aSnippet.clear();
|
||||
@@ -1266,8 +1372,8 @@ namespace basegfx::utils
|
||||
}
|
||||
|
||||
// append snippet [fLastDotDashMovingLength, fEdgeLength]
|
||||
const bool bHandleLine(bIsLine && pLineTarget);
|
||||
const bool bHandleGap(!bIsLine && pGapTarget);
|
||||
const bool bHandleLine(bIsLine && aLineTargetCallback);
|
||||
const bool bHandleGap(!bIsLine && aGapTargetCallback);
|
||||
|
||||
if(bHandleLine || bHandleGap)
|
||||
{
|
||||
@@ -1291,73 +1397,28 @@ namespace basegfx::utils
|
||||
// append last intermediate results (if exists)
|
||||
if(aSnippet.count())
|
||||
{
|
||||
if(bIsLine && pLineTarget)
|
||||
const bool bHandleLine(bIsLine && aLineTargetCallback);
|
||||
const bool bHandleGap(!bIsLine && aGapTargetCallback);
|
||||
|
||||
if(bHandleLine)
|
||||
{
|
||||
pLineTarget->append(aSnippet);
|
||||
implHandleSnippet(aSnippet, aLineTargetCallback, aFirstLine, aLastLine);
|
||||
}
|
||||
else if(!bIsLine && pGapTarget)
|
||||
|
||||
if(bHandleGap)
|
||||
{
|
||||
pGapTarget->append(aSnippet);
|
||||
implHandleSnippet(aSnippet, aGapTargetCallback, aFirstGap, aLastGap);
|
||||
}
|
||||
}
|
||||
|
||||
// check if start and end polygon may be merged
|
||||
if(pLineTarget)
|
||||
if(bIsClosed && aLineTargetCallback)
|
||||
{
|
||||
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)))
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
implHandleFirstLast(aLineTargetCallback, aFirstLine, aLastLine);
|
||||
}
|
||||
|
||||
if(pGapTarget)
|
||||
if(bIsClosed && aGapTargetCallback)
|
||||
{
|
||||
const sal_uInt32 nCount(pGapTarget->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(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// parameters make no sense, just add source to targets
|
||||
if(pLineTarget)
|
||||
{
|
||||
pLineTarget->append(rCandidate);
|
||||
}
|
||||
|
||||
if(pGapTarget)
|
||||
{
|
||||
pGapTarget->append(rCandidate);
|
||||
}
|
||||
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,
|
||||
|
Reference in New Issue
Block a user