Fix Path#arcTo() when from/to points are equal

Closes #1613
This commit is contained in:
sasensi 2018-11-23 11:04:45 +01:00 committed by Jürg Lehni
parent 4ba406bfe3
commit 3177c7ac46
3 changed files with 51 additions and 39 deletions

View file

@ -13,6 +13,7 @@
- Do not ignore `Group#clipItem.matrix` in `Group#internalBounds` (#1427). - Do not ignore `Group#clipItem.matrix` in `Group#internalBounds` (#1427).
- Correctly calculate bounds with nested empty items (#1467). - Correctly calculate bounds with nested empty items (#1467).
- Fix color change propagation on groups (#1152). - Fix color change propagation on groups (#1152).
- Fix `Path#arcTo()` where `from` and `to` points are equal (#1613).
- SVG Export: Fix error when `Item#matrix` is not invertible (#1580). - SVG Export: Fix error when `Item#matrix` is not invertible (#1580).
- SVG Export: Include missing viewBox attribute (#1576). - SVG Export: Include missing viewBox attribute (#1576).
- SVG Import: Use correct default values for gradients (#1632, #1661). - SVG Import: Use correct default values for gradients (#1632, #1661).

View file

@ -2467,9 +2467,10 @@ new function() { // PostScript-style drawing commands
// #2: arcTo(through, to) // #2: arcTo(through, to)
through = to; through = to;
to = Point.read(arguments); to = Point.read(arguments);
} else { } else if (!from.equals(to)) {
// #3: arcTo(to, radius, rotation, clockwise, large) // #3: arcTo(to, radius, rotation, clockwise, large)
// Drawing arcs in SVG style: // Draw arc in SVG style, but only if `from` and `to` are not
// equal (#1613).
var radius = Size.read(arguments), var radius = Size.read(arguments),
isZero = Numerical.isZero; isZero = Numerical.isZero;
// If rx = 0 or ry = 0 then this arc is treated as a // If rx = 0 or ry = 0 then this arc is treated as a
@ -2565,47 +2566,49 @@ new function() { // PostScript-style drawing commands
extent += extent < 0 ? 360 : -360; extent += extent < 0 ? 360 : -360;
} }
} }
var epsilon = /*#=*/Numerical.GEOMETRIC_EPSILON, if (extent) {
ext = abs(extent), var epsilon = /*#=*/Numerical.GEOMETRIC_EPSILON,
// Calculate the amount of segments required to approximate over ext = abs(extent),
// `extend` degrees (extend / 90), but prevent ceil() from // Calculate amount of segments required to approximate over
// rounding up small imprecisions by subtracting epsilon first. // `extend` degrees (extend / 90), but prevent ceil() from
count = ext >= 360 ? 4 : Math.ceil((ext - epsilon) / 90), // rounding up small imprecisions by subtracting epsilon.
inc = extent / count, count = ext >= 360 ? 4 : Math.ceil((ext - epsilon) / 90),
half = inc * Math.PI / 360, inc = extent / count,
z = 4 / 3 * Math.sin(half) / (1 + Math.cos(half)), half = inc * Math.PI / 360,
segments = []; z = 4 / 3 * Math.sin(half) / (1 + Math.cos(half)),
for (var i = 0; i <= count; i++) { segments = [];
// Explicitly use to point for last segment, since depending for (var i = 0; i <= count; i++) {
// on values the calculation adds imprecision: // Explicitly use to point for last segment, since depending
var pt = to, // on values the calculation adds imprecision:
out = null; var pt = to,
if (i < count) { out = null;
out = vector.rotate(90).multiply(z); if (i < count) {
if (matrix) { out = vector.rotate(90).multiply(z);
pt = matrix._transformPoint(vector); if (matrix) {
out = matrix._transformPoint(vector.add(out)) pt = matrix._transformPoint(vector);
.subtract(pt); out = matrix._transformPoint(vector.add(out))
.subtract(pt);
} else {
pt = center.add(vector);
}
}
if (!i) {
// Modify startSegment
current.setHandleOut(out);
} else { } else {
pt = center.add(vector); // Add new Segment
var _in = vector.rotate(-90).multiply(z);
if (matrix) {
_in = matrix._transformPoint(vector.add(_in))
.subtract(pt);
}
segments.push(new Segment(pt, _in, out));
} }
vector = vector.rotate(inc);
} }
if (!i) { // Add all segments at once at the end for higher performance
// Modify startSegment this._add(segments);
current.setHandleOut(out);
} else {
// Add new Segment
var _in = vector.rotate(-90).multiply(z);
if (matrix) {
_in = matrix._transformPoint(vector.add(_in))
.subtract(pt);
}
segments.push(new Segment(pt, _in, out));
}
vector = vector.rotate(inc);
} }
// Add all segments at once at the end for higher performance
this._add(segments);
}, },
lineBy: function(/* to */) { lineBy: function(/* to */) {

View file

@ -645,3 +645,11 @@ test('Path#arcTo(through, to) is on through point side (#1477)', function() {
path.arcTo(p2, p3); path.arcTo(p2, p3);
equals(true, path.segments[1].point.x > p1.x); equals(true, path.segments[1].point.x > p1.x);
}); });
test('Path#arcTo(to, radius, rotation, clockwise, large) when from and to are equal (#1613)', function(){
var point = new Point(10,10);
var path = new Path();
path.moveTo(point);
path.arcTo(point, new Size(10), 0, true, true);
expect(0);
});