fix(core): Make path.shiftAlong more precise. Closes #976
This commit is contained in:
parent
dd26804534
commit
b51add044b
3 changed files with 49 additions and 14 deletions
|
@ -1,3 +1,13 @@
|
|||
2.15.2:
|
||||
date: 2021-04-28
|
||||
|
||||
Fixed:
|
||||
core:
|
||||
- Path.shiftAlong takes now an optional second paramter to control
|
||||
the number of steps the path will be divided in per Mm (if it's a curve)
|
||||
default is 25
|
||||
See [#976](https://github.com/freesewing/freesewing/issues/976)
|
||||
|
||||
2.15.1:
|
||||
date: 2021-04-24
|
||||
|
||||
|
|
|
@ -420,7 +420,7 @@ function joinPaths(paths, closed = false, raise = false) {
|
|||
}
|
||||
|
||||
/** Returns a point that lies at distance along this */
|
||||
Path.prototype.shiftAlong = function (distance) {
|
||||
Path.prototype.shiftAlong = function (distance, stepsPerMm = 25) {
|
||||
if (typeof distance !== 'number')
|
||||
this.raise.error('Called `Path.shiftAlong(distance)` but `distance` is not a number')
|
||||
let len = 0
|
||||
|
@ -439,7 +439,8 @@ Path.prototype.shiftAlong = function (distance) {
|
|||
{ x: op.to.x, y: op.to.y }
|
||||
)
|
||||
let thisLen = bezier.length()
|
||||
if (len + thisLen > distance) return shiftAlongBezier(distance - len, bezier)
|
||||
if (len + thisLen > distance)
|
||||
return shiftAlongBezier(distance - len, bezier, thisLen * stepsPerMm)
|
||||
else len += thisLen
|
||||
}
|
||||
current = op.to
|
||||
|
@ -450,15 +451,14 @@ Path.prototype.shiftAlong = function (distance) {
|
|||
}
|
||||
|
||||
/** Returns a point that lies at fraction along this */
|
||||
Path.prototype.shiftFractionAlong = function (fraction) {
|
||||
Path.prototype.shiftFractionAlong = function (fraction, stepsPerMm = 25) {
|
||||
if (typeof fraction !== 'number')
|
||||
this.raise.error('Called `Path.shiftFractionAlong(fraction)` but `fraction` is not a number')
|
||||
return this.shiftAlong(this.length() * fraction)
|
||||
return this.shiftAlong(this.length() * fraction, stepsPerMm)
|
||||
}
|
||||
|
||||
/** Returns a point that lies at distance along bezier */
|
||||
function shiftAlongBezier(distance, bezier) {
|
||||
let steps = 100
|
||||
function shiftAlongBezier(distance, bezier, steps = 100) {
|
||||
let previous, next, t, thisLen
|
||||
let len = 0
|
||||
for (let i = 0; i <= steps; i++) {
|
||||
|
|
|
@ -38,8 +38,8 @@ it("Should offset a curve where cp1 = start", () => {
|
|||
.curve(new a.Point(0, 0), new a.Point(123, 34), new a.Point(23, 4));
|
||||
a.paths.offset = a.paths.curve.offset(10);
|
||||
pattern.render();
|
||||
expect(round(a.paths.offset.bottomRight.x)).to.equal(72.68);
|
||||
expect(round(a.paths.offset.bottomRight.y)).to.equal(26.49);
|
||||
expect(round(a.paths.offset.bottomRight.x)).to.equal(72.63);
|
||||
expect(round(a.paths.offset.bottomRight.y)).to.equal(26.48);
|
||||
});
|
||||
|
||||
it("Should offset a curve where cp2 = end", () => {
|
||||
|
@ -221,6 +221,30 @@ it("Should throw error when shifting along path further than it's long", () => {
|
|||
expect(() => a.paths.test.shiftAlong(500)).to.throw();
|
||||
});
|
||||
|
||||
it("Should shift along with sufficient precision", () => {
|
||||
let pattern = new freesewing.Pattern();
|
||||
pattern.parts.a = new pattern.Part();
|
||||
let a = pattern.parts.a;
|
||||
a.paths.test = new a.Path()
|
||||
.move(new a.Point(0, 0))
|
||||
.curve(new a.Point(123, 123), new a.Point(-123, 456), new a.Point(456, -123))
|
||||
a.points.a = a.paths.test.shiftAlong(100)
|
||||
a.points.b = a.paths.test.reverse().shiftAlong(a.paths.test.length()-100)
|
||||
expect(a.points.a.dist(a.points.b)).to.below(0.05);
|
||||
});
|
||||
|
||||
it("Should shift fraction with sufficient precision", () => {
|
||||
let pattern = new freesewing.Pattern();
|
||||
pattern.parts.a = new pattern.Part();
|
||||
let a = pattern.parts.a;
|
||||
a.paths.test = new a.Path()
|
||||
.move(new a.Point(0, 0))
|
||||
.curve(new a.Point(123, 123), new a.Point(-123, 456), new a.Point(456, -123))
|
||||
a.points.a = a.paths.test.shiftFractionAlong(0.5)
|
||||
a.points.b = a.paths.test.reverse().shiftFractionAlong(0.5)
|
||||
expect(a.points.a.dist(a.points.b)).to.below(0.05);
|
||||
});
|
||||
|
||||
it("Should shift a fraction along a line", () => {
|
||||
let pattern = new freesewing.Pattern();
|
||||
pattern.parts.a = new pattern.Part();
|
||||
|
@ -600,12 +624,12 @@ it("Should split a path on a curve", () => {
|
|||
let halves = a.paths.test.split(a.points.split);
|
||||
let curve = halves[0].ops.pop();
|
||||
expect(curve.type).to.equal("curve");
|
||||
expect(round(curve.cp1.x)).to.equal(35.2);
|
||||
expect(round(curve.cp1.y)).to.equal(21.6);
|
||||
expect(round(curve.cp2.x)).to.equal(46.29);
|
||||
expect(round(curve.cp2.y)).to.equal(-15.02);
|
||||
expect(round(curve.to.x)).to.equal(72.9);
|
||||
expect(round(curve.to.y)).to.equal(9.03);
|
||||
expect(round(curve.cp1.x)).to.equal(35.08);
|
||||
expect(round(curve.cp1.y)).to.equal(21.64);
|
||||
expect(round(curve.cp2.x)).to.equal(46.19);
|
||||
expect(round(curve.cp2.y)).to.equal(-14.69);
|
||||
expect(round(curve.to.x)).to.equal(72.53);
|
||||
expect(round(curve.to.y)).to.equal(8.71);
|
||||
});
|
||||
|
||||
it("Should split a path on a line", () => {
|
||||
|
@ -750,3 +774,4 @@ it("Should overwrite a path attribute", () => {
|
|||
.attr("class", "overwritten", true);
|
||||
expect(a.paths.line.attributes.get("class")).to.equal("overwritten");
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue