Implement a better approach to calculate Path#clockwise...

...merging code with Path#area.

Closes #788
This commit is contained in:
Jürg Lehni 2015-09-18 21:41:54 +02:00
parent 8cf562c57b
commit b5af47a7b1
2 changed files with 16 additions and 28 deletions

View file

@ -665,29 +665,26 @@ statics: {
},
getArea: function(v) {
var p1x = v[0], p1y = v[1],
c1x = v[2], c1y = v[3],
c2x = v[4], c2y = v[5],
p2x = v[6], p2y = v[7];
// This is a combination of the methods to decide if a path is clockwise
// and to calculate the area, as described here:
// http://objectmix.com/graphics/133553-area-closed-bezier-curve.html
return ( 3.0 * c1y * p1x - 1.5 * c1y * c2x
- 1.5 * c1y * p2x - 3.0 * p1y * c1x
- 1.5 * p1y * c2x - 0.5 * p1y * p2x
+ 1.5 * c2y * p1x + 1.5 * c2y * c1x
- 3.0 * c2y * p2x + 0.5 * p2y * p1x
+ 1.5 * p2y * c1x + 3.0 * p2y * c2x) / 10;
},
getEdgeSum: function(v) {
// 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
return (v[0] - v[2]) * (v[3] + v[1])
+ (v[2] - v[4]) * (v[5] + v[3])
+ (v[4] - v[6]) * (v[7] + v[5]);
// telling you whether it's mostly clockwise.
// With bezier curves, the trick appears to be to calculate edge sum
// with half the handles' lengths, and then:
// area = 6 * edge-sum / 10
var p1x = v[0], p1y = v[1],
p2x = v[6], p2y = v[7],
h1x = (v[2] + p1x) / 2,
h1y = (v[3] + p1y) / 2,
h2x = (v[4] + v[6]) / 2,
h2y = (v[5] + v[7]) / 2;
return 6 * ((p1x - h1x) * (h1y + p1y)
+ (h1x - h2x) * (h2y + h1y)
+ (h2x - p2x) * (p2y + h2y)) / 10;
},
getBounds: function(v) {

View file

@ -847,16 +847,7 @@ var Path = PathItem.extend(/** @lends Path# */{
isClockwise: function() {
if (this._clockwise !== undefined)
return this._clockwise;
var segments = this._segments,
count = segments.length,
last = count - 1,
sum = 0;
// TODO: Check if this works correctly for all open paths.
for (var i = 0, l = this._closed ? count : last; i < l; i++) {
sum += Curve.getEdgeSum(Curve.getValues(
segments[i], segments[i < last ? i + 1 : 0]));
}
return sum > 0;
return this.getArea() >= 0;
},
setClockwise: function(clockwise) {