diff --git a/examples/autoFill.html b/examples/autoFill.html
new file mode 100644
index 0000000..0da9d0b
--- /dev/null
+++ b/examples/autoFill.html
@@ -0,0 +1,56 @@
+
+
+
+
+
+ AutoFill Example
+
+
+
+
+
+
diff --git a/package.json b/package.json
index 0604e20..837efad 100644
--- a/package.json
+++ b/package.json
@@ -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"
diff --git a/src/Browser/Utils.ts b/src/Browser/Utils.ts
index f43041e..e6e6b98 100644
--- a/src/Browser/Utils.ts
+++ b/src/Browser/Utils.ts
@@ -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,
@@ -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);
diff --git a/src/Graphics/getSvg.ts b/src/Graphics/getSvg.ts
index f9b91d1..035ce0c 100644
--- a/src/Graphics/getSvg.ts
+++ b/src/Graphics/getSvg.ts
@@ -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,
diff --git a/src/IO/Writers/IWriter.ts b/src/IO/Writers/IWriter.ts
index 74d067a..1557491 100644
--- a/src/IO/Writers/IWriter.ts
+++ b/src/IO/Writers/IWriter.ts
@@ -1,3 +1,5 @@
+import { IResolvedStitches } from '../../Core/Pattern';
+
export interface IWriter {
- write: (IResolvedStitches, string) => void;
+ write: (resolvedStitches: IResolvedStitches, filename: string) => void;
}
diff --git a/src/Math/Graph.ts b/src/Math/Graph.ts
index 4f858ae..68b2640 100644
--- a/src/Math/Graph.ts
+++ b/src/Math/Graph.ts
@@ -24,15 +24,13 @@ export class Graph {
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) {
diff --git a/src/Math/Polyline.ts b/src/Math/Polyline.ts
index 1f8ed21..797953a 100644
--- a/src/Math/Polyline.ts
+++ b/src/Math/Polyline.ts
@@ -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;
@@ -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 (
@@ -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];
@@ -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];
@@ -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;
@@ -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]);
@@ -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 (
diff --git a/src/Math/Random.ts b/src/Math/Random.ts
index 6101785..431cfee 100644
--- a/src/Math/Random.ts
+++ b/src/Math/Random.ts
@@ -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;
@@ -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();
}
diff --git a/src/Math/Utils.ts b/src/Math/Utils.ts
index 881c94a..3fc49be 100644
--- a/src/Math/Utils.ts
+++ b/src/Math/Utils.ts
@@ -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;
@@ -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 =
@@ -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(
@@ -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;
},
};
diff --git a/src/Runs/AutoFill.ts b/src/Runs/AutoFill.ts
index 9d76d68..c6c57dd 100644
--- a/src/Runs/AutoFill.ts
+++ b/src/Runs/AutoFill.ts
@@ -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;
@@ -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;
@@ -105,7 +112,7 @@ export class AutoFill {
}
return rows;
}
- getFillStitchGraph(rows) {
+ getFillStitchGraph(rows: IIntersection[][][]) {
const fillStitchGraph = new Graph();
for (let i = 0; i < rows.length; i++) {
for (let j = 0; j < rows[i].length; j++) {
@@ -243,7 +250,11 @@ export class AutoFill {
return newPath;
}
- getStitchesFromPath(stitchPath, fillStitchGraph, pixelsPerMm) {
+ getStitchesFromPath(
+ stitchPath: IPathStep[],
+ fillStitchGraph: Graph,
+ pixelsPerMm: number,
+ ) {
let stitches = [] as Vector[];
if (stitchPath[0].key !== 'segment') {
stitches.push(fillStitchGraph.vertices[stitchPath[0].from].position);
@@ -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,
@@ -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) {
diff --git a/src/Runs/ClassicSatin.ts b/src/Runs/ClassicSatin.ts
index 0263c74..a318f54 100644
--- a/src/Runs/ClassicSatin.ts
+++ b/src/Runs/ClassicSatin.ts
@@ -17,7 +17,7 @@ export class ClassicSatin {
this.segments = [];
}
- static fromQuadStripVectors(vectors, densityMm = 0.4) {
+ static fromQuadStripVectors(vectors: Vector[], densityMm = 0.4) {
const run = new ClassicSatin(densityMm);
for (let i = 0; i < vectors.length; i += 2) {
run.addVector(vectors[i]);
@@ -25,11 +25,11 @@ export class ClassicSatin {
return run;
}
- addVertex(x, y) {
+ addVertex(x: number, y: number) {
this.addVector(new Vector(x, y));
}
- addVector(v) {
+ addVector(v: Vector) {
this.vertices.push(v);
const vertexCount = this.vertices.length;
if (vertexCount > 2 && vertexCount % 2 === 0) {
@@ -48,7 +48,7 @@ export class ClassicSatin {
}
}
- getStitches(pixelsPerMm) {
+ getStitches(pixelsPerMm: number) {
const run = [] as Vector[];
run.push(this.vertices[this.segments[0].side0.startIndex]);
run.push(this.vertices[this.segments[0].side1.startIndex]);
diff --git a/src/Runs/Satin.ts b/src/Runs/Satin.ts
index 0d9c7ca..a9ea327 100644
--- a/src/Runs/Satin.ts
+++ b/src/Runs/Satin.ts
@@ -5,10 +5,10 @@ export class Satin {
polyline: Polyline;
widthPx: number;
densityMm: number;
- constructor(polyline, widthPx, densityMm) {
+ constructor(polyline: Polyline, widthPx: number, densityMm: number) {
[this.polyline, this.widthPx, this.densityMm] = [polyline, widthPx, densityMm];
}
- getStitches(pixelsPerMm) {
+ getStitches(pixelsPerMm: number) {
const resampled = this.polyline.getResampled(pixelsPerMm * this.densityMm).vertices;
if (this.polyline.isClosed) resampled.push(resampled[0]);
const stitches = [] as Vector[];
diff --git a/src/index.ts b/src/index.ts
index f3f790a..ededf31 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -5,4 +5,5 @@ import { IO } from './IO';
import { Math } from './Math';
import { Runs } from './Runs';
+// export { Browser, Core, Graphics, IO, Math, Runs };
export { Browser, Core, Graphics, IO, Math, Runs };
diff --git a/tsconfig.json b/tsconfig.json
index 5f2eb15..d4a25f7 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -82,8 +82,8 @@
/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */
- "noImplicitAny": false, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
- "strictNullChecks": false, /* When type checking, take into account 'null' and 'undefined'. */
+ // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
+ // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
@@ -95,7 +95,7 @@
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
- "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
+ // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */