[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