summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--svx/qa/unit/customshapes.cxx53
-rw-r--r--svx/qa/unit/data/tdf103474_commandG_CaseZeroHeight.odpbin0 -> 12420 bytes
-rw-r--r--svx/qa/unit/data/tdf122323_swingAngle_larger360deg.pptxbin0 -> 15580 bytes
-rw-r--r--svx/source/customshapes/EnhancedCustomShape2d.cxx112
4 files changed, 120 insertions, 45 deletions
diff --git a/svx/qa/unit/customshapes.cxx b/svx/qa/unit/customshapes.cxx
index d8f7fb8a5bf9..309c5155d8da 100644
--- a/svx/qa/unit/customshapes.cxx
+++ b/svx/qa/unit/customshapes.cxx
@@ -704,6 +704,59 @@ CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf103474_commandT_CaseZeroHeight)
CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aStart y-coordinate", 9999.0, aStart.getY(), 1.0);
CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aEnd y-coordinate", 1999.0, aEnd.getY(), 1.0);
}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf103474_commandG_CaseZeroHeight)
+{
+ // Some as above, but with shape with command G.
+ OUString sURL
+ = m_directories.getURLFromSrc(sDataDirectory) + "tdf103474_commandG_CaseZeroHeight.odp";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.presentation.PresentationDocument");
+ CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is());
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ // The end points of the straight line segment should have the same x-coordinate of left
+ // of shape, and different y-coordinates, one top and the other bottom of the shape.
+ SdrObjCustomShape& rSdrObjCustomShape(
+ static_cast<SdrObjCustomShape&>(*GetSdrObjectFromXShape(xShape)));
+ EnhancedCustomShape2d aCustomShape2d(rSdrObjCustomShape);
+ SdrPathObj* pPathObj = static_cast<SdrPathObj*>(aCustomShape2d.CreateLineGeometry());
+ CPPUNIT_ASSERT_MESSAGE("Could not convert to SdrPathObj", pPathObj);
+ const basegfx::B2DPolyPolygon aPolyPolygon(pPathObj->GetPathPoly());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("count polygons", static_cast<sal_uInt32>(1),
+ aPolyPolygon.count());
+ const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(0));
+ // Get the middle points of the polygon. They are the endpoints of the
+ // straight line segment regardless of the quarter ellipse parts, because
+ // the shape is symmetric.
+ const basegfx::B2DPoint aStart(aPolygon.getB2DPoint(aPolygon.count() / 2 - 1));
+ const basegfx::B2DPoint aEnd(aPolygon.getB2DPoint(aPolygon.count() / 2));
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aStart x-coordinate", 1999.0, aStart.getX(), 1.0);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aEnd x-coordinate", 1999.0, aEnd.getX(), 1.0);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aStart y-coordinate", 9999.0, aStart.getY(), 1.0);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aEnd y-coordinate", 1999.0, aEnd.getY(), 1.0);
+}
+
+CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf122323_largeSwingAngle)
+{
+ // SwingAngles are clamped to [-360;360] in MS Office. Error was, that LO calculated
+ // the end angle and used it modulo 360, no full ellipse was drawn.
+ OUString sURL
+ = m_directories.getURLFromSrc(sDataDirectory) + "tdf122323_swingAngle_larger360deg.pptx";
+ mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.presentation.PresentationDocument");
+ CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is());
+ uno::Reference<drawing::XShape> xShape(getShape(0));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ SdrObjCustomShape& rSdrObjCustomShape(
+ static_cast<SdrObjCustomShape&>(*GetSdrObjectFromXShape(xShape)));
+ EnhancedCustomShape2d aCustomShape2d(rSdrObjCustomShape);
+ SdrPathObj* pPathObj = static_cast<SdrPathObj*>(aCustomShape2d.CreateLineGeometry());
+ CPPUNIT_ASSERT_MESSAGE("Could not convert to SdrPathObj", pPathObj);
+ const basegfx::B2DPolyPolygon aPolyPolygon(pPathObj->GetPathPoly());
+ const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(0));
+ const basegfx::B2DPoint aStart(aPolygon.getB2DPoint(0));
+ // last point comes from line to center, therefore -2 instead of -1
+ const basegfx::B2DPoint aEnd(aPolygon.getB2DPoint(aPolygon.count() - 2));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Start <> End", aStart, aEnd);
+}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/qa/unit/data/tdf103474_commandG_CaseZeroHeight.odp b/svx/qa/unit/data/tdf103474_commandG_CaseZeroHeight.odp
new file mode 100644
index 000000000000..9b36d45eed6a
--- /dev/null
+++ b/svx/qa/unit/data/tdf103474_commandG_CaseZeroHeight.odp
Binary files differ
diff --git a/svx/qa/unit/data/tdf122323_swingAngle_larger360deg.pptx b/svx/qa/unit/data/tdf122323_swingAngle_larger360deg.pptx
new file mode 100644
index 000000000000..919675ef9d27
--- /dev/null
+++ b/svx/qa/unit/data/tdf122323_swingAngle_larger360deg.pptx
Binary files differ
diff --git a/svx/source/customshapes/EnhancedCustomShape2d.cxx b/svx/source/customshapes/EnhancedCustomShape2d.cxx
index 8b570edd809e..89360b62fc70 100644
--- a/svx/source/customshapes/EnhancedCustomShape2d.cxx
+++ b/svx/source/customshapes/EnhancedCustomShape2d.cxx
@@ -2356,58 +2356,80 @@ void EnhancedCustomShape2d::CreateSubPath(
case ARCANGLETO :
{
- double fWR, fHR, fStartAngle, fSwingAngle;
+ double fWR, fHR; // in Shape coordinate system
+ double fStartAngle, fSwingAngle; // in deg
for ( sal_uInt16 i = 0; ( i < nPntCount ) && ( rSrcPt + 1 < nCoordSize ); i++ )
{
- GetParameter ( fWR, seqCoordinates[ static_cast<sal_uInt16>(rSrcPt) ].First, true, false );
- GetParameter ( fHR, seqCoordinates[ static_cast<sal_uInt16>(rSrcPt) ].Second, false, true );
-
- GetParameter ( fStartAngle, seqCoordinates[ static_cast<sal_uInt16>( rSrcPt + 1) ].First, false, false );
- GetParameter ( fSwingAngle, seqCoordinates[ static_cast<sal_uInt16>( rSrcPt + 1 ) ].Second, false, false );
-
- // Convert angles to radians, but don't do any scaling / translation yet.
-
- fStartAngle = basegfx::deg2rad(fStartAngle);
- fSwingAngle = basegfx::deg2rad(fSwingAngle);
+ basegfx::B2DPoint aTempPair;
+ aTempPair = GetPointAsB2DPoint(seqCoordinates[static_cast<sal_uInt16>(rSrcPt)], false /*bScale*/, false /*bReplaceGeoSize*/);
+ fWR = aTempPair.getX();
+ fHR = aTempPair.getY();
+ aTempPair = GetPointAsB2DPoint(seqCoordinates[static_cast<sal_uInt16>(rSrcPt + 1)], false /*bScale*/, false /*bReplaceGeoSize*/);
+ fStartAngle = aTempPair.getX();
+ fSwingAngle = aTempPair.getY();
+
+ // tdf#122323 MS Office clamps the swing angle to [-360,360]. Such restriction
+ // is neither in OOXML nor in ODF. Nevertheless, to be compatible we do it for
+ // "ooxml-foo" shapes. Those shapes have their origin in MS Office.
+ if (bOOXMLShape)
+ {
+ fSwingAngle = std::clamp(fSwingAngle, -360.0, 360.0);
+ }
SAL_INFO("svx", "ARCANGLETO scale: " << fWR << "x" << fHR << " angles: " << fStartAngle << "," << fSwingAngle);
- bool bClockwise = fSwingAngle >= 0.0;
-
- if (aNewB2DPolygon.count() > 0)
+ if (aNewB2DPolygon.count() > 0) // otherwise no "current point"
{
- basegfx::B2DPoint aStartPointB2D( aNewB2DPolygon.getB2DPoint(aNewB2DPolygon.count() - 1 ) );
- Point aStartPoint( 0, 0 );
-
- double fT = atan2((fWR*sin(fStartAngle)), (fHR*cos(fStartAngle)));
- double fTE = atan2((fWR*sin(fStartAngle + fSwingAngle)), fHR*cos(fStartAngle + fSwingAngle));
-
- SAL_INFO("svx", "ARCANGLETO angles: " << fStartAngle << ", " << fSwingAngle
- << " --> parameters: " << fT <<", " << fTE );
-
- fWR *= fXScale;
- fHR *= fYScale;
-
- tools::Rectangle aRect ( Point ( aStartPoint.getX() - fWR*cos(fT) - fWR, aStartPoint.getY() - fHR*sin(fT) - fHR ),
- Point ( aStartPoint.getX() - fWR*cos(fT) + fWR, aStartPoint.getY() - fHR*sin(fT) + fHR) );
-
- Point aEndPoint ( aStartPoint.getX() - fWR*(cos(fT) - cos(fTE)), aStartPoint.getY() - fHR*(sin(fT) - sin(fTE)) );
-
- SAL_INFO(
- "svx",
- "ARCANGLETO rect: " << aRect.Left() << ", "
- << aRect.Top() << " x " << aRect.Right()
- << ", " << aRect.Bottom() << " start: "
- << aStartPoint.X() << ", "
- << aStartPoint.Y() << " end: "
- << aEndPoint.X() << ", " << aEndPoint.Y()
- << " clockwise: " << int(bClockwise));
- basegfx::B2DPolygon aArc = CreateArc( aRect, bClockwise ? aEndPoint : aStartPoint, bClockwise ? aStartPoint : aEndPoint, bClockwise, aStartPoint == aEndPoint && ((bClockwise && fSwingAngle > F_PI) || (!bClockwise && fSwingAngle < -F_PI)));
- // Now that we have the arc, move it to aStartPointB2D.
- basegfx::B2DHomMatrix aMatrix = basegfx::utils::createTranslateB2DHomMatrix(aStartPointB2D.getX(), aStartPointB2D.getY());
- aArc.transform(aMatrix);
- aNewB2DPolygon.append(aArc);
+ // use similar methods as in command U
+ basegfx::B2DPolygon aTempB2DPolygon;
+
+ if (fWR == 0.0 && fHR == 0.0)
+ {
+ // degenerated ellipse, add this one point
+ aTempB2DPolygon.append(basegfx::B2DPoint(0.0, 0.0));
+ }
+ else
+ {
+ double fEndAngle = fStartAngle + fSwingAngle;
+ // Generate arc with ellipse left|top = 0|0.
+ basegfx::B2DPoint aCenter(fWR, fHR);
+ if (fSwingAngle < 0.0)
+ std::swap(fStartAngle, fEndAngle);
+ double fS; // fFrom in radians in [0..2Pi[
+ double fE; // fTo or fEndAngle in radians in [0..2PI[
+ double fFrom(fStartAngle);
+ // createPolygonFromEllipseSegment expects angles in [0..2PI[.
+ if (fSwingAngle >= 360.0 || fSwingAngle <= -360.0)
+ {
+ double fTo(fFrom + 180.0);
+ while (fTo < fEndAngle)
+ {
+ fS = lcl_getNormalizedCircleAngleRad(fWR, fHR, fFrom);
+ fE = lcl_getNormalizedCircleAngleRad(fWR, fHR, fTo);
+ aTempB2DPolygon.append(basegfx::utils::createPolygonFromEllipseSegment(aCenter, fWR, fHR, fS,fE));
+ fFrom = fTo;
+ fTo += 180.0;
+ }
+ }
+ fS = lcl_getNormalizedCircleAngleRad(fWR, fHR, fFrom);
+ fE = lcl_getNormalizedCircleAngleRad(fWR, fHR, fEndAngle);
+ aTempB2DPolygon.append(basegfx::utils::createPolygonFromEllipseSegment(aCenter, fWR, fHR,fS, fE));
+ if (fSwingAngle < 0)
+ aTempB2DPolygon.flip();
+ aTempB2DPolygon.removeDoublePoints();
+ }
+ // Scale arc to 1/100mm
+ basegfx::B2DHomMatrix aMatrix = basegfx::utils::createScaleB2DHomMatrix(fXScale, fYScale);
+ aTempB2DPolygon.transform(aMatrix);
+
+ // Now that we have the arc, move it to the "current point".
+ basegfx::B2DPoint aCurrentPointB2D( aNewB2DPolygon.getB2DPoint(aNewB2DPolygon.count() - 1 ) );
+ const double fDx(aCurrentPointB2D.getX() - aTempB2DPolygon.getB2DPoint(0).getX());
+ const double fDy(aCurrentPointB2D.getY() - aTempB2DPolygon.getB2DPoint(0).getY());
+ aMatrix = basegfx::utils::createTranslateB2DHomMatrix(fDx, fDy);
+ aTempB2DPolygon.transform(aMatrix);
+ aNewB2DPolygon.append(aTempB2DPolygon);
}
rSrcPt += 2;