Author: alg
Date: Mon Jul 30 10:40:40 2012
New Revision: 1367054

URL: http://svn.apache.org/viewvc?rev=1367054&view=rev
Log:
#115917# Better conversion of C1 and C2 bezier curve points
Patch by: osnola
Review by: alg

Modified:
    incubator/ooo/trunk/main/tools/source/generic/poly.cxx

Modified: incubator/ooo/trunk/main/tools/source/generic/poly.cxx
URL: 
http://svn.apache.org/viewvc/incubator/ooo/trunk/main/tools/source/generic/poly.cxx?rev=1367054&r1=1367053&r2=1367054&view=diff
==============================================================================
--- incubator/ooo/trunk/main/tools/source/generic/poly.cxx (original)
+++ incubator/ooo/trunk/main/tools/source/generic/poly.cxx Mon Jul 30 10:40:40 
2012
@@ -2106,7 +2106,7 @@ void Polygon::Write( SvStream& rOStream 
 }
 
 // -----------------------------------------------------------------------
-// #i74631# numerical correction method for B2DPolygon
+// numerical correction method for B2DPolygon
 void impCorrectContinuity(basegfx::B2DPolygon& roPolygon, sal_uInt32 nIndex, 
sal_uInt8 nCFlag)
 {
        const sal_uInt32 nPointCount(roPolygon.count());
@@ -2116,21 +2116,49 @@ void impCorrectContinuity(basegfx::B2DPo
        {
                if(roPolygon.isPrevControlPointUsed(nIndex) && 
roPolygon.isNextControlPointUsed(nIndex))
                {
+            // #115917# Patch from osnola (modified, thanks for showing the 
porblem)
+            //
+            // The correction is needed because an integer polygon with 
control points
+            // is converted to double precision. When C1 or C2 is used the 
involved vectors
+            // may not have the same directions/lengths since these come from 
integer coordinates
+            //  and may have been snapped to different nearest integer 
coordinates. The snap error
+            // is in the range of +-1 in y and y, thus 0.0 <= error <= 
sqrt(2.0). Nonetheless,
+            // it needs to be corrected to be able to detect the continuity in 
this points
+            // correctly.
+            //
+            // We only have the integer data here (already in double precision 
form, but no mantisses 
+            // used), so the best correction is to use:
+            //
+            // for C1: The longest vector since it potentially has best 
preserved the original vector.
+            //         Even better the sum of the vectors, weighted by their 
length. This gives the
+            //         normal vector addition to get the vector itself, 
lengths need to be preserved.
+            // for C2: The mediated vector(s) since both should be the same, 
but mirrored
+
+            // extract the point and vectors
                        const basegfx::B2DPoint 
aPoint(roPolygon.getB2DPoint(nIndex));
+            const basegfx::B2DVector 
aNext(roPolygon.getNextControlPoint(nIndex) - aPoint);
+            const basegfx::B2DVector aPrev(aPoint - 
roPolygon.getPrevControlPoint(nIndex));
+
+            // calculate common direction vector, normalize
+            const basegfx::B2DVector aDirection(aNext + aPrev);
 
                        if(POLY_SMOOTH == nCFlag)
                        {
-                               // C1: apply inverse direction of prev to next, 
keep length of next
-                               const basegfx::B2DVector 
aOriginalNext(roPolygon.getNextControlPoint(nIndex) - aPoint);
-                               basegfx::B2DVector aNewNext(aPoint - 
roPolygon.getPrevControlPoint(nIndex));
-
-                               aNewNext.setLength(aOriginalNext.getLength());
-                               roPolygon.setNextControlPoint(nIndex, 
basegfx::B2DPoint(aPoint + aNewNext));
+                // C1: apply common direction vector, preserve individual 
lengths
+                const double fInvDirectionLen(1.0 / aDirection.getLength());
+                               roPolygon.setNextControlPoint(nIndex, 
basegfx::B2DPoint(aPoint + (aDirection * (aNext.getLength() * 
fInvDirectionLen))));
+                               roPolygon.setPrevControlPoint(nIndex, 
basegfx::B2DPoint(aPoint - (aDirection * (aPrev.getLength() * 
fInvDirectionLen))));
                        }
                        else // POLY_SYMMTR
                        {
-                               // C2: apply inverse control point to next
-                               roPolygon.setNextControlPoint(nIndex, (2.0 * 
aPoint) - roPolygon.getPrevControlPoint(nIndex));
+                // C2: get mediated length. Taking half of the unnormalized 
direction would be
+                // an approximation, but not correct.
+                const double fMedLength((aNext.getLength() + 
aPrev.getLength()) * (0.5 / aDirection.getLength()));
+                const basegfx::B2DVector aScaledDirection(aDirection * 
fMedLength);
+
+                // Bring Direction to correct length and apply
+                               roPolygon.setNextControlPoint(nIndex, 
basegfx::B2DPoint(aPoint + aScaledDirection));
+                               roPolygon.setPrevControlPoint(nIndex, 
basegfx::B2DPoint(aPoint - aScaledDirection));
                        }
                }
        }


Reply via email to