mirror of
https://github.com/jhbruhn/respira.git
synced 2026-01-27 10:23:41 +00:00
Merge pull request #11 from jhbruhn/feature/add-pen-conversion-tests
fix: add lock stitch at start of design
This commit is contained in:
commit
38c34315f8
2 changed files with 109 additions and 42 deletions
|
|
@ -4,6 +4,7 @@ import {
|
||||||
calculateLockDirection,
|
calculateLockDirection,
|
||||||
generateLockStitches,
|
generateLockStitches,
|
||||||
encodeStitchesToPen,
|
encodeStitchesToPen,
|
||||||
|
LOCK_STITCH_JUMP_SIZE
|
||||||
} from './encoder';
|
} from './encoder';
|
||||||
import { decodeAllPenStitches } from './decoder';
|
import { decodeAllPenStitches } from './decoder';
|
||||||
import { STITCH, MOVE, TRIM, END } from '../import/constants';
|
import { STITCH, MOVE, TRIM, END } from '../import/constants';
|
||||||
|
|
@ -258,6 +259,7 @@ describe('encodeStitchesToPen', () => {
|
||||||
const decoded = decodeAllPenStitches(result.penBytes);
|
const decoded = decodeAllPenStitches(result.penBytes);
|
||||||
|
|
||||||
// Expected sequence:
|
// Expected sequence:
|
||||||
|
// 0. 8 starting lock stitches at (0, 0)
|
||||||
// 1. Stitch at (0, 0) - color 0
|
// 1. Stitch at (0, 0) - color 0
|
||||||
// 2. Stitch at (10, 0) - color 0 (last before change)
|
// 2. Stitch at (10, 0) - color 0 (last before change)
|
||||||
// 3. 8 finishing lock stitches around (10, 0)
|
// 3. 8 finishing lock stitches around (10, 0)
|
||||||
|
|
@ -274,7 +276,12 @@ describe('encodeStitchesToPen', () => {
|
||||||
expect(decoded[idx].y).toBe(0);
|
expect(decoded[idx].y).toBe(0);
|
||||||
expect(decoded[idx].isFeed).toBe(false);
|
expect(decoded[idx].isFeed).toBe(false);
|
||||||
expect(decoded[idx].isCut).toBe(false);
|
expect(decoded[idx].isCut).toBe(false);
|
||||||
idx++;
|
|
||||||
|
// 0. 8 starting lock stitches at (0, 0)
|
||||||
|
for (; idx < 9; idx++) {
|
||||||
|
expect(decoded[idx].x).to.be.closeTo(0, LOCK_STITCH_JUMP_SIZE);
|
||||||
|
expect(decoded[idx].y).to.be.closeTo(0, LOCK_STITCH_JUMP_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
// 2. Second stitch (10, 0) - last before color change
|
// 2. Second stitch (10, 0) - last before color change
|
||||||
expect(decoded[idx].x).toBe(10);
|
expect(decoded[idx].x).toBe(10);
|
||||||
|
|
@ -284,8 +291,8 @@ describe('encodeStitchesToPen', () => {
|
||||||
// 3. 8 finishing lock stitches (should be around position 10, 0)
|
// 3. 8 finishing lock stitches (should be around position 10, 0)
|
||||||
for (let i = 0; i < 8; i++) {
|
for (let i = 0; i < 8; i++) {
|
||||||
const lockStitch = decoded[idx];
|
const lockStitch = decoded[idx];
|
||||||
expect(lockStitch.x).toBeCloseTo(10, 1); // Allow some deviation due to rotation
|
expect(lockStitch.x).to.be.closeTo(10, LOCK_STITCH_JUMP_SIZE); // Allow some deviation due to rotation
|
||||||
expect(lockStitch.y).toBeCloseTo(0, 1);
|
expect(lockStitch.y).to.be.closeTo(0, LOCK_STITCH_JUMP_SIZE);
|
||||||
expect(lockStitch.isFeed).toBe(false);
|
expect(lockStitch.isFeed).toBe(false);
|
||||||
expect(lockStitch.isCut).toBe(false);
|
expect(lockStitch.isCut).toBe(false);
|
||||||
idx++;
|
idx++;
|
||||||
|
|
@ -308,8 +315,8 @@ describe('encodeStitchesToPen', () => {
|
||||||
// 6. 8 starting lock stitches for new color
|
// 6. 8 starting lock stitches for new color
|
||||||
for (let i = 0; i < 8; i++) {
|
for (let i = 0; i < 8; i++) {
|
||||||
const lockStitch = decoded[idx];
|
const lockStitch = decoded[idx];
|
||||||
expect(lockStitch.x).toBeCloseTo(10, 1);
|
expect(lockStitch.x).to.be.closeTo(10, LOCK_STITCH_JUMP_SIZE);
|
||||||
expect(lockStitch.y).toBeCloseTo(0, 1);
|
expect(lockStitch.y).to.be.closeTo(0, LOCK_STITCH_JUMP_SIZE);
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -336,13 +343,13 @@ describe('encodeStitchesToPen', () => {
|
||||||
const result = encodeStitchesToPen(stitches);
|
const result = encodeStitchesToPen(stitches);
|
||||||
const decoded = decodeAllPenStitches(result.penBytes);
|
const decoded = decodeAllPenStitches(result.penBytes);
|
||||||
|
|
||||||
let idx = 2; // Skip first two regular stitches
|
let idx = 10; // Skip 8 starting locks + first two regular stitches
|
||||||
|
|
||||||
// After second stitch, should have:
|
// After second stitch, should have:
|
||||||
// 1. 8 finishing lock stitches at (10, 0)
|
// 1. 8 finishing lock stitches at (10, 0)
|
||||||
for (let i = 0; i < 8; i++) {
|
for (let i = 0; i < 8; i++) {
|
||||||
expect(decoded[idx].x).toBeCloseTo(10, 1);
|
expect(decoded[idx].x).to.be.closeTo(10, LOCK_STITCH_JUMP_SIZE);
|
||||||
expect(decoded[idx].y).toBeCloseTo(0, 1);
|
expect(decoded[idx].y).to.be.closeTo(0, LOCK_STITCH_JUMP_SIZE);
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -365,8 +372,8 @@ describe('encodeStitchesToPen', () => {
|
||||||
|
|
||||||
// 5. 8 starting lock stitches at (30, 10)
|
// 5. 8 starting lock stitches at (30, 10)
|
||||||
for (let i = 0; i < 8; i++) {
|
for (let i = 0; i < 8; i++) {
|
||||||
expect(decoded[idx].x).toBeCloseTo(30, 1);
|
expect(decoded[idx].x).to.be.closeTo(30, LOCK_STITCH_JUMP_SIZE);
|
||||||
expect(decoded[idx].y).toBeCloseTo(10, 1);
|
expect(decoded[idx].y).to.be.closeTo(10, LOCK_STITCH_JUMP_SIZE);
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -404,12 +411,13 @@ describe('encodeStitchesToPen', () => {
|
||||||
|
|
||||||
// 1-2. First two stitches
|
// 1-2. First two stitches
|
||||||
expect(decoded[idx++].x).toBe(0);
|
expect(decoded[idx++].x).toBe(0);
|
||||||
|
idx = 9; // skip startingLock
|
||||||
expect(decoded[idx++].x).toBe(10);
|
expect(decoded[idx++].x).toBe(10);
|
||||||
|
|
||||||
// 3. 8 finishing lock stitches at (10, 0)
|
// 3. 8 finishing lock stitches at (10, 0)
|
||||||
for (let i = 0; i < 8; i++) {
|
for (let i = 0; i < 8; i++) {
|
||||||
expect(decoded[idx].x).toBeCloseTo(10, 1);
|
expect(decoded[idx].x).to.be.closeTo(10, LOCK_STITCH_JUMP_SIZE);
|
||||||
expect(decoded[idx].y).toBeCloseTo(0, 1);
|
expect(decoded[idx].y).to.be.closeTo(0, LOCK_STITCH_JUMP_SIZE);
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -433,8 +441,8 @@ describe('encodeStitchesToPen', () => {
|
||||||
|
|
||||||
// 7. 8 starting lock stitches at (50, 20)
|
// 7. 8 starting lock stitches at (50, 20)
|
||||||
for (let i = 0; i < 8; i++) {
|
for (let i = 0; i < 8; i++) {
|
||||||
expect(decoded[idx].x).toBeCloseTo(50, 1);
|
expect(decoded[idx].x).to.be.closeTo(50, LOCK_STITCH_JUMP_SIZE);
|
||||||
expect(decoded[idx].y).toBeCloseTo(20, 1);
|
expect(decoded[idx].y).to.be.closeTo(20, LOCK_STITCH_JUMP_SIZE);
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -472,17 +480,18 @@ describe('encodeStitchesToPen', () => {
|
||||||
// 6. Stitch at (110, 0)
|
// 6. Stitch at (110, 0)
|
||||||
// 7. Stitch at (120, 0) with END flag
|
// 7. Stitch at (120, 0) with END flag
|
||||||
|
|
||||||
let idx = 0;
|
let idx = 0;
|
||||||
|
|
||||||
// 1-2. First two stitches
|
// 1-2. First two stitches
|
||||||
expect(decoded[idx++].x).toBe(0);
|
expect(decoded[idx++].x).toBe(0);
|
||||||
|
idx = 9; // Skip 8 starting lock stitches
|
||||||
expect(decoded[idx++].x).toBe(10);
|
expect(decoded[idx++].x).toBe(10);
|
||||||
|
|
||||||
// 3. 8 finishing lock stitches at (10, 0)
|
// 3. 8 finishing lock stitches at (10, 0)
|
||||||
for (let i = 0; i < 8; i++) {
|
for (let i = 0; i < 8; i++) {
|
||||||
const lockStitch = decoded[idx];
|
const lockStitch = decoded[idx];
|
||||||
expect(lockStitch.x).toBeCloseTo(10, 1);
|
expect(lockStitch.x).to.be.closeTo(10, LOCK_STITCH_JUMP_SIZE);
|
||||||
expect(lockStitch.y).toBeCloseTo(0, 1);
|
expect(lockStitch.y).to.be.closeTo(0, LOCK_STITCH_JUMP_SIZE);
|
||||||
expect(lockStitch.isFeed).toBe(false);
|
expect(lockStitch.isFeed).toBe(false);
|
||||||
expect(lockStitch.isCut).toBe(false);
|
expect(lockStitch.isCut).toBe(false);
|
||||||
idx++;
|
idx++;
|
||||||
|
|
@ -500,8 +509,8 @@ describe('encodeStitchesToPen', () => {
|
||||||
// 5. 8 starting lock stitches at (100, 0)
|
// 5. 8 starting lock stitches at (100, 0)
|
||||||
for (let i = 0; i < 8; i++) {
|
for (let i = 0; i < 8; i++) {
|
||||||
const lockStitch = decoded[idx];
|
const lockStitch = decoded[idx];
|
||||||
expect(lockStitch.x).toBeCloseTo(100, 1);
|
expect(lockStitch.x).to.be.closeTo(100, LOCK_STITCH_JUMP_SIZE);
|
||||||
expect(lockStitch.y).toBeCloseTo(0, 1);
|
expect(lockStitch.y).to.be.closeTo(0, LOCK_STITCH_JUMP_SIZE);
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -526,7 +535,7 @@ describe('encodeStitchesToPen', () => {
|
||||||
// Second stitch (jump) should have FEED_DATA flag (0x01) in Y low byte
|
// Second stitch (jump) should have FEED_DATA flag (0x01) in Y low byte
|
||||||
// Stitch format: [xLow, xHigh, yLow, yHigh]
|
// Stitch format: [xLow, xHigh, yLow, yHigh]
|
||||||
// We need to find the jump stitch - it's the second one encoded
|
// We need to find the jump stitch - it's the second one encoded
|
||||||
const jumpStitchStart = 4; // Skip first stitch
|
const jumpStitchStart = 36; // Skip 8 starting locks (32 bytes) + first stitch (4 bytes)
|
||||||
const yLow = result.penBytes[jumpStitchStart + 2];
|
const yLow = result.penBytes[jumpStitchStart + 2];
|
||||||
expect(yLow & 0x01).toBe(0x01); // FEED_DATA flag
|
expect(yLow & 0x01).toBe(0x01); // FEED_DATA flag
|
||||||
});
|
});
|
||||||
|
|
@ -558,21 +567,26 @@ describe('encodeStitchesToPen', () => {
|
||||||
const result = encodeStitchesToPen(stitches);
|
const result = encodeStitchesToPen(stitches);
|
||||||
const decoded = decodeAllPenStitches(result.penBytes);
|
const decoded = decodeAllPenStitches(result.penBytes);
|
||||||
|
|
||||||
|
let idx = 0;
|
||||||
|
|
||||||
// Verify sequence:
|
// Verify sequence:
|
||||||
// 1. Regular stitch at (0, 0)
|
// 1. Regular stitch at (0, 0)
|
||||||
expect(decoded[0].x).toBe(0);
|
const firstIdx = idx;
|
||||||
expect(decoded[0].isCut).toBe(false);
|
expect(decoded[idx++].x).toBe(0);
|
||||||
|
idx = 9; // Skip 8 starting lock stitches
|
||||||
|
expect(decoded[firstIdx].isCut).toBe(false);
|
||||||
|
|
||||||
// 2. TRIM command at (10, 0) - should have CUT flag
|
// 2. TRIM command at (10, 0) - should have CUT flag
|
||||||
expect(decoded[1].x).toBe(10);
|
const trimIdx = idx;
|
||||||
expect(decoded[1].y).toBe(0);
|
expect(decoded[idx++].x).toBe(10);
|
||||||
expect(decoded[1].isCut).toBe(true);
|
expect(decoded[trimIdx].y).toBe(0);
|
||||||
expect(decoded[1].isFeed).toBe(false); // TRIM doesn't include FEED
|
expect(decoded[trimIdx].isCut).toBe(true);
|
||||||
expect(decoded[1].yFlags).toBe(PEN_CUT_DATA); // Only CUT flag
|
expect(decoded[trimIdx].isFeed).toBe(false); // TRIM doesn't include FEED
|
||||||
|
expect(decoded[trimIdx].yFlags).toBe(PEN_CUT_DATA); // Only CUT flag
|
||||||
|
|
||||||
// 3. Final stitch with DATA_END
|
// 3. Final stitch with DATA_END
|
||||||
expect(decoded[2].x).toBe(20);
|
expect(decoded[idx].x).toBe(20);
|
||||||
expect(decoded[2].isDataEnd).toBe(true);
|
expect(decoded[idx].isDataEnd).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle empty stitch array', () => {
|
it('should handle empty stitch array', () => {
|
||||||
|
|
@ -594,7 +608,7 @@ describe('encodeStitchesToPen', () => {
|
||||||
|
|
||||||
const result = encodeStitchesToPen(stitches);
|
const result = encodeStitchesToPen(stitches);
|
||||||
|
|
||||||
expect(result.penBytes.length).toBe(4);
|
expect(result.penBytes.length).toBe(36); // 8 starting locks (32 bytes) + 1 stitch (4 bytes)
|
||||||
expect(result.bounds.minX).toBe(5);
|
expect(result.bounds.minX).toBe(5);
|
||||||
expect(result.bounds.maxX).toBe(5);
|
expect(result.bounds.maxX).toBe(5);
|
||||||
expect(result.bounds.minY).toBe(10);
|
expect(result.bounds.minY).toBe(10);
|
||||||
|
|
@ -614,14 +628,14 @@ describe('encodeStitchesToPen', () => {
|
||||||
const result = encodeStitchesToPen(stitches);
|
const result = encodeStitchesToPen(stitches);
|
||||||
const decoded = decodeAllPenStitches(result.penBytes);
|
const decoded = decodeAllPenStitches(result.penBytes);
|
||||||
|
|
||||||
// First two stitches should NOT have DATA_END flag
|
// First two stitches (after 8 starting locks) should NOT have DATA_END flag
|
||||||
expect(decoded[0].isDataEnd).toBe(false);
|
expect(decoded[8].isDataEnd).toBe(false);
|
||||||
expect(decoded[1].isDataEnd).toBe(false);
|
expect(decoded[9].isDataEnd).toBe(false);
|
||||||
|
|
||||||
// Last stitch SHOULD have DATA_END flag automatically added
|
// Last stitch SHOULD have DATA_END flag automatically added
|
||||||
expect(decoded[2].isDataEnd).toBe(true);
|
expect(decoded[10].isDataEnd).toBe(true);
|
||||||
expect(decoded[2].x).toBe(20);
|
expect(decoded[10].x).toBe(20);
|
||||||
expect(decoded[2].y).toBe(0);
|
expect(decoded[10].y).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add DATA_END flag when input has explicit END flag', () => {
|
it('should add DATA_END flag when input has explicit END flag', () => {
|
||||||
|
|
@ -636,8 +650,46 @@ describe('encodeStitchesToPen', () => {
|
||||||
const decoded = decodeAllPenStitches(result.penBytes);
|
const decoded = decodeAllPenStitches(result.penBytes);
|
||||||
|
|
||||||
// Last stitch should have DATA_END flag
|
// Last stitch should have DATA_END flag
|
||||||
expect(decoded[2].isDataEnd).toBe(true);
|
expect(decoded[10].isDataEnd).toBe(true);
|
||||||
expect(decoded[2].x).toBe(20);
|
expect(decoded[10].x).toBe(20);
|
||||||
expect(decoded[2].y).toBe(0);
|
expect(decoded[10].y).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add lock stitches at the very start of the pattern', () => {
|
||||||
|
// Matching C# behavior: Nuihajime_TomeDataPlus is called when counter <= 2
|
||||||
|
// This adds starting lock stitches to secure the thread at pattern start
|
||||||
|
const stitches = [
|
||||||
|
[10, 20, MOVE, 0],
|
||||||
|
[20, 20, STITCH, 0],
|
||||||
|
[30, 20, STITCH | END, 0],
|
||||||
|
];
|
||||||
|
|
||||||
|
const result = encodeStitchesToPen(stitches);
|
||||||
|
const decoded = decodeAllPenStitches(result.penBytes);
|
||||||
|
console.log(decoded);
|
||||||
|
// Expected sequence:
|
||||||
|
// 0. Feed move to proper location (should always happen here)
|
||||||
|
// 1. 8 starting lock stitches at (10, 20)
|
||||||
|
// 2. First actual stitch at (10, 20)
|
||||||
|
// 3. Second stitch at (20, 20)
|
||||||
|
// 4. Last stitch at (30, 20)
|
||||||
|
expect(decoded[0].x).toBe(10);
|
||||||
|
expect(decoded[0].y).toBe(20);
|
||||||
|
expect(decoded[0].isFeed).toBe(true);
|
||||||
|
|
||||||
|
// First 8 stitches should be lock stitches around the starting position
|
||||||
|
for (let i = 1; i < 1 + 8; i++) {
|
||||||
|
expect(decoded[i].x).to.be.closeTo(10, LOCK_STITCH_JUMP_SIZE);
|
||||||
|
expect(decoded[i].y).to.be.closeTo(20, LOCK_STITCH_JUMP_SIZE);
|
||||||
|
expect(decoded[i].isFeed).toBe(false);
|
||||||
|
expect(decoded[i].isCut).toBe(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then the actual stitches
|
||||||
|
expect(decoded[9].x).toBe(20);
|
||||||
|
expect(decoded[9].y).toBe(20);
|
||||||
|
expect(decoded[10].x).toBe(30);
|
||||||
|
expect(decoded[10].y).toBe(20);
|
||||||
|
expect(decoded[10].isDataEnd).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@ const PEN_DATA_END = 0x05; // Last stitch of entire pattern
|
||||||
const FEED_LENGTH = 50; // Long jump threshold requiring lock stitches and cut
|
const FEED_LENGTH = 50; // Long jump threshold requiring lock stitches and cut
|
||||||
const TARGET_LENGTH = 8.0; // Target accumulated length for lock stitch direction
|
const TARGET_LENGTH = 8.0; // Target accumulated length for lock stitch direction
|
||||||
const MAX_POINTS = 5; // Maximum points to accumulate for lock stitch direction
|
const MAX_POINTS = 5; // Maximum points to accumulate for lock stitch direction
|
||||||
const LOCK_STITCH_SCALE = 0.4 / 8.0; // Scale the magnitude-8 vector down to 0.4
|
export const LOCK_STITCH_JUMP_SIZE = 4.0;
|
||||||
|
const LOCK_STITCH_SCALE = LOCK_STITCH_JUMP_SIZE / 8.0; // Scale the magnitude-8 vector down to 4
|
||||||
|
|
||||||
export interface StitchData {
|
export interface StitchData {
|
||||||
x: number;
|
x: number;
|
||||||
|
|
@ -153,7 +154,9 @@ export function generateLockStitches(x: number, y: number, dirX: number, dirY: n
|
||||||
for (let i = 0; i < 8; i++) {
|
for (let i = 0; i < 8; i++) {
|
||||||
// Alternate between forward (+) and backward (-) direction
|
// Alternate between forward (+) and backward (-) direction
|
||||||
const sign = (i % 2 === 0) ? 1 : -1;
|
const sign = (i % 2 === 0) ? 1 : -1;
|
||||||
lockBytes.push(...encodeStitchPosition(x + scaledDirX * sign, y + scaledDirY * sign));
|
const xAdd = scaledDirX * sign;
|
||||||
|
const yAdd = scaledDirY * sign;
|
||||||
|
lockBytes.push(...encodeStitchPosition(x + xAdd, y + yAdd));
|
||||||
}
|
}
|
||||||
|
|
||||||
return lockBytes;
|
return lockBytes;
|
||||||
|
|
@ -177,6 +180,7 @@ export function encodeStitchesToPen(stitches: number[][]): PenEncodingResult {
|
||||||
// Track position for calculating jump distances
|
// Track position for calculating jump distances
|
||||||
let prevX = 0;
|
let prevX = 0;
|
||||||
let prevY = 0;
|
let prevY = 0;
|
||||||
|
|
||||||
|
|
||||||
for (let i = 0; i < stitches.length; i++) {
|
for (let i = 0; i < stitches.length; i++) {
|
||||||
const stitch = stitches[i];
|
const stitch = stitches[i];
|
||||||
|
|
@ -194,11 +198,13 @@ export function encodeStitchesToPen(stitches: number[][]): PenEncodingResult {
|
||||||
maxY = Math.max(maxY, absY);
|
maxY = Math.max(maxY, absY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isFirstStitch = i == 0;
|
||||||
|
|
||||||
// Check for long jumps that need lock stitches and cuts
|
// Check for long jumps that need lock stitches and cuts
|
||||||
if (cmd & MOVE) {
|
if (cmd & MOVE) {
|
||||||
const jumpDist = Math.sqrt((absX - prevX) ** 2 + (absY - prevY) ** 2);
|
const jumpDist = Math.sqrt((absX - prevX) ** 2 + (absY - prevY) ** 2);
|
||||||
|
|
||||||
if (jumpDist > FEED_LENGTH) {
|
if (!isFirstStitch && jumpDist > FEED_LENGTH) {
|
||||||
// Long jump - add finishing lock stitches at previous position
|
// Long jump - add finishing lock stitches at previous position
|
||||||
// Loop B: End/Cut Vector - Look BACKWARD at previous stitches
|
// Loop B: End/Cut Vector - Look BACKWARD at previous stitches
|
||||||
// This hides the knot inside the embroidery we just finished
|
// This hides the knot inside the embroidery we just finished
|
||||||
|
|
@ -271,6 +277,15 @@ export function encodeStitchesToPen(stitches: number[][]): PenEncodingResult {
|
||||||
prevX = absX;
|
prevX = absX;
|
||||||
prevY = absY;
|
prevY = absY;
|
||||||
|
|
||||||
|
if (isFirstStitch) {
|
||||||
|
// Add starting lock stitches at the very beginning of the pattern
|
||||||
|
// Matches C# behavior: Nuihajime_TomeDataPlus is called when counter <= 2
|
||||||
|
|
||||||
|
// Calculate direction for starting locks (look forward into the pattern)
|
||||||
|
const startDir = calculateLockDirection(stitches, i, true);
|
||||||
|
penStitches.push(...generateLockStitches(absX, absY, startDir.dirX, startDir.dirY));
|
||||||
|
}
|
||||||
|
|
||||||
// Handle color change: finishing lock, cut, jump, COLOR_END, starting lock
|
// Handle color change: finishing lock, cut, jump, COLOR_END, starting lock
|
||||||
if (isColorChange) {
|
if (isColorChange) {
|
||||||
const nextStitchCmd = nextStitch[2];
|
const nextStitchCmd = nextStitch[2];
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue