emfio/qa/cppunit/emf/EmfImportTest.cxx | 61 +------- emfio/qa/cppunit/emf/data/TestEllipseWithSelectClipPath.emf |binary emfio/qa/cppunit/emf/data/TestEllipseXformIntersectClipRect.emf |binary emfio/source/reader/emfreader.cxx | 10 - tools/source/generic/poly.cxx | 71 +++++----- 5 files changed, 51 insertions(+), 91 deletions(-)
New commits: commit ccf1476f70d39797f968444ac585c19b0edbff36 Author: Bartosz Kosiorek <gan...@poczta.onet.pl> AuthorDate: Wed Aug 6 21:23:28 2025 +0200 Commit: Bartosz Kosiorek <gan...@poczta.onet.pl> CommitDate: Fri Aug 8 17:46:09 2025 +0200 tdf#103859 EMF Fix quality of EMR_ELLIPSE by using Bazier curve for drawing Change-Id: I7eaca22dac921229b4a88e07739d379948730bd9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189024 Reviewed-by: Bartosz Kosiorek <gan...@poczta.onet.pl> Tested-by: Jenkins diff --git a/emfio/qa/cppunit/emf/EmfImportTest.cxx b/emfio/qa/cppunit/emf/EmfImportTest.cxx index e3f7f07f7f83..a32db251df92 100644 --- a/emfio/qa/cppunit/emf/EmfImportTest.cxx +++ b/emfio/qa/cppunit/emf/EmfImportTest.cxx @@ -726,17 +726,11 @@ CPPUNIT_TEST_FIXTURE(Test, testEllipseWithSelectClipPath) assertXPath(pDocument, aXPathPrefix + "group/mask/polypolygon", 1); assertXPath(pDocument, aXPathPrefix + "group/mask/polypolygon[1]", "path", - u"m2790 " - "776v-36-35h-36v-35l-35-35-35-36h-36l-35-35-35-35h-35-36l-35-35h-35-36l-35-36h-35-" - "36l-35-35h-35-71-35l-36-35h-70-35-36-70l-36-35h-35-71-35-71-35-71-35-35-71-35-71-" - "35-71-35l-35 35h-71-35-36-70l-35 35h-36-70-36l-35 35h-35-36l-35 36h-35-36l-35 " - "35h-35-36l-35 35-35 35h-35l-36 36-35 35v35h-35v35 36 35 35h35v35l35 36 36 " - "35h35l35 35 35 35h36 35l35 36h36 35l35 35h36 35l35 35h36 70 36l35 35h70 36 35 " - "71l35 36h35 71 35 71 35 71 35 35 71 35 71 35 71 35l36-36h70 36 35 70l36-35h35 71 " - "35l35-35h36 35l35-35h36 35l35-36h36 35l35-35 35-35h36l35-35 35-36v-35h36v-35z"); + u"m177 776c0 211 565 423 1306 423 706 0 1307-212 1307-423 " + u"0-247-601-423-1307-423-741 0-1306 176-1306 423z"); assertXPath(pDocument, aXPathPrefix + "group/mask/polypolygoncolor", 1); - assertXPath(pDocument, aXPathPrefix + "group/mask/polypolygoncolor[1]", "color", u"#ffff00"); + assertXPath(pDocument, aXPathPrefix + "group/mask/polypolygoncolor[1]", "color", u"#ff1100"); assertXPath(pDocument, aXPathPrefix + "group/mask/polypolygoncolor[1]/polypolygon[1]", "path", u"m353 353h2472v1057h-2472z"); @@ -758,49 +752,12 @@ CPPUNIT_TEST_FIXTURE(Test, testEllipseXformIntersectClipRect) assertXPath(pDocument, aXPathPrefix + "mask/polypolygon", "path", u"m0 0h3000v2000h-3000z"); assertXPath(pDocument, aXPathPrefix + "mask/group/mask/polypolygon", "path", u"m370 152 1128-409 592 1623-1128 410z"); - assertXPath( - pDocument, aXPathPrefix + "mask/group/mask/polypolygoncolor/polypolygon", "path", - u"m3613 287-12-33-12-33-12-33-12-33-33 12-12-34-13-33-45-21-12-33-33 " - "12-12-33-45-21-46-21-12-33-33 12-12-33-45-21-33 12-46-21-45-21-33 12-45-21-34 12-45-21-33 " - "12-45-21-34 12-45-21-33 12-45-21-33 12-34 12-45-21-33 12-33 12-45-21-34 12-66 24-45-21-33 " - "12-34 12-66 24-33 12-45-21-34 12-66 24-33 12-33 12-34 12-66 24-33 12-33 12-67 25-33 12-33 " - "12-33 12-67 24-33 12-21 45-33 12-66 24-34 12-33 12-21 46-66 24-33 12-22 45-33 12-33 12-21 " - "45-33 12-33 12-21 46-34 12-21 45-33 12-21 45-33 12-21 45-34 12-21 45-33 13-21 45-21 45-33 " - "12-21 45 12 33-33 12 12 33-21 46-22 45 13 33-34 12 12 33-21 45 12 33 12 34-33 12 12 33 12 " - "33 13 33 12 33 12 33 12 33 12 33 12 34 33-12 12 33 12 33 46 21 12 33 33-12 12 33 45 21 45 " - "21 12 33 34-12 12 33 45 21 33-12 45 21 46 22 33-13 45 22 33-13 46 22 33-13 45 22 33-13 45 " - "22 34-13 45 22 33-12 33-13 46 22 33-13 33-12 45 21 33-12 67-24 45 21 33-12 33-12 67-24 " - "33-12 45 21 33-12 67-24 33-12 33-12 33-12 67-24 33-12 33-12 66-25 34-12 33-12 33-12 66-24 " - "33-12 22-45 33-12 66-24 33-12 33-12 22-45 66-25 33-12 21-45 33-12 34-12 21-45 33-12 33-12 " - "21-45 33-12 21-46 34-12 21-45 33-12 21-45 33-12 21-45 33-12 22-46 21-45 33-12 21-45-12-33 " - "33-12-12-33 21-46 21-45-12-33 33-12-12-33 21-45-12-33-12-33 33-12-12-34-12-33-12-33z"); - assertXPathContent( - pDocument, aXPathPrefix + "mask/group/mask/polygonstroke/polygon", - u"3613,287 3601,254 3601,254 3589,221 3577,188 3565,155 3532,167 3520,133 3507,100 " - u"3507,100 " - "3462,79 3450,46 3417,58 3405,25 3360,4 3360,4 3314,-17 3302,-50 3269,-38 3257,-71 " - "3212,-92 3179,-80 3133,-101 3133,-101 3088,-122 3055,-110 3010,-131 2976,-119 2931,-140 " - "2898,-128 2853,-149 2819,-137 2774,-158 2741,-146 2696,-167 2663,-155 2629,-143 2584,-164 " - "2551,-152 2518,-140 2473,-161 2439,-149 2373,-125 2328,-146 2295,-134 2261,-122 2195,-98 " - "2162,-86 2117,-107 2083,-95 2017,-71 1984,-59 1951,-47 1917,-35 1851,-11 1818,1 1818,1 " - "1785,13 1718,38 1685,50 1652,62 1619,74 1552,98 1519,110 1498,155 1465,167 1399,191 " - "1365,203 1332,215 1311,261 1245,285 1212,297 1190,342 1157,354 1124,366 1103,411 1070,423 " - "1037,435 1016,481 982,493 961,538 928,550 907,595 874,607 853,652 819,664 798,709 765,722 " - "744,767 744,767 723,812 690,824 669,869 681,902 648,914 660,947 639,993 639,993 617,1038 " - "630,1071 596,1083 608,1116 587,1161 587,1161 599,1194 611,1228 578,1240 590,1273 602,1306 " - "615,1339 615,1339 627,1372 627,1372 639,1405 639,1405 651,1438 663,1471 675,1505 708,1493 " - "720,1526 732,1559 732,1559 778,1580 790,1613 823,1601 835,1634 880,1655 880,1655 925,1676 " - "937,1709 971,1697 983,1730 1028,1751 1061,1739 1106,1760 1106,1760 1152,1782 1185,1769 " - "1230,1791 1263,1778 1309,1800 1342,1787 1387,1809 1420,1796 1465,1818 1499,1805 1544,1827 " - "1577,1815 1610,1802 1656,1824 1689,1811 1722,1799 1767,1820 1800,1808 1867,1784 1912,1805 " - "1945,1793 1978,1781 2045,1757 2078,1745 2123,1766 2156,1754 2223,1730 2256,1718 2289,1706 " - "2322,1694 2389,1670 2422,1658 2422,1658 2455,1646 2521,1621 2555,1609 2588,1597 2621,1585 " - "2687,1561 2720,1549 2742,1504 2775,1492 2841,1468 2874,1456 2907,1444 2929,1399 2995,1374 " - "3028,1362 3049,1317 3082,1305 3116,1293 3137,1248 3170,1236 3203,1224 3224,1179 3257,1167 " - "3278,1121 3312,1109 3333,1064 3366,1052 3387,1007 3420,995 3441,950 3474,938 3496,892 " - "3496,892 3517,847 3550,835 3571,790 3559,757 3592,745 3580,712 3601,666 3601,666 3622,621 " - "3610,588 3643,576 3631,543 3652,498 3652,498 3640,465 3628,432 3661,420 3649,386 3637,353 " - "3625,320 3625,320"); + assertXPath(pDocument, aXPathPrefix + "mask/group/mask/polypolygoncolor", "color", u"#bbaa00"); + assertXPath(pDocument, aXPathPrefix + "mask/group/mask/polypolygoncolor/polypolygon", "path", + u"m627 1372c157 431 965 587 1795 286 796-290 1348-940 " + u"1191-1371-169-464-999-575-1795-286-830 302-1360 907-1191 1371z"); + assertXPathContent(pDocument, aXPathPrefix + "mask/group/mask/polygonstroke/polygon", + u"627,1372 2422,1658 3613,287 1818,1"); } CPPUNIT_TEST_FIXTURE(Test, testSetArcDirection) diff --git a/emfio/qa/cppunit/emf/data/TestEllipseWithSelectClipPath.emf b/emfio/qa/cppunit/emf/data/TestEllipseWithSelectClipPath.emf index ed0d52401238..b1bc76092c9e 100644 Binary files a/emfio/qa/cppunit/emf/data/TestEllipseWithSelectClipPath.emf and b/emfio/qa/cppunit/emf/data/TestEllipseWithSelectClipPath.emf differ diff --git a/emfio/qa/cppunit/emf/data/TestEllipseXformIntersectClipRect.emf b/emfio/qa/cppunit/emf/data/TestEllipseXformIntersectClipRect.emf index bda2ad233f4a..b5add75de831 100644 Binary files a/emfio/qa/cppunit/emf/data/TestEllipseXformIntersectClipRect.emf and b/emfio/qa/cppunit/emf/data/TestEllipseXformIntersectClipRect.emf differ diff --git a/emfio/source/reader/emfreader.cxx b/emfio/source/reader/emfreader.cxx index 1764013bb14d..7a7b2a370377 100644 --- a/emfio/source/reader/emfreader.cxx +++ b/emfio/source/reader/emfreader.cxx @@ -1315,9 +1315,9 @@ namespace emfio } break; - case EMR_ELLIPSE : + case EMR_ELLIPSE: { - mpInputStream->ReadInt32( nX32 ).ReadInt32( nY32 ).ReadInt32( nx32 ).ReadInt32( ny32 ); + mpInputStream->ReadInt32(nX32).ReadInt32(nY32).ReadInt32(nx32).ReadInt32(ny32); SAL_INFO("emfio", " Rectangle, left: " << nX32 << ", top: " << nY32 << ", right: " << nx32 << ", bottom: " << ny32); sal_Int32 w(0), h(0); @@ -1327,9 +1327,9 @@ namespace emfio { tools::Long dw = w / 2; tools::Long dh = h / 2; - Point aCenter( nX32 + dw, nY32 + dh ); - tools::Polygon aPoly( aCenter, dw, dh ); - DrawPolygon( std::move(aPoly), mbRecordPath ); + Point aCenter(nX32 + dw, nY32 + dh); + tools::Polygon aPoly(aCenter, dw, dh); + DrawPolygon(std::move(aPoly), mbRecordPath); } } break; diff --git a/tools/source/generic/poly.cxx b/tools/source/generic/poly.cxx index 60345425fc53..f4bae3abb277 100644 --- a/tools/source/generic/poly.cxx +++ b/tools/source/generic/poly.cxx @@ -44,6 +44,10 @@ #include <limits.h> #include <cmath> +// Best approximation of circle with Bazier curve. +// Euclidean error between two curves is 0.00735 +constexpr double fKappa = 4.0 / 3.0 * (M_SQRT2 - 1); + constexpr int EDGE_LEFT = 1; constexpr int EDGE_TOP = 2; constexpr int EDGE_RIGHT = 4; @@ -194,46 +198,45 @@ ImplPolygon::ImplPolygon(const tools::Rectangle& rRect, sal_uInt32 nHorzRound, mnPoints = 0; } -ImplPolygon::ImplPolygon( const Point& rCenter, tools::Long nRadX, tools::Long nRadY ) +ImplPolygon::ImplPolygon(const Point& rCenter, tools::Long nRadX, tools::Long nRadY) { - if( nRadX && nRadY ) + if(nRadX && nRadY) { - // Compute default (depends on size) - sal_uInt16 nPoints = std::clamp( - ( M_PI * ( 1.5 * ( nRadX + nRadY ) - sqrt( std::fabs(double(nRadX) * nRadY) ) ) ), - 32.0, 256.0 ); + ImplInitSize(13, true); - if( ( nRadX > 32 ) && ( nRadY > 32 ) && ( nRadX + nRadY ) < 8192 ) - nPoints >>= 1; + mxPointAry[0] = Point(rCenter.X() - nRadX, rCenter.Y()); - // Ceil number of points until divisible by four - nPoints = (nPoints + 3) & ~3; - ImplInitSize(nPoints); + mxPointAry[1] = Point(rCenter.X() - nRadX, rCenter.Y() + fKappa * nRadY); + mxFlagAry[1] = PolyFlags::Control; - sal_uInt16 i; - sal_uInt16 nPoints2 = nPoints >> 1; - sal_uInt16 nPoints4 = nPoints >> 2; - double nAngle; - double nAngleStep = M_PI_2 / ( nPoints4 - 1 ); + mxPointAry[2] = Point(rCenter.X() - fKappa * nRadX, rCenter.Y() + nRadY); + mxFlagAry[2] = PolyFlags::Control; - for( i=0, nAngle = 0.0; i < nPoints4; i++, nAngle += nAngleStep ) - { - tools::Long nX = basegfx::fround<tools::Long>(nRadX * cos(nAngle)); - tools::Long nY = basegfx::fround<tools::Long>(nRadY * -sin(nAngle)); - - Point* pPt = &(mxPointAry[i]); - pPt->setX( nX + rCenter.X() ); - pPt->setY( nY + rCenter.Y() ); - pPt = &(mxPointAry[nPoints2-i-1]); - pPt->setX( -nX + rCenter.X() ); - pPt->setY( nY + rCenter.Y() ); - pPt = &(mxPointAry[i+nPoints2]); - pPt->setX( -nX + rCenter.X() ); - pPt->setY( -nY + rCenter.Y() ); - pPt = &(mxPointAry[nPoints-i-1]); - pPt->setX( nX + rCenter.X() ); - pPt->setY( -nY + rCenter.Y() ); - } + mxPointAry[3] = Point(rCenter.X(), rCenter.Y() + nRadY); + + mxPointAry[4] = Point(rCenter.X() + fKappa * nRadX, rCenter.Y() + nRadY); + mxFlagAry[4] = PolyFlags::Control; + + mxPointAry[5] = Point(rCenter.X() + nRadX, rCenter.Y() + fKappa * nRadY); + mxFlagAry[5] = PolyFlags::Control; + + mxPointAry[6] = Point(rCenter.X() + nRadX, rCenter.Y()); + + mxPointAry[7] = Point(rCenter.X() + nRadX, rCenter.Y() - fKappa * nRadY); + mxFlagAry[7] = PolyFlags::Control; + + mxPointAry[8] = Point(rCenter.X() + fKappa * nRadX, rCenter.Y() - nRadY); + mxFlagAry[8] = PolyFlags::Control; + + mxPointAry[9] = Point(rCenter.X(), rCenter.Y() - nRadY); + + mxPointAry[10] = Point(rCenter.X() - fKappa * nRadX, rCenter.Y() - nRadY); + mxFlagAry[10] = PolyFlags::Control; + + mxPointAry[11] = Point(rCenter.X() - nRadX, rCenter.Y() - fKappa * nRadY); + mxFlagAry[11] = PolyFlags::Control; + + mxPointAry[12] = mxPointAry[0]; } else mnPoints = 0;