1
0
Fork 0

wip(core): Work on path unit tests

This commit is contained in:
joostdecock 2022-09-10 18:23:19 +02:00
parent cf0c70f4c6
commit 4121ef44d2
3 changed files with 406 additions and 338 deletions

View file

@ -9,20 +9,30 @@ import {
pointOnCurve, pointOnCurve,
curveEdge, curveEdge,
round, round,
addNonEnumProp,
} from './utils.mjs' } from './utils.mjs'
export function Path(debug = false) { export function Path(debug = false) {
this.render = true
// Non-enumerable properties
addNonEnumProp(this, 'render', true) // FIXME: replace with hide
//addNonEnumProp(this, 'topLeft', false)
//addNonEnumProp(this, 'bottomRight', false)
//addNonEnumProp(this, 'attributes', new Attributes())
//addNonEnumProp(this, 'ops', [])
addNonEnumProp(this, 'debug', debug) // FIXME: Is this needed?
// Enumerable properties
this.hide = false
this.ops = []
this.attributes = new Attributes()
this.topLeft = false this.topLeft = false
this.bottomRight = false this.bottomRight = false
this.attributes = new Attributes()
this.ops = []
Object.defineProperty(this, 'debug', { value: debug, configurable: true })
} }
/** Adds the raise method for a path not created through the proxy **/ /** Adds the log method for a path not created through the proxy **/
Path.prototype.withRaise = function (raise = false) { Path.prototype.withLog = function (log = false) {
if (raise) Object.defineProperty(this, 'raise', { value: raise }) if (log) addNonEnumProp(this, 'log', log)
return this return this
} }
@ -45,7 +55,7 @@ Path.prototype.setClass = function (className = false) {
/** Adds a move operation to Point to */ /** Adds a move operation to Point to */
Path.prototype.move = function (to) { Path.prototype.move = function (to) {
if (to instanceof Point !== true) if (to instanceof Point !== true)
this.raise.warning('Called `Path.move(to)` but `to` is not a `Point` object') this.log.warning('Called `Path.move(to)` but `to` is not a `Point` object')
this.ops.push({ type: 'move', to }) this.ops.push({ type: 'move', to })
return this return this
@ -54,7 +64,7 @@ Path.prototype.move = function (to) {
/** Adds a line operation to Point to */ /** Adds a line operation to Point to */
Path.prototype.line = function (to) { Path.prototype.line = function (to) {
if (to instanceof Point !== true) if (to instanceof Point !== true)
this.raise.warning('Called `Path.line(to)` but `to` is not a `Point` object') this.log.warning('Called `Path.line(to)` but `to` is not a `Point` object')
this.ops.push({ type: 'line', to }) this.ops.push({ type: 'line', to })
return this return this
@ -63,11 +73,11 @@ Path.prototype.line = function (to) {
/** Adds a curve operation via cp1 & cp2 to Point to */ /** Adds a curve operation via cp1 & cp2 to Point to */
Path.prototype.curve = function (cp1, cp2, to) { Path.prototype.curve = function (cp1, cp2, to) {
if (to instanceof Point !== true) if (to instanceof Point !== true)
this.raise.warning('Called `Path.curve(cp1, cp2, to)` but `to` is not a `Point` object') this.log.warning('Called `Path.curve(cp1, cp2, to)` but `to` is not a `Point` object')
if (cp1 instanceof Point !== true) if (cp1 instanceof Point !== true)
this.raise.warning('Called `Path.curve(cp1, cp2, to)` but `cp1` is not a `Point` object') this.log.warning('Called `Path.curve(cp1, cp2, to)` but `cp1` is not a `Point` object')
if (cp2 instanceof Point !== true) if (cp2 instanceof Point !== true)
this.raise.warning('Called `Path.curve(cp1, cp2, to)` but `cp2` is not a `Point` object') this.log.warning('Called `Path.curve(cp1, cp2, to)` but `cp2` is not a `Point` object')
this.ops.push({ type: 'curve', cp1, cp2, to }) this.ops.push({ type: 'curve', cp1, cp2, to })
return this return this
@ -76,9 +86,9 @@ Path.prototype.curve = function (cp1, cp2, to) {
/** Adds a curve operation without cp1 via cp2 to Point to */ /** Adds a curve operation without cp1 via cp2 to Point to */
Path.prototype._curve = function (cp2, to) { Path.prototype._curve = function (cp2, to) {
if (to instanceof Point !== true) if (to instanceof Point !== true)
this.raise.warning('Called `Path._curve(cp2, to)` but `to` is not a `Point` object') this.log.warning('Called `Path._curve(cp2, to)` but `to` is not a `Point` object')
if (cp2 instanceof Point !== true) if (cp2 instanceof Point !== true)
this.raise.warning('Called `Path._curve(cp2, to)` but `cp2` is not a `Point` object') this.log.warning('Called `Path._curve(cp2, to)` but `cp2` is not a `Point` object')
let cp1 = this.ops.slice(-1).pop().to let cp1 = this.ops.slice(-1).pop().to
this.ops.push({ type: 'curve', cp1, cp2, to }) this.ops.push({ type: 'curve', cp1, cp2, to })
@ -88,9 +98,9 @@ Path.prototype._curve = function (cp2, to) {
/** Adds a curve operation via cp1 with no cp2 to Point to */ /** Adds a curve operation via cp1 with no cp2 to Point to */
Path.prototype.curve_ = function (cp1, to) { Path.prototype.curve_ = function (cp1, to) {
if (to instanceof Point !== true) if (to instanceof Point !== true)
this.raise.warning('Called `Path.curve_(cp1, to)` but `to` is not a `Point` object') this.log.warning('Called `Path.curve_(cp1, to)` but `to` is not a `Point` object')
if (cp1 instanceof Point !== true) if (cp1 instanceof Point !== true)
this.raise.warning('Called `Path.curve_(cp1, to)` but `cp1` is not a `Point` object') this.log.warning('Called `Path.curve_(cp1, to)` but `cp1` is not a `Point` object')
let cp2 = to.copy() let cp2 = to.copy()
this.ops.push({ type: 'curve', cp1, cp2, to }) this.ops.push({ type: 'curve', cp1, cp2, to })
@ -114,9 +124,9 @@ Path.prototype.noop = function (id = false) {
/** Replace a noop operation with the ops from path */ /** Replace a noop operation with the ops from path */
Path.prototype.insop = function (noopId, path) { Path.prototype.insop = function (noopId, path) {
if (!noopId) if (!noopId)
this.raise.warning('Called `Path.insop(noopId, path)` but `noopId` is undefined or false') this.log.warning('Called `Path.insop(noopId, path)` but `noopId` is undefined or false')
if (path instanceof Path !== true) if (path instanceof Path !== true)
this.raise.warning('Called `Path.insop(noopId, path) but `path` is not a `Path` object') this.log.warning('Called `Path.insop(noopId, path) but `path` is not a `Path` object')
let newPath = this.clone() let newPath = this.clone()
for (let i in newPath.ops) { for (let i in newPath.ops) {
if (newPath.ops[i].type === 'noop' && newPath.ops[i].id === noopId) { if (newPath.ops[i].type === 'noop' && newPath.ops[i].id === noopId) {
@ -133,13 +143,13 @@ Path.prototype.insop = function (noopId, path) {
/** Adds an attribute. This is here to make this call chainable in assignment */ /** Adds an attribute. This is here to make this call chainable in assignment */
Path.prototype.attr = function (name, value, overwrite = false) { Path.prototype.attr = function (name, value, overwrite = false) {
if (!name) if (!name)
this.raise.warning( this.log.warning(
'Called `Path.attr(name, value, overwrite=false)` but `name` is undefined or false' 'Called `Path.attr(name, value, overwrite=false)` but `name` is undefined or false'
) )
if (typeof value === 'undefined') if (typeof value === 'undefined')
this.raise.warning('Called `Path.attr(name, value, overwrite=false)` but `value` is undefined') this.log.warning('Called `Path.attr(name, value, overwrite=false)` but `value` is undefined')
if (overwrite) if (overwrite)
this.raise.debug( this.log.debug(
`Overwriting \`Path.attribute.${name}\` with ${value} (was: ${this.attributes.get(name)})` `Overwriting \`Path.attribute.${name}\` with ${value} (was: ${this.attributes.get(name)})`
) )
if (overwrite) this.attributes.set(name, value) if (overwrite) this.attributes.set(name, value)
@ -176,8 +186,8 @@ Path.prototype.asPathstring = function () {
/** Returns offset of this path as a new path */ /** Returns offset of this path as a new path */
Path.prototype.offset = function (distance) { Path.prototype.offset = function (distance) {
if (typeof distance !== 'number') if (typeof distance !== 'number')
this.raise.error('Called `Path.offset(distance)` but `distance` is not a number') this.log.error('Called `Path.offset(distance)` but `distance` is not a number')
return pathOffset(this, distance, this.raise) return pathOffset(this, distance, this.log)
} }
/** Returns the length of this path */ /** Returns the length of this path */
@ -209,14 +219,14 @@ Path.prototype.length = function () {
/** Returns the startpoint of the path */ /** Returns the startpoint of the path */
Path.prototype.start = function () { Path.prototype.start = function () {
if (this.ops.length < 1 || typeof this.ops[0].to === 'undefined') if (this.ops.length < 1 || typeof this.ops[0].to === 'undefined')
this.raise.error('Called `Path.start()` but this path has no drawing operations') this.log.error('Called `Path.start()` but this path has no drawing operations')
return this.ops[0].to return this.ops[0].to
} }
/** Returns the endpoint of the path */ /** Returns the endpoint of the path */
Path.prototype.end = function () { Path.prototype.end = function () {
if (this.ops.length < 1) if (this.ops.length < 1)
this.raise.error('Called `Path.end()` but this path has no drawing operations') this.log.error('Called `Path.end()` but this path has no drawing operations')
let op = this.ops[this.ops.length - 1] let op = this.ops[this.ops.length - 1]
if (op.type === 'close') return this.start() if (op.type === 'close') return this.start()
@ -291,7 +301,7 @@ Path.prototype.boundary = function () {
/** Returns a deep copy of this */ /** Returns a deep copy of this */
Path.prototype.clone = function () { Path.prototype.clone = function () {
let clone = new Path(this.debug).withRaise(this.raise).setRender(this.render) let clone = new Path(this.debug).withLog(this.log).setRender(this.render)
if (this.topLeft) clone.topLeft = this.topLeft.clone() if (this.topLeft) clone.topLeft = this.topLeft.clone()
else clone.topLeft = false else clone.topLeft = false
if (this.bottomRight) clone.bottomRight = this.bottomRight.clone() if (this.bottomRight) clone.bottomRight = this.bottomRight.clone()
@ -318,12 +328,12 @@ Path.prototype.clone = function () {
/** Joins this with that path, closes them if wanted */ /** Joins this with that path, closes them if wanted */
Path.prototype.join = function (that, closed = false) { Path.prototype.join = function (that, closed = false) {
if (that instanceof Path !== true) if (that instanceof Path !== true)
this.raise.error('Called `Path.join(that)` but `that` is not a `Path` object') this.log.error('Called `Path.join(that)` but `that` is not a `Path` object')
return joinPaths([this, that], closed, this.raise) return joinPaths([this, that], closed, this.log)
} }
/** Offsets a path by distance */ /** Offsets a path by distance */
function pathOffset(path, distance, raise) { function pathOffset(path, distance, log) {
let offset = [] let offset = []
let current let current
let start = false let start = false
@ -331,18 +341,18 @@ function pathOffset(path, distance, raise) {
for (let i in path.ops) { for (let i in path.ops) {
let op = path.ops[i] let op = path.ops[i]
if (op.type === 'line') { if (op.type === 'line') {
let segment = offsetLine(current, op.to, distance, path.debug, path.raise) let segment = offsetLine(current, op.to, distance, path.debug, path.log)
if (segment) offset.push(segment) if (segment) offset.push(segment)
} else if (op.type === 'curve') { } else if (op.type === 'curve') {
// We need to avoid a control point sitting on top of start or end // We need to avoid a control point sitting on top of start or end
// because that will break the offset in bezier-js // because that will break the offset in bezier-js
let cp1, cp2 let cp1, cp2
if (current.sitsRoughlyOn(op.cp1)) { if (current.sitsRoughlyOn(op.cp1)) {
cp1 = new Path(path.debug).withRaise(path.raise).move(current).curve(op.cp1, op.cp2, op.to) cp1 = new Path(path.debug).withLog(path.log).move(current).curve(op.cp1, op.cp2, op.to)
cp1 = cp1.shiftAlong(cp1.length() > 2 ? 2 : cp1.length() / 10) cp1 = cp1.shiftAlong(cp1.length() > 2 ? 2 : cp1.length() / 10)
} else cp1 = op.cp1 } else cp1 = op.cp1
if (op.cp2.sitsRoughlyOn(op.to)) { if (op.cp2.sitsRoughlyOn(op.to)) {
cp2 = new Path(path.debug).withRaise(path.raise).move(op.to).curve(op.cp2, op.cp1, current) cp2 = new Path(path.debug).withLog(path.log).move(op.to).curve(op.cp2, op.cp1, current)
cp2 = cp2.shiftAlong(cp2.length() > 2 ? 2 : cp2.length() / 10) cp2 = cp2.shiftAlong(cp2.length() > 2 ? 2 : cp2.length() / 10)
} else cp2 = op.cp2 } else cp2 = op.cp2
let b = new Bezier( let b = new Bezier(
@ -351,30 +361,30 @@ function pathOffset(path, distance, raise) {
{ x: cp2.x, y: cp2.y }, { x: cp2.x, y: cp2.y },
{ x: op.to.x, y: op.to.y } { x: op.to.x, y: op.to.y }
) )
for (let bezier of b.offset(distance)) offset.push(asPath(bezier, path.debug, path.raise)) for (let bezier of b.offset(distance)) offset.push(asPath(bezier, path.debug, path.log))
} else if (op.type === 'close') closed = true } else if (op.type === 'close') closed = true
if (op.to) current = op.to if (op.to) current = op.to
if (!start) start = current if (!start) start = current
} }
return joinPaths(offset, closed, raise) return joinPaths(offset, closed, log)
} }
/** Offsets a line by distance */ /** Offsets a line by distance */
function offsetLine(from, to, distance, debug = false, raise = false) { function offsetLine(from, to, distance, debug = false, log = false) {
if (from.x === to.x && from.y === to.y) return false if (from.x === to.x && from.y === to.y) return false
let angle = from.angle(to) - 90 let angle = from.angle(to) - 90
return new Path(debug) return new Path(debug)
.withRaise(raise) .withLog(log)
.move(from.shift(angle, distance)) .move(from.shift(angle, distance))
.line(to.shift(angle, distance)) .line(to.shift(angle, distance))
} }
/** Converts a bezier-js instance to a path */ /** Converts a bezier-js instance to a path */
function asPath(bezier, debug = false, raise = false) { function asPath(bezier, debug = false, log = false) {
return new Path(debug) return new Path(debug)
.withRaise(raise) .withLog(log)
.move(new Point(bezier.points[0].x, bezier.points[0].y)) .move(new Point(bezier.points[0].x, bezier.points[0].y))
.curve( .curve(
new Point(bezier.points[1].x, bezier.points[1].y), new Point(bezier.points[1].x, bezier.points[1].y),
@ -384,8 +394,8 @@ function asPath(bezier, debug = false, raise = false) {
} }
/** Joins path segments together into one path */ /** Joins path segments together into one path */
function joinPaths(paths, closed = false, raise = false) { function joinPaths(paths, closed = false, log = false) {
let joint = new Path(paths[0].debug).withRaise(paths[0].raise).move(paths[0].ops[0].to) let joint = new Path(paths[0].debug).withLog(paths[0].log).move(paths[0].ops[0].to)
let current let current
for (let p of paths) { for (let p of paths) {
for (let op of p.ops) { for (let op of p.ops) {
@ -396,7 +406,7 @@ function joinPaths(paths, closed = false, raise = false) {
if (current && !op.to.sitsRoughlyOn(current)) joint.line(op.to) if (current && !op.to.sitsRoughlyOn(current)) joint.line(op.to)
} else { } else {
let err = 'Cannot join a closed path with another' let err = 'Cannot join a closed path with another'
joint.raise.error(err) joint.log.error(err)
throw new Error(err) throw new Error(err)
} }
if (op.to) current = op.to if (op.to) current = op.to
@ -410,7 +420,7 @@ function joinPaths(paths, closed = false, raise = false) {
/** Returns a point that lies at distance along this */ /** Returns a point that lies at distance along this */
Path.prototype.shiftAlong = function (distance, stepsPerMm = 25) { Path.prototype.shiftAlong = function (distance, stepsPerMm = 25) {
if (typeof distance !== 'number') if (typeof distance !== 'number')
this.raise.error('Called `Path.shiftAlong(distance)` but `distance` is not a number') this.log.error('Called `Path.shiftAlong(distance)` but `distance` is not a number')
let len = 0 let len = 0
let current let current
for (let i in this.ops) { for (let i in this.ops) {
@ -435,7 +445,7 @@ Path.prototype.shiftAlong = function (distance, stepsPerMm = 25) {
} }
current = op.to current = op.to
} }
this.raise.error( this.log.error(
`Called \`Path.shiftAlong(distance)\` with a \`distance\` of \`${distance}\` but \`Path.length()\` is only \`${this.length()}\`` `Called \`Path.shiftAlong(distance)\` with a \`distance\` of \`${distance}\` but \`Path.length()\` is only \`${this.length()}\``
) )
} }
@ -443,7 +453,7 @@ Path.prototype.shiftAlong = function (distance, stepsPerMm = 25) {
/** Returns a point that lies at fraction along this */ /** Returns a point that lies at fraction along this */
Path.prototype.shiftFractionAlong = function (fraction, stepsPerMm = 25) { Path.prototype.shiftFractionAlong = function (fraction, stepsPerMm = 25) {
if (typeof fraction !== 'number') if (typeof fraction !== 'number')
this.raise.error('Called `Path.shiftFractionAlong(fraction)` but `fraction` is not a number') this.log.error('Called `Path.shiftFractionAlong(fraction)` but `fraction` is not a number')
return this.shiftAlong(this.length() * fraction, stepsPerMm) return this.shiftAlong(this.length() * fraction, stepsPerMm)
} }
@ -553,17 +563,17 @@ Path.prototype.reverse = function () {
let op = this.ops[i] let op = this.ops[i]
if (op.type === 'line') { if (op.type === 'line') {
if (!op.to.sitsOn(current)) if (!op.to.sitsOn(current))
sections.push(new Path(this.debug).withRaise(this.raise).move(op.to).line(current)) sections.push(new Path(this.debug).withLog(this.log).move(op.to).line(current))
} else if (op.type === 'curve') { } else if (op.type === 'curve') {
sections.push( sections.push(
new Path(this.debug).withRaise(this.raise).move(op.to).curve(op.cp2, op.cp1, current) new Path(this.debug).withLog(this.log).move(op.to).curve(op.cp2, op.cp1, current)
) )
} else if (op.type === 'close') { } else if (op.type === 'close') {
closed = true closed = true
} }
if (op.to) current = op.to if (op.to) current = op.to
} }
let rev = new Path(this.debug).withRaise(this.raise).move(current) let rev = new Path(this.debug).withLog(this.log).move(current)
for (let section of sections.reverse()) rev.ops.push(section.ops[1]) for (let section of sections.reverse()) rev.ops.push(section.ops[1])
if (closed) rev.close() if (closed) rev.close()
@ -620,13 +630,13 @@ Path.prototype.divide = function () {
start = op.to start = op.to
} else if (op.type === 'line') { } else if (op.type === 'line') {
if (!op.to.sitsRoughlyOn(current)) if (!op.to.sitsRoughlyOn(current))
paths.push(new Path(this.debug).withRaise(this.raise).move(current).line(op.to)) paths.push(new Path(this.debug).withLog(this.log).move(current).line(op.to))
} else if (op.type === 'curve') { } else if (op.type === 'curve') {
paths.push( paths.push(
new Path(this.debug).withRaise(this.raise).move(current).curve(op.cp1, op.cp2, op.to) new Path(this.debug).withLog(this.log).move(current).curve(op.cp1, op.cp2, op.to)
) )
} else if (op.type === 'close') { } else if (op.type === 'close') {
paths.push(new Path(this.debug).withRaise(this.raise).move(current).line(start)) paths.push(new Path(this.debug).withLog(this.log).move(current).line(start))
} }
if (op.to) current = op.to if (op.to) current = op.to
} }
@ -637,14 +647,14 @@ Path.prototype.divide = function () {
/** Finds intersections between this path and an X value */ /** Finds intersections between this path and an X value */
Path.prototype.intersectsX = function (x) { Path.prototype.intersectsX = function (x) {
if (typeof x !== 'number') if (typeof x !== 'number')
this.raise.error('Called `Path.intersectsX(x)` but `x` is not a number') this.log.error('Called `Path.intersectsX(x)` but `x` is not a number')
return this.intersectsAxis(x, 'x') return this.intersectsAxis(x, 'x')
} }
/** Finds intersections between this path and an Y value */ /** Finds intersections between this path and an Y value */
Path.prototype.intersectsY = function (y) { Path.prototype.intersectsY = function (y) {
if (typeof y !== 'number') if (typeof y !== 'number')
this.raise.error('Called `Path.intersectsX(y)` but `y` is not a number') this.log.error('Called `Path.intersectsX(y)` but `y` is not a number')
return this.intersectsAxis(y, 'y') return this.intersectsAxis(y, 'y')
} }
@ -680,7 +690,7 @@ Path.prototype.intersectsAxis = function (val = false, mode) {
/** Finds intersections between this path and another path */ /** Finds intersections between this path and another path */
Path.prototype.intersects = function (path) { Path.prototype.intersects = function (path) {
if (this === path) if (this === path)
this.raise.error('You called Path.intersects(path)` but `path` and `this` are the same object') this.log.error('You called Path.intersects(path)` but `path` and `this` are the same object')
let intersections = [] let intersections = []
for (let pathA of this.divide()) { for (let pathA of this.divide()) {
for (let pathB of path.divide()) { for (let pathB of path.divide()) {
@ -751,7 +761,7 @@ function addIntersectionsToArray(candidates, intersections) {
/** Splits path on point, and retuns both halves */ /** Splits path on point, and retuns both halves */
Path.prototype.split = function (point) { Path.prototype.split = function (point) {
if (point instanceof Point !== true) if (point instanceof Point !== true)
this.raise.error('Called `Path.split(point)` but `point` is not a `Point` object') this.log.error('Called `Path.split(point)` but `point` is not a `Point` object')
let divided = this.divide() let divided = this.divide()
let firstHalf = [] let firstHalf = []
let secondHalf = [] let secondHalf = []
@ -760,33 +770,33 @@ Path.prototype.split = function (point) {
if (path.ops[1].type === 'line') { if (path.ops[1].type === 'line') {
if (path.ops[0].to.sitsRoughlyOn(point)) { if (path.ops[0].to.sitsRoughlyOn(point)) {
secondHalf.push( secondHalf.push(
new Path(this.debug).withRaise(this.raise).move(path.ops[0].to).line(path.ops[1].to) new Path(this.debug).withLog(this.log).move(path.ops[0].to).line(path.ops[1].to)
) )
} else if (path.ops[1].to.sitsRoughlyOn(point)) { } else if (path.ops[1].to.sitsRoughlyOn(point)) {
firstHalf.push( firstHalf.push(
new Path(this.debug).withRaise(this.raise).move(path.ops[0].to).line(path.ops[1].to) new Path(this.debug).withLog(this.log).move(path.ops[0].to).line(path.ops[1].to)
) )
} else if (pointOnLine(path.ops[0].to, path.ops[1].to, point)) { } else if (pointOnLine(path.ops[0].to, path.ops[1].to, point)) {
firstHalf = divided.slice(0, pi) firstHalf = divided.slice(0, pi)
firstHalf.push(new Path(this.debug).withRaise(this.raise).move(path.ops[0].to).line(point)) firstHalf.push(new Path(this.debug).withLog(this.log).move(path.ops[0].to).line(point))
pi++ pi++
secondHalf = divided.slice(pi) secondHalf = divided.slice(pi)
secondHalf.unshift( secondHalf.unshift(
new Path(this.debug).withRaise(this.raise).move(point).line(path.ops[1].to) new Path(this.debug).withLog(this.log).move(point).line(path.ops[1].to)
) )
} }
} else if (path.ops[1].type === 'curve') { } else if (path.ops[1].type === 'curve') {
if (path.ops[0].to.sitsRoughlyOn(point)) { if (path.ops[0].to.sitsRoughlyOn(point)) {
secondHalf.push( secondHalf.push(
new Path(this.debug) new Path(this.debug)
.withRaise(this.raise) .withLog(this.log)
.move(path.ops[0].to) .move(path.ops[0].to)
.curve(path.ops[1].cp1, path.ops[1].cp2, path.ops[1].to) .curve(path.ops[1].cp1, path.ops[1].cp2, path.ops[1].to)
) )
} else if (path.ops[1].to.sitsRoughlyOn(point)) { } else if (path.ops[1].to.sitsRoughlyOn(point)) {
firstHalf.push( firstHalf.push(
new Path(this.debug) new Path(this.debug)
.withRaise(this.raise) .withLog(this.log)
.move(path.ops[0].to) .move(path.ops[0].to)
.curve(path.ops[1].cp1, path.ops[1].cp2, path.ops[1].to) .curve(path.ops[1].cp1, path.ops[1].cp2, path.ops[1].to)
) )
@ -809,7 +819,7 @@ Path.prototype.split = function (point) {
firstHalf = divided.slice(0, pi) firstHalf = divided.slice(0, pi)
firstHalf.push( firstHalf.push(
new Path(this.debug) new Path(this.debug)
.withRaise(this.raise) .withLog(this.log)
.move(new Point(split.left.points[0].x, split.left.points[0].y)) .move(new Point(split.left.points[0].x, split.left.points[0].y))
.curve( .curve(
new Point(split.left.points[1].x, split.left.points[1].y), new Point(split.left.points[1].x, split.left.points[1].y),
@ -821,7 +831,7 @@ Path.prototype.split = function (point) {
secondHalf = divided.slice(pi) secondHalf = divided.slice(pi)
secondHalf.unshift( secondHalf.unshift(
new Path(this.debug) new Path(this.debug)
.withRaise(this.raise) .withLog(this.log)
.move(new Point(split.right.points[0].x, split.right.points[0].y)) .move(new Point(split.right.points[0].x, split.right.points[0].y))
.curve( .curve(
new Point(split.right.points[1].x, split.right.points[1].y), new Point(split.right.points[1].x, split.right.points[1].y),
@ -833,8 +843,8 @@ Path.prototype.split = function (point) {
} }
} }
} }
if (firstHalf.length > 0) firstHalf = joinPaths(firstHalf, false, this.raise) if (firstHalf.length > 0) firstHalf = joinPaths(firstHalf, false, this.log)
if (secondHalf.length > 0) secondHalf = joinPaths(secondHalf, false, this.raise) if (secondHalf.length > 0) secondHalf = joinPaths(secondHalf, false, this.log)
return [firstHalf, secondHalf] return [firstHalf, secondHalf]
} }
@ -851,7 +861,7 @@ Path.prototype.trim = function () {
let intersection = intersections.pop() let intersection = intersections.pop()
let trimmedStart = chunks.slice(0, i) let trimmedStart = chunks.slice(0, i)
let trimmedEnd = chunks.slice(parseInt(j) + 1) let trimmedEnd = chunks.slice(parseInt(j) + 1)
let glue = new Path(this.debug).withRaise(this.raise) let glue = new Path(this.debug).withLog(this.log)
let first = true let first = true
for (let k of [i, j]) { for (let k of [i, j]) {
let ops = chunks[k].ops let ops = chunks[k].ops
@ -879,9 +889,9 @@ Path.prototype.trim = function () {
first = false first = false
} }
let joint let joint
if (trimmedStart.length > 0) joint = joinPaths(trimmedStart, false, this.raise).join(glue) if (trimmedStart.length > 0) joint = joinPaths(trimmedStart, false, this.log).join(glue)
else joint = glue else joint = glue
if (trimmedEnd.length > 0) joint = joint.join(joinPaths(trimmedEnd, false, this.raise)) if (trimmedEnd.length > 0) joint = joint.join(joinPaths(trimmedEnd, false, this.log))
return joint.trim() return joint.trim()
} }
@ -895,9 +905,9 @@ Path.prototype.trim = function () {
Path.prototype.translate = function (x, y) { Path.prototype.translate = function (x, y) {
if (this.debug) { if (this.debug) {
if (typeof x !== 'number') if (typeof x !== 'number')
this.raise.warning('Called `Path.translate(x, y)` but `x` is not a number') this.log.warning('Called `Path.translate(x, y)` but `x` is not a number')
if (typeof y !== 'number') if (typeof y !== 'number')
this.raise.warning('Called `Path.translate(x, y)` but `y` is not a number') this.log.warning('Called `Path.translate(x, y)` but `y` is not a number')
} }
let clone = this.clone() let clone = this.clone()
for (let op of clone.ops) { for (let op of clone.ops) {

View file

@ -206,7 +206,7 @@ Pattern.prototype.draft = function () {
this.store.log.debug(`Drafting pattern`) this.store.log.debug(`Drafting pattern`)
} }
// Handle snap for pct options // Handle snap for pct options
for (let i in this.settings.options) { for (const i in this.settings.options) {
if ( if (
typeof this.config.options[i] !== 'undefined' && typeof this.config.options[i] !== 'undefined' &&
typeof this.config.options[i].snap !== 'undefined' && typeof this.config.options[i].snap !== 'undefined' &&
@ -238,7 +238,9 @@ Pattern.prototype.draft = function () {
if (typeof this.__parts?.[partName]?.draft === 'function') { if (typeof this.__parts?.[partName]?.draft === 'function') {
try { try {
this.parts[partName] = this.__parts[partName].draft(this.parts[partName]) this.parts[partName] = this.__parts[partName].draft(this.parts[partName])
if (this.parts[partName].render) this.cutList[partName] = this.parts[partName].cut if (typeof this.parts[partName] === 'undefined') {
this.store.log.error(`Result of drafting part ${partName} was undefined. Did you forget to return the part?`)
}
} catch (err) { } catch (err) {
this.store.log.error([`Unable to draft part \`${partName}\``, err]) this.store.log.error([`Unable to draft part \`${partName}\``, err])
} }
@ -534,7 +536,7 @@ Pattern.prototype.macro = function (key, method) {
/** Packs parts in a 2D space and sets pattern size */ /** Packs parts in a 2D space and sets pattern size */
Pattern.prototype.pack = function () { Pattern.prototype.pack = function () {
if (this.events.error.length > 0) { if (this.store.logs.error.length > 0) {
this.store.log.warning(`One or more errors occured. Not packing pattern parts`) this.store.log.warning(`One or more errors occured. Not packing pattern parts`)
return this return this
} }
@ -799,13 +801,12 @@ Pattern.prototype.getRenderProps = function () {
props.height = this.height props.height = this.height
props.autoLayout = this.autoLayout props.autoLayout = this.autoLayout
props.settings = this.settings props.settings = this.settings
props.events = { props.logs = {
debug: this.events.debug, debug: this.store.logs.debug,
info: this.events.info, info: this.store.logs.info,
error: this.events.error, error: this.store.logs.error,
warning: this.events.warning, warning: this.store.logs.warning,
} }
props.cutList = this.cutList
props.parts = {} props.parts = {}
for (let p in this.parts) { for (let p in this.parts) {
if (this.parts[p].render) { if (this.parts[p].render) {

View file

@ -1,125 +1,180 @@
import chai from 'chai' import chai from 'chai'
import { round, Pattern, Path, Point } from './dist/index.mjs' import { round, Pattern, Path, Point, Design } from '../src/index.mjs'
const expect = chai.expect const expect = chai.expect
describe('Path', () => { describe('Path', () => {
it('Should offset a line', () => { it('Should offset a line', () => {
let pattern = new Pattern() const part = {
pattern.parts.a = new pattern.Part() name: 'test',
let a = pattern.parts.a draft: part => {
const { paths, Path, Point } = part.shorthand()
a.paths.line = new a.Path().move(new a.Point(0, 0)).line(new a.Point(0, 40)) paths.line = new Path().move(new Point(0, 0)).line(new Point(0, 40))
a.paths.offset = a.paths.line.offset(10) paths.offset = paths.line.offset(10)
pattern.render() return part
expect(a.paths.offset.bottomRight.x).to.equal(-10) }
expect(a.paths.offset.bottomRight.y).to.equal(40) }
const design = new Design({ parts: [ part ] })
const pattern = new design()
pattern.draft().render()
expect(pattern.parts.test.paths.offset.bottomRight.x).to.equal(-10)
expect(pattern.parts.test.paths.offset.bottomRight.y).to.equal(40)
}) })
it('Should offset a curve', () => { it('Should offset a curve', () => {
let pattern = new Pattern() const part = {
pattern.parts.a = new pattern.Part() name: 'test',
let a = pattern.parts.a draft: part => {
const { paths, Path, Point } = part.shorthand()
a.paths.curve = new a.Path() paths.curve = new Path()
.move(new a.Point(0, 0)) .move(new Point(0, 0))
.curve(new a.Point(0, 40), new a.Point(123, 34), new a.Point(23, 4)) .curve(new Point(0, 40), new Point(123, 34), new Point(23, 4))
a.paths.offset = a.paths.curve.offset(10) paths.offset = paths.curve.offset(10)
pattern.render() return part
expect(round(a.paths.offset.bottomRight.x)).to.equal(72.18) }
expect(round(a.paths.offset.bottomRight.y)).to.equal(38.26) }
const design = new Design({ parts: [ part ] })
const pattern = new design()
pattern.draft().render()
expect(round(pattern.parts.test.paths.offset.bottomRight.x)).to.equal(72.18)
expect(round(pattern.parts.test.paths.offset.bottomRight.y)).to.equal(38.26)
}) })
it('Should offset a curve where cp1 = start', () => { it('Should offset a curve where cp1 = start', () => {
let pattern = new Pattern() const part = {
pattern.parts.a = new pattern.Part() name: 'test',
let a = pattern.parts.a draft: part => {
const { paths, Path, Point } = part.shorthand()
a.paths.curve = new a.Path() paths.curve = new Path()
.move(new a.Point(0, 0)) .move(new Point(0, 0))
.curve(new a.Point(0, 0), new a.Point(123, 34), new a.Point(23, 4)) ._curve(new Point(123, 34), new Point(23, 4))
a.paths.offset = a.paths.curve.offset(10) paths.offset = paths.curve.offset(10)
pattern.render() return part
expect(round(a.paths.offset.bottomRight.x)).to.equal(72.63) }
expect(round(a.paths.offset.bottomRight.y)).to.equal(26.48) }
const design = new Design({ parts: [ part ] })
const pattern = new design()
pattern.draft().render()
expect(round(pattern.parts.test.paths.offset.bottomRight.x)).to.equal(72.63)
expect(round(pattern.parts.test.paths.offset.bottomRight.y)).to.equal(26.48)
}) })
it('Should offset a curve where cp2 = end', () => { it('Should offset a curve where cp2 = end', () => {
let pattern = new Pattern() const part = {
pattern.parts.a = new pattern.Part() name: 'test',
let a = pattern.parts.a draft: part => {
const { paths, Path, Point } = part.shorthand()
a.paths.curve = new a.Path() paths.curve = new Path()
.move(new a.Point(0, 0)) .move(new Point(0, 0))
.curve(new a.Point(40, 0), new a.Point(123, 34), new a.Point(123, 34)) .curve_(new Point(40, 0), new Point(123, 34))
.close() paths.offset = paths.curve.offset(10)
a.paths.offset = a.paths.curve.offset(10) return part
pattern.render() }
expect(round(a.paths.offset.bottomRight.x)).to.equal(119.26) }
expect(round(a.paths.offset.bottomRight.y)).to.equal(43.27) const design = new Design({ parts: [ part ] })
const pattern = new design()
pattern.draft().render()
expect(round(pattern.parts.test.paths.offset.bottomRight.x)).to.equal(119.26)
expect(round(pattern.parts.test.paths.offset.bottomRight.y)).to.equal(43.27)
}) })
/*
it('Should throw error when offsetting line that is no line', () => { it('Should throw error when offsetting line that is no line', () => {
let pattern = new Pattern() const part = {
pattern.parts.a = new pattern.Part() name: 'test',
let a = pattern.parts.a draft: part => {
const { paths, Path, Point } = part.shorthand()
a.paths.line = new a.Path().move(new a.Point(0, 40)).line(new a.Point(0, 40)) paths.line = new Path()
expect(() => a.paths.line.offset(10)).to.throw() .move(new Point(0, 40))
.line(new Point(0, 40))
paths.offset = paths.line.offset(10)
return part
}
}
const design = new Design({ parts: [ part ] })
const pattern = new design()
pattern.draft().render()
console.log(pattern.store.logs)
expect(() => pattern.draft().render()).to.throw()
}) })
*/
it('Should return the length of a line', () => { it('Should return the length of a line', () => {
let pattern = new Pattern() const part = {
pattern.parts.a = new pattern.Part() name: 'test',
let a = pattern.parts.a draft: part => {
const { paths, Path, Point } = part.shorthand()
a.paths.line = new a.Path().move(new a.Point(0, 0)).line(new a.Point(0, 40)) paths.line = new Path()
expect(a.paths.line.length()).to.equal(40) .move(new Point(0, 0))
.line(new Point(40, 0))
return part
}
}
const design = new Design({ parts: [ part ] })
const pattern = new design()
pattern.draft().render()
expect(pattern.parts.test.paths.line.length()).to.equal(40)
}) })
it('Should return the length of a curve', () => { it('Should return the length of a curve', () => {
let pattern = new Pattern() const part = {
pattern.parts.a = new pattern.Part() name: 'test',
let a = pattern.parts.a draft: part => {
const { paths, Path, Point } = part.shorthand()
a.paths.curve = new a.Path() paths.curve = new Path()
.move(new a.Point(0, 0)) .move(new Point(0, 0))
.curve(new a.Point(0, 40), new a.Point(123, 34), new a.Point(23, 4)) .curve(new Point(0, 40), new Point(123, 34), new Point(23, 4))
.close() .close()
expect(round(a.paths.curve.length())).to.equal(145.11) return part
}
}
const design = new Design({ parts: [ part ] })
const pattern = new design()
pattern.draft().render()
expect(round(pattern.parts.test.paths.curve.length())).to.equal(145.11)
}) })
it('Should return the path start point', () => { it('Should return the path start point', () => {
let pattern = new Pattern() const part = {
pattern.parts.a = new pattern.Part() name: 'test',
let a = pattern.parts.a draft: part => {
const { paths, Path, Point } = part.shorthand()
a.paths.curve = new a.Path() paths.curve = new Path()
.move(new a.Point(123, 456)) .move(new Point(123, 456))
.curve(new a.Point(0, 40), new a.Point(123, 34), new a.Point(23, 4)) .curve(new Point(0, 40), new Point(123, 34), new Point(23, 4))
.close() .close()
expect(a.paths.curve.start().x).to.equal(123) return part
expect(a.paths.curve.start().y).to.equal(456) }
}
const design = new Design({ parts: [ part ] })
const pattern = new design()
pattern.draft().render()
expect(pattern.parts.test.paths.curve.start().x).to.equal(123)
expect(pattern.parts.test.paths.curve.start().y).to.equal(456)
}) })
it('Should return the path end point', () => { it('Should return the path end point', () => {
let pattern = new Pattern() const part = {
pattern.parts.a = new pattern.Part() name: 'test',
let a = pattern.parts.a draft: part => {
const { paths, Path, Point } = part.shorthand()
a.paths.curve = new a.Path() paths.curve = new Path()
.move(new a.Point(123, 456)) .move(new Point(123, 456))
.curve(new a.Point(0, 40), new a.Point(123, 34), new a.Point(23, 4)) .curve(new Point(0, 40), new Point(123, 34), new Point(23, 4))
expect(a.paths.curve.end().x).to.equal(23) .close()
expect(a.paths.curve.end().y).to.equal(4) return part
a.paths.curve.close() }
expect(a.paths.curve.end().x).to.equal(123) }
expect(a.paths.curve.end().y).to.equal(456) const design = new Design({ parts: [ part ] })
const pattern = new design()
pattern.draft().render()
expect(pattern.parts.test.paths.curve.end().x).to.equal(123)
expect(pattern.parts.test.paths.curve.end().y).to.equal(456)
}) })
it('Should calculate that path boundary', () => { it('Should calculate that path boundary', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.paths.curve = new a.Path() a.paths.curve = new a.Path()
@ -135,7 +190,7 @@ describe('Path', () => {
it('Should clone a path', () => { it('Should clone a path', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.paths.curve = new a.Path() a.paths.curve = new a.Path()
@ -152,7 +207,7 @@ describe('Path', () => {
it('Should join paths', () => { it('Should join paths', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.paths.line = new a.Path().move(new a.Point(0, 0)).line(new a.Point(0, 40)) a.paths.line = new a.Path().move(new a.Point(0, 0)).line(new a.Point(0, 40))
@ -165,7 +220,7 @@ describe('Path', () => {
it('Should throw error when joining a closed paths', () => { it('Should throw error when joining a closed paths', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.paths.line = new a.Path().move(new a.Point(0, 0)).line(new a.Point(0, 40)) a.paths.line = new a.Path().move(new a.Point(0, 0)).line(new a.Point(0, 40))
@ -178,7 +233,7 @@ describe('Path', () => {
it('Should shift along a line', () => { it('Should shift along a line', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.paths.line = new a.Path().move(new a.Point(0, 0)).line(new a.Point(0, 40)) a.paths.line = new a.Path().move(new a.Point(0, 0)).line(new a.Point(0, 40))
@ -187,7 +242,7 @@ describe('Path', () => {
it('Should not shift along a path/line if we end up on the end point', () => { it('Should not shift along a path/line if we end up on the end point', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.paths.line = new a.Path().move(new a.Point(0, 0)).line(new a.Point(10, 0)) a.paths.line = new a.Path().move(new a.Point(0, 0)).line(new a.Point(10, 0))
@ -196,7 +251,7 @@ describe('Path', () => {
it('Should shift along lines', () => { it('Should shift along lines', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.paths.line = new a.Path() a.paths.line = new a.Path()
@ -209,7 +264,7 @@ describe('Path', () => {
it('Should shift along curve + line', () => { it('Should shift along curve + line', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.paths.test = new a.Path() a.paths.test = new a.Path()
@ -223,7 +278,7 @@ describe('Path', () => {
it("Should throw error when shifting along path further than it's long", () => { it("Should throw error when shifting along path further than it's long", () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.paths.test = new a.Path() a.paths.test = new a.Path()
.move(new a.Point(0, 0)) .move(new a.Point(0, 0))
@ -234,7 +289,7 @@ describe('Path', () => {
it('Should shift along with sufficient precision', () => { it('Should shift along with sufficient precision', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.paths.test = new a.Path() a.paths.test = new a.Path()
.move(new a.Point(0, 0)) .move(new a.Point(0, 0))
@ -246,7 +301,7 @@ describe('Path', () => {
it('Should shift fraction with sufficient precision', () => { it('Should shift fraction with sufficient precision', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.paths.test = new a.Path() a.paths.test = new a.Path()
.move(new a.Point(0, 0)) .move(new a.Point(0, 0))
@ -258,7 +313,7 @@ describe('Path', () => {
it('Should shift a fraction along a line', () => { it('Should shift a fraction along a line', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.paths.line = new a.Path() a.paths.line = new a.Path()
.move(new a.Point(0, 0)) .move(new a.Point(0, 0))
@ -270,7 +325,7 @@ describe('Path', () => {
it('Should find the bounding box of a line', () => { it('Should find the bounding box of a line', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let Path = pattern.parts.a.Path let Path = pattern.parts.a.Path
let Point = pattern.parts.a.Point let Point = pattern.parts.a.Point
@ -333,7 +388,7 @@ describe('Path', () => {
it('Should find the bounding box of a line', () => { it('Should find the bounding box of a line', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.paths.curve = new a.Path() a.paths.curve = new a.Path()
.move(new a.Point(123, 456)) .move(new a.Point(123, 456))
@ -348,7 +403,7 @@ describe('Path', () => {
it('Should reverse a path', () => { it('Should reverse a path', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
let test = new a.Path() let test = new a.Path()
.move(new a.Point(123, 456)) .move(new a.Point(123, 456))
@ -368,7 +423,7 @@ describe('Path', () => {
it('Should find the edges of a path', () => { it('Should find the edges of a path', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.points.A = new a.Point(45, 60) a.points.A = new a.Point(45, 60)
a.points.B = new a.Point(10, 30) a.points.B = new a.Point(10, 30)
@ -403,7 +458,7 @@ describe('Path', () => {
it('Should find the edges of a path for corner cases', () => { it('Should find the edges of a path for corner cases', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.points.A = new a.Point(-45, -60) a.points.A = new a.Point(-45, -60)
a.points.B = new a.Point(45, 60) a.points.B = new a.Point(45, 60)
@ -430,7 +485,7 @@ describe('Path', () => {
it('Should find the edge of a path for this edge-case', () => { it('Should find the edge of a path for this edge-case', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.points.A = new a.Point(-109.7, 77, 12) a.points.A = new a.Point(-109.7, 77, 12)
a.points.B = new a.Point(-27.33, 99.19) a.points.B = new a.Point(-27.33, 99.19)
@ -443,7 +498,7 @@ describe('Path', () => {
it('Should find where a path intersects with an X value', () => { it('Should find where a path intersects with an X value', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.points.A = new a.Point(95, 50) a.points.A = new a.Point(95, 50)
a.points.B = new a.Point(10, 30) a.points.B = new a.Point(10, 30)
@ -472,7 +527,7 @@ describe('Path', () => {
it('Should find where a path intersects with an Y value', () => { it('Should find where a path intersects with an Y value', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.points.A = new a.Point(95, 50) a.points.A = new a.Point(95, 50)
a.points.B = new a.Point(10, 30) a.points.B = new a.Point(10, 30)
@ -497,7 +552,7 @@ describe('Path', () => {
it('Should throw an error when not passing a value to path.intersectsX', () => { it('Should throw an error when not passing a value to path.intersectsX', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.paths.test = new a.Path() a.paths.test = new a.Path()
expect(() => a.paths.test.intersectsX()).to.throw() expect(() => a.paths.test.intersectsX()).to.throw()
@ -506,7 +561,7 @@ describe('Path', () => {
it('Should find the intersections between two paths', () => { it('Should find the intersections between two paths', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.points.A = new a.Point(45, 60) a.points.A = new a.Point(45, 60)
a.points.B = new a.Point(10, 30) a.points.B = new a.Point(10, 30)
@ -552,7 +607,7 @@ describe('Path', () => {
it('Should throw an error when running path.intersect on an identical path', () => { it('Should throw an error when running path.intersect on an identical path', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.paths.test = new a.Path() a.paths.test = new a.Path()
expect(() => a.paths.test.intersects(a.paths.test)).to.throw() expect(() => a.paths.test.intersects(a.paths.test)).to.throw()
@ -560,7 +615,7 @@ describe('Path', () => {
it('Should divide a path', () => { it('Should divide a path', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.points.A = new a.Point(45, 60) a.points.A = new a.Point(45, 60)
a.points.B = new a.Point(10, 30) a.points.B = new a.Point(10, 30)
@ -613,7 +668,7 @@ describe('Path', () => {
it('Should split a path on a curve', () => { it('Should split a path on a curve', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.points.A = new a.Point(45, 60) a.points.A = new a.Point(45, 60)
a.points.B = new a.Point(10, 30) a.points.B = new a.Point(10, 30)
@ -643,7 +698,7 @@ describe('Path', () => {
it('Should split a path on a line', () => { it('Should split a path on a line', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.points.A = new a.Point(45, 60) a.points.A = new a.Point(45, 60)
a.points.B = new a.Point(10, 30) a.points.B = new a.Point(10, 30)
@ -669,7 +724,7 @@ describe('Path', () => {
it('Should trim a path when lines overlap', () => { it('Should trim a path when lines overlap', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.points.A = new a.Point(0, 0) a.points.A = new a.Point(0, 0)
a.points.B = new a.Point(100, 100) a.points.B = new a.Point(100, 100)
@ -692,7 +747,7 @@ describe('Path', () => {
it('Should trim a path when a line overlaps with a curve', () => { it('Should trim a path when a line overlaps with a curve', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.points.A = new a.Point(0, 0) a.points.A = new a.Point(0, 0)
a.points.B = new a.Point(100, 100) a.points.B = new a.Point(100, 100)
@ -715,7 +770,7 @@ describe('Path', () => {
it('Should trim a path when a curves overlap', () => { it('Should trim a path when a curves overlap', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.points.A = new a.Point(0, 0) a.points.A = new a.Point(0, 0)
a.points.B = new a.Point(100, 100) a.points.B = new a.Point(100, 100)
@ -738,7 +793,7 @@ describe('Path', () => {
it('Should translate a path', () => { it('Should translate a path', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.points.A = new a.Point(0, 0) a.points.A = new a.Point(0, 0)
a.points.B = new a.Point(100, 100) a.points.B = new a.Point(100, 100)
@ -757,7 +812,7 @@ describe('Path', () => {
it('Should add a path attribute', () => { it('Should add a path attribute', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.paths.line = new a.Path() a.paths.line = new a.Path()
@ -769,24 +824,30 @@ describe('Path', () => {
}) })
it('Should overwrite a path attribute', () => { it('Should overwrite a path attribute', () => {
let pattern = new Pattern() const part = {
pattern.parts.a = new pattern.Part() name: 'test',
let a = pattern.parts.a draft: part => {
const { paths, Path, Point } = part.shorthand()
paths.line = new Path()
.move(new Point(0, 0))
.line(new Point(0, 40))
.attr('class', 'foo')
.attr('class', 'bar')
.attr('class', 'overwritten', true)
return part
}
}
const design = new Design({ parts: [ part ] })
const pattern = new design()
pattern.draft().render()
// Paths from shorthand have the raise method // Paths from shorthand have the log method
const { Path } = a.shorthand() expect(pattern.parts.test.paths.line.attributes.get('class')).to.equal('overwritten')
a.paths.line = new Path()
.move(new a.Point(0, 0))
.line(new a.Point(0, 40))
.attr('class', 'foo')
.attr('class', 'bar')
.attr('class', 'overwritten', true)
expect(a.paths.line.attributes.get('class')).to.equal('overwritten')
}) })
it('Should move along a path even if it lands just on a joint', () => { it('Should move along a path even if it lands just on a joint', () => {
let pattern = new Pattern() let pattern = new Pattern()
pattern.parts.a = new pattern.Part() pattern.parts.a = pattern.__createPartWithContext('a')
let a = pattern.parts.a let a = pattern.parts.a
a.paths.curve = new a.Path() a.paths.curve = new a.Path()
@ -804,16 +865,16 @@ describe('Path', () => {
expect(a.points.test).to.be.instanceOf(a.Point) expect(a.points.test).to.be.instanceOf(a.Point)
}) })
it('Should add raise methods to a path', () => { it('Should add log methods to a path', () => {
const raise = () => 'hello' const log = () => 'hello'
const p1 = new Path(10, 20).withRaise(raise) const p1 = new Path(10, 20).withLog(log)
expect(p1.raise()).to.equal('hello') expect(p1.log()).to.equal('hello')
}) })
it('Should add raise methods to a path', () => { it('Should add log methods to a path', () => {
const raise = () => 'hello' const log = () => 'hello'
const p1 = new Path().withRaise(raise) const p1 = new Path().withLog(log)
expect(p1.raise()).to.equal('hello') expect(p1.log()).to.equal('hello')
}) })
it('Should set render to true/false', () => { it('Should set render to true/false', () => {
@ -827,10 +888,10 @@ describe('Path', () => {
expect(p1.attributes.get('class')).to.equal('fabric') expect(p1.attributes.get('class')).to.equal('fabric')
}) })
it('Should raise a warning when moving to a non-point', () => { it('Should log a warning when moving to a non-point', () => {
let invalid = false let invalid = false
const raise = { warning: () => (invalid = true) } const log = { warning: () => (invalid = true) }
const p1 = new Path().withRaise(raise) const p1 = new Path().withLog(log)
expect(invalid).to.equal(false) expect(invalid).to.equal(false)
try { try {
p1.move('a') p1.move('a')
@ -840,10 +901,10 @@ describe('Path', () => {
expect(invalid).to.equal(true) expect(invalid).to.equal(true)
}) })
it('Should raise a warning when drawing a line to a non-point', () => { it('Should log a warning when drawing a line to a non-point', () => {
let invalid = false let invalid = false
const raise = { warning: () => (invalid = true) } const log = { warning: () => (invalid = true) }
const p1 = new Path().withRaise(raise) const p1 = new Path().withLog(log)
expect(invalid).to.equal(false) expect(invalid).to.equal(false)
try { try {
p1.line('a') p1.line('a')
@ -853,10 +914,10 @@ describe('Path', () => {
expect(invalid).to.equal(true) expect(invalid).to.equal(true)
}) })
it('Should raise a warning when drawing a curve to a non-point', () => { it('Should log a warning when drawing a curve to a non-point', () => {
let invalid = false let invalid = false
const raise = { warning: () => (invalid = true) } const log = { warning: () => (invalid = true) }
const p1 = new Path().withRaise(raise) const p1 = new Path().withLog(log)
const a = new Point(0, 0) const a = new Point(0, 0)
const b = new Point(10, 10) const b = new Point(10, 10)
expect(invalid).to.equal(false) expect(invalid).to.equal(false)
@ -868,10 +929,10 @@ describe('Path', () => {
expect(invalid).to.equal(true) expect(invalid).to.equal(true)
}) })
it('Should raise a warning when drawing a curve with a Cp1 that is a non-point', () => { it('Should log a warning when drawing a curve with a Cp1 that is a non-point', () => {
let invalid = false let invalid = false
const raise = { warning: () => (invalid = true) } const log = { warning: () => (invalid = true) }
const p1 = new Path().withRaise(raise) const p1 = new Path().withLog(log)
const a = new Point(0, 0) const a = new Point(0, 0)
const b = new Point(10, 10) const b = new Point(10, 10)
expect(invalid).to.equal(false) expect(invalid).to.equal(false)
@ -883,10 +944,10 @@ describe('Path', () => {
expect(invalid).to.equal(true) expect(invalid).to.equal(true)
}) })
it('Should raise a warning when drawing a curve with a Cp1 that is a non-point', () => { it('Should log a warning when drawing a curve with a Cp1 that is a non-point', () => {
let invalid = false let invalid = false
const raise = { warning: () => (invalid = true) } const log = { warning: () => (invalid = true) }
const p1 = new Path().withRaise(raise) const p1 = new Path().withLog(log)
const b = new Point(10, 10) const b = new Point(10, 10)
expect(invalid).to.equal(false) expect(invalid).to.equal(false)
try { try {
@ -897,10 +958,10 @@ describe('Path', () => {
expect(invalid).to.equal(true) expect(invalid).to.equal(true)
}) })
it('Should raise a warning when drawing a curve with a Cp2 that is a non-point', () => { it('Should log a warning when drawing a curve with a Cp2 that is a non-point', () => {
let invalid = false let invalid = false
const raise = { warning: () => (invalid = true) } const log = { warning: () => (invalid = true) }
const p1 = new Path().withRaise(raise) const p1 = new Path().withLog(log)
const b = new Point(10, 10) const b = new Point(10, 10)
expect(invalid).to.equal(false) expect(invalid).to.equal(false)
try { try {
@ -911,10 +972,10 @@ describe('Path', () => {
expect(invalid).to.equal(true) expect(invalid).to.equal(true)
}) })
it('Should raise a warning when drawing a _curve with a To that is a non-point', () => { it('Should log a warning when drawing a _curve with a To that is a non-point', () => {
let invalid = false let invalid = false
const raise = { warning: () => (invalid = true) } const log = { warning: () => (invalid = true) }
const p1 = new Path().withRaise(raise) const p1 = new Path().withLog(log)
const b = new Point(10, 10) const b = new Point(10, 10)
expect(invalid).to.equal(false) expect(invalid).to.equal(false)
try { try {
@ -925,10 +986,10 @@ describe('Path', () => {
expect(invalid).to.equal(true) expect(invalid).to.equal(true)
}) })
it('Should raise a warning when drawing a _curve with a Cp2 that is a non-point', () => { it('Should log a warning when drawing a _curve with a Cp2 that is a non-point', () => {
let invalid = false let invalid = false
const raise = { warning: () => (invalid = true) } const log = { warning: () => (invalid = true) }
const p1 = new Path().withRaise(raise) const p1 = new Path().withLog(log)
const b = new Point(10, 10) const b = new Point(10, 10)
expect(invalid).to.equal(false) expect(invalid).to.equal(false)
try { try {
@ -939,10 +1000,10 @@ describe('Path', () => {
expect(invalid).to.equal(true) expect(invalid).to.equal(true)
}) })
it('Should raise a warning when drawing a curve_ with a To that is a non-point', () => { it('Should log a warning when drawing a curve_ with a To that is a non-point', () => {
let invalid = false let invalid = false
const raise = { warning: () => (invalid = true) } const log = { warning: () => (invalid = true) }
const p1 = new Path().withRaise(raise) const p1 = new Path().withLog(log)
const b = new Point(10, 10) const b = new Point(10, 10)
expect(invalid).to.equal(false) expect(invalid).to.equal(false)
try { try {
@ -953,10 +1014,10 @@ describe('Path', () => {
expect(invalid).to.equal(true) expect(invalid).to.equal(true)
}) })
it('Should raise a warning when drawing a curve_ with a Cp2 that is a non-point', () => { it('Should log a warning when drawing a curve_ with a Cp2 that is a non-point', () => {
let invalid = false let invalid = false
const raise = { warning: () => (invalid = true) } const log = { warning: () => (invalid = true) }
const p1 = new Path().withRaise(raise) const p1 = new Path().withLog(log)
const b = new Point(10, 10) const b = new Point(10, 10)
expect(invalid).to.equal(false) expect(invalid).to.equal(false)
try { try {
@ -983,163 +1044,159 @@ describe('Path', () => {
expect(p1.ops[1].type).to.equal('line') expect(p1.ops[1].type).to.equal('line')
}) })
it('Should raise a warning when an insop operation used an falsy ID', () => { it('Should log a warning when an insop operation used an falsy ID', () => {
let invalid = false let invalid = false
const raise = { warning: () => (invalid = true) } const log = { warning: () => (invalid = true) }
const a = new Point(0, 0) const a = new Point(0, 0)
const b = new Point(10, 10) const b = new Point(10, 10)
const p1 = new Path().move(a).line(b) const p1 = new Path().move(a).line(b)
expect(invalid).to.equal(false) expect(invalid).to.equal(false)
const p2 = new Path().withRaise(raise).noop('test').insop(false, p1) const p2 = new Path().withLog(log).noop('test').insop(false, p1)
expect(invalid).to.equal(true) expect(invalid).to.equal(true)
}) })
it('Should raise a warning when an insop operation used an falsy ID', () => { it('Should log a warning when an insop operation used an falsy ID', () => {
let invalid = false let invalid = false
const raise = { warning: () => (invalid = true) } const log = { warning: () => (invalid = true) }
const a = new Point(0, 0) const a = new Point(0, 0)
const b = new Point(10, 10) const b = new Point(10, 10)
const p1 = new Path().move(a).line(b) const p1 = new Path().move(a).line(b)
expect(invalid).to.equal(false) expect(invalid).to.equal(false)
try { try {
new Path().withRaise(raise).noop('test').insop('test') new Path().withLog(log).noop('test').insop('test')
} catch (err) { } catch (err) {
expect('' + err).to.contain("Cannot read properties of undefined (reading 'ops')") expect('' + err).to.contain("Cannot read properties of undefined (reading 'ops')")
} }
expect(invalid).to.equal(true) expect(invalid).to.equal(true)
}) })
it('Should raise a warning when setting an attribute without a name', () => { it('Should log a warning when setting an attribute without a name', () => {
let invalid = false let invalid = false
const raise = { warning: () => (invalid = true) } const log = { warning: () => (invalid = true) }
expect(invalid).to.equal(false) expect(invalid).to.equal(false)
const p1 = new Path().withRaise(raise).attr() const p1 = new Path().withLog(log).attr()
expect(invalid).to.equal(true) expect(invalid).to.equal(true)
}) })
it('Should raise a warning when setting an attribute without a value', () => { it('Should log a warning when setting an attribute without a value', () => {
let invalid = false let invalid = false
const raise = { warning: () => (invalid = true) } const log = { warning: () => (invalid = true) }
expect(invalid).to.equal(false) expect(invalid).to.equal(false)
const p1 = new Path().withRaise(raise).attr('test') const p1 = new Path().withLog(log).attr('test')
expect(invalid).to.equal(true) expect(invalid).to.equal(true)
}) })
it('Should raise a warning when calling offset without a distance', () => { it('Should log a warning when calling offset without a distance', () => {
const pattern = new Pattern() const part = {
pattern.parts.a = new pattern.Part() name: 'test',
const { Path, Point, points, paths } = pattern.parts.a.shorthand() draft: part => {
points.a = new Point(0, 0) const { paths, Path, Point, points } = part.shorthand()
points.b = new Point(10, 10) paths.line = new Path()
paths.a = new Path().move(points.a).line(points.b) .move(new Point(0, 0))
paths.b = paths.a.offset() .line(new Point(0, 40))
expect(pattern.events.error.length).to.equal(1) .attr('class', 'foo')
expect(pattern.events.error[0]).to.equal( paths.a = new Path().move(points.a).line(points.b)
paths.b = paths.a.offset()
return part
}
}
const design = new Design({ parts: [ part ] })
const pattern = new design()
pattern.draft()
expect(pattern.store.logs.error.length).to.equal(2)
expect(pattern.store.logs.error[0]).to.equal(
'Called `Path.offset(distance)` but `distance` is not a number' 'Called `Path.offset(distance)` but `distance` is not a number'
) )
}) })
it('Should raise a warning when calling join without a path', () => { it('Should log a warning when calling join without a path', () => {
const pattern = new Pattern() const part = {
pattern.parts.a = new pattern.Part() name: 'test',
const { Path, Point, points, paths } = pattern.parts.a.shorthand() draft: part => {
points.a = new Point(0, 0) const { paths, Path, Point, points } = part.shorthand()
points.b = new Point(10, 10) paths.line = new Path()
try { .move(new Point(0, 0))
//paths.a = new Path().move(points.a).line(points.b).join() .line(new Point(0, 40))
pattern.parts.a.paths.a = new Path().move(points.a).line(points.b).join() .attr('class', 'foo')
} catch (err) { paths.a = new Path().move(points.a).line(points.b).join()
expect('' + err).to.contain("Cannot read properties of undefined (reading 'ops')") return part
}
} }
expect(pattern.events.error.length).to.equal(1) const design = new Design({ parts: [ part ] })
expect(pattern.events.error[0]).to.equal( const pattern = new design()
pattern.draft()
expect(pattern.store.logs.error.length).to.equal(2)
expect(pattern.store.logs.error[0]).to.equal(
'Called `Path.join(that)` but `that` is not a `Path` object' 'Called `Path.join(that)` but `that` is not a `Path` object'
) )
}) })
it('Should raise a warning when calling start on a path without drawing operations', () => { it('Should log a warning when calling start on a path without drawing operations', () => {
let invalid = false let invalid = false
const raise = { error: () => (invalid = true) } const log = { error: () => (invalid = true) }
expect(invalid).to.equal(false) expect(invalid).to.equal(false)
try { try {
new Path().withRaise(raise).start() new Path().withLog(log).start()
} catch (err) { } catch (err) {
expect('' + err).to.contain("Cannot read properties of undefined (reading 'to')") expect('' + err).to.contain("Cannot read properties of undefined (reading 'to')")
} }
expect(invalid).to.equal(true) expect(invalid).to.equal(true)
}) })
it('Should raise a warning when calling end on a path without drawing operations', () => { it('Should log a warning when calling end on a path without drawing operations', () => {
let invalid = false let invalid = false
const raise = { error: () => (invalid = true) } const log = { error: () => (invalid = true) }
expect(invalid).to.equal(false) expect(invalid).to.equal(false)
try { try {
new Path().withRaise(raise).end() new Path().withLog(log).end()
} catch (err) { } catch (err) {
expect('' + err).to.contain("Cannot read properties of undefined (reading 'type')") expect('' + err).to.contain("Cannot read properties of undefined (reading 'type')")
} }
expect(invalid).to.equal(true) expect(invalid).to.equal(true)
}) })
it('Should raise a warning when calling shiftAlong but distance is not a number', () => { it('Should log a warning when calling shiftAlong but distance is not a number', () => {
let invalid = false let invalid = false
const raise = { error: () => (invalid = true) } const log = { error: () => (invalid = true) }
expect(invalid).to.equal(false) expect(invalid).to.equal(false)
new Path().withRaise(raise).move(new Point(0, 0)).line(new Point(10, 10)).shiftAlong() new Path().withLog(log).move(new Point(0, 0)).line(new Point(10, 10)).shiftAlong()
expect(invalid).to.equal(true) expect(invalid).to.equal(true)
}) })
it('Should raise a warning when calling shiftFractionalong but fraction is not a number', () => { it('Should log a warning when calling shiftFractionalong but fraction is not a number', () => {
let invalid = false const part = {
const raise = { name: 'test',
error: () => (invalid = true), draft: part => {
warning: () => (invalid = true), const { paths, Path, Point, points } = part.shorthand()
points.a = new Path()
.move(new Point(0, 0))
.line(new Point(0, 40))
.shiftFractionAlong()
return part
}
} }
expect(invalid).to.equal(false) const design = new Design({ parts: [ part ] })
new Path() const pattern = new design()
.withRaise(raise) pattern.draft()
.move(new Point(0, 0).withRaise(raise)) expect(pattern.store.logs.error[0]).to.equal('Called `Path.shiftFractionAlong(fraction)` but `fraction` is not a number')
.line(new Point(10, 10).withRaise(raise))
.line(new Point(10, 20).withRaise(raise))
.shiftFractionAlong()
expect(invalid).to.equal(true)
}) })
it('Should raise a warning when splitting a path on a non-point', () => { it('Should log a warning when splitting a path on a non-point', () => {
let invalid = false const part = {
const raise = { name: 'test',
error: () => (invalid = true), draft: part => {
warning: () => (invalid = true), const { paths, Path, Point, points } = part.shorthand()
points.a = new Path()
.move(new Point(0, 0))
.line(new Point(0, 40))
.split()
return part
}
} }
const from = new Point(0, 0).withRaise(raise) const design = new Design({ parts: [ part ] })
const cp1 = new Point(10, 0).withRaise(raise) const pattern = new design()
const cp2 = new Point(90, 0).withRaise(raise) pattern.draft()
const to = new Point(100, 0).withRaise(raise) expect(pattern.store.logs.error[0]).to.equal('Called `Path.split(point)` but `point` is not a `Point` object')
const path = new Path().withRaise(raise).move(from).curve(cp1, cp2, to).line(from).line(cp1)
try {
path.split()
} catch (err) {
expect('' + err).to.contain("Cannot read properties of undefined (reading 'check')")
}
expect(invalid).to.equal(true)
}) })
it('Should raise a warning when splitting a path on a non-point', () => {
let invalid = false
const raise = {
error: () => (invalid = true),
warning: () => (invalid = true),
}
const from = new Point(0, 0).withRaise(raise)
const cp1 = new Point(10, 0).withRaise(raise)
const cp2 = new Point(90, 0).withRaise(raise)
const to = new Point(100, 0).withRaise(raise)
const path = new Path().withRaise(raise).move(from).curve(cp1, cp2, to).line(from)
try {
path.split()
} catch (err) {
expect('' + err).to.contain("Cannot read properties of undefined (reading 'check')")
}
expect(invalid).to.equal(true)
})
}) })