diff --git a/src/features/effects/Mask.js b/src/features/effects/Mask.js index 33b1058..a5edbc0 100644 --- a/src/features/effects/Mask.js +++ b/src/features/effects/Mask.js @@ -31,6 +31,10 @@ const options = { title: "Invert", type: "checkbox", }, + maskBorder: { + title: "Draw border", + type: "checkbox", + } } export default class Mask extends Effect { @@ -64,6 +68,7 @@ export default class Mask extends Effect { maskMinimizeMoves: false, maskMachine: "rectangle", maskInvert: false, + maskBorder: false, }, } } @@ -112,7 +117,7 @@ export default class Mask extends Effect { maxRadius: effect.width / 2, mask: true, }) - vertices = machine.polish(vertices) + vertices = machine.polish(vertices, { border: effect.maskBorder }) } return vertices.map((vertex) => { diff --git a/src/features/machines/Machine.js b/src/features/machines/Machine.js index a374b67..2f83d76 100644 --- a/src/features/machines/Machine.js +++ b/src/features/machines/Machine.js @@ -1,4 +1,4 @@ -import { vertexRoundP, annotateVertices } from "@/common/geometry" +import { vertexRoundP, annotateVertices, downsample } from "@/common/geometry" export const machineOptions = { name: { @@ -40,11 +40,13 @@ export default class Machine { this.layerInfo = layerInfo this.enforceLimits().cleanVertices().limitPrecision().optimizePerimeter() + if (this.layerInfo.border) this.outlinePerimeter() if (this.layerInfo.start) this.addStartPoint() if (this.layerInfo.end) this.addEndPoint() // second call to limit precision for final cleanup this.limitPrecision() + return this.vertices } diff --git a/src/features/machines/PolarMachine.js b/src/features/machines/PolarMachine.js index 0c2713b..26e1926 100644 --- a/src/features/machines/PolarMachine.js +++ b/src/features/machines/PolarMachine.js @@ -1,4 +1,11 @@ -import { angle, onSegment, arc, annotateVertex } from "@/common/geometry" +import { + angle, + onSegment, + arc, + annotateVertex, + subsample, + circle, +} from "@/common/geometry" import Victor from "victor" import Machine, { machineOptions } from "./Machine" @@ -143,6 +150,17 @@ export default class PolarMachine extends Machine { return arc(this.state.maxRadius, start.angle(), end.angle()) } + outlinePerimeter() { + const last = this.vertices[this.vertices.length - 1] + + if (last) { + this.vertices = this.vertices.concat( + circle(this.state.maxRadius, parseInt((last.angle() * 64) / Math.PI)), + ) + } + return this + } + // Returns whether a given path lies on the perimeter of the circle. onPerimeter(v1, v2, delta = 1) { let rm = Math.pow(this.state.maxRadius, 2) diff --git a/src/features/machines/RectMachine.js b/src/features/machines/RectMachine.js index fc149ab..a705437 100644 --- a/src/features/machines/RectMachine.js +++ b/src/features/machines/RectMachine.js @@ -137,6 +137,26 @@ export default class RectMachine extends Machine { return (rDx < delta && dx < delta) || (rDy < delta && dy < delta) } + outlinePerimeter() { + const last = this.vertices[this.vertices.length - 1] + + if (last) { + const s = this.nearestPerimeterVertex(last) + const idx = this.nearestCornerIndex(s) + const corners = [ + s, + cloneVertex(this.corners[idx]), + cloneVertex(this.corners[(idx + 1) % 4]), + cloneVertex(this.corners[(idx + 2) % 4]), + cloneVertex(this.corners[(idx + 3) % 4]), + cloneVertex(this.corners[idx]), + ] + this.vertices = this.vertices.concat(corners) + } + + return this + } + // Given two perimeter points, traces the shortest valid path between them (stays on // perimeter). Returns a list of intermediate points on that path (if any). // On further consideration, this could be redone using Dijsktra's algorithm, I believe,