@tscircuit/schematic-trace-solver 0.0.100 → 0.0.101

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -894,7 +894,7 @@ var generateEndpointCollisionDetours = ({
894
894
  collidingSegmentIndex,
895
895
  obstacle
896
896
  }) => {
897
- if (path.length !== 3) return [];
897
+ if (path.length < 3 || path.length > 4) return [];
898
898
  const lastSegmentIndex = path.length - 2;
899
899
  if (collidingSegmentIndex !== 0 && collidingSegmentIndex !== lastSegmentIndex) {
900
900
  return [];
@@ -917,7 +917,7 @@ var generateEndpointCollisionDetours = ({
917
917
  const detours = [];
918
918
  for (const escapeCoordinate of [...new Set(escapeCoordinates)]) {
919
919
  for (const detourCoordinate of [...new Set(detourCoordinates)]) {
920
- const orderedDetour = firstSegmentAxis === "y" ? [
920
+ const orderedDetourPrefix = firstSegmentAxis === "y" ? [
921
921
  start,
922
922
  { x: escapeCoordinate, y: start.y },
923
923
  { x: escapeCoordinate, y: detourCoordinate },
@@ -930,6 +930,7 @@ var generateEndpointCollisionDetours = ({
930
930
  { x: detourCoordinate, y: end.y },
931
931
  end
932
932
  ];
933
+ const orderedDetour = [...orderedDetourPrefix, ...orderedPath.slice(3)];
933
934
  const detour = shouldReverse ? orderedDetour.reverse() : orderedDetour;
934
935
  if (hasOnlyNonzeroOrthogonalSegments(detour)) detours.push(detour);
935
936
  }
@@ -1287,7 +1288,9 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
1287
1288
  let { segIndex, rect } = collision;
1288
1289
  const isFirstSegment = segIndex === 0;
1289
1290
  const isLastSegment = segIndex === path.length - 2;
1290
- if (path.length === 3 && (isFirstSegment || isLastSegment)) {
1291
+ const isEndpointChipObstacle = rect.kind === "chip" && this.pins.some((pin) => pin.chipId === rect.chipId);
1292
+ const canGenerateEndpointDetour = path.length === 3 || path.length === 4 && this.connectionPair !== void 0 && !isEndpointChipObstacle;
1293
+ if (canGenerateEndpointDetour && (isFirstSegment || isLastSegment)) {
1291
1294
  const detours = generateEndpointCollisionDetours({
1292
1295
  path,
1293
1296
  collidingSegmentIndex: segIndex,
@@ -357,8 +357,19 @@ export class SchematicTraceSingleLineSolver2 extends BaseSolver {
357
357
  // Never move the first or last segments - move adjacent segment instead
358
358
  const isFirstSegment = segIndex === 0
359
359
  const isLastSegment = segIndex === path.length - 2
360
-
361
- if (path.length === 3 && (isFirstSegment || isLastSegment)) {
360
+ const isEndpointChipObstacle =
361
+ rect.kind === "chip" &&
362
+ this.pins.some((pin) => pin.chipId === rect.chipId)
363
+ // U-shaped detours are local repairs for fixed MSP pairs obstructed by an
364
+ // intermediate obstacle. Endpoint-chip and optional long-distance routing
365
+ // require multi-trace or net-level selection instead.
366
+ const canGenerateEndpointDetour =
367
+ path.length === 3 ||
368
+ (path.length === 4 &&
369
+ this.connectionPair !== undefined &&
370
+ !isEndpointChipObstacle)
371
+
372
+ if (canGenerateEndpointDetour && (isFirstSegment || isLastSegment)) {
362
373
  const detours = generateEndpointCollisionDetours({
363
374
  path,
364
375
  collidingSegmentIndex: segIndex,
@@ -28,7 +28,9 @@ export const generateEndpointCollisionDetours = ({
28
28
  collidingSegmentIndex: number
29
29
  obstacle: ObstacleRect
30
30
  }): Point[][] => {
31
- if (path.length !== 3) return []
31
+ // Endpoint detours expand the initial L- and U-shaped elbow candidates.
32
+ // Longer paths have already been expanded and are handled by segment shifts.
33
+ if (path.length < 3 || path.length > 4) return []
32
34
 
33
35
  const lastSegmentIndex = path.length - 2
34
36
  if (
@@ -58,7 +60,7 @@ export const generateEndpointCollisionDetours = ({
58
60
  const detours: Point[][] = []
59
61
  for (const escapeCoordinate of [...new Set(escapeCoordinates)]) {
60
62
  for (const detourCoordinate of [...new Set(detourCoordinates)]) {
61
- const orderedDetour =
63
+ const orderedDetourPrefix =
62
64
  firstSegmentAxis === "y"
63
65
  ? [
64
66
  start!,
@@ -75,6 +77,7 @@ export const generateEndpointCollisionDetours = ({
75
77
  end!,
76
78
  ]
77
79
 
80
+ const orderedDetour = [...orderedDetourPrefix, ...orderedPath.slice(3)]
78
81
  const detour = shouldReverse ? orderedDetour.reverse() : orderedDetour
79
82
  if (hasOnlyNonzeroOrthogonalSegments(detour)) detours.push(detour)
80
83
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tscircuit/schematic-trace-solver",
3
3
  "main": "dist/index.js",
4
- "version": "0.0.100",
4
+ "version": "0.0.101",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "start": "cosmos",
@@ -1,25 +1,21 @@
1
- <svg width="640" height="640" viewBox="0 0 640 640" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="white"/><g><polyline data-points="0.48,0.765 -0.48,-0.765" data-type="line" data-label="" points="394.9116607773851,224.94699646643113 259.2226148409894,441.2014134275618" fill="none" stroke="hsl(224, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="1.58,0.765 -1.58,-0.765" data-type="line" data-label="" points="550.3886925795052,224.94699646643113 103.74558303886928,441.2014134275618" fill="none" stroke="hsl(224, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="0.5800000000000001,-0.665 -1.58,0.765" data-type="line" data-label="" points="409.0459363957597,427.0671378091873 103.74558303886928,224.94699646643113" fill="none" stroke="hsl(168, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="1.48,-0.665 -0.48,0.765" data-type="line" data-label="" points="536.2544169611307,427.0671378091873 259.2226148409894,224.94699646643113" fill="none" stroke="hsl(168, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="0.48,0.765 0,0.765 0,-0.765 -0.48,-0.765" data-type="line" data-label="" points="394.9116607773851,224.94699646643113 327.0671378091873,224.94699646643113 327.0671378091873,441.2014134275618 259.2226148409894,441.2014134275618" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.58,0.765 1.7800000000000002,0.765 1.7800000000000002,0 -1.78,0 -1.78,-0.765 -1.58,-0.765" data-type="line" data-label="" points="550.3886925795052,224.94699646643113 578.6572438162544,224.94699646643113 578.6572438162544,333.0742049469965 75.47703180212017,333.0742049469965 75.47703180212017,441.2014134275618 103.74558303886928,441.2014134275618" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="schematic_component_0" data-x="-1.03" data-y="0.765" x="103.74558303886927" y="197.4621413427563" width="155.47703180212014" height="54.969710247349695" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.0070750000000000006"/></g><g><rect data-type="rect" data-label="schematic_component_1" data-x="1.03" data-y="0.765" x="394.9116607773851" y="197.4621413427563" width="155.4770318021201" height="54.969710247349695" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.0070750000000000006"/></g><g><rect data-type="rect" data-label="schematic_component_2" data-x="-1.03" data-y="-0.765" x="103.74558303886927" y="413.7165583038869" width="155.47703180212014" height="54.969710247349724" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.0070750000000000006"/></g><g><rect data-type="rect" data-label="schematic_component_3" data-x="1.03" data-y="-0.765" x="409.04593639575967" y="403.7455830388692" width="127.20848056537096" height="74.91166077738518" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.0070750000000000006"/></g><g><rect data-type="rect" data-label="netId: .J1 &gt; .pin1 to .R1 &gt; .pin1
2
- globalConnNetId: connectivity_net2" data-x="0.3540000000000001" data-y="-0.665" x="345.30035335689047" y="412.9328621908127" width="63.60424028268551" height="28.26855123674909" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.0070750000000000006"/></g><g><rect data-type="rect" data-label="netId: .J1 &gt; .pin1 to .R1 &gt; .pin1
3
- globalConnNetId: connectivity_net2" data-x="-1.806" data-y="0.765" x="40.000000000000014" y="210.81272084805659" width="63.60424028268554" height="28.26855123674912" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.0070750000000000006"/></g><g><rect data-type="rect" data-label="netId: .J1 &gt; .pin3 to .R1 &gt; .pin2
4
- globalConnNetId: connectivity_net3" data-x="1.706" data-y="-0.665" x="536.3957597173144" y="412.9328621908127" width="63.60424028268562" height="28.26855123674909" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.0070750000000000006"/></g><g><rect data-type="rect" data-label="netId: .J1 &gt; .pin3 to .R1 &gt; .pin2
5
- globalConnNetId: connectivity_net3" data-x="-0.254" data-y="0.765" x="259.36395759717317" y="210.81272084805659" width="63.60424028268551" height="28.26855123674912" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.0070750000000000006"/></g><g><rect data-type="rect" data-label="netId: .R2 &gt; .pin1 to .R3 &gt; .pin2
6
- globalConnNetId: connectivity_net0" data-x="0.24" data-y="0.99" x="346.8551236749116" y="161.34275618374562" width="28.268551236749147" height="63.60424028268554" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.0070750000000000006"/></g><g><rect data-type="rect" data-label="netId: .R2 &gt; .pin2 to .R3 &gt; .pin1
7
- globalConnNetId: connectivity_net1" data-x="1.7800000000000002" data-y="0.99" x="564.5229681978799" y="161.34275618374562" width="28.26855123674909" height="63.60424028268554" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.0070750000000000006"/></g><g><circle data-type="point" data-label="R1.1
8
- x-" data-x="-1.58" data-y="0.765" cx="103.74558303886928" cy="224.94699646643113" r="3" fill="hsl(226, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R1.2
9
- x+" data-x="-0.48" data-y="0.765" cx="259.2226148409894" cy="224.94699646643113" r="3" fill="hsl(227, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R2.1
10
- x-" data-x="0.48" data-y="0.765" cx="394.9116607773851" cy="224.94699646643113" r="3" fill="hsl(107, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R2.2
11
- x+" data-x="1.58" data-y="0.765" cx="550.3886925795052" cy="224.94699646643113" r="3" fill="hsl(108, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R3.1
12
- x-" data-x="-1.58" data-y="-0.765" cx="103.74558303886928" cy="441.2014134275618" r="3" fill="hsl(348, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R3.2
13
- x+" data-x="-0.48" data-y="-0.765" cx="259.2226148409894" cy="441.2014134275618" r="3" fill="hsl(349, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J1.1
14
- x-" data-x="0.5800000000000001" data-y="-0.665" cx="409.0459363957597" cy="427.0671378091873" r="3" fill="hsl(218, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J1.2
15
- y-" data-x="1.03" data-y="-1.03" cx="472.6501766784452" cy="478.65724381625444" r="3" fill="hsl(219, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J1.3
16
- x+" data-x="1.48" data-y="-0.665" cx="536.2544169611307" cy="427.0671378091873" r="3" fill="hsl(220, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="anchorPoint
17
- orientation: x-" data-x="0.5800000000000001" data-y="-0.665" cx="409.0459363957597" cy="427.0671378091873" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
18
- orientation: x-" data-x="-1.58" data-y="0.765" cx="103.74558303886928" cy="224.94699646643113" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
19
- orientation: x+" data-x="1.48" data-y="-0.665" cx="536.2544169611307" cy="427.0671378091873" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
20
- orientation: x+" data-x="-0.48" data-y="0.765" cx="259.2226148409894" cy="224.94699646643113" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
21
- orientation: y+" data-x="0.24" data-y="0.765" cx="360.9893992932862" cy="224.94699646643113" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
22
- orientation: y+" data-x="1.7800000000000002" data-y="0.765" cx="578.6572438162544" cy="224.94699646643113" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g id="crosshair" style="display: none"><line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5"/><line id="crosshair-v" x1="0" x2="640" stroke="#666" stroke-width="0.5"/><text id="coordinates" font-family="monospace" font-size="12" fill="#666"></text></g><script><![CDATA[
1
+ <svg width="640" height="640" viewBox="0 0 640 640" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="white"/><g><polyline data-points="0.48,0.765 -0.48,-0.765" data-type="line" data-label="" points="391.4893617021276,213.51063829787233 248.51063829787228,441.3829787234042" fill="none" stroke="hsl(224, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="1.58,0.765 -1.58,-0.765" data-type="line" data-label="" points="555.3191489361701,213.51063829787233 84.68085106382975,441.3829787234042" fill="none" stroke="hsl(224, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="0.5800000000000001,-0.665 -1.58,0.765" data-type="line" data-label="" points="406.3829787234042,426.48936170212767 84.68085106382975,213.51063829787233" fill="none" stroke="hsl(168, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="1.48,-0.665 -0.48,0.765" data-type="line" data-label="" points="540.4255319148936,426.48936170212767 248.51063829787228,213.51063829787233" fill="none" stroke="hsl(168, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="0.48,0.765 0.27999999999999997,0.765 0.27999999999999997,0.665 -0.1,0.665 -0.1,-0.765 -0.48,-0.765" data-type="line" data-label="" points="391.4893617021276,213.51063829787233 361.7021276595744,213.51063829787233 361.7021276595744,228.40425531914892 305.10638297872333,228.40425531914892 305.10638297872333,441.3829787234042 248.51063829787228,441.3829787234042" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.58,0.765 1.7800000000000002,0.765 1.7800000000000002,0 -1.8800000000000001,0 -1.8800000000000001,-0.765 -1.58,-0.765" data-type="line" data-label="" points="555.3191489361701,213.51063829787233 585.1063829787233,213.51063829787233 585.1063829787233,327.4468085106383 39.99999999999994,327.4468085106383 39.99999999999994,441.3829787234042 84.68085106382975,441.3829787234042" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="0.5800000000000001,-0.665 0.050000000000000044,-0.665 0.050000000000000044,-0.37054465000000053 -1.68,-0.37054465000000053 -1.68,0.765 -1.58,0.765" data-type="line" data-label="" points="406.3829787234042,426.48936170212767 327.4468085106382,426.48936170212767 327.4468085106382,382.63430957446815 69.78723404255317,382.63430957446815 69.78723404255317,213.51063829787233 84.68085106382975,213.51063829787233" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.48,-0.665 1.68,-0.665 1.68,0.37054465000000053 0.1,0.37054465000000053 0.1,0.865 -0.38,0.865 -0.38,0.765 -0.48,0.765" data-type="line" data-label="" points="540.4255319148936,426.48936170212767 570.2127659574467,426.48936170212767 570.2127659574467,272.2593074468084 334.89361702127655,272.2593074468084 334.89361702127655,198.61702127659575 263.4042553191489,198.61702127659575 263.4042553191489,213.51063829787233 248.51063829787228,213.51063829787233" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="schematic_component_0" data-x="-1.03" data-y="0.765" x="84.68085106382976" y="184.54920319148943" width="163.82978723404253" height="57.922870212765815" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.006714285714285715"/></g><g><rect data-type="rect" data-label="schematic_component_1" data-x="1.03" data-y="0.765" x="391.48936170212767" y="184.54920319148943" width="163.8297872340425" height="57.922870212765815" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.006714285714285715"/></g><g><rect data-type="rect" data-label="schematic_component_2" data-x="-1.03" data-y="-0.765" x="84.68085106382976" y="412.4215436170213" width="163.82978723404253" height="57.922870212765815" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.006714285714285715"/></g><g><rect data-type="rect" data-label="schematic_component_3" data-x="1.03" data-y="-0.765" x="406.3829787234042" y="401.9148936170212" width="134.04255319148933" height="78.936170212766" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.006714285714285715"/></g><g><rect data-type="rect" data-label="netId: .J1 &gt; .pin1 to .R1 &gt; .pin1
2
+ globalConnNetId: connectivity_net2" data-x="0.31500000000000006" data-y="-0.44000000000000006" x="352.0212765957446" y="359.468085106383" width="29.787234042553223" height="67.02127659574472" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.006714285714285715"/></g><g><rect data-type="rect" data-label="netId: .J1 &gt; .pin3 to .R1 &gt; .pin2
3
+ globalConnNetId: connectivity_net3" data-x="1.68" data-y="-0.89" x="555.31914893617" y="426.48936170212767" width="29.787234042553223" height="67.02127659574467" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.006714285714285715"/></g><g><rect data-type="rect" data-label="netId: .R2 &gt; .pin1 to .R3 &gt; .pin2
4
+ globalConnNetId: connectivity_net0" data-x="0.27999999999999997" data-y="0.99" x="346.8085106382978" y="146.48936170212767" width="29.787234042553166" height="67.0212765957447" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.006714285714285715"/></g><g><rect data-type="rect" data-label="netId: .R2 &gt; .pin2 to .R3 &gt; .pin1
5
+ globalConnNetId: connectivity_net1" data-x="1.7800000000000002" data-y="0.99" x="570.2127659574467" y="146.48936170212767" width="29.787234042553223" height="67.0212765957447" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.006714285714285715"/></g><g><circle data-type="point" data-label="R1.1
6
+ x-" data-x="-1.58" data-y="0.765" cx="84.68085106382975" cy="213.51063829787233" r="3" fill="hsl(226, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R1.2
7
+ x+" data-x="-0.48" data-y="0.765" cx="248.51063829787228" cy="213.51063829787233" r="3" fill="hsl(227, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R2.1
8
+ x-" data-x="0.48" data-y="0.765" cx="391.4893617021276" cy="213.51063829787233" r="3" fill="hsl(107, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R2.2
9
+ x+" data-x="1.58" data-y="0.765" cx="555.3191489361701" cy="213.51063829787233" r="3" fill="hsl(108, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R3.1
10
+ x-" data-x="-1.58" data-y="-0.765" cx="84.68085106382975" cy="441.3829787234042" r="3" fill="hsl(348, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R3.2
11
+ x+" data-x="-0.48" data-y="-0.765" cx="248.51063829787228" cy="441.3829787234042" r="3" fill="hsl(349, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J1.1
12
+ x-" data-x="0.5800000000000001" data-y="-0.665" cx="406.3829787234042" cy="426.48936170212767" r="3" fill="hsl(218, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J1.2
13
+ y-" data-x="1.03" data-y="-1.03" cx="473.4042553191489" cy="480.8510638297872" r="3" fill="hsl(219, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J1.3
14
+ x+" data-x="1.48" data-y="-0.665" cx="540.4255319148936" cy="426.48936170212767" r="3" fill="hsl(220, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="anchorPoint
15
+ orientation: y+" data-x="0.31500000000000006" data-y="-0.665" cx="366.9148936170212" cy="426.48936170212767" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
16
+ orientation: y-" data-x="1.68" data-y="-0.665" cx="570.2127659574467" cy="426.48936170212767" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
17
+ orientation: y+" data-x="0.27999999999999997" data-y="0.765" cx="361.7021276595744" cy="213.51063829787233" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
18
+ orientation: y+" data-x="1.7800000000000002" data-y="0.765" cx="585.1063829787233" cy="213.51063829787233" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g id="crosshair" style="display: none"><line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5"/><line id="crosshair-v" x1="0" x2="640" stroke="#666" stroke-width="0.5"/><text id="coordinates" font-family="monospace" font-size="12" fill="#666"></text></g><script><![CDATA[
23
19
  document.currentScript.parentElement.addEventListener('mousemove', (e) => {
24
20
  const svg = e.currentTarget;
25
21
  const rect = svg.getBoundingClientRect();
@@ -41,7 +37,7 @@ orientation: y+" data-x="1.7800000000000002" data-y="0.765" cx="578.657243816254
41
37
  v.setAttribute('y2', '640');
42
38
 
43
39
  // Calculate real coordinates using inverse transformation
44
- const matrix = {"a":141.34275618374556,"c":0,"e":327.0671378091873,"b":0,"d":-141.34275618374556,"f":333.0742049469965};
40
+ const matrix = {"a":148.93617021276594,"c":0,"e":319.99999999999994,"b":0,"d":-148.93617021276594,"f":327.4468085106383};
45
41
  // Manually invert and apply the affine transform
46
42
  // Since we only use translate and scale, we can directly compute:
47
43
  // x' = (x - tx) / sx
@@ -1,25 +1,21 @@
1
- <svg width="640" height="640" viewBox="0 0 640 640" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="white"/><g><polyline data-points="0.6499999999999999,0.825 -0.6499999999999999,-0.825" data-type="line" data-label="" points="410.65315315315314,198.6036036036036 205.6981981981982,458.7387387387388" fill="none" stroke="hsl(224, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="1.25,0.825 -1.25,-0.825" data-type="line" data-label="" points="505.2477477477478,198.6036036036036 111.1036036036036,458.7387387387388" fill="none" stroke="hsl(224, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="0.49999999999999994,-0.725 -1.25,0.825" data-type="line" data-label="" points="387.0045045045045,442.97297297297297 111.1036036036036,198.6036036036036" fill="none" stroke="hsl(168, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="1.4,-0.725 -0.6499999999999999,0.825" data-type="line" data-label="" points="528.8963963963964,442.97297297297297 205.6981981981982,198.6036036036036" fill="none" stroke="hsl(168, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="0.6499999999999999,0.825 0,0.825 0,-0.825 -0.6499999999999999,-0.825" data-type="line" data-label="" points="410.65315315315314,198.6036036036036 308.1756756756757,198.6036036036036 308.1756756756757,458.7387387387388 205.6981981981982,458.7387387387388" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.25,0.825 1.4500000000000002,0.825 1.4500000000000002,0 -1.45,0 -1.45,-0.825 -1.25,-0.825" data-type="line" data-label="" points="505.2477477477478,198.6036036036036 536.7792792792793,198.6036036036036 536.7792792792793,328.6711711711712 79.57207207207207,328.6711711711712 79.57207207207207,458.7387387387388 111.1036036036036,458.7387387387388" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="schematic_component_0" data-x="-0.95" data-y="0.825" x="111.10360360360359" y="145" width="94.59459459459461" height="107.20720720720723" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.006342857142857142"/></g><g><rect data-type="rect" data-label="schematic_component_1" data-x="0.95" data-y="0.825" x="410.6531531531532" y="145" width="94.59459459459464" height="107.20720720720723" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.006342857142857142"/></g><g><rect data-type="rect" data-label="schematic_component_2" data-x="-0.95" data-y="-0.825" x="111.10360360360359" y="405.13513513513516" width="94.59459459459461" height="107.20720720720726" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.006342857142857142"/></g><g><rect data-type="rect" data-label="schematic_component_3" data-x="0.95" data-y="-0.825" x="387.00450450450455" y="414.9290282263514" width="141.89189189189193" height="87.61942102477474" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.006342857142857142"/></g><g><rect data-type="rect" data-label="netId: .J1 &gt; .pin1 to .R1 &gt; .pin1
2
- globalConnNetId: connectivity_net2" data-x="0.2739999999999999" data-y="-0.725" x="315.9009009009009" y="427.20720720720715" width="70.94594594594594" height="31.531531531531584" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.006342857142857142"/></g><g><rect data-type="rect" data-label="netId: .J1 &gt; .pin1 to .R1 &gt; .pin1
3
- globalConnNetId: connectivity_net2" data-x="-1.476" data-y="0.825" x="39.999999999999986" y="182.8378378378378" width="70.94594594594597" height="31.531531531531556" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.006342857142857142"/></g><g><rect data-type="rect" data-label="netId: .J1 &gt; .pin3 to .R1 &gt; .pin2
4
- globalConnNetId: connectivity_net3" data-x="1.626" data-y="-0.725" x="529.0540540540542" y="427.20720720720715" width="70.94594594594594" height="31.531531531531584" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.006342857142857142"/></g><g><rect data-type="rect" data-label="netId: .J1 &gt; .pin3 to .R1 &gt; .pin2
5
- globalConnNetId: connectivity_net3" data-x="-0.42399999999999993" data-y="0.825" x="205.85585585585585" y="182.8378378378378" width="70.94594594594594" height="31.531531531531556" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.006342857142857142"/></g><g><rect data-type="rect" data-label="netId: .R2 &gt; .pin1 to .R3 &gt; .pin2
6
- globalConnNetId: connectivity_net0" data-x="0.32499999999999996" data-y="1.05" x="343.64864864864865" y="127.65765765765765" width="31.531531531531527" height="70.94594594594597" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.006342857142857142"/></g><g><rect data-type="rect" data-label="netId: .R2 &gt; .pin2 to .R3 &gt; .pin1
7
- globalConnNetId: connectivity_net1" data-x="1.4500000000000002" data-y="1.05" x="521.0135135135135" y="127.65765765765765" width="31.531531531531527" height="70.94594594594597" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.006342857142857142"/></g><g><circle data-type="point" data-label="R1.1
8
- x-" data-x="-1.25" data-y="0.825" cx="111.1036036036036" cy="198.6036036036036" r="3" fill="hsl(226, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R1.2
9
- x+" data-x="-0.6499999999999999" data-y="0.825" cx="205.6981981981982" cy="198.6036036036036" r="3" fill="hsl(227, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R2.1
10
- x-" data-x="0.6499999999999999" data-y="0.825" cx="410.65315315315314" cy="198.6036036036036" r="3" fill="hsl(107, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R2.2
11
- x+" data-x="1.25" data-y="0.825" cx="505.2477477477478" cy="198.6036036036036" r="3" fill="hsl(108, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R3.1
12
- x-" data-x="-1.25" data-y="-0.825" cx="111.1036036036036" cy="458.7387387387388" r="3" fill="hsl(348, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R3.2
13
- x+" data-x="-0.6499999999999999" data-y="-0.825" cx="205.6981981981982" cy="458.7387387387388" r="3" fill="hsl(349, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J1.1
14
- x-" data-x="0.49999999999999994" data-y="-0.725" cx="387.0045045045045" cy="442.97297297297297" r="3" fill="hsl(218, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J1.2
15
- y-" data-x="0.95" data-y="-1.1028787352499998" cx="457.9504504504505" cy="502.5484492511261" r="3" fill="hsl(219, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J1.3
16
- x+" data-x="1.4" data-y="-0.725" cx="528.8963963963964" cy="442.97297297297297" r="3" fill="hsl(220, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="anchorPoint
17
- orientation: x-" data-x="0.49999999999999994" data-y="-0.725" cx="387.0045045045045" cy="442.97297297297297" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
18
- orientation: x-" data-x="-1.25" data-y="0.825" cx="111.1036036036036" cy="198.6036036036036" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
19
- orientation: x+" data-x="1.4" data-y="-0.725" cx="528.8963963963964" cy="442.97297297297297" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
20
- orientation: x+" data-x="-0.6499999999999999" data-y="0.825" cx="205.6981981981982" cy="198.6036036036036" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
21
- orientation: y+" data-x="0.32499999999999996" data-y="0.825" cx="359.4144144144144" cy="198.6036036036036" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
22
- orientation: y+" data-x="1.4500000000000002" data-y="0.825" cx="536.7792792792793" cy="198.6036036036036" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g id="crosshair" style="display: none"><line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5"/><line id="crosshair-v" x1="0" x2="640" stroke="#666" stroke-width="0.5"/><text id="coordinates" font-family="monospace" font-size="12" fill="#666"></text></g><script><![CDATA[
1
+ <svg width="640" height="640" viewBox="0 0 640 640" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="white"/><g><polyline data-points="0.6499999999999999,0.825 -0.6499999999999999,-0.825" data-type="line" data-label="" points="413.3333333333333,182.22222222222226 182.22222222222223,475.55555555555554" fill="none" stroke="hsl(224, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="1.25,0.825 -1.25,-0.825" data-type="line" data-label="" points="520,182.22222222222226 75.55555555555554,475.55555555555554" fill="none" stroke="hsl(224, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="0.49999999999999994,-0.725 -1.25,0.825" data-type="line" data-label="" points="386.66666666666663,457.7777777777778 75.55555555555554,182.22222222222226" fill="none" stroke="hsl(168, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="1.4,-0.725 -0.6499999999999999,0.825" data-type="line" data-label="" points="546.6666666666666,457.7777777777778 182.22222222222223,182.22222222222226" fill="none" stroke="hsl(168, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="0.6499999999999999,0.825 0.4499999999999999,0.825 0.4499999999999999,0.725 -0.1,0.725 -0.1,-0.825 -0.6499999999999999,-0.825" data-type="line" data-label="" points="413.3333333333333,182.22222222222226 377.77777777777777,182.22222222222226 377.77777777777777,200.00000000000003 280,200.00000000000003 280,475.55555555555554 182.22222222222223,475.55555555555554" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.25,0.825 1.4500000000000002,0.825 1.4500000000000002,0 -1.45,0 -1.45,-0.825 -1.25,-0.825" data-type="line" data-label="" points="520,182.22222222222226 555.5555555555557,182.22222222222226 555.5555555555557,328.8888888888889 40,328.8888888888889 40,475.55555555555554 75.55555555555554,475.55555555555554" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="0.5,-0.725 -0.07499999999999996,-0.725 -0.07499999999999996,0.17000000000000004 -1.45,0.17000000000000004 -1.45,0.825 -1.25,0.825" data-type="line" data-label="" points="386.66666666666663,457.7777777777778 284.44444444444446,457.7777777777778 284.44444444444446,298.6666666666667 40,298.6666666666667 40,182.22222222222226 75.55555555555554,182.22222222222226" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.4,-0.725 1.5999999999999999,-0.725 1.5999999999999999,0.28499999999999986 0.1,0.28499999999999986 0.1,0.825 -0.6499999999999999,0.825" data-type="line" data-label="" points="546.6666666666666,457.7777777777778 582.2222222222222,457.7777777777778 582.2222222222222,278.2222222222223 315.55555555555554,278.2222222222223 315.55555555555554,182.22222222222226 182.22222222222223,182.22222222222226" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="schematic_component_0" data-x="-0.95" data-y="0.825" x="75.55555555555554" y="121.7777777777778" width="106.66666666666669" height="120.88888888888891" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.005625"/></g><g><rect data-type="rect" data-label="schematic_component_1" data-x="0.95" data-y="0.825" x="413.33333333333326" y="121.7777777777778" width="106.66666666666669" height="120.88888888888891" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.005625"/></g><g><rect data-type="rect" data-label="schematic_component_2" data-x="-0.95" data-y="-0.825" x="75.55555555555554" y="415.1111111111111" width="106.66666666666669" height="120.88888888888891" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.005625"/></g><g><rect data-type="rect" data-label="schematic_component_3" data-x="0.95" data-y="-0.825" x="386.66666666666663" y="426.15489151111115" width="160" height="98.8013280888888" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.005625"/></g><g><rect data-type="rect" data-label="netId: .J1 &gt; .pin1 to .R1 &gt; .pin1
2
+ globalConnNetId: connectivity_net2" data-x="0.21250000000000002" data-y="-0.5" x="317.77777777777777" y="377.7777777777778" width="35.55555555555554" height="80" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.005625"/></g><g><rect data-type="rect" data-label="netId: .J1 &gt; .pin3 to .R1 &gt; .pin2
3
+ globalConnNetId: connectivity_net3" data-x="1.5999999999999999" data-y="-0.95" x="564.4444444444443" y="457.7777777777778" width="35.55555555555566" height="80" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.005625"/></g><g><rect data-type="rect" data-label="netId: .R2 &gt; .pin1 to .R3 &gt; .pin2
4
+ globalConnNetId: connectivity_net0" data-x="0.4499999999999999" data-y="1.05" x="360" y="102.22222222222226" width="35.5555555555556" height="80" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.005625"/></g><g><rect data-type="rect" data-label="netId: .R2 &gt; .pin2 to .R3 &gt; .pin1
5
+ globalConnNetId: connectivity_net1" data-x="1.4500000000000002" data-y="1.05" x="537.7777777777778" y="102.22222222222226" width="35.55555555555554" height="80" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.005625"/></g><g><circle data-type="point" data-label="R1.1
6
+ x-" data-x="-1.25" data-y="0.825" cx="75.55555555555554" cy="182.22222222222226" r="3" fill="hsl(226, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R1.2
7
+ x+" data-x="-0.6499999999999999" data-y="0.825" cx="182.22222222222223" cy="182.22222222222226" r="3" fill="hsl(227, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R2.1
8
+ x-" data-x="0.6499999999999999" data-y="0.825" cx="413.3333333333333" cy="182.22222222222226" r="3" fill="hsl(107, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R2.2
9
+ x+" data-x="1.25" data-y="0.825" cx="520" cy="182.22222222222226" r="3" fill="hsl(108, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R3.1
10
+ x-" data-x="-1.25" data-y="-0.825" cx="75.55555555555554" cy="475.55555555555554" r="3" fill="hsl(348, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="R3.2
11
+ x+" data-x="-0.6499999999999999" data-y="-0.825" cx="182.22222222222223" cy="475.55555555555554" r="3" fill="hsl(349, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J1.1
12
+ x-" data-x="0.49999999999999994" data-y="-0.725" cx="386.66666666666663" cy="457.7777777777778" r="3" fill="hsl(218, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J1.2
13
+ y-" data-x="0.95" data-y="-1.1028787352499998" cx="466.66666666666663" cy="524.9562195999999" r="3" fill="hsl(219, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="J1.3
14
+ x+" data-x="1.4" data-y="-0.725" cx="546.6666666666666" cy="457.7777777777778" r="3" fill="hsl(220, 100%, 50%, 0.8)"/></g><g><circle data-type="point" data-label="anchorPoint
15
+ orientation: y+" data-x="0.21250000000000002" data-y="-0.725" cx="335.55555555555554" cy="457.7777777777778" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
16
+ orientation: y-" data-x="1.5999999999999999" data-y="-0.725" cx="582.2222222222222" cy="457.7777777777778" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
17
+ orientation: y+" data-x="0.4499999999999999" data-y="0.825" cx="377.77777777777777" cy="182.22222222222226" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g><circle data-type="point" data-label="anchorPoint
18
+ orientation: y+" data-x="1.4500000000000002" data-y="0.825" cx="555.5555555555557" cy="182.22222222222226" r="3" fill="hsl(40, 100%, 50%, 0.9)"/></g><g id="crosshair" style="display: none"><line id="crosshair-h" y1="0" y2="640" stroke="#666" stroke-width="0.5"/><line id="crosshair-v" x1="0" x2="640" stroke="#666" stroke-width="0.5"/><text id="coordinates" font-family="monospace" font-size="12" fill="#666"></text></g><script><![CDATA[
23
19
  document.currentScript.parentElement.addEventListener('mousemove', (e) => {
24
20
  const svg = e.currentTarget;
25
21
  const rect = svg.getBoundingClientRect();
@@ -41,7 +37,7 @@ orientation: y+" data-x="1.4500000000000002" data-y="0.825" cx="536.779279279279
41
37
  v.setAttribute('y2', '640');
42
38
 
43
39
  // Calculate real coordinates using inverse transformation
44
- const matrix = {"a":157.65765765765767,"c":0,"e":308.1756756756757,"b":0,"d":-157.65765765765767,"f":328.6711711711712};
40
+ const matrix = {"a":177.77777777777777,"c":0,"e":297.77777777777777,"b":0,"d":-177.77777777777777,"f":328.8888888888889};
45
41
  // Manually invert and apply the affine transform
46
42
  // Since we only use translate and scale, we can directly compute:
47
43
  // x' = (x - tx) / sx
@@ -3,7 +3,7 @@ import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipeline
3
3
  import "tests/fixtures/matcher"
4
4
  import inputProblem from "./assets/repro47-endpoint-obstacle-detour.input.json"
5
5
 
6
- test("repro47: endpoint obstacle detours fall back to net labels", () => {
6
+ test("repro47: endpoint obstacle detours route around nearby components", () => {
7
7
  const solver = new SchematicTracePipelineSolver(inputProblem as any)
8
8
 
9
9
  solver.solve()
@@ -14,6 +14,6 @@ test("repro47: endpoint obstacle detours fall back to net labels", () => {
14
14
  (pair) => pair.mspPairId,
15
15
  )
16
16
  .sort(),
17
- ).toEqual(["J1.1-R1.1", "J1.3-R1.2"])
17
+ ).toEqual([])
18
18
  expect(solver).toMatchSolverSnapshot(import.meta.path)
19
19
  })
@@ -36,3 +36,40 @@ test("endpoint collision detours preserve both endpoint anchors", () => {
36
36
  ),
37
37
  ).toBe(true)
38
38
  })
39
+
40
+ test("endpoint collision detours preserve the remainder of a U-shaped path", () => {
41
+ const path = [
42
+ { x: 0, y: 1 },
43
+ { x: 2, y: 1 },
44
+ { x: 2, y: -1 },
45
+ { x: 4, y: -1 },
46
+ ]
47
+
48
+ const obstacle = {
49
+ minX: 1,
50
+ maxX: 3,
51
+ minY: 0,
52
+ maxY: 2,
53
+ kind: "chip" as const,
54
+ chipId: "U1",
55
+ }
56
+
57
+ for (const collidingSegmentIndex of [0, 2]) {
58
+ const detours = generateEndpointCollisionDetours({
59
+ path,
60
+ collidingSegmentIndex,
61
+ obstacle,
62
+ })
63
+
64
+ expect(detours.length).toBeGreaterThan(0)
65
+ const preservedSegment =
66
+ collidingSegmentIndex === 0 ? path.slice(-2) : path.slice(0, 2)
67
+ for (const detour of detours) {
68
+ expect(detour[0]).toEqual(path[0])
69
+ expect(detour.at(-1)).toEqual(path.at(-1))
70
+ expect(
71
+ collidingSegmentIndex === 0 ? detour.slice(-2) : detour.slice(0, 2),
72
+ ).toEqual(preservedSegment)
73
+ }
74
+ }
75
+ })