26#include <rtl/ustring.hxx>
28#include <rtl/math.hxx>
29#include <rtl/character.hxx>
35void putCommandChar(OUStringBuffer& rBuffer,
sal_Unicode& rLastSVGCommand,
sal_Unicode aChar,
bool bToLower,
bool bVerbose)
39 if (bVerbose && rBuffer.getLength())
42 if (bVerbose || rLastSVGCommand != aCommand)
44 rBuffer.append(aCommand);
49void putNumberChar(OUStringBuffer& rStr,
double fValue,
double fOldValue,
bool bUseRelativeCoordinates,
bool bVerbose)
51 if (bUseRelativeCoordinates)
54 const sal_Int32 aLen(rStr.getLength());
77 std::u16string_view rSvgDStatement,
78 bool bHandleRelativeNextPointCompatible,
81 o_rPolyPolygon.
clear();
82 const sal_Int32 nLen(rSvgDStatement.size());
93 bool bRelative(
false);
96 if(o_rPolyPolygon.
count() && !aCurrPoly.
count() && aCurrChar !=
'm' && aCurrChar !=
'M')
114 if(aCurrPoly.
count())
116 if(!bHandleRelativeNextPointCompatible)
126 o_rPolyPolygon.
append(aCurrPoly);
137 if(aCurrPoly.
count())
139 o_rPolyPolygon.
append(aCurrPoly);
147 if(aCurrChar ==
'm' || aCurrChar ==
'l')
191 double nX, nY(nLastY);
221 double nX(nLastX), nY;
268 if(!aCurrPoly.
count())
275 B2DPoint aPrevControl(nLastX, nLastY);
284 aPrevControl.
setX((2.0 * aPrevPoint.
getX()) - aPrevControlPoint.
getX());
285 aPrevControl.
setY((2.0 * aPrevPoint.
getY()) - aPrevControlPoint.
getY());
332 if(!aCurrPoly.
count())
377 if(!aCurrPoly.
count())
417 if(!aCurrPoly.
count())
424 B2DPoint aPrevControl(nLastX, nLastY);
433 aPrevControl.
setX((2.0 * aPrevPoint.
getX()) - aPrevControlPoint.
getX());
434 aPrevControl.
setY((2.0 * aPrevPoint.
getY()) - aPrevControlPoint.
getY());
437 if(!aPrevControl.
equal(aPrevPoint))
443 ((3.0 * aPrevControl.
getX()) - aPrevPoint.
getX()) / 2.0,
444 ((3.0 * aPrevControl.
getY()) - aPrevPoint.
getY()) / 2.0);
447 const double nX2Prime((aQuadControlPoint.
getX() * 2.0 + nX) / 3.0);
448 const double nY2Prime((aQuadControlPoint.
getY() * 2.0 + nY) / 3.0);
480 double fRX, fRY, fPhi;
481 sal_Int32 bLargeArcFlag, bSweepFlag;
497 if( rtl::math::approxEqual(nX, nLastX) && rtl::math::approxEqual(nY, nLastY) )
500 if( fRX == 0.0 || fRY == 0.0 )
508 fRX=fabs(fRX); fRY=fabs(fRY);
528 const double fRadicant(
529 (fRX*fRX*fRY*fRY - fRX*fRX*p1_prime.
getY()*p1_prime.
getY() - fRY*fRY*p1_prime.
getX()*p1_prime.
getX())/
530 (fRX*fRX*p1_prime.
getY()*p1_prime.
getY() + fRY*fRY*p1_prime.
getX()*p1_prime.
getX()));
531 if( fRadicant < 0.0 )
539 const double fRatio(fRX/fRY);
540 const double fRadicant2(
542 p1_prime.
getX()*p1_prime.
getX()/(fRatio*fRatio));
543 if( fRadicant2 < 0.0 )
553 fRY=sqrt(fRadicant2);
560 const double fFactor(
561 (bLargeArcFlag==bSweepFlag ? -1.0 : 1.0) *
566 fFactor*fRX*p1_prime.
getY()/fRY,
567 -fFactor*fRY*p1_prime.
getX()/fRX);
580 (p1_prime-aCenter_prime)/aRadii));
587 (-p1_prime-aCenter_prime)/aRadii));
590 fTheta1 = fmod(2*M_PI+fTheta1,2*M_PI);
591 fTheta2 = fmod(2*M_PI+fTheta2,2*M_PI);
598 std::swap(fTheta1,fTheta2);
608 aCenter_prime.
getY());
610 const B2DPoint aOffset((p1+p2)/2.0);
623 sal_uInt32 nPointIndex(aCurrPoly.
count() + 1);
624 aCurrPoly.
append(aSegment);
628 if(pHelpPointIndexSet && aCurrPoly.
count() > 1)
630 const sal_uInt32 nPolyIndex(o_rPolyPolygon.
count());
632 for(;nPointIndex + 1 < aCurrPoly.
count(); nPointIndex++)
648 SAL_WARN(
"basegfx",
"importFromSvgD(): skipping tags in svg:d element (unknown: \""
649 << OUString(aCurrChar)
658 if(aCurrPoly.
count())
660 o_rPolyPolygon.
append(aCurrPoly);
667 std::u16string_view rSvgPointsAttribute )
670 const sal_Int32 nLen(rSvgPointsAttribute.size());
695 const sal_uInt32 nPointCount(rPoly.
count());
696 OUStringBuffer aResult;
698 for(sal_uInt32
a(0);
a < nPointCount;
a++)
707 aResult.append(OUString::number(aPoint.
getX())
709 + OUString::number(aPoint.
getY()));
712 return aResult.makeStringAndClear();
717 bool bUseRelativeCoordinates,
718 bool bDetectQuadraticBeziers,
719 bool bHandleRelativeNextPointCompatible,
720 bool bOOXMLMotionPath)
723 sal_uInt32 nCombinedPointCount = 0;
727 nCombinedPointCount += aPolygon.
count();
730 OUStringBuffer aResult(std::max<int>(nCombinedPointCount * 32,512));
731 B2DPoint aCurrentSVGPosition(0.0, 0.0);
736 const sal_uInt32 nPointCount(aPolygon.
count());
741 const sal_uInt32 nEdgeCount(aPolygon.
isClosed() ? nPointCount : nPointCount - 1);
747 bool bUseRelativeCoordinatesForFirstPoint(bUseRelativeCoordinates);
749 if(bHandleRelativeNextPointCompatible)
754 bUseRelativeCoordinatesForFirstPoint =
false;
758 putCommandChar(aResult, aLastSVGCommand,
'M', bUseRelativeCoordinatesForFirstPoint, bOOXMLMotionPath);
759 putNumberChar(aResult, aEdgeStart.
getX(), aCurrentSVGPosition.
getX(), bUseRelativeCoordinatesForFirstPoint, bOOXMLMotionPath);
760 putNumberChar(aResult, aEdgeStart.
getY(), aCurrentSVGPosition.
getY(), bUseRelativeCoordinatesForFirstPoint, bOOXMLMotionPath);
761 aLastSVGCommand = bUseRelativeCoordinatesForFirstPoint ?
'l' :
'L';
762 aCurrentSVGPosition = aEdgeStart;
767 const sal_uInt32 nNextIndex((
nIndex + 1) % nPointCount);
771 const bool bEdgeIsBezier(bPolyUsesControlPoints
779 bool bIsQuadraticBezier(
false);
792 const bool bSymmetricAtEdgeStart(
793 !bOOXMLMotionPath &&
nIndex != 0
796 if(bDetectQuadraticBeziers)
805 aLeft =
B2DPoint((3.0 * aControlEdgeStart - aEdgeStart) / 2.0);
806 aRight=
B2DPoint((3.0 * aControlEdgeEnd - aEdgeEnd) / 2.0);
807 bIsQuadraticBezier = aLeft.
equal(aRight);
810 if(bIsQuadraticBezier)
813 if(bSymmetricAtEdgeStart)
815 putCommandChar(aResult, aLastSVGCommand,
'T', bUseRelativeCoordinates, bOOXMLMotionPath);
817 putNumberChar(aResult, aEdgeEnd.
getX(), aCurrentSVGPosition.
getX(), bUseRelativeCoordinates, bOOXMLMotionPath);
818 putNumberChar(aResult, aEdgeEnd.
getY(), aCurrentSVGPosition.
getY(), bUseRelativeCoordinates, bOOXMLMotionPath);
819 aCurrentSVGPosition = aEdgeEnd;
823 putCommandChar(aResult, aLastSVGCommand,
'Q', bUseRelativeCoordinates, bOOXMLMotionPath);
825 putNumberChar(aResult, aLeft.
getX(), aCurrentSVGPosition.
getX(), bUseRelativeCoordinates, bOOXMLMotionPath);
826 putNumberChar(aResult, aLeft.
getY(), aCurrentSVGPosition.
getY(), bUseRelativeCoordinates, bOOXMLMotionPath);
827 putNumberChar(aResult, aEdgeEnd.
getX(), aCurrentSVGPosition.
getX(), bUseRelativeCoordinates, bOOXMLMotionPath);
828 putNumberChar(aResult, aEdgeEnd.
getY(), aCurrentSVGPosition.
getY(), bUseRelativeCoordinates, bOOXMLMotionPath);
829 aCurrentSVGPosition = aEdgeEnd;
835 if(bSymmetricAtEdgeStart)
837 putCommandChar(aResult, aLastSVGCommand,
'S', bUseRelativeCoordinates, bOOXMLMotionPath);
839 putNumberChar(aResult, aControlEdgeEnd.
getX(), aCurrentSVGPosition.
getX(), bUseRelativeCoordinates, bOOXMLMotionPath);
840 putNumberChar(aResult, aControlEdgeEnd.
getY(), aCurrentSVGPosition.
getY(), bUseRelativeCoordinates, bOOXMLMotionPath);
841 putNumberChar(aResult, aEdgeEnd.
getX(), aCurrentSVGPosition.
getX(), bUseRelativeCoordinates, bOOXMLMotionPath);
842 putNumberChar(aResult, aEdgeEnd.
getY(), aCurrentSVGPosition.
getY(), bUseRelativeCoordinates, bOOXMLMotionPath);
843 aCurrentSVGPosition = aEdgeEnd;
847 putCommandChar(aResult, aLastSVGCommand,
'C', bUseRelativeCoordinates, bOOXMLMotionPath);
849 putNumberChar(aResult, aControlEdgeStart.
getX(), aCurrentSVGPosition.
getX(), bUseRelativeCoordinates, bOOXMLMotionPath);
850 putNumberChar(aResult, aControlEdgeStart.
getY(), aCurrentSVGPosition.
getY(), bUseRelativeCoordinates, bOOXMLMotionPath);
851 putNumberChar(aResult, aControlEdgeEnd.
getX(), aCurrentSVGPosition.
getX(), bUseRelativeCoordinates, bOOXMLMotionPath);
852 putNumberChar(aResult, aControlEdgeEnd.
getY(), aCurrentSVGPosition.
getY(), bUseRelativeCoordinates, bOOXMLMotionPath);
853 putNumberChar(aResult, aEdgeEnd.
getX(), aCurrentSVGPosition.
getX(), bUseRelativeCoordinates, bOOXMLMotionPath);
854 putNumberChar(aResult, aEdgeEnd.
getY(), aCurrentSVGPosition.
getY(), bUseRelativeCoordinates, bOOXMLMotionPath);
855 aCurrentSVGPosition = aEdgeEnd;
869 const bool bXEqual(rtl::math::approxEqual(aEdgeStart.
getX(), aEdgeEnd.
getX()));
870 const bool bYEqual(rtl::math::approxEqual(aEdgeStart.
getY(), aEdgeEnd.
getY()));
872 if(bXEqual && bYEqual)
876 else if(bXEqual && !bOOXMLMotionPath)
879 putCommandChar(aResult, aLastSVGCommand,
'V', bUseRelativeCoordinates, bOOXMLMotionPath);
881 putNumberChar(aResult, aEdgeEnd.
getY(), aCurrentSVGPosition.
getY(), bUseRelativeCoordinates, bOOXMLMotionPath);
882 aCurrentSVGPosition = aEdgeEnd;
884 else if(bYEqual && !bOOXMLMotionPath)
887 putCommandChar(aResult, aLastSVGCommand,
'H', bUseRelativeCoordinates, bOOXMLMotionPath);
889 putNumberChar(aResult, aEdgeEnd.
getX(), aCurrentSVGPosition.
getX(), bUseRelativeCoordinates, bOOXMLMotionPath);
890 aCurrentSVGPosition = aEdgeEnd;
895 putCommandChar(aResult, aLastSVGCommand,
'L', bUseRelativeCoordinates, bOOXMLMotionPath);
897 putNumberChar(aResult, aEdgeEnd.
getX(), aCurrentSVGPosition.
getX(), bUseRelativeCoordinates, bOOXMLMotionPath);
898 putNumberChar(aResult, aEdgeEnd.
getY(), aCurrentSVGPosition.
getY(), bUseRelativeCoordinates, bOOXMLMotionPath);
899 aCurrentSVGPosition = aEdgeEnd;
905 aEdgeStart = aEdgeEnd;
911 putCommandChar(aResult, aLastSVGCommand,
'Z', bUseRelativeCoordinates, bOOXMLMotionPath);
913 else if (bOOXMLMotionPath)
915 putCommandChar(aResult, aLastSVGCommand,
'E', bUseRelativeCoordinates, bOOXMLMotionPath);
918 if(!bHandleRelativeNextPointCompatible)
927 return aResult.makeStringAndClear();
void rotate(double fRadiant)
void translate(double fX, double fY)
Base Point class with two double values.
B2DPolygon const & getB2DPolygon(sal_uInt32 nIndex) const
void append(const B2DPolygon &rPolygon, sal_uInt32 nCount=1)
bool isPrevControlPointUsed(sal_uInt32 nIndex) const
bool isNextControlPointUsed(sal_uInt32 nIndex) const
void clear()
clear all points
void appendQuadraticBezierSegment(const basegfx::B2DPoint &rQuadControlPoint, const basegfx::B2DPoint &rPoint)
This is a shortcut to append a quadratic bezier segment.
bool isClosed() const
closed state interface
basegfx::B2DPoint const & getB2DPoint(sal_uInt32 nIndex) const
Coordinate interface.
void transform(const basegfx::B2DHomMatrix &rMatrix)
apply transformation given in matrix form
basegfx::B2DPoint getPrevControlPoint(sal_uInt32 nIndex) const
Basic ControlPoint interface.
bool areControlPointsUsed() const
ControlPoint checks.
B2VectorContinuity getContinuityInPoint(sal_uInt32 nIndex) const
void append(const basegfx::B2DPoint &rPoint, sal_uInt32 nCount)
sal_uInt32 count() const
member count
void setClosed(bool bNew)
basegfx::B2DPoint getNextControlPoint(sal_uInt32 nIndex) const
void flip()
flip polygon direction
void appendBezierSegment(const basegfx::B2DPoint &rNextControlPoint, const basegfx::B2DPoint &rPrevControlPoint, const basegfx::B2DPoint &rPoint)
Bezier segment append with control points. The current last polygon point is implicitly taken as star...
Base Point class with two double values.
bool equal(const Tuple2D< TYPE > &rTup) const
TYPE getX() const
Get X-Coordinate of 2D Tuple.
void setY(TYPE fY)
Set Y-Coordinate of 2D Tuple.
TYPE getY() const
Get Y-Coordinate of 2D Tuple.
void setX(TYPE fX)
Set X-Coordinate of 2D Tuple.
Helper class to transport PointIndices to a PolyPolygon, with an operator< for convenient sorting in ...
sal_uInt32 getPolygonIndex() const
sal_uInt32 getPointIndex() const
bool operator<(const PointIndex &rComp) const
std::pair< const_iterator, bool > insert(Value &&x)
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
void skipSpaces(sal_Int32 &io_rPos, std::u16string_view rStr, const sal_Int32 nLen)
bool importFlagAndSpaces(sal_Int32 &o_nRetval, sal_Int32 &io_rPos, std::u16string_view rStr, const sal_Int32 nLen)
bool importDoubleAndSpaces(double &o_fRetval, sal_Int32 &io_rPos, std::u16string_view rStr, const sal_Int32 nLen)
bool isOnNumberChar(const sal_Unicode aChar, bool bSignAllowed)
bool importFromSvgPoints(B2DPolygon &o_rPoly, std::u16string_view rSvgPointsAttribute)
Read poly-polygon from SVG.
OUString exportToSvgD(const B2DPolyPolygon &rPolyPolygon, bool bUseRelativeCoordinates, bool bDetectQuadraticBeziers, bool bHandleRelativeNextPointCompatible, bool bOOXMLMotionPath)
Export poly-polygon to SVG.
B2DHomMatrix createScaleB2DHomMatrix(double fScaleX, double fScaleY)
Tooling methods for on-the-fly matrix generation e.g.
OUString exportToSvgPoints(const B2DPolygon &rPoly)
Write poly-polygon to SVG.
bool importFromSvgD(B2DPolyPolygon &o_rPolyPolygon, std::u16string_view rSvgDStatement, bool bHandleRelativeNextPointCompatible, PointIndexSet *pHelpPointIndexSet)
Read poly-polygon from SVG.
B2DHomMatrix createRotateB2DHomMatrix(double fRadiant)
B2DPolygon createPolygonFromUnitEllipseSegment(double fStart, double fEnd)
@ C2
mathematically neutral, thus parallel
constexpr double deg2rad(double v)
Convert value from degrees to radians.