[Libreoffice-commits] libcdr.git: src/lib

Fridrich Å trba fridrich.strba at bluewin.ch
Fri Apr 5 16:07:10 PDT 2013


 src/lib/CDRTransforms.cpp |  142 +++++++++++++++++++++++++++++++---------------
 src/lib/CDRTransforms.h   |    2 
 src/lib/libcdr_utils.h    |    2 
 3 files changed, 99 insertions(+), 47 deletions(-)

New commits:
commit 1c679333dfa9fd5c02110323955bbc1412eafea1
Author: Fridrich Å trba <fridrich.strba at bluewin.ch>
Date:   Sat Apr 6 01:06:40 2013 +0200

    Rewrite the elliptical arc transformations

diff --git a/src/lib/CDRTransforms.cpp b/src/lib/CDRTransforms.cpp
index 5876664..950f0fc 100644
--- a/src/lib/CDRTransforms.cpp
+++ b/src/lib/CDRTransforms.cpp
@@ -56,71 +56,123 @@ void libcdr::CDRTransform::applyToPoint(double &x, double &y) const
   x = tmpX;
 }
 
-void libcdr::CDRTransform::applyToArc(double &rx, double &ry, double &rotation, bool &sweep, double &x, double &y) const
+void libcdr::CDRTransform::applyToArc(double &rx, double &ry, double &rotation, bool &sweep, double &endx, double &endy) const
 {
-  // First transform the end-point, which is the easiest
-  applyToPoint(x, y);
+  // Transform the end-point, which is the easiest
+  applyToPoint(endx, endy);
+
+  // Determine whether sweep should change
+  double determinant = m_v0*m_v4 - m_v1*m_v3;
+  if (determinant < 0.0)
+    sweep = !sweep;
 
-  // represent ellipse as a transformed unit circle
-  double v0 = m_v0*rx*cos(rotation) - m_v1*rx*sin(rotation);
-  double v1 = m_v1*ry*cos(rotation) + m_v0*ry*sin(rotation);
-  double v3 = m_v3*rx*cos(rotation) - m_v4*rx*sin(rotation);
-  double v4 = m_v4*ry*cos(rotation) + m_v3*ry*sin(rotation);
+  // Transform a centered ellipse
+
+  // rx = 0 and ry = 0
+  if (CDR_ALMOST_ZERO(rx) && CDR_ALMOST_ZERO(ry))
+  {
+    rotation = rx = ry = 0.0;
+    return;
+  }
 
-  // centered implicit equation
-  double A = v0*v0 + v1*v1;
-  double C = v3*v3 + v4*v4;
-  double B = 2.0*(v0*v3  +  v1*v4);
+  double c = cos(rotation);
+  double s = sin(rotation);
 
-  double r1, r2;
-  // convert implicit equation to angle and halfaxis:
-  if (CDR_ALMOST_ZERO(B))
+  // rx > 0, ry = 0
+  if (CDR_ALMOST_ZERO(ry))
   {
-    rotation = 0;
-    r1 = A;
-    r2 = C;
+    double x = m_v0*c + m_v1*s;
+    double y = m_v3*c + m_v4*s;
+    rx *= sqrt(x*x + y*y);
+    if (CDR_ALMOST_ZERO(rx))
+    {
+      rotation = rx = ry = 0;
+      return;
+    }
+    rotation = atan2(y, x);
+    return;
   }
-  else
+
+  // rx = 0, ry > 0
+  if (CDR_ALMOST_ZERO(rx))
   {
-    if (CDR_ALMOST_ZERO(A-C))
+    double x = -m_v0*s + m_v1*c;
+    double y = -m_v3*s + m_v4*c;
+    ry *= sqrt(x*x + y*y);
+    if (CDR_ALMOST_ZERO(ry))
     {
-      r1 = A + B / 2.0;
-      r2 = A - B / 2.0;
-      rotation = M_PI / 4.0;
+      rotation = rx = ry = 0;
+      return;
     }
+    rotation = atan2(y, x) - M_PI/2.0;
+    return;
+  }
+
+  double v0, v1, v2, v3;
+  if (!CDR_ALMOST_ZERO(determinant))
+  {
+    v0 = ry*(m_v4*c - m_v3*s);
+    v1 = ry*(m_v0*s - m_v1*c);
+    v2 = -rx*(m_v4*s + m_v3*c);
+    v3 = rx*(m_v1*s + m_v0*c);
+
+    // Transformed ellipse
+    double A = v0*v0 + v2*v2;
+    double B = 2.0*(v0*v1 + v2*v3);
+    double C = v1*v1 + v3*v3;
+
+    // Rotate the transformed ellipse
+    if (CDR_ALMOST_ZERO(B))
+      rotation = 0;
     else
     {
-      double radical = 1.0 + B*B /((A-C)*(A-C));
-      radical = radical < 0.0 ? 0.0 : sqrt (radical);
+      rotation = atan2(B, A-C) / 2.0;
+      c = cos(rotation);
+      s = sin(rotation);
+      double cc = c*c;
+      double ss = s*s;
+      double sc = B*s*c;
+      B = A;
+      A = B*cc + sc + C*ss;
+      C = B*ss - sc + C*cc;
+    }
 
-      r1 = (A+C + radical*(A-C)) / 2.0;
-      r2 = (A+C - radical*(A-C)) / 2.0;
-      rotation = atan2(B,(A-C)) / 2.0;
+    // Compute rx and ry from A and C
+    if (!CDR_ALMOST_ZERO(A) && !CDR_ALMOST_ZERO(C))
+    {
+      double abdet = fabs(rx*ry*determinant);
+      A = sqrt(fabs(A));
+      C = sqrt(fabs(C));
+      rx = abdet / A;
+      ry = abdet / C;
+      return;
     }
   }
 
-  // Prevent sqrt of a negative number, however small it might be.
-  r1 = r1 < 0.0 ? 0.0 : sqrt(r1);
-  r2 = r2 < 0.0 ? 0.0 : sqrt(r2);
+  // Special case of a close to singular transformation
+  v0 = ry*(m_v4*c - m_v3*s);
+  v1 = ry*(m_v1*c - m_v0*s);
+  v2 = rx*(m_v3*c + m_v4*s);
+  v3 = rx*(m_v0*c + m_v1*s);
 
-  // now r1 and r2 are half-axis:
-  if ((A-C) <= 0)
+  // The result of transformation is a point
+  if (CDR_ALMOST_ZERO(v3*v3 + v1*v1) && CDR_ALMOST_ZERO(v2*v2 + v0*v0))
   {
-    ry = r1;
-    rx = r2;
+    rotation = rx = ry = 0;
+    return;
   }
-  else
+  else // The result of transformation is a line
   {
-    ry = r2;
-    rx = r1;
+    double x = sqrt(v3*v3 + v1*v1);
+    double y = sqrt(v2*v2 + v0*v0);
+    if (v3*v3 + v1*v1 >= v2*v2 + v0*v0)
+      y = (v2*v2 + v0*v0) / x;
+    else
+      x = (v3*v3 + v1*v1) / y;
+    rx = sqrt(x*x + y*y);
+    ry = 0;
+    rotation = atan2(y, x);
   }
-
-  // sweep is inversed each time the arc is flipped
-  if (v0 < 0)
-    sweep = !sweep;
-  if (v4 < 0)
-    sweep = !sweep;
-
 }
 
 double libcdr::CDRTransform::_getScaleX() const
diff --git a/src/lib/CDRTransforms.h b/src/lib/CDRTransforms.h
index 0e96c80..8bcbe34 100644
--- a/src/lib/CDRTransforms.h
+++ b/src/lib/CDRTransforms.h
@@ -44,7 +44,7 @@ public:
   CDRTransform(const CDRTransform &trafo);
 
   void applyToPoint(double &x, double &y) const;
-  void applyToArc(double &rx, double &ry, double &rotation, bool &sweep, double &x, double &y) const;
+  void applyToArc(double &rx, double &ry, double &rotation, bool &sweep, double &endx, double &endy) const;
   double getScaleX() const;
   double getScaleY() const;
   double getTranslateX() const;
diff --git a/src/lib/libcdr_utils.h b/src/lib/libcdr_utils.h
index 271b8bf..e9f80eb 100644
--- a/src/lib/libcdr_utils.h
+++ b/src/lib/libcdr_utils.h
@@ -43,7 +43,7 @@
 #endif
 
 #define CDR_EPSILON 1E-6
-#define CDR_ALMOST_ZERO(m) fabs(m) <= CDR_EPSILON
+#define CDR_ALMOST_ZERO(m) (fabs(m) <= CDR_EPSILON)
 
 #ifdef _MSC_VER
 


More information about the Libreoffice-commits mailing list