Add sameDir parameter it #isCollinear() functions and use it in Path#reduce().

This commit is contained in:
Jürg Lehni 2016-01-05 14:51:55 +01:00
parent 0a7bb06d93
commit cb6afda083
4 changed files with 17 additions and 10 deletions

View file

@ -113,8 +113,9 @@ var Line = Base.extend(/** @lends Line# */{
point.x, point.y, true)); point.x, point.y, true));
}, },
isCollinear: function(line) { isCollinear: function(line, sameDir) {
return Point.isCollinear(this._vx, this._vy, line._vx, line._vy); return Point.isCollinear(this._vx, this._vy, line._vx, line._vy,
sameDir);
}, },
isOrthogonal: function(line) { isOrthogonal: function(line) {

View file

@ -704,8 +704,9 @@ var Point = Base.extend(/** @lends Point# */{
* @return {Boolean} {@true it is collinear} * @return {Boolean} {@true it is collinear}
*/ */
isCollinear: function(/* point */) { isCollinear: function(/* point */) {
var point = Point.read(arguments); var point = Point.read(arguments),
return Point.isCollinear(this.x, this.y, point.x, point.y); sameDir = Base.read(arguments);
return Point.isCollinear(this.x, this.y, point.x, point.y, sameDir);
}, },
// TODO: Remove version with typo after a while (deprecated June 2015) // TODO: Remove version with typo after a while (deprecated June 2015)
@ -917,14 +918,16 @@ var Point = Base.extend(/** @lends Point# */{
return new Point(Math.random(), Math.random()); return new Point(Math.random(), Math.random());
}, },
isCollinear: function(x1, y1, x2, y2) { isCollinear: function(x1, y1, x2, y2, sameDir) {
// NOTE: We use normalized vectors so that the epsilon comparison is // NOTE: We use normalized vectors so that the epsilon comparison is
// reliable. We could instead scale the epsilon based on the vector // reliable. We could instead scale the epsilon based on the vector
// length. But instead of normalizing the vectors before calculating // length. But instead of normalizing the vectors before calculating
// the cross product, we can scale the epsilon accordingly. // the cross product, we can scale the epsilon accordingly.
var d2 = x2 * x2 + y2 * y2;
return Math.abs(x1 * y2 - y1 * x2) return Math.abs(x1 * y2 - y1 * x2)
<= Math.sqrt((x1 * x1 + y1 * y1) * (x2 * x2 + y2 * y2)) <= Math.sqrt((x1 * x1 + y1 * y1) * d2)
* /*#=*/Numerical.TRIGONOMETRIC_EPSILON; * /*#=*/Numerical.TRIGONOMETRIC_EPSILON
&& (!sameDir || (x1 * x2 + y1 * y2) / d2 >= 0);
}, },
isOrthogonal: function(x1, y1, x2, y2) { isOrthogonal: function(x1, y1, x2, y2) {

View file

@ -949,9 +949,9 @@ statics: {
* @param {Curve} curve the other curve to check against * @param {Curve} curve the other curve to check against
* @return {Boolean} {@true if the two lines are collinear} * @return {Boolean} {@true if the two lines are collinear}
*/ */
isCollinear: function(curve) { isCollinear: function(curve, sameDir) {
return curve && this.isStraight() && curve.isStraight() return curve && this.isStraight() && curve.isStraight()
&& this.getLine().isCollinear(curve.getLine()); && this.getLine().isCollinear(curve.getLine(), sameDir);
}, },
/** /**

View file

@ -1032,7 +1032,10 @@ var Path = PathItem.extend(/** @lends Path# */{
var curve = curves[i]; var curve = curves[i];
if (!curve.hasHandles() if (!curve.hasHandles()
&& (curve.getLength() < /*#=*/Numerical.GEOMETRIC_EPSILON && (curve.getLength() < /*#=*/Numerical.GEOMETRIC_EPSILON
|| curve.isCollinear(curve.getNext()))) // Pass true for sameDir, as we can only remove straight
// curves if they point in the same direction as the next
// curve, not 180° in the opposite direction.
|| curve.isCollinear(curve.getNext(), true)))
curve.remove(); curve.remove();
} }
return this; return this;