diff --git a/src/curve/monotone.js b/src/curve/monotone.js index f36b7ac..2599031 100644 --- a/src/curve/monotone.js +++ b/src/curve/monotone.js @@ -9,8 +9,8 @@ function sign(x) { function slope3(that, x2, y2) { var h0 = that._x1 - that._x0, h1 = x2 - that._x1, - s0 = (that._y1 - that._y0) / h0, - s1 = (y2 - that._y1) / h1, + s0 = (that._y1 - that._y0) / (h0 || h1 < 0 && -0), + s1 = (y2 - that._y1) / (h1 || h0 < 0 && -0), p = (s0 * h1 + s1 * h0) / (h0 + h1); return (sign(s0) + sign(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0; } diff --git a/test/curve/monotoneX-test.js b/test/curve/monotoneX-test.js index 30baaf1..c5efb26 100644 --- a/test/curve/monotoneX-test.js +++ b/test/curve/monotoneX-test.js @@ -27,6 +27,13 @@ tape("line.curve(curveMonotoneX)(data) handles duplicate x-values", function(tes test.end(); }); +tape("line.curve(curveMonotoneX)(data) handles segments of infinite slope", function(test) { + var l = shape.line().curve(shape.curveMonotoneX); + test.pathEqual(l([[0, 200], [100, 150], [100, 50], [200, 0]]), "M0,200C33.333333,191.666667,66.666667,183.333333,100,150C100,150,100,50,100,50C133.333333,16.666667,166.666667,8.333333,200,0"); + test.pathEqual(l([[200, 0], [100, 50], [100, 150], [0, 200]]), "M200,0C166.666667,8.333333,133.333333,16.666667,100,50C100,50,100,150,100,150C66.666667,183.333333,33.333333,191.666667,0,200"); + test.end(); +}); + tape("line.curve(curveMonotoneX)(data) ignores coincident points", function(test) { var l = shape.line().curve(shape.curveMonotoneX), p = l([[0, 200], [50, 200], [100, 100], [150, 0], [200, 0]]); diff --git a/test/curve/monotoneY-test.js b/test/curve/monotoneY-test.js index f2eab0c..690252a 100644 --- a/test/curve/monotoneY-test.js +++ b/test/curve/monotoneY-test.js @@ -27,6 +27,13 @@ tape("line.curve(curveMonotoneY)(data) handles duplicate x-values", function(tes test.end(); }); +tape("line.curve(curveMonotoneY)(data) handles segments of infinite slope", function(test) { + var l = shape.line().curve(shape.curveMonotoneY); + test.pathEqual(l([[0, 200], [100, 150], [100, 50], [200, 0]].map(reflect)), "M200,0C191.666667,33.333333,183.333333,66.666667,150,100C150,100,50,100,50,100C16.666667,133.333333,8.333333,166.666667,0,200"); + test.pathEqual(l([[200, 0], [100, 50], [100, 150], [0, 200]].map(reflect)), "M0,200C8.333333,166.666667,16.666667,133.333333,50,100C50,100,150,100,150,100C183.333333,66.666667,191.666667,33.333333,200,0"); + test.end(); +}); + tape("line.curve(curveMonotoneY)(data) ignores coincident points", function(test) { var l = shape.line().curve(shape.curveMonotoneY), p = l([[0, 200], [50, 200], [100, 100], [150, 0], [200, 0]].map(reflect));