Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions build/lib/buildInfo.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion build/lib/buildInfo.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 13 additions & 5 deletions build/lib/mapCreator.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion build/lib/mapCreator.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion build/tsconfig.tsbuildinfo

Large diffs are not rendered by default.

18 changes: 13 additions & 5 deletions src/lib/mapCreator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,17 @@ export class MapCreator {
}

private robotXtoCanvasX(image: any, robotCoord: number): number {
return (robotCoord - image.position.left) * VISUAL_BLOCK_SIZE;
// Calculate base X
const x = (robotCoord - image.position.left) * VISUAL_BLOCK_SIZE;
// Add centering offset (+1.5px) to align with pixel center
return x + VISUAL_BLOCK_SIZE / 2;
}

private robotYtoCanvasY(image: any, robotCoord: number): number {
return (image.dimensions.height / VISUAL_BLOCK_SIZE + image.position.top - robotCoord) * VISUAL_BLOCK_SIZE;
// Calculate base Y
const y = (image.dimensions.height / VISUAL_BLOCK_SIZE + image.position.top - robotCoord) * VISUAL_BLOCK_SIZE;
// Add centering offset (-1.5px) to align with pixel center
return y - VISUAL_BLOCK_SIZE / 2;
}

// --------------------
Expand Down Expand Up @@ -177,8 +183,9 @@ export class MapCreator {
) {
if (!pathSegments || pathSegments.length === 0) return;

const offsetX = 4;
const offsetY = -4;
// No additional offsets required
const offsetX = 0;
const offsetY = 0;

const w = (tempCtx as any).canvas.width;
const h = (tempCtx as any).canvas.height;
Expand Down Expand Up @@ -458,7 +465,8 @@ export class MapCreator {
const tempCanvas = createCanvas(ctx.canvas.width, ctx.canvas.height);
const tempCtx = tempCanvas.getContext("2d");

this.drawPathSegments(ctx, tempCtx, pathSegments.mainPath, LEGACY_COLORS.path, lwMain, 0.5);
this.drawPathSegments(ctx, tempCtx, pathSegments.mopPath, "rgba(255, 255, 255, 1)", 6.5 * VISUAL_BLOCK_SIZE, 0.18);
this.drawPathSegments(ctx, tempCtx, pathSegments.mainPath, LEGACY_COLORS.path, lwMain, 1.0);
}

private drawActiveZones(ctx: ExtendedContext2D, zones: any, image: any) {
Expand Down
75 changes: 41 additions & 34 deletions src/www/coords.test.ts
Original file line number Diff line number Diff line change
@@ -1,54 +1,61 @@
//
// coords.test.ts
//

import { describe, it } from "vitest";
import { expect } from "chai";
import { localCoordsToRobotCoords, robotCoordsToLocalCoords } from "./coords";
import { localCoordsToRobotCoords, robotCoordsToLocalCoords, VISUAL_BLOCK_SIZE, GRID_CENTER_OFFSET } from "./coords";

// --- Mock-Daten (basierend auf deinen Logs) ---
// --- Mock Data (Scale = 3 matches reality) ---
const MOCK_PARAMS = {
scaleFactor: 8, // Dein Wert aus der Config (angenommen)
left: 284, // aus map.IMAGE.position.left
topMap: 364, // aus map.IMAGE.position.top
imageHeight: 2880, // aus map.IMAGE.dimensions.height
mapMaxY: 0 // Wird nicht mehr verwendet, aber benötigt vom Interface
scaleFactor: 3, // VISUAL_BLOCK_SIZE
left: 284, // map.IMAGE.position.left
topMap: 364, // map.IMAGE.position.top
imageHeight: 2880, // map.IMAGE.dimensions.height
imageWidth: 2880,
mapMaxY: 0
};

// Deine bekannten Test-Werte aus dem Log
const KNOWN_WORLD_PIXEL = { x: 1744.85, y: 1672.19 };
const KNOWN_ROBOT_COORDS = { x: 25105, y: 25749 };

// Known Point: Robot @ (25105, 25749)
// Let's manually calculate expected WORLD pixel
// X = (25105 / 50 - 284) * 3 + 1.5
// X = (502.1 - 284) * 3 + 1.5 = 218.1 * 3 + 1.5 = 654.3 + 1.5 = 655.8
// Y = (364 + 2880 - 25749 / 50) * 3 - 1.5
// Y = (3244 - 514.98) * 3 - 1.5 = 2729.02 * 3 - 1.5 = 8187.06 - 1.5 = 8185.56

// --- Die Tests ---

describe("Koordinaten-Umrechnung (mit Chai)", () => {
const KNOWN_ROBOT_COORDS = { x: 25105, y: 25749 };
const EXPECTED_WORLD_PIXEL = { x: 655.8, y: 8185.56 };

it("sollte Pixel korrekt in Roboter-Koordinaten umwandeln (Statisch)", () => {
const calculated = localCoordsToRobotCoords(KNOWN_WORLD_PIXEL, MOCK_PARAMS);
describe("Coordinate Conversion (Scale=3, Centered)", () => {

expect(calculated.x).to.equal(KNOWN_ROBOT_COORDS.x);
expect(calculated.y).to.equal(KNOWN_ROBOT_COORDS.y);
it("should export constants", () => {
expect(VISUAL_BLOCK_SIZE).to.equal(3);
expect(GRID_CENTER_OFFSET).to.equal(1.5);
});

it("sollte Roboter-Koordinaten korrekt in Pixel umwandeln (Statisch)", () => {
it("Robot -> Local: Should apply Scale=3 and Offsets (+1.5, -1.5)", () => {
const calculated = robotCoordsToLocalCoords(KNOWN_ROBOT_COORDS, MOCK_PARAMS);

// Toleranz von 1 Pixel wegen Rundungsdifferenzen
expect(calculated.x).to.be.closeTo(KNOWN_WORLD_PIXEL.x, 1);
expect(calculated.y).to.be.closeTo(KNOWN_WORLD_PIXEL.y, 1);
expect(calculated.x).to.be.closeTo(EXPECTED_WORLD_PIXEL.x, 0.01);
expect(calculated.y).to.be.closeTo(EXPECTED_WORLD_PIXEL.y, 0.01);
});

it("sollte ein perfekter Round-Trip sein", () => {
// Nimm einen sauberen Startwert
const startPixel = { x: 1800, y: 1700 };
it("Local -> Robot: Should reverse correctly (Round Trip)", () => {
// Start with World Pixel
const startPixel = { x: 655.8, y: 8185.56 };

// Pixel -> Roboter -> Pixel
// Pixel -> Robot
const robotCoords = localCoordsToRobotCoords(startPixel, MOCK_PARAMS);
// Robot -> Pixel
const pixelCoords = robotCoordsToLocalCoords(robotCoords, MOCK_PARAMS);

// Muss wieder nahe am Startwert sein (Toleranz 1 Pixel)
expect(pixelCoords.x).to.be.closeTo(startPixel.x, 1);
expect(pixelCoords.y).to.be.closeTo(startPixel.y, 1);
// Should be close (rounding errors in mm conversion are normal, so ~1-2px tolerance is fine)
// Note: localCoordsToRobotCoords uses Math.round(), creating quantization.
expect(pixelCoords.x).to.be.closeTo(startPixel.x, 3);
expect(pixelCoords.y).to.be.closeTo(startPixel.y, 3);
});

it("Centering Logic: Should place a robot exactly in the center of a grid block", () => {
// If robot is exactly at (left + 0) * 50 = left * 50, it is at Grid Index 0.
// Result should be 0 * 3 + 1.5 = 1.5
const originRobot = { x: MOCK_PARAMS.left * 50, y: 0 }; // Y is irrelevant for X-test
const calculated = robotCoordsToLocalCoords(originRobot, MOCK_PARAMS);

expect(calculated.x).to.equal(1.5);
});
});
33 changes: 25 additions & 8 deletions src/www/coords.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ interface MapParams {
imageHeight: number; // Unscaled Pixel Height
}

export const VISUAL_BLOCK_SIZE = 3;
export const GRID_CENTER_OFFSET = VISUAL_BLOCK_SIZE / 2;

/**
* Converts LOCAL "world" pixel coordinates (px, Y-down) back to ROBOT coordinates (mm).
* Used for Click-Tests, GoTo, and Zones.
Expand All @@ -24,10 +27,14 @@ export function localCoordsToRobotCoords(localPoint: Point, params: MapParams):
if (!params) return { x: 0, y: 0 };

// X-Axis: (Unscaled Pixel X + Offset X) * 50
const robotX = Math.round((localPoint.x / params.scaleFactor + params.left) * MM_PER_PIXEL);
// Inverse of Draw: (Point - Offset) / Scale
const robotX = Math.round(((localPoint.x - GRID_CENTER_OFFSET) / params.scaleFactor + params.left) * MM_PER_PIXEL);

// Y-Axis (Inverted Logic): ((H_px) + top_px - Y_px / s) * 50
const robotY = Math.round((params.imageHeight + params.topMap - localPoint.y / params.scaleFactor) * MM_PER_PIXEL);
// Y-Axis (Inverted Logic): ((H_px + top_px) - (Y_px - Offset) / s) * 50
// Note: imageHeight is already unscaled, do NOT divide by scaleFactor.
// Inverse of Draw (Y): (Top + Height - Y_mm/50) * Scale + Offset
// => Y_mm/50 = Top + Height - (Y_pix - Offset) / Scale
const robotY = Math.round((params.imageHeight + params.topMap - (localPoint.y - (-GRID_CENTER_OFFSET)) / params.scaleFactor) * MM_PER_PIXEL);

return { x: robotX, y: robotY };
}
Expand All @@ -39,11 +46,21 @@ export function localCoordsToRobotCoords(localPoint: Point, params: MapParams):
export function robotCoordsToLocalCoords(robotPoint: Point, params: MapParams): Point {
if (!params) return { x: 0, y: 0 };

// X-Axis: (mm / 50 - Offset px) * scale
const worldX = (robotPoint.x / MM_PER_PIXEL - params.left) * params.scaleFactor;
// The map image is generated with 3 pixels per grid unit (VISUAL_BLOCK_SIZE=3).
// So we must scale the coordinates by 3 to match the image features.
const correctScale = VISUAL_BLOCK_SIZE;

// X-Axis: Center in the middle of the grid block (0 -> 1.5)
const offsetX = GRID_CENTER_OFFSET;

// Y-Axis: Center in the middle of the grid block (0 -> -1.5 inverted)
const offsetY = -GRID_CENTER_OFFSET;

// X-Axis: (mm / 50 - Params) * Scale + Offset
const worldX = (robotPoint.x / MM_PER_PIXEL - params.left) * correctScale + offsetX;

// Y-Axis (Inverted Logic): ((H_px) + top_px - Y_mm/50) * scale
const worldY = (params.imageHeight + params.topMap - robotPoint.y / MM_PER_PIXEL) * params.scaleFactor;
// Y-Axis: (Top + Height - Y_mm/50) * Scale + Offset
const finalY = (params.topMap + params.imageHeight - robotPoint.y / MM_PER_PIXEL) * correctScale + offsetY;

return { x: worldX, y: worldY };
return { x: worldX, y: finalY };
}
Loading