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.st...@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
_______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits