From 40c988b313c6972afc27db69f0d115f969f4b6e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Sun, 15 May 2011 17:59:06 +0100 Subject: [PATCH 1/5] Add Path#is/setClockwise(), as a way to check and define a path's orientation. --- src/path/Path.js | 83 +++++++++++++++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 30 deletions(-) diff --git a/src/path/Path.js b/src/path/Path.js index 330d0058..4c84f60c 100644 --- a/src/path/Path.js +++ b/src/path/Path.js @@ -34,6 +34,8 @@ var Path = this.Path = PathItem.extend({ delete this._bounds; delete this._position; delete this._strokeBounds; + // Clockwise state becomes undefined as soon as geometry changes. + delete this._clockwise; } else if (flags & ChangeFlags.STROKE) { delete this._strokeBounds; } @@ -302,20 +304,66 @@ var Path = this.Path = PathItem.extend({ // TODO: curvesToPoints([maxPointDistance[, flatness]]) // TODO: reduceSegments([flatness]) // TODO: split(offset) / split(location) / split(index[, parameter]) - + + /** + * Returns true if the path is oriented clock-wise, false otherwise. + */ + isClockwise: function() { + if (this._clockwise !== undefined) + return this._clockwise; + var sum = 0, + xPre, yPre; + function edge(x, y) { + if (xPre !== undefined) + sum += (xPre - x) * (y + yPre); + xPre = x; + yPre = y; + } + // Method derived from: + // http://stackoverflow.com/questions/1165647 + // We treat the curve points and handles as the outline of a polygon of + // which we determine the orientation using the method of calculating + // the sum over the edges. This will work even with non-convex polygons, + // telling you whether it's mostly clockwise + for (var i = 0, l = this._segments.length; i < l; i++) { + var seg1 = this._segments[i], + seg2 = this._segments[i + 1 < l ? i + 1 : 0], + point1 = seg1._point, + handle1 = seg1._handleOut, + handle2 = seg2._handleIn, + point2 = seg2._point; + edge(point1._x, point1._y); + edge(point1._x + handle1._x, point1._y + handle1._y); + edge(point2._x + handle2._x, point2._y + handle2._y); + edge(point2._x, point2._y); + } + return this._clockwise = sum > 0; + }, + + setClockwise: function(clockwise) { + // On-the-fly conversion to boolean: + if (this.isClockwise() != (clockwise = !!clockwise)) { + // Only revers the path if its clockwise orientation is not the same + // as what it is now demanded to be. + this.reverse(); + } + }, + /** * Reverses the segments of the path. */ reverse: function() { - var segments = this._segments; - segments.reverse(); + this._segments.reverse(); // Reverse the handles: - for (var i = 0, l = segments.length; i < l; i++) { - var segment = segments[i]; + for (var i = 0, l = this._segments.length; i < l; i++) { + var segment = this._segments[i]; var handleIn = segment._handleIn; segment._handleIn = segment._handleOut; segment._handleOut = handleIn; } + // Flip clockwise state if it's defined + if (this._clockwise !== undefined) + this._clockwise = !this._clockwise; }, join: function(path) { @@ -356,31 +404,6 @@ var Path = this.Path = PathItem.extend({ return false; }, - getOrientation: function() { - var sum = 0; - var xPre, yPre; - function edge(x, y) { - if (xPre !== undefined) { - sum += (xPre - x) * (y + yPre); - } - xPre = x; - yPre = y; - } - for (var i = 0, l = this._segments.length; i < l; i++) { - var seg1 = this._segments[i]; - var seg2 = this._segments[i + 1 < l ? i + 1 : 0]; - var point1 = seg1._point; - var handle1 = seg1._handleOut; - var handle2 = seg2._handleIn; - var point2 = seg2._point; - edge(point1._x, point1._y); - edge(point1._x + handle1._x, point1._y + handle1._y); - edge(point2._x + handle2._x, point2._y + handle2._y); - edge(point2._x, point2._y); - } - return sum; - }, - getLength: function() { if (this._length == null) { var curves = this.getCurves(); From 6e0e31480ac331bdacb4efa96f7af2e9744ccf9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Sun, 15 May 2011 17:59:37 +0100 Subject: [PATCH 2/5] Remove recently introduced code blocks for small conditional statements. --- src/tool/ToolHandler.js | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/src/tool/ToolHandler.js b/src/tool/ToolHandler.js index 51e1ca41..db45ac74 100644 --- a/src/tool/ToolHandler.js +++ b/src/tool/ToolHandler.js @@ -25,9 +25,8 @@ var ToolHandler = this.ToolHandler = Base.extend({ this._firstMove = true; this._count = 0; this._downCount = 0; - for (var i in handlers) { + for (var i in handlers) this[i] = handlers[i]; - } }, /** @@ -59,10 +58,8 @@ var ToolHandler = this.ToolHandler = Base.extend({ }, getFixedDistance: function() { - if (this._minDistance == this._maxDistance) { - return this._minDistance; - } - return null; + return this._minDistance == this._maxDistance + ? this._minDistance : null; }, setFixedDistance: function(distance) { @@ -77,9 +74,8 @@ var ToolHandler = this.ToolHandler = Base.extend({ var minDist = minDistance != null ? minDistance : 0; var vector = pt.subtract(this._point); var distance = vector.getLength(); - if (distance < minDist) { + if (distance < minDist) return false; - } // Produce a new point on the way to pt if pt is further away // than maxDistance var maxDist = maxDistance != null ? maxDistance : 0; @@ -91,9 +87,8 @@ var ToolHandler = this.ToolHandler = Base.extend({ } } } - if (needsChange && pt.equals(this._point)) { + if (needsChange && pt.equals(this._point)) return false; - } } this._lastPoint = this._point; this._point = pt; @@ -118,9 +113,8 @@ var ToolHandler = this.ToolHandler = Base.extend({ switch (type) { case 'mousedown': this.updateEvent(type, pt, null, null, true, false, false); - if (this.onMouseDown) { + if (this.onMouseDown) this.onMouseDown(new ToolEvent(this, type, event)); - } break; case 'mousedrag': // In order for idleInterval drag events to work, we need to not @@ -135,9 +129,8 @@ var ToolHandler = this.ToolHandler = Base.extend({ matchMaxDistance = false; while (this.updateEvent(type, pt, this.minDistance, this.maxDistance, false, needsChange, matchMaxDistance)) { - if (this.onMouseDrag) { + if (this.onMouseDrag) this.onMouseDrag(new ToolEvent(this, type, event)); - } needsChange = true; matchMaxDistance = true; } @@ -148,15 +141,13 @@ var ToolHandler = this.ToolHandler = Base.extend({ if ((this._point.x != pt.x || this._point.y != pt.y) && this.updateEvent('mousedrag', pt, this.minDistance, this.maxDistance, false, false, false)) { - if (this.onMouseDrag) { + if (this.onMouseDrag) this.onMouseDrag(new ToolEvent(this, type, event)); - } } this.updateEvent(type, pt, null, this.maxDistance, false, false, false); - if (this.onMouseUp) { + if (this.onMouseUp) this.onMouseUp(new ToolEvent(this, type, event)); - } // Start with new values for 'mousemove' this.updateEvent(type, pt, null, null, true, false, false); this._firstMove = true; @@ -164,9 +155,8 @@ var ToolHandler = this.ToolHandler = Base.extend({ case 'mousemove': while (this.updateEvent(type, pt, this.minDistance, this.maxDistance, this._firstMove, true, false)) { - if (this.onMouseMove) { + if (this.onMouseMove) this.onMouseMove(new ToolEvent(this, type, event)); - } this._firstMove = false; } break; From 813b70c70bdab3455a13e84780fb2d935112d09f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Sun, 15 May 2011 17:59:57 +0100 Subject: [PATCH 3/5] Update comment a bit to make code more clear. --- src/path/CompoundPath.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/path/CompoundPath.js b/src/path/CompoundPath.js index e856b874..78305a7e 100644 --- a/src/path/CompoundPath.js +++ b/src/path/CompoundPath.js @@ -22,9 +22,9 @@ var CompoundPath = this.CompoundPath = PathItem.extend({ if (items) { for (var i = 0, l = items.length; i < l; i++) { var item = items[i]; - // All paths except for the first one are reversed when - // creating a compound path, so that they draw holes. - // When keepDirection is set to true, child paths aren't reversed. + // All paths except for the top one (last one in list) are + // reversed when creating a compound path, so that they draw + // holes. When keepDirection is set, children aren't reversed. if (!keepDirection && i != l - 1) item.reverse(); this.appendTop(items[i]); From 3d760346006339b7b57ee962df9995274c8314cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Sun, 15 May 2011 18:05:00 +0100 Subject: [PATCH 4/5] Use Path#setClockwise() in CompoundPath constructor to reverse top path so that the others appear as holes cut out from it. --- src/path/CompoundPath.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/path/CompoundPath.js b/src/path/CompoundPath.js index 78305a7e..4608efe1 100644 --- a/src/path/CompoundPath.js +++ b/src/path/CompoundPath.js @@ -15,18 +15,18 @@ */ var CompoundPath = this.CompoundPath = PathItem.extend({ - // PORT: port the reversing of segments and keepDirection flag - initialize: function(items, keepDirection) { + initialize: function(items) { this.base(); this._children = []; if (items) { for (var i = 0, l = items.length; i < l; i++) { var item = items[i]; // All paths except for the top one (last one in list) are - // reversed when creating a compound path, so that they draw - // holes. When keepDirection is set, children aren't reversed. - if (!keepDirection && i != l - 1) - item.reverse(); + // set to clockwise orientation when creating a compound path, + // so that they appear as holes, but only if their orientation + // was not already specified before (= _clockwise is defined). + if (item._clockwise === undefined) + item.setClockwise(i < l - 1); this.appendTop(items[i]); } } From 4cee442a05b1dc2f906712593085cfe9d5f916d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Sun, 15 May 2011 18:05:47 +0100 Subject: [PATCH 5/5] Rename items parameter to paths. --- src/path/CompoundPath.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/path/CompoundPath.js b/src/path/CompoundPath.js index 4608efe1..0bc95726 100644 --- a/src/path/CompoundPath.js +++ b/src/path/CompoundPath.js @@ -15,19 +15,19 @@ */ var CompoundPath = this.CompoundPath = PathItem.extend({ - initialize: function(items) { + initialize: function(paths) { this.base(); this._children = []; - if (items) { - for (var i = 0, l = items.length; i < l; i++) { - var item = items[i]; + if (paths) { + for (var i = 0, l = paths.length; i < l; i++) { + var path = paths[i]; // All paths except for the top one (last one in list) are // set to clockwise orientation when creating a compound path, // so that they appear as holes, but only if their orientation // was not already specified before (= _clockwise is defined). - if (item._clockwise === undefined) - item.setClockwise(i < l - 1); - this.appendTop(items[i]); + if (path._clockwise === undefined) + path.setClockwise(i < l - 1); + this.appendTop(path); } } },