Add backend and frontend test suites for Arduino compilation and simulation
- Implemented a comprehensive backend test suite in `test_compilation.py` to validate the Arduino CLI installation, AVR core presence, compilation service, and API endpoint functionality.
- Created a frontend test suite in `simulation.test.ts` to test the `PinManager` and `AVRSimulator` components, ensuring proper functionality and integration.
- Introduced new components for wire management in the simulator, including `PinOverlay`, `WireInProgressRenderer`, `WireLayer`, and `WireRenderer`, enhancing the visual wiring system.
- Developed utility functions for pin position calculations and wire color management, ensuring accurate connections and visual representation.
- Added types for wire management in `wire.ts`, defining structures for wire endpoints, control points, and signal types.
2026-03-04 02:44:07 +07:00
|
|
|
/**
|
|
|
|
|
* Pin Position Calculator
|
|
|
|
|
*
|
|
|
|
|
* Converts pin coordinates from element space to canvas space (pixels).
|
|
|
|
|
* This is the CRITICAL piece for wire system - without accurate pin positions,
|
|
|
|
|
* wires cannot connect properly to components.
|
|
|
|
|
*
|
|
|
|
|
* Coordinate Systems:
|
|
|
|
|
* 1. Element Space: Pin positions in pinInfo are in CSS pixels relative to element origin
|
|
|
|
|
* 2. Canvas Space: Absolute positioning in pixels on the canvas
|
|
|
|
|
*
|
|
|
|
|
* Note: wokwi-elements pinInfo x/y are already in CSS pixels.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Calculates the absolute canvas position of a specific pin.
|
|
|
|
|
*
|
|
|
|
|
* @param componentId - The DOM ID of the component element
|
|
|
|
|
* @param pinName - The name of the pin (e.g., 'A', 'C', 'GND.1', '13')
|
fix(canvas): wires follow components on rotation
Rotating a part with the 90° button used to leave every wire pinned to
the pre-rotation pixel coordinates — the component visually unhooked
from its cables. Two paths were missing:
1. useSimulatorStore.updateComponent only triggered updateWirePositions
for x/y changes. A rotation went through properties.rotation, so
wires never recomputed.
2. calculatePinPosition didn't know about rotation. Even when called,
it returned the unrotated offset, so the new endpoints would still
have been wrong.
3. recordRotate (undo/redo) skipped updateWirePositions on both legs,
so Ctrl+Z after a rotate left the canvas inconsistent.
Fix:
- calculatePinPosition gets a 5th `rotation` argument. When non-zero,
it finds the .dynamic-component-wrapper ancestor in the DOM, reads
its offsetWidth/Height (layout-only, immune to CSS transforms) to
locate the wrapper centre, and applies a 2D rotation matrix around
that pivot. The wrapper top-left is recovered as (componentX - 4,
componentY - 6) to match the offset convention updateWirePositions
already uses.
- updateWirePositions and recalculateAllWirePositions read the per-
component rotation and thread it through.
- updateComponent recomputes wires whenever properties.rotation
changes, mirroring the existing x/y path.
- recordRotate.execute and .undo both call updateWirePositions so
Ctrl+Z keeps the canvas coherent.
Tests (pin-position-rotation.test.ts, 6 cases): unrotated identity,
90° (left edge → bottom), 180° (point reflection), 360° round-trip,
negative angles, and a store-level integration that rotates a fake
component and asserts wires[0].start moves to the rotated coordinate.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 04:03:32 +07:00
|
|
|
* @param componentX - Component's X position on canvas (pixels). For a
|
|
|
|
|
* rotated component this is still the UNROTATED inner-element top-left
|
|
|
|
|
* (callers already add the wrapper offset of 4 horizontal / 6 vertical).
|
Add backend and frontend test suites for Arduino compilation and simulation
- Implemented a comprehensive backend test suite in `test_compilation.py` to validate the Arduino CLI installation, AVR core presence, compilation service, and API endpoint functionality.
- Created a frontend test suite in `simulation.test.ts` to test the `PinManager` and `AVRSimulator` components, ensuring proper functionality and integration.
- Introduced new components for wire management in the simulator, including `PinOverlay`, `WireInProgressRenderer`, `WireLayer`, and `WireRenderer`, enhancing the visual wiring system.
- Developed utility functions for pin position calculations and wire color management, ensuring accurate connections and visual representation.
- Added types for wire management in `wire.ts`, defining structures for wire endpoints, control points, and signal types.
2026-03-04 02:44:07 +07:00
|
|
|
* @param componentY - Component's Y position on canvas (pixels)
|
fix(canvas): wires follow components on rotation
Rotating a part with the 90° button used to leave every wire pinned to
the pre-rotation pixel coordinates — the component visually unhooked
from its cables. Two paths were missing:
1. useSimulatorStore.updateComponent only triggered updateWirePositions
for x/y changes. A rotation went through properties.rotation, so
wires never recomputed.
2. calculatePinPosition didn't know about rotation. Even when called,
it returned the unrotated offset, so the new endpoints would still
have been wrong.
3. recordRotate (undo/redo) skipped updateWirePositions on both legs,
so Ctrl+Z after a rotate left the canvas inconsistent.
Fix:
- calculatePinPosition gets a 5th `rotation` argument. When non-zero,
it finds the .dynamic-component-wrapper ancestor in the DOM, reads
its offsetWidth/Height (layout-only, immune to CSS transforms) to
locate the wrapper centre, and applies a 2D rotation matrix around
that pivot. The wrapper top-left is recovered as (componentX - 4,
componentY - 6) to match the offset convention updateWirePositions
already uses.
- updateWirePositions and recalculateAllWirePositions read the per-
component rotation and thread it through.
- updateComponent recomputes wires whenever properties.rotation
changes, mirroring the existing x/y path.
- recordRotate.execute and .undo both call updateWirePositions so
Ctrl+Z keeps the canvas coherent.
Tests (pin-position-rotation.test.ts, 6 cases): unrotated identity,
90° (left edge → bottom), 180° (point reflection), 360° round-trip,
negative angles, and a store-level integration that rotates a fake
component and asserts wires[0].start moves to the rotated coordinate.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 04:03:32 +07:00
|
|
|
* @param rotation - Optional CSS rotation in degrees applied to the
|
|
|
|
|
* component's wrapper (0 / 90 / 180 / 270). When non-zero the pin
|
|
|
|
|
* position is rotated around the wrapper's center so wire endpoints
|
|
|
|
|
* land on the visually-rotated pin instead of the old layout-space pin.
|
Add backend and frontend test suites for Arduino compilation and simulation
- Implemented a comprehensive backend test suite in `test_compilation.py` to validate the Arduino CLI installation, AVR core presence, compilation service, and API endpoint functionality.
- Created a frontend test suite in `simulation.test.ts` to test the `PinManager` and `AVRSimulator` components, ensuring proper functionality and integration.
- Introduced new components for wire management in the simulator, including `PinOverlay`, `WireInProgressRenderer`, `WireLayer`, and `WireRenderer`, enhancing the visual wiring system.
- Developed utility functions for pin position calculations and wire color management, ensuring accurate connections and visual representation.
- Added types for wire management in `wire.ts`, defining structures for wire endpoints, control points, and signal types.
2026-03-04 02:44:07 +07:00
|
|
|
* @returns Absolute canvas coordinates { x, y } or null if pin not found
|
|
|
|
|
*/
|
|
|
|
|
export function calculatePinPosition(
|
|
|
|
|
componentId: string,
|
|
|
|
|
pinName: string,
|
|
|
|
|
componentX: number,
|
2026-04-22 02:45:45 +07:00
|
|
|
componentY: number,
|
fix(canvas): wires follow components on rotation
Rotating a part with the 90° button used to leave every wire pinned to
the pre-rotation pixel coordinates — the component visually unhooked
from its cables. Two paths were missing:
1. useSimulatorStore.updateComponent only triggered updateWirePositions
for x/y changes. A rotation went through properties.rotation, so
wires never recomputed.
2. calculatePinPosition didn't know about rotation. Even when called,
it returned the unrotated offset, so the new endpoints would still
have been wrong.
3. recordRotate (undo/redo) skipped updateWirePositions on both legs,
so Ctrl+Z after a rotate left the canvas inconsistent.
Fix:
- calculatePinPosition gets a 5th `rotation` argument. When non-zero,
it finds the .dynamic-component-wrapper ancestor in the DOM, reads
its offsetWidth/Height (layout-only, immune to CSS transforms) to
locate the wrapper centre, and applies a 2D rotation matrix around
that pivot. The wrapper top-left is recovered as (componentX - 4,
componentY - 6) to match the offset convention updateWirePositions
already uses.
- updateWirePositions and recalculateAllWirePositions read the per-
component rotation and thread it through.
- updateComponent recomputes wires whenever properties.rotation
changes, mirroring the existing x/y path.
- recordRotate.execute and .undo both call updateWirePositions so
Ctrl+Z keeps the canvas coherent.
Tests (pin-position-rotation.test.ts, 6 cases): unrotated identity,
90° (left edge → bottom), 180° (point reflection), 360° round-trip,
negative angles, and a store-level integration that rotates a fake
component and asserts wires[0].start moves to the rotated coordinate.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 04:03:32 +07:00
|
|
|
rotation: number = 0,
|
Add backend and frontend test suites for Arduino compilation and simulation
- Implemented a comprehensive backend test suite in `test_compilation.py` to validate the Arduino CLI installation, AVR core presence, compilation service, and API endpoint functionality.
- Created a frontend test suite in `simulation.test.ts` to test the `PinManager` and `AVRSimulator` components, ensuring proper functionality and integration.
- Introduced new components for wire management in the simulator, including `PinOverlay`, `WireInProgressRenderer`, `WireLayer`, and `WireRenderer`, enhancing the visual wiring system.
- Developed utility functions for pin position calculations and wire color management, ensuring accurate connections and visual representation.
- Added types for wire management in `wire.ts`, defining structures for wire endpoints, control points, and signal types.
2026-03-04 02:44:07 +07:00
|
|
|
): { x: number; y: number } | null {
|
|
|
|
|
// Get the DOM element
|
|
|
|
|
const element = document.getElementById(componentId);
|
|
|
|
|
if (!element) {
|
|
|
|
|
console.warn(`[pinPositionCalculator] Component ${componentId} not found in DOM`);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Access the pinInfo property (all wokwi-elements expose this)
|
|
|
|
|
const pinInfo = (element as any).pinInfo;
|
|
|
|
|
if (!pinInfo || !Array.isArray(pinInfo)) {
|
|
|
|
|
console.warn(`[pinPositionCalculator] Component ${componentId} does not have pinInfo`);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find the specific pin
|
2026-03-21 03:11:12 +07:00
|
|
|
let pin = pinInfo.find((p: any) => p.name === pinName);
|
|
|
|
|
// Fallback: try numbered variant (e.g. GND → GND.1) for pins that have suffix variants
|
|
|
|
|
if (!pin && !pinName.includes('.')) {
|
|
|
|
|
pin = pinInfo.find((p: any) => p.name === `${pinName}.1`);
|
|
|
|
|
}
|
2026-03-22 00:02:46 +07:00
|
|
|
// Fallback: GP-prefix → match description field (e.g. 'GP15' → description 'GPIO15')
|
|
|
|
|
// Needed for Nano RP2040 Connect which uses D-prefix pin names but GPIO descriptions
|
|
|
|
|
if (!pin && pinName.startsWith('GP')) {
|
|
|
|
|
const gpioNum = parseInt(pinName.substring(2), 10);
|
|
|
|
|
if (!isNaN(gpioNum)) {
|
|
|
|
|
pin = pinInfo.find((p: any) => p.description === `GPIO${gpioNum}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
Add backend and frontend test suites for Arduino compilation and simulation
- Implemented a comprehensive backend test suite in `test_compilation.py` to validate the Arduino CLI installation, AVR core presence, compilation service, and API endpoint functionality.
- Created a frontend test suite in `simulation.test.ts` to test the `PinManager` and `AVRSimulator` components, ensuring proper functionality and integration.
- Introduced new components for wire management in the simulator, including `PinOverlay`, `WireInProgressRenderer`, `WireLayer`, and `WireRenderer`, enhancing the visual wiring system.
- Developed utility functions for pin position calculations and wire color management, ensuring accurate connections and visual representation.
- Added types for wire management in `wire.ts`, defining structures for wire endpoints, control points, and signal types.
2026-03-04 02:44:07 +07:00
|
|
|
if (!pin) {
|
|
|
|
|
console.warn(`[pinPositionCalculator] Pin ${pinName} not found on component ${componentId}`);
|
2026-04-22 02:45:45 +07:00
|
|
|
console.warn(
|
|
|
|
|
`Available pins:`,
|
|
|
|
|
pinInfo.map((p: any) => p.name),
|
|
|
|
|
);
|
Add backend and frontend test suites for Arduino compilation and simulation
- Implemented a comprehensive backend test suite in `test_compilation.py` to validate the Arduino CLI installation, AVR core presence, compilation service, and API endpoint functionality.
- Created a frontend test suite in `simulation.test.ts` to test the `PinManager` and `AVRSimulator` components, ensuring proper functionality and integration.
- Introduced new components for wire management in the simulator, including `PinOverlay`, `WireInProgressRenderer`, `WireLayer`, and `WireRenderer`, enhancing the visual wiring system.
- Developed utility functions for pin position calculations and wire color management, ensuring accurate connections and visual representation.
- Added types for wire management in `wire.ts`, defining structures for wire endpoints, control points, and signal types.
2026-03-04 02:44:07 +07:00
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
fix(canvas): wires follow components on rotation
Rotating a part with the 90° button used to leave every wire pinned to
the pre-rotation pixel coordinates — the component visually unhooked
from its cables. Two paths were missing:
1. useSimulatorStore.updateComponent only triggered updateWirePositions
for x/y changes. A rotation went through properties.rotation, so
wires never recomputed.
2. calculatePinPosition didn't know about rotation. Even when called,
it returned the unrotated offset, so the new endpoints would still
have been wrong.
3. recordRotate (undo/redo) skipped updateWirePositions on both legs,
so Ctrl+Z after a rotate left the canvas inconsistent.
Fix:
- calculatePinPosition gets a 5th `rotation` argument. When non-zero,
it finds the .dynamic-component-wrapper ancestor in the DOM, reads
its offsetWidth/Height (layout-only, immune to CSS transforms) to
locate the wrapper centre, and applies a 2D rotation matrix around
that pivot. The wrapper top-left is recovered as (componentX - 4,
componentY - 6) to match the offset convention updateWirePositions
already uses.
- updateWirePositions and recalculateAllWirePositions read the per-
component rotation and thread it through.
- updateComponent recomputes wires whenever properties.rotation
changes, mirroring the existing x/y path.
- recordRotate.execute and .undo both call updateWirePositions so
Ctrl+Z keeps the canvas coherent.
Tests (pin-position-rotation.test.ts, 6 cases): unrotated identity,
90° (left edge → bottom), 180° (point reflection), 360° round-trip,
negative angles, and a store-level integration that rotates a fake
component and asserts wires[0].start moves to the rotated coordinate.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 04:03:32 +07:00
|
|
|
// Unrotated pin position in canvas space.
|
|
|
|
|
let pinX = componentX + pin.x;
|
|
|
|
|
let pinY = componentY + pin.y;
|
|
|
|
|
|
|
|
|
|
// Rotation: the DynamicComponent wrapper applies
|
|
|
|
|
// transform: rotate(<deg>deg); transform-origin: center center;
|
|
|
|
|
// around its OWN center (the wrapper, not the inner web component). So
|
|
|
|
|
// when the user rotates 90° the pin moves on an arc centered on the
|
|
|
|
|
// wrapper center, not on the component origin or the pin's own axis.
|
|
|
|
|
//
|
|
|
|
|
// We compute the wrapper center in canvas space from `offsetWidth /
|
|
|
|
|
// offsetHeight` of the wrapper — those reflect the layout box and are
|
|
|
|
|
// UNAFFECTED by CSS transforms, so reading them right after a state
|
|
|
|
|
// change but before React commits the new transform is safe.
|
|
|
|
|
//
|
|
|
|
|
// Wrapper top-left ≈ inner-element top-left minus the wrapper padding
|
|
|
|
|
// + border. updateWirePositions / recalculateAllWirePositions add
|
|
|
|
|
// (+4, +6) to component.x / component.y to land on the inner-element
|
|
|
|
|
// top-left, so the wrapper top-left is (componentX - 4, componentY - 6).
|
|
|
|
|
// This convention is hardcoded in the store; we honour it here so the
|
|
|
|
|
// math stays consistent across the rotation boundary.
|
|
|
|
|
const angle = ((rotation % 360) + 360) % 360;
|
|
|
|
|
if (angle !== 0) {
|
|
|
|
|
const wrapper = element.closest('.dynamic-component-wrapper') as HTMLElement | null;
|
|
|
|
|
if (wrapper) {
|
|
|
|
|
const wrapperW = wrapper.offsetWidth;
|
|
|
|
|
const wrapperH = wrapper.offsetHeight;
|
|
|
|
|
const wrapperLeft = componentX - 4;
|
|
|
|
|
const wrapperTop = componentY - 6;
|
|
|
|
|
const pivotX = wrapperLeft + wrapperW / 2;
|
|
|
|
|
const pivotY = wrapperTop + wrapperH / 2;
|
|
|
|
|
const theta = (angle * Math.PI) / 180;
|
|
|
|
|
const cos = Math.cos(theta);
|
|
|
|
|
const sin = Math.sin(theta);
|
|
|
|
|
const dx = pinX - pivotX;
|
|
|
|
|
const dy = pinY - pivotY;
|
|
|
|
|
pinX = pivotX + (dx * cos - dy * sin);
|
|
|
|
|
pinY = pivotY + (dx * sin + dy * cos);
|
|
|
|
|
}
|
|
|
|
|
}
|
Add backend and frontend test suites for Arduino compilation and simulation
- Implemented a comprehensive backend test suite in `test_compilation.py` to validate the Arduino CLI installation, AVR core presence, compilation service, and API endpoint functionality.
- Created a frontend test suite in `simulation.test.ts` to test the `PinManager` and `AVRSimulator` components, ensuring proper functionality and integration.
- Introduced new components for wire management in the simulator, including `PinOverlay`, `WireInProgressRenderer`, `WireLayer`, and `WireRenderer`, enhancing the visual wiring system.
- Developed utility functions for pin position calculations and wire color management, ensuring accurate connections and visual representation.
- Added types for wire management in `wire.ts`, defining structures for wire endpoints, control points, and signal types.
2026-03-04 02:44:07 +07:00
|
|
|
|
|
|
|
|
return { x: pinX, y: pinY };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Gets all pins for a component with their absolute canvas positions.
|
|
|
|
|
* Useful for rendering pin overlays and finding nearby pins.
|
|
|
|
|
*
|
|
|
|
|
* @param componentId - The DOM ID of the component element
|
|
|
|
|
* @param componentX - Component's X position on canvas
|
|
|
|
|
* @param componentY - Component's Y position on canvas
|
|
|
|
|
* @returns Array of pins with absolute positions and signal info
|
|
|
|
|
*/
|
|
|
|
|
export function getAllPinPositions(
|
|
|
|
|
componentId: string,
|
|
|
|
|
componentX: number,
|
2026-04-22 02:45:45 +07:00
|
|
|
componentY: number,
|
Add backend and frontend test suites for Arduino compilation and simulation
- Implemented a comprehensive backend test suite in `test_compilation.py` to validate the Arduino CLI installation, AVR core presence, compilation service, and API endpoint functionality.
- Created a frontend test suite in `simulation.test.ts` to test the `PinManager` and `AVRSimulator` components, ensuring proper functionality and integration.
- Introduced new components for wire management in the simulator, including `PinOverlay`, `WireInProgressRenderer`, `WireLayer`, and `WireRenderer`, enhancing the visual wiring system.
- Developed utility functions for pin position calculations and wire color management, ensuring accurate connections and visual representation.
- Added types for wire management in `wire.ts`, defining structures for wire endpoints, control points, and signal types.
2026-03-04 02:44:07 +07:00
|
|
|
): Array<{ name: string; x: number; y: number; signals: any[] }> {
|
|
|
|
|
const element = document.getElementById(componentId);
|
|
|
|
|
if (!element) return [];
|
|
|
|
|
|
|
|
|
|
const pinInfo = (element as any).pinInfo;
|
|
|
|
|
if (!pinInfo || !Array.isArray(pinInfo)) return [];
|
|
|
|
|
|
|
|
|
|
return pinInfo.map((pin: any) => ({
|
|
|
|
|
name: pin.name,
|
|
|
|
|
x: componentX + pin.x,
|
|
|
|
|
y: componentY + pin.y,
|
|
|
|
|
signals: pin.signals || [],
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Finds the closest pin to a given canvas position.
|
|
|
|
|
* Useful for snapping wire endpoints to nearby pins.
|
|
|
|
|
*
|
|
|
|
|
* @param componentId - The component to search
|
|
|
|
|
* @param componentX - Component's X position
|
|
|
|
|
* @param componentY - Component's Y position
|
|
|
|
|
* @param targetX - Target X coordinate to find nearest pin
|
|
|
|
|
* @param targetY - Target Y coordinate to find nearest pin
|
|
|
|
|
* @param maxDistance - Maximum distance in pixels to consider (default 20)
|
|
|
|
|
* @returns Closest pin info or null if none within maxDistance
|
|
|
|
|
*/
|
|
|
|
|
export function findClosestPin(
|
|
|
|
|
componentId: string,
|
|
|
|
|
componentX: number,
|
|
|
|
|
componentY: number,
|
|
|
|
|
targetX: number,
|
|
|
|
|
targetY: number,
|
2026-04-22 02:45:45 +07:00
|
|
|
maxDistance: number = 20,
|
Add backend and frontend test suites for Arduino compilation and simulation
- Implemented a comprehensive backend test suite in `test_compilation.py` to validate the Arduino CLI installation, AVR core presence, compilation service, and API endpoint functionality.
- Created a frontend test suite in `simulation.test.ts` to test the `PinManager` and `AVRSimulator` components, ensuring proper functionality and integration.
- Introduced new components for wire management in the simulator, including `PinOverlay`, `WireInProgressRenderer`, `WireLayer`, and `WireRenderer`, enhancing the visual wiring system.
- Developed utility functions for pin position calculations and wire color management, ensuring accurate connections and visual representation.
- Added types for wire management in `wire.ts`, defining structures for wire endpoints, control points, and signal types.
2026-03-04 02:44:07 +07:00
|
|
|
): { name: string; x: number; y: number; signals: any[] } | null {
|
|
|
|
|
const pins = getAllPinPositions(componentId, componentX, componentY);
|
|
|
|
|
|
|
|
|
|
let closestPin: { name: string; x: number; y: number; signals: any[] } | null = null;
|
|
|
|
|
let minDistance = maxDistance;
|
|
|
|
|
|
|
|
|
|
for (const pin of pins) {
|
2026-04-22 02:45:45 +07:00
|
|
|
const distance = Math.sqrt(Math.pow(pin.x - targetX, 2) + Math.pow(pin.y - targetY, 2));
|
Add backend and frontend test suites for Arduino compilation and simulation
- Implemented a comprehensive backend test suite in `test_compilation.py` to validate the Arduino CLI installation, AVR core presence, compilation service, and API endpoint functionality.
- Created a frontend test suite in `simulation.test.ts` to test the `PinManager` and `AVRSimulator` components, ensuring proper functionality and integration.
- Introduced new components for wire management in the simulator, including `PinOverlay`, `WireInProgressRenderer`, `WireLayer`, and `WireRenderer`, enhancing the visual wiring system.
- Developed utility functions for pin position calculations and wire color management, ensuring accurate connections and visual representation.
- Added types for wire management in `wire.ts`, defining structures for wire endpoints, control points, and signal types.
2026-03-04 02:44:07 +07:00
|
|
|
|
|
|
|
|
if (distance < minDistance) {
|
|
|
|
|
minDistance = distance;
|
|
|
|
|
closestPin = pin;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return closestPin;
|
|
|
|
|
}
|