diff options
author | Regina Henschel <rb.henschel@t-online.de> | 2018-12-15 17:51:25 +0100 |
---|---|---|
committer | Regina Henschel <rb.henschel@t-online.de> | 2018-12-23 22:42:11 +0100 |
commit | a4c46ceec433edf0c5de03ea8d36857a455cafd2 (patch) | |
tree | f91219d16a75f38f27c3910e0e0aeaa52c04e796 /svx/source | |
parent | 721bc6dafbed2185a9aedae35a34d3395eaed0bc (diff) |
tdf#121761, tdf#121952 Accurate ellipsequadrant in custom shape
The current solution uses one, bad valued Bezier curve and does not
toggle direction. The patch uses the more accurate solution from
basegfx and simplifies the decision tree. In addition it extracts the
calculation in double from GetPoint, so they can be used directly
instead of double->long->double conversion.
Change-Id: I298f49415d1b7624b36ca561647f2e58af5eb5c6
Reviewed-on: https://gerrit.libreoffice.org/65203
Tested-by: Jenkins
Reviewed-by: Regina Henschel <rb.henschel@t-online.de>
Diffstat (limited to 'svx/source')
-rw-r--r-- | svx/source/customshapes/EnhancedCustomShape2d.cxx | 189 |
1 files changed, 104 insertions, 85 deletions
diff --git a/svx/source/customshapes/EnhancedCustomShape2d.cxx b/svx/source/customshapes/EnhancedCustomShape2d.cxx index 12448ca95054..c01c49949f94 100644 --- a/svx/source/customshapes/EnhancedCustomShape2d.cxx +++ b/svx/source/customshapes/EnhancedCustomShape2d.cxx @@ -917,40 +917,32 @@ bool EnhancedCustomShape2d::SetAdjustValueAsDouble( const double& rValue, const return bRetValue; } -Point EnhancedCustomShape2d::GetPoint( const css::drawing::EnhancedCustomShapeParameterPair& rPair, +basegfx::B2DPoint EnhancedCustomShape2d::GetPointAsB2DPoint( const css::drawing::EnhancedCustomShapeParameterPair& rPair, const bool bScale, const bool bReplaceGeoSize ) const { - Point aRetValue; - sal_uInt32 nPass = 0; - do + double fValX, fValY; + // width + GetParameter(fValX, rPair.First, bReplaceGeoSize, false); + fValX -= nCoordLeft; + if (bScale) { - sal_uInt32 nIndex = nPass; - - double fVal; - const EnhancedCustomShapeParameter& rParameter = nIndex ? rPair.Second : rPair.First; - if ( nPass ) // height - { - GetParameter( fVal, rParameter, false, bReplaceGeoSize ); - fVal -= nCoordTop; - if ( bScale ) - { - fVal *= fYScale; - } - aRetValue.setY( static_cast<sal_Int32>(fVal) ); - } - else // width - { - GetParameter( fVal, rParameter, bReplaceGeoSize, false ); - fVal -= nCoordLeft; - if ( bScale ) - { - fVal *= fXScale; - } - aRetValue.setX( static_cast<long>(fVal) ); - } + fValX *= fXScale; } - while ( ++nPass < 2 ); - return aRetValue; + // height + GetParameter(fValY, rPair.Second, false, bReplaceGeoSize); + fValY -= nCoordTop; + if (bScale) + { + fValY *= fYScale; + } + return basegfx::B2DPoint(fValX,fValY); +} + +Point EnhancedCustomShape2d::GetPoint( const css::drawing::EnhancedCustomShapeParameterPair& rPair, + const bool bScale, const bool bReplaceGeoSize ) const +{ + basegfx::B2DPoint aPoint(GetPointAsB2DPoint(rPair, bScale, bReplaceGeoSize)); + return Point(static_cast<long>(aPoint.getX()), static_cast<long>(aPoint.getY())); } void EnhancedCustomShape2d::GetParameter( double& rRetValue, const EnhancedCustomShapeParameter& rParameter, @@ -1841,69 +1833,96 @@ void EnhancedCustomShape2d::CreateSubPath( case ELLIPTICALQUADRANTX : case ELLIPTICALQUADRANTY : { - bool bFirstDirection(true); - basegfx::B2DPoint aControlPointA; - basegfx::B2DPoint aControlPointB; - - for ( sal_uInt16 i = 0; ( i < nPntCount ) && ( rSrcPt < nCoordSize ); i++ ) + if (nPntCount && (rSrcPt < nCoordSize)) { - sal_uInt32 nModT = ( nCommand == ELLIPTICALQUADRANTX ) ? 1 : 0; - Point aCurrent( GetPoint( seqCoordinates[ rSrcPt ], true, true ) ); - - if ( rSrcPt ) // we need a previous point + // The arc starts at the previous point and ends at the point given in the parameter. + basegfx::B2DPoint aStart; + basegfx::B2DPoint aEnd; + sal_uInt16 i = 0; + if (rSrcPt) { - Point aPrev( GetPoint( seqCoordinates[ rSrcPt - 1 ], true, true ) ); - sal_Int32 nX, nY; - nX = aCurrent.X() - aPrev.X(); - nY = aCurrent.Y() - aPrev.Y(); - if ( ( nY ^ nX ) & 0x80000000 ) - { - if ( !i ) - bFirstDirection = true; - else if ( !bFirstDirection ) - nModT ^= 1; - } - else - { - if ( !i ) - bFirstDirection = false; - else if ( bFirstDirection ) - nModT ^= 1; - } - if ( nModT ) // get the right corner + aStart = GetPointAsB2DPoint(seqCoordinates[rSrcPt - 1], true, true); + } + else + { // no previous point, path is ill-structured. But we want to show as much as possible. + // Thus make a moveTo to the point given as parameter and continue from there. + aStart = GetPointAsB2DPoint(seqCoordinates[static_cast<sal_uInt16>(rSrcPt)], true, true); + aNewB2DPolygon.append(aStart); + rSrcPt++; + i++; + } + // If there are several points, then the direction changes with every point. + bool bIsXDirection(nCommand == ELLIPTICALQUADRANTX); + basegfx::B2DPolygon aArc; + for ( ; ( i < nPntCount ) && ( rSrcPt < nCoordSize ); i++ ) + { + aEnd = GetPointAsB2DPoint(seqCoordinates[rSrcPt], true, true); + basegfx::B2DPoint aCenter; + double fRadiusX = fabs(aEnd.getX() - aStart.getX()); + double fRadiusY = fabs(aEnd.getY() - aStart.getY()); + if (bIsXDirection) { - nX = aCurrent.X(); - nY = aPrev.Y(); + aCenter = basegfx::B2DPoint(aStart.getX(),aEnd.getY()); + if (aEnd.getX()<aStart.getX()) + { + if (aEnd.getY()<aStart.getY()) // left, up + { + aArc = basegfx::utils::createPolygonFromEllipseSegment(aCenter, fRadiusX, fRadiusY, F_PI2, F_PI); + } + else // left, down + { + aArc = basegfx::utils::createPolygonFromEllipseSegment(aCenter, fRadiusX, fRadiusY, F_PI, 1.5*F_PI); + aArc.flip(); + } + } + else // aEnd.getX()>=aStart.getX() + { + if (aEnd.getY()<aStart.getY()) // right, up + { + aArc = basegfx::utils::createPolygonFromEllipseSegment(aCenter, fRadiusX, fRadiusY, 0.0, F_PI2); + aArc.flip(); + } + else // right, down + { + aArc = basegfx::utils::createPolygonFromEllipseSegment(aCenter, fRadiusX, fRadiusY, 1.5*F_PI, F_2PI); + } + } } - else + else // y-direction { - nX = aPrev.X(); - nY = aCurrent.Y(); + aCenter = basegfx::B2DPoint(aEnd.getX(),aStart.getY()); + if (aEnd.getX()<aStart.getX()) + { + if (aEnd.getY()<aStart.getY()) // up, left + { + aArc = basegfx::utils::createPolygonFromEllipseSegment(aCenter, fRadiusX, fRadiusY, 1.5*F_PI, F_2PI); + aArc.flip(); + } + else // down, left + { + aArc = basegfx::utils::createPolygonFromEllipseSegment(aCenter, fRadiusX, fRadiusY, 0.0, F_PI2); + } + } + else // aEnd.getX()>=aStart.getX() + { + if (aEnd.getY()<aStart.getY()) // up, right + { + aArc = basegfx::utils::createPolygonFromEllipseSegment(aCenter, fRadiusX, fRadiusY, F_PI, 1.5*F_PI); + } + else // down, right + { + aArc = basegfx::utils::createPolygonFromEllipseSegment(aCenter, fRadiusX, fRadiusY, F_PI2, F_PI); + aArc.flip(); + } + } } - sal_Int32 nXVec = ( nX - aPrev.X() ) >> 1; - sal_Int32 nYVec = ( nY - aPrev.Y() ) >> 1; - Point aControl1( aPrev.X() + nXVec, aPrev.Y() + nYVec ); - - aControlPointA = basegfx::B2DPoint(aControl1.X(), aControl1.Y()); - - nXVec = ( nX - aCurrent.X() ) >> 1; - nYVec = ( nY - aCurrent.Y() ) >> 1; - Point aControl2( aCurrent.X() + nXVec, aCurrent.Y() + nYVec ); - - aControlPointB = basegfx::B2DPoint(aControl2.X(), aControl2.Y()); - - aNewB2DPolygon.appendBezierSegment( - aControlPointA, - aControlPointB, - basegfx::B2DPoint(aCurrent.X(), aCurrent.Y())); - } - else - { - aNewB2DPolygon.append(basegfx::B2DPoint(aCurrent.X(), aCurrent.Y())); + aNewB2DPolygon.append(aArc); + rSrcPt++; + bIsXDirection = !bIsXDirection; + aStart = aEnd; } - - rSrcPt++; } + // else error in path syntax, do nothing } break; |