Skip to content

Commit

Permalink
fixing ts compilation errors and adding example
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewjacobson committed Jun 26, 2024
1 parent 49771fd commit 1bec0cb
Show file tree
Hide file tree
Showing 14 changed files with 137 additions and 60 deletions.
56 changes: 56 additions & 0 deletions examples/autoFill.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>AutoFill Example</title>
<script src="../dist/stitch.global.js"></script>
</head>
<body>
<script>

let simplificationRatio = 0.5;
let shape = [
Stitch.Math.Polyline.fromArrays([
[102, 356], [ 24, 251], [ 32, 179], [ 84, 250], [ 58, 145], [ 80, 108], [127, 46], [127, 102],
[102, 140], [116, 164], [135, 188], [171, 151], [193, 106], [201, 73], [233, 57], [232, 86],
[225, 112], [240, 116], [256, 94], [279, 73], [320, 85], [329, 118], [354, 173], [362, 228],
[356, 266], [312, 211], [269, 190], [247, 206], [227, 240], [228, 262], [243, 255], [246, 233],
[256, 218], [282, 219], [312, 246], [323, 268], [331, 301], [319, 325], [290, 356], [248, 362],
[216, 357], [205, 337], [199, 293], [189, 246], [172, 235], [152, 245], [139, 261], [138, 283],
[146, 277], [159, 257], [174, 256], [174, 274], [177, 302], [177, 336], [158, 358], [121, 366]
], true).getSimplified(simplificationRatio),
Stitch.Math.Polyline.fromArrays([[142, 324], [142, 296], [121, 297], [108, 315], [125, 338]], true).getSimplified(simplificationRatio),
Stitch.Math.Polyline.fromArrays([[206, 139], [194, 150], [203, 166], [217, 146]], true).getSimplified(simplificationRatio),
Stitch.Math.Polyline.fromArrays([[234, 309], [234, 326], [260, 326], [286, 295], [286, 264], [254, 279]], true).getSimplified(simplificationRatio)
];

let pattern = new Stitch.Core.Pattern(400, 400);

let thread = pattern.addThread(0, 0, 0);

let angle = 0.25 * Math.PI;

// underlay
thread.addRun(new Stitch.Runs.AutoFill(shape.map(p => p.getOffset(-5).getRounded(5)), angle + 0.5 * Math.PI, 1, 3, shape[0].vertices[0], shape[0].vertices[0]));

// fill
thread.addRun(new Stitch.Runs.AutoFill(shape.map(p => p.getRounded(5)), angle, 0.2, 3, shape[0].vertices[0], shape[0].vertices[0]));

let svg = Stitch.Graphics.getSvg(pattern, window.innerWidth, window.innerHeight);
svg.setAttribute("style", "margin: auto; position: absolute; inset: 0;")
document.body.append(svg);

let modal = Stitch.Browser.Modal.createDownloadModal(pattern, "autoFill", 10, 500);
window.addEventListener('click', (e) => {
if (e.target === modal.container) modal.close();
});
window.addEventListener('keydown', (e) => {
if (e.code === 'KeyD') modal.open();
});
document.body.appendChild(modal.container);


</script>
</body>
</html>
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"module": "dist/stitch.mjs",
"types": "dist/stitch.d.ts",
"scripts": {
"build": "tsup --entry.stitch src/index.ts --format cjs,esm,iife --dts --clean --minify --global-name Stitch",
"build": "pnpm run lint:write && tsup --entry.stitch src/index.ts --format cjs,esm,iife --dts --clean --minify --global-name Stitch",
"release": "pnpm run lint:check && pnpm run build && changeset publish",
"lint:write": "prettier --write \"**/*.{ts, tsx}\" && tsc",
"lint:check": "prettier --check \"**/*.{ts, tsx}\" && tsc"
Expand Down
17 changes: 11 additions & 6 deletions src/Browser/Utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,19 @@ export const Utils = {
for (const [name, value] of Object.entries(attributes))
element.setAttribute(name, value);
},
setStyles: function (element: HTMLElement, styles: { [name: string]: string }): void {
for (const [name, value] of Object.entries(styles)) element.style[name] = value;
setStyles: function (element: HTMLElement, styles: { [key: string]: string }): void {
for (const [key, value] of Object.entries(styles))
element.style.setProperty(key, value);
},
setProperties: function (
element: HTMLElement,
properties: { [name: string]: string },
properties: { [key: string]: any },
): void {
for (const [name, value] of Object.entries(properties)) element[name] = value;
for (const [key, value] of Object.entries(properties)) {
if (element.hasOwnProperty(key)) {
(element as any)[key] = value;
}
}
},
createElement: function (
elementName: string,
Expand All @@ -30,8 +35,8 @@ export const Utils = {
if (properties) this.setProperties(element, properties);
return element;
},
debounce: function (func, time = 0): (event: Event) => void {
let timer;
debounce: function (func: TimerHandler, time = 0): (event: Event) => void {
let timer: number;
return function (event) {
if (timer) clearTimeout(timer);
timer = setTimeout(func, time, event);
Expand Down
7 changes: 2 additions & 5 deletions src/Graphics/getSvg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,9 @@ export function getSvg(
pattern: Pattern,
widthPx: number,
heightPx: number,
svgOptions: ISvgOptions,
svgOptions: ISvgOptions = defaultSvgOptions,
): SVGElement {
// if (svgOptions !== undefined) {
// for (const [key, value] of Object.entries(defaultSvgOptions))
// if (!(key as keyof ISvgOptions in svgOptions)) svgOptions[key] = value;
// } else svgOptions = defaultSvgOptions;
svgOptions = { ...svgOptions, ...defaultSvgOptions };
const resolvedStitches = pattern.getStitches(
widthPx,
heightPx,
Expand Down
4 changes: 3 additions & 1 deletion src/IO/Writers/IWriter.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { IResolvedStitches } from '../../Core/Pattern';

export interface IWriter {
write: (IResolvedStitches, string) => void;
write: (resolvedStitches: IResolvedStitches, filename: string) => void;
}
8 changes: 3 additions & 5 deletions src/Math/Graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,13 @@ export class Graph<VertexPropertyType, EdgePropertyType> {
this.vertices[vertexId] = properties;
this.adjacency[vertexId] = [];
}
addEdge(vertexId1: string, vertexId2: string, properties: EdgePropertyType): void {
addEdge(vertexId1: string, vertexId2: string, properties: EdgePropertyType) {
const edgeId = Object.keys(this.edges).length;
if (vertexId1 in this.adjacency) {
this.adjacency[vertexId1].push({ edgeId: edgeId, vertexId: vertexId2 });
}
this.adjacency[vertexId1].push({ edgeId: edgeId, vertexId: vertexId2 });
this.adjacency[vertexId2].push({ edgeId: edgeId, vertexId: vertexId1 });
this.edges[edgeId] = { vertexId1, vertexId2, properties };
}
removeEdge(edgeId) {
removeEdge(edgeId: number) {
const edge = this.edges[edgeId];
for (let i = 0; i < this.adjacency[edge.vertexId1].length; i++) {
if (this.adjacency[edge.vertexId1][i].edgeId === edgeId) {
Expand Down
20 changes: 10 additions & 10 deletions src/Math/Polyline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export class Polyline {
polyline.vertices = vectors;
return polyline;
}
static fromArrays(arrays: number[][], isClosed = false) {
static fromArrays(arrays: [number, number][], isClosed = false) {
const polyline = new Polyline(isClosed);
for (const array of arrays) polyline.addVertex(array[0], array[1]);
return polyline;
Expand All @@ -27,13 +27,13 @@ export class Polyline {
addVertex(x: number, y: number): void {
this.vertices.push(new Vector(x, y));
}
translate(x, y) {
translate(x: number, y: number): Polyline {
const translatePolyline = new Polyline(this.isClosed);
for (const vertex of this.vertices)
translatePolyline.addVertex(vertex.x + x, vertex.y + y);
return translatePolyline;
}
getRounded(radius, stepAngle = 0.1) {
getRounded(radius: number, stepAngle = 0.1): Polyline {
const roundedPolyline = new Polyline(this.isClosed);
if (!this.isClosed) roundedPolyline.addVertex(this.vertices[0].x, this.vertices[0].y);
for (
Expand Down Expand Up @@ -124,7 +124,7 @@ export class Polyline {
);
return roundedPolyline;
}
getResampled(spacing) {
getResampled(spacing: number): Polyline {
if (spacing <= 0 || this.vertices.length === 0) return this;
let totalLength = 0;
const lengths = [0];
Expand Down Expand Up @@ -157,7 +157,7 @@ export class Polyline {
);
return resampledPolyline;
}
getOffset(distance) {
getOffset(distance: number): Polyline {
const offsetPolyline = new Polyline(this.isClosed);
for (let i = 0; i < this.vertices.length; i++) {
const prev = this.vertices[(i - 1 + this.vertices.length) % this.vertices.length];
Expand All @@ -180,14 +180,14 @@ export class Polyline {
continue;
}
const intersection = Utils.lineLineIntersection(p1, p2, q1, q2);
if (intersection) offsetPolyline.vertices.push(intersection);
if (intersection instanceof Vector) offsetPolyline.vertices.push(intersection);
}
return offsetPolyline;
}
getSimplified(tolerance) {
getSimplified(tolerance: number): Polyline {
// https://gist.github.com/adammiller/826148?permalink_comment_id=317898#gistcomment-317898
const squaredTolerance = tolerance * tolerance;
const simplifyDP = function (v, j, k, mk) {
const simplifyDP = function (v: Vector[], j: number, k: number, mk: number[]) {
if (k < j) return;
// let [maxi, maxd2, S] = [j, 0, [v[j], v[k]]];
let maxi = j;
Expand Down Expand Up @@ -229,7 +229,7 @@ export class Polyline {
for (i = m = 0; i < k; i++) if (mk[i]) simplifiedPolyline.vertices.push(vt[i]);
return simplifiedPolyline;
}
getClosestVertex(position) {
getClosestVertex(position: Vector): Vector {
let [minDistance, result] = [Infinity, new Vector(0, 0)];
for (let i = 0; i < this.vertices.length; i++) {
const distance = position.distance(this.vertices[i]);
Expand Down Expand Up @@ -273,7 +273,7 @@ export class Polyline {
}
return centroid.multiply(1 / 6 / this.getArea());
}
containsPoint(point) {
containsPoint(point: Vector): boolean {
let contains = false;
for (let i = 0, j = this.vertices.length - 1; i < this.vertices.length; j = i++) {
if (
Expand Down
4 changes: 2 additions & 2 deletions src/Math/Random.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export class Random {
prngA: () => number;
prngB: () => number;
constructor(hash: string) {
if (!hash) {
if (hash === undefined) {
hash = this.randomHash();
}
this.useA = false;
Expand All @@ -39,7 +39,7 @@ export class Random {
for (let i = 0; i < 64; i++) hash += Math.floor(Math.random() * 16).toString(16);
return hash;
}
random_dec(): number {
random_dec() {
this.useA = !this.useA;
return this.useA ? this.prngA() : this.prngB();
}
Expand Down
27 changes: 17 additions & 10 deletions src/Math/Utils.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
import { Vector } from './Vector';

export const Utils = {
constrain: function (value, low, high) {
constrain: function (value: number, low: number, high: number) {
return Math.max(Math.min(value, high), low);
},
map: function (value, a, b, c, d, clamp = false) {
map: function (
value: number,
a: number,
b: number,
c: number,
d: number,
clamp = false,
) {
const mapped = ((value - a) / (b - a)) * (d - c) + c;
if (!clamp) return mapped;
if (c < d) return Utils.constrain(mapped, c, d);
else return Utils.constrain(mapped, d, c);
},
isPointLeft: function (start, end, point) {
isPointLeft: function (start: Vector, end: Vector, point: Vector) {
return (
(end.x - start.x) * (point.y - start.y) - (end.y - start.y) * (point.x - start.x) >
0
);
},
lineSegmentIntersection: function (p1, p2, q1, q2) {
lineSegmentIntersection: function (p1: Vector, p2: Vector, q1: Vector, q2: Vector) {
const s1 = p2.subtract(p1);
const s2 = q2.subtract(q1);
const d = -s2.x * s1.y + s1.x * s2.y;
Expand All @@ -26,12 +33,12 @@ export const Utils = {
return new Vector(p1.x + t * s1.x, p1.y + t * s1.y);
else return null;
},
getAngleBetween: function (a, b, c) {
getAngleBetween: function (a: Vector, b: Vector, c: Vector) {
const v1 = b.subtract(a).normalized();
const v2 = c.subtract(b).normalized();
return Math.atan2(v2.y * v1.x - v2.x * v1.y, v2.x * v1.x + v2.y * v1.y) + Math.PI;
},
lineLineIntersection: function (p1, p2, q1, q2) {
lineLineIntersection: function (p1: Vector, p2: Vector, q1: Vector, q2: Vector) {
const denominator = (q2.y - q1.y) * (p2.x - p1.x) - (q2.x - q1.x) * (p2.y - p1.y);
if (denominator === 0) return false;
const ua =
Expand All @@ -40,7 +47,7 @@ export const Utils = {
((p2.x - p1.x) * (p1.y - q1.y) - (p2.y - p1.y) * (p1.x - q1.x)) / denominator;
return p1.add(p2.subtract(p1).multiply(ua));
},
sdfLine: function (p1, p2, v) {
sdfLine: function (p1: Vector, p2: Vector, v: Vector) {
const m = (p2.y - p1.y) / (p2.x - p1.x);
const b = p1.y - m * p1.x;
return Math.min(
Expand All @@ -49,13 +56,13 @@ export const Utils = {
Math.abs(v.y - m * v.x - b) / Math.sqrt(m * m + 1),
);
},
distance(x1, y1, x2, y2) {
distance(x1: number, y1: number, x2: number, y2: number) {
return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
},
inToMm: function (inches) {
inToMm: function (inches: number) {
return inches * 25.4;
},
mmToIn: function (millimeters) {
mmToIn: function (millimeters: number) {
return millimeters / 25.4;
},
};
33 changes: 22 additions & 11 deletions src/Runs/AutoFill.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,14 @@ export class AutoFill {
bounds: BoundingBox;
center: Vector;
distance: number;
constructor(shape, angle, rowSpacingMm, stitchSpacingMm, startPosition, endPosition) {
constructor(
shape: Polyline[],
angle: number,
rowSpacingMm: number,
stitchSpacingMm: number,
startPosition: Vector,
endPosition: Vector,
) {
this.shape = shape;
this.angle = angle;
this.rowSpacingMm = rowSpacingMm;
Expand All @@ -55,14 +62,14 @@ export class AutoFill {
this.center = this.bounds.min.add(this.bounds.max).multiply(0.5);
this.distance = this.center.distance(this.bounds.min);
}
getStitches(pixelsPerMm) {
getStitches(pixelsPerMm: number) {
const rows = this.getRows(pixelsPerMm);
const fillStitchGraph = this.getFillStitchGraph(rows);
const travelGraph = this.getTravelGraph(fillStitchGraph);
const stitchPath = this.getStitchPath(fillStitchGraph, travelGraph);
return this.getStitchesFromPath(stitchPath, fillStitchGraph, pixelsPerMm);
}
getRows(pixelsPerMm) {
getRows(pixelsPerMm: number) {
const rows = [] as IIntersection[][][];
for (
let offset = -this.distance;
Expand Down Expand Up @@ -105,7 +112,7 @@ export class AutoFill {
}
return rows;
}
getFillStitchGraph(rows) {
getFillStitchGraph(rows: IIntersection[][][]) {
const fillStitchGraph = new Graph<IIntersection, { key: string }>();
for (let i = 0; i < rows.length; i++) {
for (let j = 0; j < rows[i].length; j++) {
Expand Down Expand Up @@ -243,7 +250,11 @@ export class AutoFill {

return newPath;
}
getStitchesFromPath(stitchPath, fillStitchGraph, pixelsPerMm) {
getStitchesFromPath(
stitchPath: IPathStep[],
fillStitchGraph: Graph<IIntersection, { key: string }>,
pixelsPerMm: number,
) {
let stitches = [] as Vector[];
if (stitchPath[0].key !== 'segment') {
stitches.push(fillStitchGraph.vertices[stitchPath[0].from].position);
Expand All @@ -268,7 +279,7 @@ export class AutoFill {
}
return stitches;
}
stitchRow(from, to, pixelsPerMm) {
stitchRow(from: IIntersection, to: IIntersection, pixelsPerMm: number) {
const rowStitches = [] as Vector[];
const offset = Utils.map(
from.rowIndex % 2,
Expand Down Expand Up @@ -300,12 +311,12 @@ export class AutoFill {
findPath(
from: Vector,
to: Vector,
maxStepSize,
minStepSize,
maxStepSize: number,
minStepSize: number,
nLayer = 0,
originalStepSize = null,
) {
if (originalStepSize === null) originalStepSize = maxStepSize;
originalStepSize?: number,
): Vector[] {
if (originalStepSize === undefined) originalStepSize = maxStepSize;
const queue: Vector[][] = [[from]];
const visited = new Set();
while (queue.length > 0) {
Expand Down
Loading

0 comments on commit 1bec0cb

Please sign in to comment.