From fe00ea424ebda161badc3d7ff57957077e7a457a Mon Sep 17 00:00:00 2001 From: Regina Henschel Date: Wed, 4 Feb 2026 00:36:04 +0100 Subject: [PATCH] tdf#139968 first shear then rotate point of arc All internal calculation for transformation use the order resize, shear, rotate, translate. Thus the transformation of the points determining the angles of non-full SdrCircObj need to use that order too. Change-Id: If05310c64813bcffa410a328cf831b3f0b4c07e2 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198630 Reviewed-by: Regina Henschel Tested-by: Jenkins --- svx/qa/unit/classicshapes.cxx | 28 +++++++++++++++++++ svx/qa/unit/data/tdf139968_shear45_rot30.odg | Bin 0 -> 10519 bytes svx/source/svdraw/svdocirc.cxx | 10 +++---- 3 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 svx/qa/unit/data/tdf139968_shear45_rot30.odg diff --git a/svx/qa/unit/classicshapes.cxx b/svx/qa/unit/classicshapes.cxx index 07a4b9f916ab..ea536ff3ec91 100644 --- a/svx/qa/unit/classicshapes.cxx +++ b/svx/qa/unit/classicshapes.cxx @@ -10,6 +10,9 @@ #include #include #include +#include +#include +#include #include @@ -187,5 +190,30 @@ CPPUNIT_TEST_FIXTURE(ClassicshapesTest, testTdf130076Flip) 26000.0, nAngle2); } } + +CPPUNIT_TEST_FIXTURE(ClassicshapesTest, testTdf139968ShearRotateArcFlip) +{ + // The document contains an arc that is rotated and sheared. When horizonally flipped, start and + // end angles had got wrong values. + loadFromFile(u"tdf139968_shear45_rot30.odg"); + + // get shape and flip it + uno::Reference xShape(getShape(0, 0)); + SdrCircObj* pSdrCircObj(static_cast(SdrObject::getSdrObjectFromXShape(xShape))); + SfxViewShell* pViewShell = SfxViewShell::Current(); + CPPUNIT_ASSERT(pViewShell); + SdrView* pSdrView = pViewShell->GetDrawView(); + pSdrView->MarkObj(pSdrCircObj, pSdrView->GetSdrPageView()); + dispatchCommand(mxComponent, u".uno:FlipHorizontal"_ustr, {}); + + // make sure start and end angle are correct. + double fAngleS(0.0), fAngleE(0.0); + uno::Reference xShapeProps(xShape, uno::UNO_QUERY); + CPPUNIT_ASSERT(xShapeProps->getPropertyValue(u"CircleStartAngle"_ustr) >>= fAngleS); + CPPUNIT_ASSERT(xShapeProps->getPropertyValue(u"CircleEndAngle"_ustr) >>= fAngleE); + // without fix, start angle was 19419, end angle was 18176. Tolerance for to ignore round errors. + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("StartAngle wrong", 22500.0, fAngleS, 2.0); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("EndAngle wrong", 18000.0, fAngleE, 2.0); +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/qa/unit/data/tdf139968_shear45_rot30.odg b/svx/qa/unit/data/tdf139968_shear45_rot30.odg new file mode 100644 index 0000000000000000000000000000000000000000..7898593c5200c809109ff2a55765e5915e99b931 GIT binary patch literal 10519 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 literal 0 HcmV?d00001 diff --git a/svx/source/svdraw/svdocirc.cxx b/svx/source/svdraw/svdocirc.cxx index eed36dbc71c1..ef4e8b5f04dc 100644 --- a/svx/source/svdraw/svdocirc.cxx +++ b/svx/source/svdraw/svdocirc.cxx @@ -901,16 +901,16 @@ void SdrCircObj::NbcMirror(const Point& rRef1, const Point& rRef2) if (nWdt==0) aTmpPt2.setX(0 ); if (nHgt==0) aTmpPt2.setY(0 ); aTmpPt2+=aCenter; - if (maGeo.m_nRotationAngle) - { - RotatePoint(aTmpPt1, getRectangle().TopLeft(), maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle); - RotatePoint(aTmpPt2, getRectangle().TopLeft(), maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle); - } if (maGeo.m_nShearAngle) { ShearPoint(aTmpPt1, getRectangle().TopLeft(), maGeo.mfTanShearAngle); ShearPoint(aTmpPt2, getRectangle().TopLeft(), maGeo.mfTanShearAngle); } + if (maGeo.m_nRotationAngle) + { + RotatePoint(aTmpPt1, getRectangle().TopLeft(), maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle); + RotatePoint(aTmpPt2, getRectangle().TopLeft(), maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle); + } } SdrTextObj::NbcMirror(rRef1,rRef2); if (meCircleKind!=SdrCircKind::Full) { // adapt starting and finishing angle