From 4c51544b6eae2089c3c507dec4299c0a013c5dfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Tue, 6 Nov 2012 01:22:16 -0800 Subject: [PATCH] Implement correct checks for primitives (rect, ellipse, circle). --- src/basic/Matrix.js | 2 +- src/path/Path.Constructors.js | 3 +- src/svg/SvgExporter.js | 63 +++++++++++++++++++++-------------- 3 files changed, 41 insertions(+), 27 deletions(-) diff --git a/src/basic/Matrix.js b/src/basic/Matrix.js index 73e07dab..03e14f7d 100644 --- a/src/basic/Matrix.js +++ b/src/basic/Matrix.js @@ -487,7 +487,7 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ getRotation: function() { var angle1 = -Math.atan2(this._b, this._d), angle2 = Math.atan2(this._c, this._a); - return Math.abs(angle1 - angle2) < Numerical.TOLERANCE + return Math.abs(angle1 - angle2) < Numerical.EPSILON ? angle1 * 180 / Math.PI : undefined; }, diff --git a/src/path/Path.Constructors.js b/src/path/Path.Constructors.js index 507c626a..75981074 100644 --- a/src/path/Path.Constructors.js +++ b/src/path/Path.Constructors.js @@ -15,7 +15,8 @@ */ Path.inject({ statics: new function() { - var kappa = 2 / 3 * (Math.sqrt(2) - 1); + // Kappa, see: http://www.whizkidtech.redprince.net/bezier/circle/kappa/ + var kappa = 2 * (Math.sqrt(2) - 1) / 3; var ovalSegments = [ new Segment([0, 0.5], [0, kappa ], [0, -kappa]), diff --git a/src/svg/SvgExporter.js b/src/svg/SvgExporter.js index 7fec59ea..5030a679 100644 --- a/src/svg/SvgExporter.js +++ b/src/svg/SvgExporter.js @@ -224,44 +224,57 @@ var SvgExporter = this.SvgExporter = new function() { } function determineType(path, segments) { + + function isOrthogonal(i) { + var segment = segments[i], + point = segment.getPoint(); + return Numerical.isZero(90 - Math.abs( + segment.getNext().getPoint().subtract(point).getAngle( + segment.getPrevious().getPoint().subtract(point)))); + } + + // Kappa, see: http://www.whizkidtech.redprince.net/bezier/circle/kappa/ + var kappa = 4 * (Math.sqrt(2) - 1) / 3; + + function isArc(i) { + var segment = segments[i], + next = segment.getNext(), + handle1 = segment.getHandleOut(), + handle2 = next.getHandleIn(); + if (Numerical.isZero(90 - Math.abs(handle1.getAngle(handle2)))) { + var from = segment.getPoint(), + to = next.getPoint(), + corner = new Line(from, handle1).intersect(new Line(to, handle2)); + return Numerical.isZero(handle1.length / corner.subtract(from).length - kappa) + && Numerical.isZero(handle2.length / corner.subtract(to).length - kappa); + } + } + // See if actually have any curves in the path. Differentiate // between straight objects (line, polyline, rect, and polygon) and // objects with curves(circle, ellipse, roundedRectangle). if (path.isPolygon()) { - // If the distance between (point0 and point1) and (point2 and - // point3) are equal, then it is a rectangle - return segments.length == 4 && Numerical.isZero( - getDistance(segments, 0, 1) - getDistance(segments, 3, 2)) + return segments.length === 4 && path._closed && isOrthogonal(0) + && isOrthogonal(1) && isOrthogonal(2) && isOrthogonal(3) ? 'rect' : segments.length >= 3 ? path._closed ? 'polygon' : 'polyline' : 'line'; - } else { - if (segments.length == 8) { + } else if (path._closed) { + if (segments.length === 8) { // If the distance between (point0 and point3) and (point7 and // point4) are equal then it is a roundedRectangle if (Numerical.isZero( getDistance(segments, 0, 3) - getDistance(segments, 7, 5))) return 'roundrect'; - } else if (segments.length == 4) { - // Check if the values of the point have values similar to - // circles and ellipses. - var checkPointValues = true; - for (var i = 0; i < segments.length && checkPointValues; i++) { - var handleIn = segments[i]._handleIn, - handleOut = segments[i]._handleOut; - checkPointValues = !handleIn.isZero() - && Numerical.isZero(Math.abs(handleIn._x) - Math.abs(handleOut._x)) - && Numerical.isZero(Math.abs(handleIn._y) - Math.abs(handleOut._y)); - } - if (checkPointValues) { - // If the distance between (point0 and point2) and (point1 - // and point3) are equal, then it is a circle - return Numerical.isZero(getDistance(segments, 0, 2) - - getDistance(segments, 1, 3)) - ? 'circle' - : 'ellipse'; - } + } else if (segments.length === 4 + && isArc(0) && isArc(1) && isArc(2) && isArc(3)) { + // If the distance between (point0 and point2) and (point1 + // and point3) are equal, then it is a circle + return Numerical.isZero(getDistance(segments, 0, 2) + - getDistance(segments, 1, 3)) + ? 'circle' + : 'ellipse'; } } return 'path';