1
0
Fork 0

chore(core): Added raise to path instances

I am not happy about this, but when a Path object is not created via
the proxied constructor, we don't have the raise method inside of it.
This commit is contained in:
Joost De Cock 2020-07-21 13:59:13 +02:00
parent 9ace3b6255
commit ffd7ecda59
3 changed files with 68 additions and 33 deletions

View file

@ -20,6 +20,14 @@ function Path(debug = false) {
this.ops = [] this.ops = []
} }
/** Adds the raise method for a path not created through the proxy **/
Path.prototype.withRaise = function (raise = false) {
if (raise) this.raise = raise
else this.raise = () => null
return this
}
/** Chainable way to set the render property */ /** Chainable way to set the render property */
Path.prototype.setRender = function (render = true) { Path.prototype.setRender = function (render = true) {
if (render) this.render = true if (render) this.render = true
@ -174,7 +182,7 @@ Path.prototype.asPathstring = function () {
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.raise.error('Called `Path.offset(distance)` but `distance` is not a number')
return pathOffset(this, distance) return pathOffset(this, distance, this.raise)
} }
/** Returns the length of this path */ /** Returns the length of this path */
@ -290,6 +298,8 @@ Path.prototype.boundary = function () {
Path.prototype.clone = function () { Path.prototype.clone = function () {
let clone = new Path() let clone = new Path()
clone.render = this.render clone.render = this.render
clone.debug = this.debug
clone.raise = this.raise
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()
@ -317,11 +327,11 @@ Path.prototype.clone = function () {
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.raise.error('Called `Path.join(that)` but `that` is not a `Path` object')
return joinPaths([this, that], closed) return joinPaths([this, that], closed, this.raise)
} }
/** Offsets a path by distance */ /** Offsets a path by distance */
function pathOffset(path, distance) { function pathOffset(path, distance, raise) {
let offset = [] let offset = []
let current let current
let start = false let start = false
@ -329,17 +339,25 @@ function pathOffset(path, distance) {
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) let segment = offsetLine(current, op.to, distance, path.raise)
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().move(current).curve(op.cp1, op.cp2, op.to).shiftAlong(2) cp1 = new Path()
.withRaise(path.raise)
.move(current)
.curve(op.cp1, op.cp2, op.to)
.shiftAlong(2)
} else cp1 = op.cp1 } else cp1 = op.cp1
if (op.cp2.sitsRoughlyOn(op.to)) { if (op.cp2.sitsRoughlyOn(op.to)) {
cp2 = new Path().move(op.to).curve(op.cp2, op.cp1, current).shiftAlong(2) cp2 = new Path()
.withRaise(path.raise)
.move(op.to)
.curve(op.cp2, op.cp1, current)
.shiftAlong(2)
} else cp2 = op.cp2 } else cp2 = op.cp2
let b = new Bezier( let b = new Bezier(
{ x: current.x, y: current.y }, { x: current.x, y: current.y },
@ -347,26 +365,30 @@ function pathOffset(path, distance) {
{ 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)) for (let bezier of b.offset(distance)) offset.push(asPath(bezier, raise))
} 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) return joinPaths(offset, closed, raise)
} }
/** Offsets a line by distance */ /** Offsets a line by distance */
function offsetLine(from, to, distance) { function offsetLine(from, to, distance, raise = 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().move(from.shift(angle, distance)).line(to.shift(angle, distance)) return new Path()
.withRaise(raise)
.move(from.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) { function asPath(bezier, raise = false) {
return new Path() return new Path()
.withRaise(raise)
.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),
@ -376,8 +398,8 @@ function asPath(bezier) {
} }
/** Joins path segments together into one path */ /** Joins path segments together into one path */
function joinPaths(paths, closed = false) { function joinPaths(paths, closed = false, raise = false) {
let joint = new Path().move(paths[0].ops[0].to) let joint = new Path().withRaise(raise).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) {
@ -542,15 +564,16 @@ Path.prototype.reverse = function () {
for (let i in this.ops) { for (let i in this.ops) {
let op = this.ops[i] let op = this.ops[i]
if (op.type === 'line') { if (op.type === 'line') {
if (!op.to.sitsOn(current)) sections.push(new Path().move(op.to).line(current)) if (!op.to.sitsOn(current))
sections.push(new Path().withRaise(this.raise).move(op.to).line(current))
} else if (op.type === 'curve') { } else if (op.type === 'curve') {
sections.push(new Path().move(op.to).curve(op.cp2, op.cp1, current)) sections.push(new Path().withRaise(this.raise).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().move(current) let rev = new Path().withRaise(this.raise).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()
@ -607,11 +630,12 @@ Path.prototype.divide = function () {
if (op.type === 'move') { if (op.type === 'move') {
start = op.to start = op.to
} else if (op.type === 'line') { } else if (op.type === 'line') {
if (!op.to.sitsRoughlyOn(current)) paths.push(new Path().move(current).line(op.to)) if (!op.to.sitsRoughlyOn(current))
paths.push(new Path().withRaise(this.raise).move(current).line(op.to))
} else if (op.type === 'curve') { } else if (op.type === 'curve') {
paths.push(new Path().move(current).curve(op.cp1, op.cp2, op.to)) paths.push(new Path().withRaise(this.raise).move(current).curve(op.cp1, op.cp2, op.to))
} else if (op.type === 'close') { } else if (op.type === 'close') {
paths.push(new Path().move(current).line(start)) paths.push(new Path().withRaise(this.raise).move(current).line(start))
} }
if (op.to) current = op.to if (op.to) current = op.to
} }
@ -745,10 +769,10 @@ Path.prototype.split = function (point) {
if (path.ops[1].type === 'line') { if (path.ops[1].type === 'line') {
if (pointOnLine(path.ops[0].to, path.ops[1].to, point)) { 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().move(path.ops[0].to).line(point)) firstHalf.push(new Path().withRaise(this.raise).move(path.ops[0].to).line(point))
pi++ pi++
secondHalf = divided.slice(pi) secondHalf = divided.slice(pi)
secondHalf.unshift(new Path().move(point).line(path.ops[1].to)) secondHalf.unshift(new Path().withRaise(this.raise).move(point).line(path.ops[1].to))
} }
} else if (path.ops[1].type === 'curve') { } else if (path.ops[1].type === 'curve') {
let t = pointOnCurve(path.ops[0].to, path.ops[1].cp1, path.ops[1].cp2, path.ops[1].to, point) let t = pointOnCurve(path.ops[0].to, path.ops[1].cp1, path.ops[1].cp2, path.ops[1].to, point)
@ -763,6 +787,7 @@ Path.prototype.split = function (point) {
firstHalf = divided.slice(0, pi) firstHalf = divided.slice(0, pi)
firstHalf.push( firstHalf.push(
new Path() new Path()
.withRaise(this.raise)
.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),
@ -774,6 +799,7 @@ Path.prototype.split = function (point) {
secondHalf = divided.slice(pi) secondHalf = divided.slice(pi)
secondHalf.unshift( secondHalf.unshift(
new Path() new Path()
.withRaise(this.raise)
.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),
@ -784,8 +810,8 @@ Path.prototype.split = function (point) {
} }
} }
} }
if (firstHalf) firstHalf = joinPaths(firstHalf) if (firstHalf) firstHalf = joinPaths(firstHalf, false, this.raise)
if (secondHalf) secondHalf = joinPaths(secondHalf) if (secondHalf) secondHalf = joinPaths(secondHalf, false, this.raise)
return [firstHalf, secondHalf] return [firstHalf, secondHalf]
} }
@ -802,7 +828,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() let glue = new Path().withRaise(this.raise)
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
@ -830,9 +856,9 @@ Path.prototype.trim = function () {
first = false first = false
} }
let joint let joint
if (trimmedStart.length > 0) joint = joinPaths(trimmedStart).join(glue) if (trimmedStart.length > 0) joint = joinPaths(trimmedStart, false, this.raise).join(glue)
else joint = glue else joint = glue
if (trimmedEnd.length > 0) joint = joint.join(joinPaths(trimmedEnd)) if (trimmedEnd.length > 0) joint = joint.join(joinPaths(trimmedEnd, false, this.raise))
return joint.trim() return joint.trim()
} }

View file

@ -12,6 +12,14 @@ function Point(x, y, debug = false) {
this.attributes = new Attributes() this.attributes = new Attributes()
} }
/** Adds the raise method for a path not created through the proxy **/
Point.prototype.withRaise = function (raise = false) {
if (raise) this.raise = raise
else this.raise = () => null
return this
}
/** Debug method to validate point data **/ /** Debug method to validate point data **/
Point.prototype.check = function () { Point.prototype.check = function () {
if (this.debug) { if (this.debug) {
@ -105,13 +113,13 @@ Point.prototype.rotate = function (deg, that) {
let x = that.x + radius * Math.cos(this.deg2rad(angle + deg)) * -1 let x = that.x + radius * Math.cos(this.deg2rad(angle + deg)) * -1
let y = that.y + radius * Math.sin(this.deg2rad(angle + deg)) let y = that.y + radius * Math.sin(this.deg2rad(angle + deg))
return new Point(x, y) return new Point(x, y).withRaise(this.raise)
} }
/** returns an identical copy of this point */ /** returns an identical copy of this point */
Point.prototype.copy = function () { Point.prototype.copy = function () {
if (this.debug) this.check() if (this.debug) this.check()
return new Point(this.x, this.y) return new Point(this.x, this.y).withRaise(this.raise)
} }
/** Mirrors this point around X value of that point */ /** Mirrors this point around X value of that point */
@ -124,8 +132,8 @@ Point.prototype.flipX = function (that = false) {
that.check() that.check()
} }
} }
if (that === false || that.x === 0) return new Point(this.x * -1, this.y) if (that === false || that.x === 0) return new Point(this.x * -1, this.y).withRaise(this.raise)
else return new Point(that.x + this.dx(that), this.y) else return new Point(that.x + this.dx(that), this.y).withRaise(this.raise)
} }
/** Mirrors this point around Y value of that point */ /** Mirrors this point around Y value of that point */
@ -138,8 +146,8 @@ Point.prototype.flipY = function (that = false) {
that.check() that.check()
} }
} }
if (that === false || that.y === 0) return new Point(this.x, this.y * -1) if (that === false || that.y === 0) return new Point(this.x, this.y * -1).withRaise(this.raise)
else return new Point(this.x, that.y + this.dy(that)) else return new Point(this.x, that.y + this.dy(that)).withRaise(this.raise)
} }
/** Shifts this point distance in the deg direction */ /** Shifts this point distance in the deg direction */
@ -231,7 +239,7 @@ Point.prototype.shiftOutwards = function (that, distance) {
/** Returns a deep copy of this */ /** Returns a deep copy of this */
Point.prototype.clone = function () { Point.prototype.clone = function () {
if (this.debug) this.check() if (this.debug) this.check()
let clone = new Point(this.x, this.y) let clone = new Point(this.x, this.y).withRaise(this.raise)
clone.attributes = this.attributes.clone() clone.attributes = this.attributes.clone()
return clone return clone

View file

@ -28,6 +28,7 @@ Snippet.prototype.attr = function (name, value, overwrite = false) {
Snippet.prototype.clone = function () { Snippet.prototype.clone = function () {
let clone = new Snippet(this.def, this.anchor.clone()) let clone = new Snippet(this.def, this.anchor.clone())
clone.attributes = this.attributes.clone() clone.attributes = this.attributes.clone()
clone.raise = this.raise
return clone return clone
} }