diff --git a/markdown/dev/reference/api/path/split/en.md b/markdown/dev/reference/api/path/split/en.md index 179ae5467b9..154bf9c5c3e 100644 --- a/markdown/dev/reference/api/path/split/en.md +++ b/markdown/dev/reference/api/path/split/en.md @@ -45,3 +45,25 @@ array path.split(Point splitPoint) } ``` + +## Notes + +### The returned array will hold null for edge cases + +Typically, the returned array will hold a `Path` object for each half. +But in some cases, one of the array entries can hold `null` if the split failed to find a path. +For example because you are splitting a `Path` on its start or end point. + +```mjs +// Return value for a normal case +[Path, Path] +// Return value when calling Path.split() on/near the path's start point +[null, Path] +// Return value when calling Path.split() on/near the path's end point +[Path, null] +``` + +### This method will snap the split point to start or end points +This method will also _snap_ to the start or end point if you are splitting a path +(very) close to it, as it checks with [`Point.sitsRoughlyOn()`](/reference/api/point/sitsroughlyon). + diff --git a/packages/core/src/path.mjs b/packages/core/src/path.mjs index 08a4972fce1..5341e3ab836 100644 --- a/packages/core/src/path.mjs +++ b/packages/core/src/path.mjs @@ -898,7 +898,12 @@ Path.prototype.split = function (point) { break } if (path.ops[1].type === 'line') { - if (pointOnLine(path.ops[0].to, path.ops[1].to, point)) { + if (path.ops[1].to.sitsRoughlyOn(point)) { + pi++ + firstHalf = divided.slice(0, pi) + secondHalf = divided.slice(pi) + break + } else if (pointOnLine(path.ops[0].to, path.ops[1].to, point)) { firstHalf = divided.slice(0, pi) firstHalf.push(new Path().__withLog(this.log).move(path.ops[0].to).line(point)) pi++ @@ -953,8 +958,9 @@ Path.prototype.split = function (point) { } } - if (firstHalf.length > 0) firstHalf = __joinPaths(firstHalf) - if (secondHalf.length > 0) secondHalf = __joinPaths(secondHalf) + firstHalf = firstHalf.length > 0 && firstHalf[0].ops.length > 1 ? __joinPaths(firstHalf) : null + secondHalf = + secondHalf.length > 0 && secondHalf[0].ops.length > 1 ? __joinPaths(secondHalf) : null return [firstHalf, secondHalf] } diff --git a/packages/core/tests/path.test.mjs b/packages/core/tests/path.test.mjs index 50562bd6f47..8eefcda4fd1 100644 --- a/packages/core/tests/path.test.mjs +++ b/packages/core/tests/path.test.mjs @@ -661,10 +661,10 @@ describe('Path', () => { const test = new Path().move(a).line(b).line(c) let halves = test.split(new Point(10.1, 29.9)) - expect(halves[0].ops[1].to.x).to.equal(10.1) - expect(halves[0].ops[1].to.y).to.equal(29.9) - expect(halves[1].ops[0].to.x).to.equal(10.1) - expect(halves[1].ops[0].to.y).to.equal(29.9) + expect(halves[0].ops[1].to.x).to.equal(10) + expect(halves[0].ops[1].to.y).to.equal(30) + expect(halves[1].ops[0].to.x).to.equal(10) + expect(halves[1].ops[0].to.y).to.equal(30) }) it('Should split a path on a curve joint', () => { @@ -680,6 +680,34 @@ describe('Path', () => { expect(halves[1].ops[0].to.y).to.equal(30) }) + // Issue 6816: https://github.com/freesewing/freesewing/issues/6816 + it('Should split a path on the start of that same path', () => { + const A = new Point(45, 60) + const B = new Point(10, 30) + + const test = new Path().move(A).line(B) + let halves = test.split(A) + expect(halves[0]).to.equal(null) + expect(halves[1].ops[0].to.x).to.equal(45) + expect(halves[1].ops[0].to.y).to.equal(60) + expect(halves[1].ops[1].to.x).to.equal(10) + expect(halves[1].ops[1].to.y).to.equal(30) + }) + + // Issue 6816: https://github.com/freesewing/freesewing/issues/6816 + it('Should split a path on the end of that same path', () => { + const A = new Point(45, 60) + const B = new Point(10, 30) + + const test = new Path().move(A).line(B) + let halves = test.split(B) + expect(halves[1]).to.equal(null) + expect(halves[0].ops[0].to.x).to.equal(45) + expect(halves[0].ops[0].to.y).to.equal(60) + expect(halves[0].ops[1].to.x).to.equal(10) + expect(halves[0].ops[1].to.y).to.equal(30) + }) + it('Should determine the angle on a path', () => { const a = new Point(0, 0) const b = new Point(0, 40)