include/svx/svdgeodata.hxx | 15 +++ include/svx/svdobj.hxx | 1 include/svx/svdtrans.hxx | 21 +++-- svx/qa/unit/svdraw.cxx | 107 +++++++++++++++++++++++++++ svx/source/svdraw/svdobj.cxx | 43 +++++++---- svx/source/svdraw/svdotxtr.cxx | 160 ++++++++++++++++++++++++++--------------- svx/source/svdraw/svdtrans.cxx | 32 ++++++++ 7 files changed, 299 insertions(+), 80 deletions(-)
New commits: commit 032e0799423b28cd4512bc863ea54bd527a8b82a Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Tue Feb 21 22:05:02 2023 +0900 Commit: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> CommitDate: Sat May 31 10:30:58 2025 +0200 svx: change SdrObjGeoData aBoundRectangle using gfx::Range2DLWrap Change-Id: I13213ea2bdbfc5badb87d1bbd836192b8ae45e72 diff --git a/include/svx/svdgeodata.hxx b/include/svx/svdgeodata.hxx index 7f5a8b9713a4..c87dacab99a6 100644 --- a/include/svx/svdgeodata.hxx +++ b/include/svx/svdgeodata.hxx @@ -23,14 +23,27 @@ #include <svx/svdglue.hxx> #include <tools/gen.hxx> #include <optional> +#include <basegfx/units/Range2DLWrap.hxx> /** * All geometrical data of an arbitrary object for use in undo/redo */ class SVXCORE_DLLPUBLIC SdrObjGeoData { +private: + gfx::Range2DLWrap maBoundRange; + public: - tools::Rectangle aBoundRect; + gfx::Range2DLWrap const& getBoundRange() const + { + return maBoundRange; + } + + void setBoundRange(gfx::Range2DLWrap const& rRange) + { + maBoundRange = rRange; + } + Point aAnchor; std::optional<SdrGluePointList> moGluePoints; bool bMovProt; diff --git a/include/svx/svdobj.hxx b/include/svx/svdobj.hxx index 7bb597b60415..c53223601501 100644 --- a/include/svx/svdobj.hxx +++ b/include/svx/svdobj.hxx @@ -396,6 +396,7 @@ public: // non-useful BoundRects sometimes) i rename that method from GetBoundRect() to // GetCurrentBoundRect(). virtual const tools::Rectangle& GetCurrentBoundRect() const; + virtual const gfx::Range2DLWrap& getCurrentBoundRange() const; // To have a possibility to get the last calculated BoundRect e.g for producing // the first rectangle for repaints (old and new need to be used) without forcing diff --git a/svx/source/svdraw/svdobj.cxx b/svx/source/svdraw/svdobj.cxx index bf1fa06b92ad..4433c023baa8 100644 --- a/svx/source/svdraw/svdobj.cxx +++ b/svx/source/svdraw/svdobj.cxx @@ -959,6 +959,13 @@ const tools::Rectangle& SdrObject::GetCurrentBoundRect() const return getOutRectangle(); } +const gfx::Range2DLWrap& SdrObject::getCurrentBoundRange() const +{ + if (m_aOutterRange.isEmpty()) + const_cast<SdrObject*>(this)->RecalcBoundRect(); + return m_aOutterRange; +} + // To have a possibility to get the last calculated BoundRect e.g for producing // the first rectangle for repaints (old and new need to be used) without forcing // a RecalcBoundRect (which may be problematical and expensive sometimes) I add here @@ -1915,7 +1922,7 @@ std::unique_ptr<SdrObjGeoData> SdrObject::NewGeoData() const void SdrObject::SaveGeoData(SdrObjGeoData& rGeo) const { - rGeo.aBoundRect =GetCurrentBoundRect(); + rGeo.setBoundRange(getCurrentBoundRange()); rGeo.aAnchor =m_aAnchor ; rGeo.bMovProt =m_bMovProt ; rGeo.bSizProt =m_bSizProt ; @@ -1935,7 +1942,7 @@ void SdrObject::SaveGeoData(SdrObjGeoData& rGeo) const void SdrObject::RestoreGeoData(const SdrObjGeoData& rGeo) { SetBoundAndSnapRectsDirty(); - setOutRectangle(rGeo.aBoundRect); + m_aOutterRange = rGeo.getBoundRange(); m_aAnchor =rGeo.aAnchor ; m_bMovProt =rGeo.bMovProt ; m_bSizProt =rGeo.bSizProt ; commit 9bc0e9c0c60b19d475e8ca55b45829d618251d32 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Sun Mar 5 18:48:23 2023 +0900 Commit: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> CommitDate: Sat May 31 10:30:57 2025 +0200 svx: use gfx::Length based types directly in SdrTextObj::NbcResize Change-Id: I839430b30685994e1767998b353c63b97f461284 diff --git a/svx/source/svdraw/svdotxtr.cxx b/svx/source/svdraw/svdotxtr.cxx index 0c6183f8ceac..45d2c55e127d 100644 --- a/svx/source/svdraw/svdotxtr.cxx +++ b/svx/source/svdraw/svdotxtr.cxx @@ -123,80 +123,102 @@ void SdrTextObj::NbcMove(const Size& rSize) void SdrTextObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact) { - bool bNotSheared=maGeo.m_nShearAngle==0_deg100; - bool bRotate90=bNotSheared && maGeo.m_nRotationAngle.get() % 9000 ==0; - bool bXMirr=(xFact.GetNumerator()<0) != (xFact.GetDenominator()<0); - bool bYMirr=(yFact.GetNumerator()<0) != (yFact.GetDenominator()<0); - if (bXMirr || bYMirr) { + bool bNotSheared = maGeo.m_nShearAngle == 0_deg100; + bool bRotate90 = bNotSheared && maGeo.m_nRotationAngle.get() % 9000 == 0; + + bool bXMirrored = (xFact.GetNumerator() < 0) != (xFact.GetDenominator() < 0); + bool bYMirrored = (yFact.GetNumerator() < 0) != (yFact.GetDenominator() < 0); + + double fFactorX = xFact.IsValid() ? double(xFact) : 1.0; + double fFactorY = yFact.IsValid() ? double(yFact) : 1.0; + + if (bXMirrored || bYMirrored) + { Point aRef1(GetSnapRect().Center()); - if (bXMirr) { + if (bXMirrored) + { Point aRef2(aRef1); aRef2.AdjustY( 1 ); NbcMirrorGluePoints(aRef1,aRef2); } - if (bYMirr) { + if (bYMirrored) + { Point aRef2(aRef1); aRef2.AdjustX( 1 ); NbcMirrorGluePoints(aRef1,aRef2); } } - if (maGeo.m_nRotationAngle==0_deg100 && maGeo.m_nShearAngle==0_deg100) { - auto aRectangle = getRectangle(); - ResizeRect(aRectangle, rRef, xFact, yFact); - setRectangle(aRectangle); - if (bYMirr) + if (maGeo.m_nRotationAngle == 0_deg100 && maGeo.m_nShearAngle == 0_deg100) + { + auto eUnit = getSdrModelFromSdrObject().getUnit(); + gfx::Tuple2DL aReference = createTupleFromPoint(rRef, eUnit); + svx::resizeRange(maRectangleRange, aReference, fFactorX, fFactorY); + + if (bYMirrored) { - moveRectangle(aRectangle.Right() - aRectangle.Left(), aRectangle.Bottom() - aRectangle.Top()); - maGeo.m_nRotationAngle=18000_deg100; + maRectangleRange.shift(maRectangleRange.getWidth(), maRectangleRange.getHeight()); + maGeo.m_nRotationAngle = 18000_deg100; maGeo.RecalcSinCos(); } } else { - tools::Polygon aPol(Rect2Poly(getRectangle(), maGeo)); + tools::Polygon aPolygon(Rect2Poly(getRectangle(), maGeo)); - for(sal_uInt16 a(0); a < aPol.GetSize(); a++) + for (sal_uInt16 a(0); a < aPolygon.GetSize(); a++) { - ResizePoint(aPol[a], rRef, xFact, yFact); + ResizePoint(aPolygon[a], rRef, xFact, yFact); } - if(bXMirr != bYMirr) + if (bXMirrored != bYMirrored) { // turn polygon and move it a little - tools::Polygon aPol0(aPol); + tools::Polygon aPol0(aPolygon); - aPol[0] = aPol0[1]; - aPol[1] = aPol0[0]; - aPol[2] = aPol0[3]; - aPol[3] = aPol0[2]; - aPol[4] = aPol0[1]; + aPolygon[0] = aPol0[1]; + aPolygon[1] = aPol0[0]; + aPolygon[2] = aPol0[3]; + aPolygon[3] = aPol0[2]; + aPolygon[4] = aPol0[1]; } - tools::Rectangle aRectangle = svx::polygonToRectangle(aPol, maGeo); + tools::Rectangle aRectangle = svx::polygonToRectangle(aPolygon, maGeo); setRectangle(aRectangle); } - if (bRotate90) { - bool bRota90=maGeo.m_nRotationAngle.get() % 9000 ==0; - if (!bRota90) { // there's seems to be a rounding error occurring: correct it - Degree100 a=NormAngle36000(maGeo.m_nRotationAngle); - if (a<4500_deg100) a=0_deg100; - else if (a<13500_deg100) a=9000_deg100; - else if (a<22500_deg100) a=18000_deg100; - else if (a<31500_deg100) a=27000_deg100; - else a=0_deg100; - maGeo.m_nRotationAngle=a; + if (bRotate90) + { + bool bRota90 = maGeo.m_nRotationAngle.get() % 9000 == 0; + if (!bRota90) + { + // there's seems to be a rounding error occurring: correct it + + Degree100 angle = NormAngle36000(maGeo.m_nRotationAngle); + if (angle < 4500_deg100) + angle = 0_deg100; + else if (angle < 13500_deg100) + angle = 9000_deg100; + else if (angle < 22500_deg100) + angle = 18000_deg100; + else if (angle < 31500_deg100) + angle = 27000_deg100; + else + angle = 0_deg100; + + maGeo.m_nRotationAngle = angle; maGeo.RecalcSinCos(); } - if (bNotSheared!=(maGeo.m_nShearAngle==0_deg100)) { // correct a rounding error occurring with Shear - maGeo.m_nShearAngle=0_deg100; + if (bNotSheared != (maGeo.m_nShearAngle == 0_deg100)) + { + // correct a rounding error occurring with Shear + maGeo.m_nShearAngle = 0_deg100; maGeo.RecalcTan(); } } AdaptTextMinSize(); - if(mbTextFrame && !getSdrModelFromSdrObject().IsPasteResize()) + if (mbTextFrame && !getSdrModelFromSdrObject().IsPasteResize()) { NbcAdjustTextFrameWidthAndHeight(); } commit 644b5d59f939e62b1d1d7ae8ebf675af44ea4604 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Sun Mar 5 14:46:10 2023 +0900 Commit: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> CommitDate: Sat May 31 10:30:57 2025 +0200 svx: use gfx::Length based types directly in SdrTextObj::NbcMove Change-Id: Ib0d4a9f60a2ae7f64d914c7a39aa146fef6a9f74 diff --git a/svx/source/svdraw/svdotxtr.cxx b/svx/source/svdraw/svdotxtr.cxx index 4d6c4014e4c8..0c6183f8ceac 100644 --- a/svx/source/svdraw/svdotxtr.cxx +++ b/svx/source/svdraw/svdotxtr.cxx @@ -40,6 +40,18 @@ using namespace com::sun::star; +namespace +{ + +gfx::Tuple2DL createTupleFromPoint(Point const& rPoint, gfx::LengthUnit eUnit = gfx::LengthUnit::hmm) +{ + auto x = gfx::Length::from(eUnit, rPoint.X()); + auto y = gfx::Length::from(eUnit, rPoint.Y()); + return gfx::Tuple2DL(x, y); +} + +} // end anonymous + void SdrTextObj::NbcSetSnapRect(const tools::Rectangle& rRect) { if (maGeo.m_nRotationAngle || maGeo.m_nShearAngle) @@ -96,8 +108,15 @@ Degree100 SdrTextObj::GetShearAngle(bool /*bVertical*/) const void SdrTextObj::NbcMove(const Size& rSize) { - moveRectangle(rSize.Width(), rSize.Height()); - moveOutRectangle(rSize.Width(), rSize.Height()); + gfx::Tuple2DL aDelta = createTupleFromPoint(Point(rSize.Width(), rSize.Height()), getSdrModelFromSdrObject().getUnit()); + gfx::Length xDelta = aDelta.getX(); + gfx::Length yDelta = aDelta.getY(); + + if (xDelta == 0_emu && yDelta == 0_emu) + return; + + maRectangleRange.shift(xDelta, yDelta); + m_aOutterRange.shift(xDelta, yDelta); maSnapRect.Move(rSize); SetBoundAndSnapRectsDirty(true); } @@ -186,19 +205,6 @@ void SdrTextObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fract SetBoundAndSnapRectsDirty(); } -namespace -{ - -gfx::Tuple2DL createTupleFromPoint(Point const& rPoint, gfx::LengthUnit eUnit = gfx::LengthUnit::hmm) -{ - auto x = gfx::Length::from(eUnit, rPoint.X()); - auto y = gfx::Length::from(eUnit, rPoint.Y()); - return gfx::Tuple2DL(x, y); -} - -} // end anonymous - - void SdrTextObj::NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs) { SetGlueReallyAbsolute(true); commit 33e84c5cb0046f83c2a6e711237adb87da15c881 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Sat Mar 4 22:12:51 2023 +0900 Commit: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> CommitDate: Sat May 31 10:29:44 2025 +0200 svx: use gfx::Length based types directly in SdrTextObj::NbcRotate Change-Id: Ic5ee712fa7507e016441595f8847649fd18b50ee diff --git a/include/svx/svdtrans.hxx b/include/svx/svdtrans.hxx index e0677e55f48b..1dab54c7603d 100644 --- a/include/svx/svdtrans.hxx +++ b/include/svx/svdtrans.hxx @@ -46,13 +46,15 @@ SVXCORE_DLLPUBLIC void ResizeRect(tools::Rectangle& rRect, const Point& rRef, co namespace svx { SVXCORE_DLLPUBLIC void resizeRange(gfx::Range2DLWrap& rRange, gfx::Tuple2DL const& rReference, double fFactorX, double fFactorY); +SVXCORE_DLLPUBLIC gfx::Tuple2DL rotatePoint(gfx::Tuple2DL const& rPoint, gfx::Tuple2DL const& rReference, double sinAngle, double cosAngle); } inline void ResizePoint(Point& rPnt, const Point& rRef, const Fraction& xFract, const Fraction& yFract); void ResizePoly(tools::Polygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact); void ResizeXPoly(XPolygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact); -inline void RotatePoint(Point& rPnt, const Point& rRef, double sn, double cs); +SVXCORE_DLLPUBLIC void RotatePoint(Point& rPnt, const Point& rRef, double sn, double cs); + SVXCORE_DLLPUBLIC void RotatePoly(tools::Polygon& rPoly, const Point& rRef, double sn, double cs); void RotateXPoly(XPolygon& rPoly, const Point& rRef, double sn, double cs); void RotateXPoly(XPolyPolygon& rPoly, const Point& rRef, double sn, double cs); @@ -107,14 +109,6 @@ inline void ResizePoint(Point& rPnt, const Point& rRef, const Fraction& xFract, rPnt.setY(rRef.Y() + basegfx::fround<tools::Long>((rPnt.Y() - rRef.Y()) * nyFract)); } -inline void RotatePoint(Point& rPnt, const Point& rRef, double sn, double cs) -{ - tools::Long dx=rPnt.X()-rRef.X(); - tools::Long dy=rPnt.Y()-rRef.Y(); - rPnt.setX(basegfx::fround<tools::Long>(rRef.X() + dx * cs + dy * sn)); - rPnt.setY(basegfx::fround<tools::Long>(rRef.Y() + dy * cs - dx * sn)); -} - inline void ShearPoint(Point& rPnt, const Point& rRef, double tn, bool bVShear) { if (!bVShear) { // Horizontal diff --git a/svx/qa/unit/svdraw.cxx b/svx/qa/unit/svdraw.cxx index 99333df65655..031a25e28980 100644 --- a/svx/qa/unit/svdraw.cxx +++ b/svx/qa/unit/svdraw.cxx @@ -950,6 +950,46 @@ CPPUNIT_TEST_FIXTURE(SvdrawTest, testResizeRect) CPPUNIT_ASSERT_EQUAL(tools::Rectangle(6, 6, 10, 10), aRectangle); } } + +CPPUNIT_TEST_FIXTURE(SvdrawTest, testRotatePoint2D) +{ + { + auto angle = 18000_deg100; + double angleRadians = toRadians(angle); + gfx::Tuple2DL aPoint(2_cm, 1_cm); + gfx::Tuple2DL aReference(1_cm, 1_cm); + aPoint + = svx::rotatePoint(aPoint, aReference, std::sin(angleRadians), std::cos(angleRadians)); + + CPPUNIT_ASSERT_EQUAL(0_cm, aPoint.getX()); + CPPUNIT_ASSERT_EQUAL(1_cm, aPoint.getY()); + } + + { + auto angle = 9000_deg100; + double angleRadians = toRadians(angle); + gfx::Tuple2DL aPoint(2_cm, 1_cm); + gfx::Tuple2DL aReference(1_cm, 1_cm); + aPoint + = svx::rotatePoint(aPoint, aReference, std::sin(angleRadians), std::cos(angleRadians)); + + CPPUNIT_ASSERT_EQUAL(1_cm, aPoint.getX()); + CPPUNIT_ASSERT_EQUAL(0_cm, aPoint.getY()); + } + + { + auto angle = 18000_deg100; + double angleRadians = toRadians(angle); + gfx::Tuple2DL aPoint(1_cm, 1_cm); + gfx::Tuple2DL aReference(2_cm, 2_cm); + aPoint + = svx::rotatePoint(aPoint, aReference, std::sin(angleRadians), std::cos(angleRadians)); + + CPPUNIT_ASSERT_EQUAL(3_cm, aPoint.getX()); + CPPUNIT_ASSERT_EQUAL(3_cm, aPoint.getY()); + } +} + } // end anonymous namespace /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/svdraw/svdotxtr.cxx b/svx/source/svdraw/svdotxtr.cxx index 30e3d7264e35..4d6c4014e4c8 100644 --- a/svx/source/svdraw/svdotxtr.cxx +++ b/svx/source/svdraw/svdotxtr.cxx @@ -186,28 +186,50 @@ void SdrTextObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fract SetBoundAndSnapRectsDirty(); } +namespace +{ + +gfx::Tuple2DL createTupleFromPoint(Point const& rPoint, gfx::LengthUnit eUnit = gfx::LengthUnit::hmm) +{ + auto x = gfx::Length::from(eUnit, rPoint.X()); + auto y = gfx::Length::from(eUnit, rPoint.Y()); + return gfx::Tuple2DL(x, y); +} + +} // end anonymous + + void SdrTextObj::NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs) { SetGlueReallyAbsolute(true); - tools::Rectangle aRectangle = getRectangle(); - tools::Long dx = aRectangle.Right() - aRectangle.Left(); - tools::Long dy = aRectangle.Bottom() - aRectangle.Top(); - Point aPoint1(aRectangle.TopLeft()); - RotatePoint(aPoint1, rRef, sn, cs); - Point aPoint2(aPoint1.X() + dx, aPoint1.Y() + dy); - aRectangle = tools::Rectangle(aPoint1, aPoint2); - setRectangle(aRectangle); + gfx::Tuple2DL aReference = createTupleFromPoint(rRef, getSdrModelFromSdrObject().getUnit()); - if (maGeo.m_nRotationAngle==0_deg100) { - maGeo.m_nRotationAngle=NormAngle36000(nAngle); - maGeo.mfSinRotationAngle=sn; - maGeo.mfCosRotationAngle=cs; - } else { - maGeo.m_nRotationAngle=NormAngle36000(maGeo.m_nRotationAngle+nAngle); + gfx::Length aWidth = maRectangleRange.getWidth(); + gfx::Length aHeight = maRectangleRange.getHeight(); + + gfx::Tuple2DL aPoint(maRectangleRange.getMinX(), maRectangleRange.getMinY()); + gfx::Tuple2DL aRotated = svx::rotatePoint(aPoint, aReference, sn, cs); + + maRectangleRange = gfx::Range2DLWrap( + aRotated.getX(), + aRotated.getY(), + aRotated.getX() + aWidth, + aRotated.getY() + aHeight); + + if (maGeo.m_nRotationAngle == 0_deg100) + { + maGeo.m_nRotationAngle = NormAngle36000(nAngle); + maGeo.mfSinRotationAngle = sn; + maGeo.mfCosRotationAngle = cs; + } + else + { + maGeo.m_nRotationAngle = NormAngle36000(maGeo.m_nRotationAngle + nAngle); maGeo.RecalcSinCos(); } + SetBoundAndSnapRectsDirty(); - NbcRotateGluePoints(rRef,nAngle,sn,cs); + NbcRotateGluePoints(rRef, nAngle, sn, cs); SetGlueReallyAbsolute(false); } diff --git a/svx/source/svdraw/svdtrans.cxx b/svx/source/svdraw/svdtrans.cxx index 4df9f3075555..3c6d006a6295 100644 --- a/svx/source/svdraw/svdtrans.cxx +++ b/svx/source/svdraw/svdtrans.cxx @@ -75,8 +75,24 @@ void resizeRange(gfx::Range2DLWrap& rRange, gfx::Tuple2DL const& rReference, dou rRange = gfx::Range2DLWrap(left, top, right, bottom, rRange.getUnit()); } +gfx::Tuple2DL rotatePoint(gfx::Tuple2DL const& rPoint, gfx::Tuple2DL const& rReference, double sinAngle, double cosAngle) +{ + gfx::Length dx = rPoint.getX() - rReference.getX(); + gfx::Length dy = rPoint.getY() - rReference.getY(); + gfx::Length x = rReference.getX() + dx * cosAngle + dy * sinAngle; + gfx::Length y = rReference.getY() + dy * cosAngle - dx * sinAngle; + return {x, y}; +} + } // end svx namespace +void RotatePoint(Point& rPoint, const Point& rRef, double sn, double cs) +{ + tools::Long dx = rPoint.X() - rRef.X(); + tools::Long dy = rPoint.Y() - rRef.Y(); + rPoint.setX(basegfx::fround(rRef.X() + dx * cs + dy * sn)); + rPoint.setY(basegfx::fround(rRef.Y() + dy * cs - dx * sn)); +} void ResizePoly(tools::Polygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact) { commit 8d29f2da6b126b7ff8408c0dabb4b24a1ec0e0a2 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Fri Feb 10 18:10:33 2023 +0900 Commit: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> CommitDate: Sat May 31 09:54:10 2025 +0200 svx: refactor SdrObject resize to use m_aOutterRange directly Change-Id: I77aad10b32a53545c7f7bbf8fd87b914395a5bad diff --git a/include/svx/svdtrans.hxx b/include/svx/svdtrans.hxx index 1d490b1e1158..e0677e55f48b 100644 --- a/include/svx/svdtrans.hxx +++ b/include/svx/svdtrans.hxx @@ -29,6 +29,9 @@ #include <tools/mapunit.hxx> #include <tools/poly.hxx> +#include <basegfx/units/Range2DLWrap.hxx> +#include <basegfx/units/LengthTypes.hxx> + // That maximum shear angle inline constexpr Degree100 SDRMAXSHEAR(8900); @@ -39,6 +42,12 @@ inline void MovePoly(tools::Polygon& rPoly, const Size& S) { rPoly.Move(S.W void MoveXPoly(XPolygon& rPoly, const Size& S); SVXCORE_DLLPUBLIC void ResizeRect(tools::Rectangle& rRect, const Point& rRef, const Fraction& xFact, const Fraction& yFact); + +namespace svx +{ +SVXCORE_DLLPUBLIC void resizeRange(gfx::Range2DLWrap& rRange, gfx::Tuple2DL const& rReference, double fFactorX, double fFactorY); +} + inline void ResizePoint(Point& rPnt, const Point& rRef, const Fraction& xFract, const Fraction& yFract); void ResizePoly(tools::Polygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact); void ResizeXPoly(XPolygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact); diff --git a/svx/qa/unit/svdraw.cxx b/svx/qa/unit/svdraw.cxx index fe3f5e2d96ff..99333df65655 100644 --- a/svx/qa/unit/svdraw.cxx +++ b/svx/qa/unit/svdraw.cxx @@ -7,7 +7,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include <test/unoapixml_test.hxx> +#include <basegfx/units/Length.hxx> #include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/drawing/XDrawPagesSupplier.hpp> @@ -45,6 +45,8 @@ #include <sdr/contact/objectcontactofobjlistpainter.hxx> +#include <test/unoapixml_test.hxx> + using namespace ::com::sun::star; namespace @@ -885,6 +887,69 @@ CPPUNIT_TEST_FIXTURE(SvdrawTest, testVisualSignResize) CPPUNIT_ASSERT_LESS(static_cast<sal_Int32>(10000), xShape->getSize().Width); CPPUNIT_ASSERT_LESS(static_cast<sal_Int32>(10000), xShape->getSize().Height); } + +CPPUNIT_TEST_FIXTURE(SvdrawTest, testResizeRect) +{ + { + tools::Rectangle aRectangle(1, 1, 10, 10); + Point aReference(1, 1); + ResizeRect(aRectangle, aReference, Fraction(1, 2), Fraction(1, 2)); + + CPPUNIT_ASSERT_EQUAL(tools::Rectangle(1, 1, 6, 6), aRectangle); + } + + { + tools::Rectangle aRectangle(1, 1, 10, 10); + Point aReference(10, 10); + ResizeRect(aRectangle, aReference, Fraction(1, 2), Fraction(1, 2)); + + CPPUNIT_ASSERT_EQUAL(tools::Rectangle(5, 5, 10, 10), aRectangle); + } + + { + gfx::Range2DLWrap aRange(1_hmm, 1_hmm, 10_hmm, 10_hmm); + CPPUNIT_ASSERT_EQUAL(9_hmm, aRange.getWidth()); + CPPUNIT_ASSERT_EQUAL(9_hmm, aRange.getHeight()); + + gfx::Tuple2DL aReference(1_hmm, 1_hmm); + svx::resizeRange(aRange, aReference, 0.5, 0.5); + + CPPUNIT_ASSERT_EQUAL(false, aRange.isEmpty()); + + CPPUNIT_ASSERT_EQUAL(1_hmm, aRange.getMinX()); + CPPUNIT_ASSERT_EQUAL(5.5_hmm, aRange.getMaxX()); + CPPUNIT_ASSERT_EQUAL(1_hmm, aRange.getMinY()); + CPPUNIT_ASSERT_EQUAL(5.5_hmm, aRange.getMaxY()); + + CPPUNIT_ASSERT_EQUAL(4.5_hmm, aRange.getWidth()); + CPPUNIT_ASSERT_EQUAL(4.5_hmm, aRange.getHeight()); + + auto aRectangle = aRange.toToolsRect(); + CPPUNIT_ASSERT_EQUAL(tools::Rectangle(1, 1, 6, 6), aRectangle); + } + + { + gfx::Range2DLWrap aRange(1_hmm, 1_hmm, 10_hmm, 10_hmm); + CPPUNIT_ASSERT_EQUAL(9_hmm, aRange.getWidth()); + CPPUNIT_ASSERT_EQUAL(9_hmm, aRange.getHeight()); + + gfx::Tuple2DL aReference(10_hmm, 10_hmm); + svx::resizeRange(aRange, aReference, 0.5, 0.5); + + CPPUNIT_ASSERT_EQUAL(false, aRange.isEmpty()); + + CPPUNIT_ASSERT_EQUAL(5.5_hmm, aRange.getMinX()); + CPPUNIT_ASSERT_EQUAL(10_hmm, aRange.getMaxX()); + CPPUNIT_ASSERT_EQUAL(5.5_hmm, aRange.getMinY()); + CPPUNIT_ASSERT_EQUAL(10_hmm, aRange.getMaxY()); + + CPPUNIT_ASSERT_EQUAL(4.5_hmm, aRange.getWidth()); + CPPUNIT_ASSERT_EQUAL(4.5_hmm, aRange.getHeight()); + + auto aRectangle = aRange.toToolsRect(); + CPPUNIT_ASSERT_EQUAL(tools::Rectangle(6, 6, 10, 10), aRectangle); + } +} } // end anonymous namespace /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/svdraw/svdobj.cxx b/svx/source/svdraw/svdobj.cxx index 06900bb082f2..bf1fa06b92ad 100644 --- a/svx/source/svdraw/svdobj.cxx +++ b/svx/source/svdraw/svdobj.cxx @@ -33,6 +33,7 @@ #include <basegfx/polygon/b2dpolypolygoncutter.hxx> #include <basegfx/polygon/b2dpolypolygontools.hxx> #include <basegfx/units/Range2DLWrap.hxx> +#include <basegfx/units/LengthTypes.hxx> #include <basegfx/range/b2drange.hxx> #include <drawinglayer/processor2d/contourextractor2d.hxx> #include <drawinglayer/processor2d/linegeometryextractor2d.hxx> @@ -974,9 +975,8 @@ void SdrObject::RecalcBoundRect() return; - auto const& rRectangle = getOutRectangle(); // central new method which will calculate the BoundRect using primitive geometry - if (!rRectangle.IsEmpty()) + if (!isOutRectangleEmpty()) return; // Use view-independent data - we do not want any connections @@ -1431,24 +1431,32 @@ void SdrObject::NbcMove(const Size& rSize) void SdrObject::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact) { - bool bXMirr=(xFact.GetNumerator()<0) != (xFact.GetDenominator()<0); - bool bYMirr=(yFact.GetNumerator()<0) != (yFact.GetDenominator()<0); - if (bXMirr || bYMirr) { + bool bXMirror = (xFact.GetNumerator() < 0) != (xFact.GetDenominator() < 0); + bool bYMirror = (yFact.GetNumerator() < 0) != (yFact.GetDenominator() < 0); + if (bXMirror || bYMirror) + { Point aRef1(GetSnapRect().Center()); - if (bXMirr) { + if (bXMirror) + { Point aRef2(aRef1); aRef2.AdjustY( 1 ); - NbcMirrorGluePoints(aRef1,aRef2); + NbcMirrorGluePoints(aRef1, aRef2); } - if (bYMirr) { + if (bYMirror) + { Point aRef2(aRef1); aRef2.AdjustX( 1 ); - NbcMirrorGluePoints(aRef1,aRef2); + NbcMirrorGluePoints(aRef1, aRef2); } } - auto aRectangle = getOutRectangle(); - ResizeRect(aRectangle, rRef, xFact, yFact); - setOutRectangle(aRectangle); + + auto eUnit = getSdrModelFromSdrObject().getUnit(); + gfx::Tuple2DL aReference{ + gfx::Length::from(eUnit, rRef.X()), + gfx::Length::from(eUnit, rRef.Y())}; + double fFactorX = xFact.IsValid() ? double(xFact) : 1.0; + double fFactorY = yFact.IsValid() ? double(yFact) : 1.0; + svx::resizeRange(m_aOutterRange, aReference, fFactorX, fFactorY); SetBoundAndSnapRectsDirty(); } diff --git a/svx/source/svdraw/svdtrans.cxx b/svx/source/svdraw/svdtrans.cxx index eb2964dec823..4df9f3075555 100644 --- a/svx/source/svdraw/svdtrans.cxx +++ b/svx/source/svdraw/svdtrans.cxx @@ -61,6 +61,22 @@ void ResizeRect(tools::Rectangle& rRect, const Point& rRef, const Fraction& rxFa rRect.Normalize(); } +namespace svx +{ + +void resizeRange(gfx::Range2DLWrap& rRange, gfx::Tuple2DL const& rReference, double fFactorX, double fFactorY) +{ + auto left = rReference.getX() + ((rRange.getMinX() - rReference.getX()) * fFactorX); + auto right = rReference.getX() + ((rRange.getMaxX() - rReference.getX()) * fFactorX); + + auto top = rReference.getY() + ((rRange.getMinY() - rReference.getY()) * fFactorY); + auto bottom = rReference.getY() + ((rRange.getMaxY() - rReference.getY()) * fFactorY); + + rRange = gfx::Range2DLWrap(left, top, right, bottom, rRange.getUnit()); +} + +} // end svx namespace + void ResizePoly(tools::Polygon& rPoly, const Point& rRef, const Fraction& xFact, const Fraction& yFact) {