1
0
Fork 0

Merge pull request #6527 from HaasJona/fix/path-offset

fix(core): Path.offset(...) improvements
This commit is contained in:
Joost De Cock 2024-04-16 19:07:55 +02:00 committed by GitHub
commit 281a04c37f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 56 additions and 3 deletions

View file

@ -192,6 +192,11 @@ Path.prototype.bbox = function () {
if (op.to) current = op.to if (op.to) current = op.to
} }
if (bbs.length === 0 && current) {
// Degenerate case: Line is a point
bbs.push(__lineBoundingBox({ from: current, to: current }))
}
return __bbbbox(bbs) return __bbbbox(bbs)
} }
@ -646,7 +651,7 @@ Path.prototype.noop = function (id = false) {
Path.prototype.offset = function (distance) { Path.prototype.offset = function (distance) {
distance = __asNumber(distance, 'distance', 'Path.offset', this.log) distance = __asNumber(distance, 'distance', 'Path.offset', this.log)
return __pathOffset(this, distance) return __pathOffset(this, distance, this.log)
} }
/** /**
@ -1391,7 +1396,7 @@ function __offsetLine(from, to, distance, log = false) {
* @param {float} distance - The distance to offset by * @param {float} distance - The distance to offset by
* @return {Path} offsetted - The offsetted Path instance * @return {Path} offsetted - The offsetted Path instance
*/ */
function __pathOffset(path, distance) { function __pathOffset(path, distance, log) {
let offset = [] let offset = []
let current let current
let start = false let start = false
@ -1428,7 +1433,24 @@ function __pathOffset(path, distance) {
if (!start) start = current if (!start) start = current
} }
return closed ? __joinPaths(offset).close() : __joinPaths(offset) let result
if (offset.length !== 0) {
result = __joinPaths(offset)
} else {
// degenerate case: Original path was likely short, so all the "if (segment)" checks returned false
// retry treating the path as a simple straight line from start to end
// note: do not call __joinPaths in this branch as this could result in "over-optimizing" this short path
let segment = __offsetLine(start, current, distance, path.log)
if (segment) {
result = segment
} else {
result = new Path().move(start).line(current)
log.warn(`Could not properly calculate offset path, the given path is likely too short.`)
}
}
return closed ? result.close() : result
} }
/** /**

View file

@ -118,6 +118,28 @@ describe('Path', () => {
expect(round(bbox.bottomRight.x)).to.equal(119.86) expect(round(bbox.bottomRight.x)).to.equal(119.86)
expect(round(bbox.bottomRight.y)).to.equal(43.49) expect(round(bbox.bottomRight.y)).to.equal(43.49)
}) })
it('Should offset small curves', () => {
const curve = new Path()
.move(new Point(0, 0))
.curve(new Point(0.1, 0.1), new Point(0.2, 0.2), new Point(0.1, 1.1))
const offset = curve.offset(1)
const bbox = offset.bbox()
expect(round(bbox.bottomRight.x)).to.equal(-0.9)
expect(round(bbox.bottomRight.y)).to.equal(1.19)
})
it('Should offset zero length path', () => {
let logged = false
const log = { warn: () => (logged = true) }
const curve = new Path().__withLog(log).move(new Point(0, 0)).line(new Point(0, 0)).close()
expect(logged).to.equal(false)
const offset = curve.offset(1)
expect(logged).to.equal(true)
const bbox = offset.bbox()
expect(round(bbox.bottomRight.x)).to.equal(0)
expect(round(bbox.bottomRight.y)).to.equal(0)
})
}) })
describe('length', () => { describe('length', () => {
@ -354,6 +376,15 @@ describe('Path', () => {
expect(box.bottomRight.y).to.equal(456) expect(box.bottomRight.y).to.equal(456)
}) })
it('Should find the bounding box of an empty path', () => {
const path = new Path().move(new Point(123, 456)).close()
const box = path.bbox()
expect(box.topLeft.x).to.equal(123)
expect(box.topLeft.y).to.equal(456)
expect(box.bottomRight.x).to.equal(123)
expect(box.bottomRight.y).to.equal(456)
})
it('Should reverse a path', () => { it('Should reverse a path', () => {
const test = new Path() const test = new Path()
.move(new Point(123, 456)) .move(new Point(123, 456))