@tscircuit/hypergraph 0.0.32 → 0.0.34
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.d.ts +8 -0
- package/dist/index.js +225 -194
- package/package.json +2 -1
package/dist/index.d.ts
CHANGED
|
@@ -241,6 +241,13 @@ declare class HyperGraphSolver<RegionType extends Region = Region, RegionPortTyp
|
|
|
241
241
|
* a route would require ripping other routes due to problematic crossings.
|
|
242
242
|
*/
|
|
243
243
|
getRipsRequiredForPortUsage(_region: RegionType, _port1: RegionPortType, _port2: RegionPortType): RegionPortAssignment[];
|
|
244
|
+
/**
|
|
245
|
+
* OPTIONALLY OVERRIDE THIS
|
|
246
|
+
*
|
|
247
|
+
* Return true if using the candidate transition should incur ripCost even
|
|
248
|
+
* when there is no direct port-assignment conflict.
|
|
249
|
+
*/
|
|
250
|
+
isRipRequiredForPortUsage(_region: RegionType, _port1: RegionPortType, _port2: RegionPortType): boolean;
|
|
244
251
|
computeG(candidate: CandidateType): number;
|
|
245
252
|
/**
|
|
246
253
|
* Return a subset of the candidates for entering a region. These candidates
|
|
@@ -378,6 +385,7 @@ declare class JumperGraphSolver extends HyperGraphSolver<JRegion, JPort> {
|
|
|
378
385
|
getPortUsagePenalty(port: JPort): number;
|
|
379
386
|
computeIncreasedRegionCostIfPortsAreUsed(region: JRegion, port1: JPort, port2: JPort): number;
|
|
380
387
|
getRipsRequiredForPortUsage(region: JRegion, port1: JPort, port2: JPort): RegionPortAssignment[];
|
|
388
|
+
isRipRequiredForPortUsage(region: JRegion, _port1: JPort, _port2: JPort): boolean;
|
|
381
389
|
routeSolvedHook(solvedRoute: SolvedRoute): void;
|
|
382
390
|
routeStartedHook(connection: Connection): void;
|
|
383
391
|
visualize(): GraphicsObject;
|
package/dist/index.js
CHANGED
|
@@ -31,6 +31,28 @@ var convertHyperGraphToSerializedHyperGraph = (graph) => {
|
|
|
31
31
|
// lib/HyperGraphSolver.ts
|
|
32
32
|
import { BaseSolver } from "@tscircuit/solver-utils";
|
|
33
33
|
|
|
34
|
+
// lib/convertSerializedConnectionsToConnections.ts
|
|
35
|
+
var convertSerializedConnectionsToConnections = (inputConnections, graph) => {
|
|
36
|
+
const connections = [];
|
|
37
|
+
for (const inputConn of inputConnections) {
|
|
38
|
+
if ("startRegionId" in inputConn) {
|
|
39
|
+
connections.push({
|
|
40
|
+
connectionId: inputConn.connectionId,
|
|
41
|
+
mutuallyConnectedNetworkId: inputConn.connectionId,
|
|
42
|
+
startRegion: graph.regions.find(
|
|
43
|
+
(region) => region.regionId === inputConn.startRegionId
|
|
44
|
+
),
|
|
45
|
+
endRegion: graph.regions.find(
|
|
46
|
+
(region) => region.regionId === inputConn.endRegionId
|
|
47
|
+
)
|
|
48
|
+
});
|
|
49
|
+
} else {
|
|
50
|
+
connections.push(inputConn);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return connections;
|
|
54
|
+
};
|
|
55
|
+
|
|
34
56
|
// lib/convertSerializedHyperGraphToHyperGraph.ts
|
|
35
57
|
var convertSerializedHyperGraphToHyperGraph = (inputGraph) => {
|
|
36
58
|
if (inputGraph.ports.length > 0 && "region1" in inputGraph.ports[0] && typeof inputGraph.ports[0].region1 === "object") {
|
|
@@ -65,28 +87,6 @@ var convertSerializedHyperGraphToHyperGraph = (inputGraph) => {
|
|
|
65
87
|
};
|
|
66
88
|
};
|
|
67
89
|
|
|
68
|
-
// lib/convertSerializedConnectionsToConnections.ts
|
|
69
|
-
var convertSerializedConnectionsToConnections = (inputConnections, graph) => {
|
|
70
|
-
const connections = [];
|
|
71
|
-
for (const inputConn of inputConnections) {
|
|
72
|
-
if ("startRegionId" in inputConn) {
|
|
73
|
-
connections.push({
|
|
74
|
-
connectionId: inputConn.connectionId,
|
|
75
|
-
mutuallyConnectedNetworkId: inputConn.connectionId,
|
|
76
|
-
startRegion: graph.regions.find(
|
|
77
|
-
(region) => region.regionId === inputConn.startRegionId
|
|
78
|
-
),
|
|
79
|
-
endRegion: graph.regions.find(
|
|
80
|
-
(region) => region.regionId === inputConn.endRegionId
|
|
81
|
-
)
|
|
82
|
-
});
|
|
83
|
-
} else {
|
|
84
|
-
connections.push(inputConn);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
return connections;
|
|
88
|
-
};
|
|
89
|
-
|
|
90
90
|
// lib/PriorityQueue.ts
|
|
91
91
|
var PriorityQueue = class {
|
|
92
92
|
// Store the heap as an array. Index 0 is the root (highest priority/smallest 'f').
|
|
@@ -328,6 +328,15 @@ var HyperGraphSolver = class extends BaseSolver {
|
|
|
328
328
|
getRipsRequiredForPortUsage(_region, _port1, _port2) {
|
|
329
329
|
return [];
|
|
330
330
|
}
|
|
331
|
+
/**
|
|
332
|
+
* OPTIONALLY OVERRIDE THIS
|
|
333
|
+
*
|
|
334
|
+
* Return true if using the candidate transition should incur ripCost even
|
|
335
|
+
* when there is no direct port-assignment conflict.
|
|
336
|
+
*/
|
|
337
|
+
isRipRequiredForPortUsage(_region, _port1, _port2) {
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
331
340
|
computeG(candidate) {
|
|
332
341
|
return candidate.parent.g + this.computeIncreasedRegionCostIfPortsAreUsed(
|
|
333
342
|
candidate.lastRegion,
|
|
@@ -396,7 +405,11 @@ var HyperGraphSolver = class extends BaseSolver {
|
|
|
396
405
|
const nextCandidatesByRegion = {};
|
|
397
406
|
for (const port of currentRegion.ports) {
|
|
398
407
|
if (port === currentCandidate.port) continue;
|
|
399
|
-
const ripRequired = port.assignment && port.assignment.connection.mutuallyConnectedNetworkId !== this.currentConnection.mutuallyConnectedNetworkId
|
|
408
|
+
const ripRequired = port.assignment && port.assignment.connection.mutuallyConnectedNetworkId !== this.currentConnection.mutuallyConnectedNetworkId || this.isRipRequiredForPortUsage(
|
|
409
|
+
currentRegion,
|
|
410
|
+
currentPort,
|
|
411
|
+
port
|
|
412
|
+
);
|
|
400
413
|
const newCandidate = {
|
|
401
414
|
port,
|
|
402
415
|
hops: currentCandidate.hops + 1,
|
|
@@ -758,6 +771,174 @@ var rotateGraph90Degrees = (graph) => {
|
|
|
758
771
|
return applyTransformToGraph(graph, matrix2);
|
|
759
772
|
};
|
|
760
773
|
|
|
774
|
+
// lib/JumperGraphSolver/perimeterChordUtils.ts
|
|
775
|
+
function perimeterT(p, xmin, xmax, ymin, ymax) {
|
|
776
|
+
const W = xmax - xmin;
|
|
777
|
+
const H = ymax - ymin;
|
|
778
|
+
const eps = 1e-6;
|
|
779
|
+
if (Math.abs(p.y - ymax) < eps) {
|
|
780
|
+
return p.x - xmin;
|
|
781
|
+
}
|
|
782
|
+
if (Math.abs(p.x - xmax) < eps) {
|
|
783
|
+
return W + (ymax - p.y);
|
|
784
|
+
}
|
|
785
|
+
if (Math.abs(p.y - ymin) < eps) {
|
|
786
|
+
return W + H + (xmax - p.x);
|
|
787
|
+
}
|
|
788
|
+
if (Math.abs(p.x - xmin) < eps) {
|
|
789
|
+
return 2 * W + H + (p.y - ymin);
|
|
790
|
+
}
|
|
791
|
+
const distTop = Math.abs(p.y - ymax);
|
|
792
|
+
const distRight = Math.abs(p.x - xmax);
|
|
793
|
+
const distBottom = Math.abs(p.y - ymin);
|
|
794
|
+
const distLeft = Math.abs(p.x - xmin);
|
|
795
|
+
const minDist = Math.min(distTop, distRight, distBottom, distLeft);
|
|
796
|
+
if (minDist === distTop) {
|
|
797
|
+
return Math.max(0, Math.min(W, p.x - xmin));
|
|
798
|
+
}
|
|
799
|
+
if (minDist === distRight) {
|
|
800
|
+
return W + Math.max(0, Math.min(H, ymax - p.y));
|
|
801
|
+
}
|
|
802
|
+
if (minDist === distBottom) {
|
|
803
|
+
return W + H + Math.max(0, Math.min(W, xmax - p.x));
|
|
804
|
+
}
|
|
805
|
+
return 2 * W + H + Math.max(0, Math.min(H, p.y - ymin));
|
|
806
|
+
}
|
|
807
|
+
function areCoincident(t1, t2, eps = 1e-6) {
|
|
808
|
+
return Math.abs(t1 - t2) < eps;
|
|
809
|
+
}
|
|
810
|
+
function chordsCross(chord1, chord2) {
|
|
811
|
+
const [a, b] = chord1[0] < chord1[1] ? chord1 : [chord1[1], chord1[0]];
|
|
812
|
+
const [c, d] = chord2[0] < chord2[1] ? chord2 : [chord2[1], chord2[0]];
|
|
813
|
+
if (areCoincident(a, c) || areCoincident(a, d) || areCoincident(b, c) || areCoincident(b, d)) {
|
|
814
|
+
return false;
|
|
815
|
+
}
|
|
816
|
+
return a < c && c < b && b < d || c < a && a < d && d < b;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
// lib/JumperGraphSolver/computeCrossingAssignments.ts
|
|
820
|
+
function computeCrossingAssignments(region, port1, port2) {
|
|
821
|
+
const { minX: xmin, maxX: xmax, minY: ymin, maxY: ymax } = region.d.bounds;
|
|
822
|
+
const t1 = perimeterT(port1.d, xmin, xmax, ymin, ymax);
|
|
823
|
+
const t2 = perimeterT(port2.d, xmin, xmax, ymin, ymax);
|
|
824
|
+
const newChord = [t1, t2];
|
|
825
|
+
const crossingAssignments = [];
|
|
826
|
+
const assignments = region.assignments ?? [];
|
|
827
|
+
for (const assignment of assignments) {
|
|
828
|
+
const existingT1 = perimeterT(
|
|
829
|
+
assignment.regionPort1.d,
|
|
830
|
+
xmin,
|
|
831
|
+
xmax,
|
|
832
|
+
ymin,
|
|
833
|
+
ymax
|
|
834
|
+
);
|
|
835
|
+
const existingT2 = perimeterT(
|
|
836
|
+
assignment.regionPort2.d,
|
|
837
|
+
xmin,
|
|
838
|
+
xmax,
|
|
839
|
+
ymin,
|
|
840
|
+
ymax
|
|
841
|
+
);
|
|
842
|
+
const existingChord = [existingT1, existingT2];
|
|
843
|
+
if (chordsCross(newChord, existingChord)) {
|
|
844
|
+
crossingAssignments.push(assignment);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
return crossingAssignments;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// lib/JumperGraphSolver/computeDifferentNetCrossings.ts
|
|
851
|
+
function computeDifferentNetCrossings(region, port1, port2) {
|
|
852
|
+
const { minX: xmin, maxX: xmax, minY: ymin, maxY: ymax } = region.d.bounds;
|
|
853
|
+
const t1 = perimeterT(port1.d, xmin, xmax, ymin, ymax);
|
|
854
|
+
const t2 = perimeterT(port2.d, xmin, xmax, ymin, ymax);
|
|
855
|
+
const newChord = [t1, t2];
|
|
856
|
+
let crossings = 0;
|
|
857
|
+
const assignments = region.assignments ?? [];
|
|
858
|
+
for (const assignment of assignments) {
|
|
859
|
+
const existingT1 = perimeterT(
|
|
860
|
+
assignment.regionPort1.d,
|
|
861
|
+
xmin,
|
|
862
|
+
xmax,
|
|
863
|
+
ymin,
|
|
864
|
+
ymax
|
|
865
|
+
);
|
|
866
|
+
const existingT2 = perimeterT(
|
|
867
|
+
assignment.regionPort2.d,
|
|
868
|
+
xmin,
|
|
869
|
+
xmax,
|
|
870
|
+
ymin,
|
|
871
|
+
ymax
|
|
872
|
+
);
|
|
873
|
+
const existingChord = [existingT1, existingT2];
|
|
874
|
+
if (chordsCross(newChord, existingChord)) {
|
|
875
|
+
crossings++;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
return crossings;
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
// lib/JumperGraphSolver/countInputConnectionCrossings.ts
|
|
882
|
+
function countInputConnectionCrossings(graph, connections) {
|
|
883
|
+
if (connections.length < 2) {
|
|
884
|
+
return 0;
|
|
885
|
+
}
|
|
886
|
+
let minX = Infinity;
|
|
887
|
+
let maxX = -Infinity;
|
|
888
|
+
let minY = Infinity;
|
|
889
|
+
let maxY = -Infinity;
|
|
890
|
+
for (const region of graph.regions) {
|
|
891
|
+
const jRegion = region;
|
|
892
|
+
if (jRegion.d?.bounds) {
|
|
893
|
+
minX = Math.min(minX, jRegion.d.bounds.minX);
|
|
894
|
+
maxX = Math.max(maxX, jRegion.d.bounds.maxX);
|
|
895
|
+
minY = Math.min(minY, jRegion.d.bounds.minY);
|
|
896
|
+
maxY = Math.max(maxY, jRegion.d.bounds.maxY);
|
|
897
|
+
} else if (jRegion.d?.center) {
|
|
898
|
+
minX = Math.min(minX, jRegion.d.center.x);
|
|
899
|
+
maxX = Math.max(maxX, jRegion.d.center.x);
|
|
900
|
+
minY = Math.min(minY, jRegion.d.center.y);
|
|
901
|
+
maxY = Math.max(maxY, jRegion.d.center.y);
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
const regionCenterMap = /* @__PURE__ */ new Map();
|
|
905
|
+
for (const region of graph.regions) {
|
|
906
|
+
const jRegion = region;
|
|
907
|
+
if (jRegion.d?.center) {
|
|
908
|
+
regionCenterMap.set(region.regionId, jRegion.d.center);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
const chords = [];
|
|
912
|
+
for (const conn of connections) {
|
|
913
|
+
let startCenter;
|
|
914
|
+
let endCenter;
|
|
915
|
+
if ("startRegion" in conn && conn.startRegion) {
|
|
916
|
+
const startRegion = conn.startRegion;
|
|
917
|
+
const endRegion = conn.endRegion;
|
|
918
|
+
startCenter = startRegion.d?.center;
|
|
919
|
+
endCenter = endRegion.d?.center;
|
|
920
|
+
} else if ("startRegionId" in conn) {
|
|
921
|
+
startCenter = regionCenterMap.get(conn.startRegionId);
|
|
922
|
+
endCenter = regionCenterMap.get(conn.endRegionId);
|
|
923
|
+
}
|
|
924
|
+
if (!startCenter || !endCenter) {
|
|
925
|
+
continue;
|
|
926
|
+
}
|
|
927
|
+
const t1 = perimeterT(startCenter, minX, maxX, minY, maxY);
|
|
928
|
+
const t2 = perimeterT(endCenter, minX, maxX, minY, maxY);
|
|
929
|
+
chords.push([t1, t2]);
|
|
930
|
+
}
|
|
931
|
+
let crossings = 0;
|
|
932
|
+
for (let i = 0; i < chords.length; i++) {
|
|
933
|
+
for (let j = i + 1; j < chords.length; j++) {
|
|
934
|
+
if (chordsCross(chords[i], chords[j])) {
|
|
935
|
+
crossings++;
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
return crossings;
|
|
940
|
+
}
|
|
941
|
+
|
|
761
942
|
// lib/JumperGraphSolver/visualizeJumperGraph.ts
|
|
762
943
|
var visualizeJumperGraph = (graph, options) => {
|
|
763
944
|
const graphics = {
|
|
@@ -971,174 +1152,6 @@ var visualizeJumperGraphSolver = (solver) => {
|
|
|
971
1152
|
return graphics;
|
|
972
1153
|
};
|
|
973
1154
|
|
|
974
|
-
// lib/JumperGraphSolver/perimeterChordUtils.ts
|
|
975
|
-
function perimeterT(p, xmin, xmax, ymin, ymax) {
|
|
976
|
-
const W = xmax - xmin;
|
|
977
|
-
const H = ymax - ymin;
|
|
978
|
-
const eps = 1e-6;
|
|
979
|
-
if (Math.abs(p.y - ymax) < eps) {
|
|
980
|
-
return p.x - xmin;
|
|
981
|
-
}
|
|
982
|
-
if (Math.abs(p.x - xmax) < eps) {
|
|
983
|
-
return W + (ymax - p.y);
|
|
984
|
-
}
|
|
985
|
-
if (Math.abs(p.y - ymin) < eps) {
|
|
986
|
-
return W + H + (xmax - p.x);
|
|
987
|
-
}
|
|
988
|
-
if (Math.abs(p.x - xmin) < eps) {
|
|
989
|
-
return 2 * W + H + (p.y - ymin);
|
|
990
|
-
}
|
|
991
|
-
const distTop = Math.abs(p.y - ymax);
|
|
992
|
-
const distRight = Math.abs(p.x - xmax);
|
|
993
|
-
const distBottom = Math.abs(p.y - ymin);
|
|
994
|
-
const distLeft = Math.abs(p.x - xmin);
|
|
995
|
-
const minDist = Math.min(distTop, distRight, distBottom, distLeft);
|
|
996
|
-
if (minDist === distTop) {
|
|
997
|
-
return Math.max(0, Math.min(W, p.x - xmin));
|
|
998
|
-
}
|
|
999
|
-
if (minDist === distRight) {
|
|
1000
|
-
return W + Math.max(0, Math.min(H, ymax - p.y));
|
|
1001
|
-
}
|
|
1002
|
-
if (minDist === distBottom) {
|
|
1003
|
-
return W + H + Math.max(0, Math.min(W, xmax - p.x));
|
|
1004
|
-
}
|
|
1005
|
-
return 2 * W + H + Math.max(0, Math.min(H, p.y - ymin));
|
|
1006
|
-
}
|
|
1007
|
-
function areCoincident(t1, t2, eps = 1e-6) {
|
|
1008
|
-
return Math.abs(t1 - t2) < eps;
|
|
1009
|
-
}
|
|
1010
|
-
function chordsCross(chord1, chord2) {
|
|
1011
|
-
const [a, b] = chord1[0] < chord1[1] ? chord1 : [chord1[1], chord1[0]];
|
|
1012
|
-
const [c, d] = chord2[0] < chord2[1] ? chord2 : [chord2[1], chord2[0]];
|
|
1013
|
-
if (areCoincident(a, c) || areCoincident(a, d) || areCoincident(b, c) || areCoincident(b, d)) {
|
|
1014
|
-
return false;
|
|
1015
|
-
}
|
|
1016
|
-
return a < c && c < b && b < d || c < a && a < d && d < b;
|
|
1017
|
-
}
|
|
1018
|
-
|
|
1019
|
-
// lib/JumperGraphSolver/computeDifferentNetCrossings.ts
|
|
1020
|
-
function computeDifferentNetCrossings(region, port1, port2) {
|
|
1021
|
-
const { minX: xmin, maxX: xmax, minY: ymin, maxY: ymax } = region.d.bounds;
|
|
1022
|
-
const t1 = perimeterT(port1.d, xmin, xmax, ymin, ymax);
|
|
1023
|
-
const t2 = perimeterT(port2.d, xmin, xmax, ymin, ymax);
|
|
1024
|
-
const newChord = [t1, t2];
|
|
1025
|
-
let crossings = 0;
|
|
1026
|
-
const assignments = region.assignments ?? [];
|
|
1027
|
-
for (const assignment of assignments) {
|
|
1028
|
-
const existingT1 = perimeterT(
|
|
1029
|
-
assignment.regionPort1.d,
|
|
1030
|
-
xmin,
|
|
1031
|
-
xmax,
|
|
1032
|
-
ymin,
|
|
1033
|
-
ymax
|
|
1034
|
-
);
|
|
1035
|
-
const existingT2 = perimeterT(
|
|
1036
|
-
assignment.regionPort2.d,
|
|
1037
|
-
xmin,
|
|
1038
|
-
xmax,
|
|
1039
|
-
ymin,
|
|
1040
|
-
ymax
|
|
1041
|
-
);
|
|
1042
|
-
const existingChord = [existingT1, existingT2];
|
|
1043
|
-
if (chordsCross(newChord, existingChord)) {
|
|
1044
|
-
crossings++;
|
|
1045
|
-
}
|
|
1046
|
-
}
|
|
1047
|
-
return crossings;
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
|
-
// lib/JumperGraphSolver/computeCrossingAssignments.ts
|
|
1051
|
-
function computeCrossingAssignments(region, port1, port2) {
|
|
1052
|
-
const { minX: xmin, maxX: xmax, minY: ymin, maxY: ymax } = region.d.bounds;
|
|
1053
|
-
const t1 = perimeterT(port1.d, xmin, xmax, ymin, ymax);
|
|
1054
|
-
const t2 = perimeterT(port2.d, xmin, xmax, ymin, ymax);
|
|
1055
|
-
const newChord = [t1, t2];
|
|
1056
|
-
const crossingAssignments = [];
|
|
1057
|
-
const assignments = region.assignments ?? [];
|
|
1058
|
-
for (const assignment of assignments) {
|
|
1059
|
-
const existingT1 = perimeterT(
|
|
1060
|
-
assignment.regionPort1.d,
|
|
1061
|
-
xmin,
|
|
1062
|
-
xmax,
|
|
1063
|
-
ymin,
|
|
1064
|
-
ymax
|
|
1065
|
-
);
|
|
1066
|
-
const existingT2 = perimeterT(
|
|
1067
|
-
assignment.regionPort2.d,
|
|
1068
|
-
xmin,
|
|
1069
|
-
xmax,
|
|
1070
|
-
ymin,
|
|
1071
|
-
ymax
|
|
1072
|
-
);
|
|
1073
|
-
const existingChord = [existingT1, existingT2];
|
|
1074
|
-
if (chordsCross(newChord, existingChord)) {
|
|
1075
|
-
crossingAssignments.push(assignment);
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
return crossingAssignments;
|
|
1079
|
-
}
|
|
1080
|
-
|
|
1081
|
-
// lib/JumperGraphSolver/countInputConnectionCrossings.ts
|
|
1082
|
-
function countInputConnectionCrossings(graph, connections) {
|
|
1083
|
-
if (connections.length < 2) {
|
|
1084
|
-
return 0;
|
|
1085
|
-
}
|
|
1086
|
-
let minX = Infinity;
|
|
1087
|
-
let maxX = -Infinity;
|
|
1088
|
-
let minY = Infinity;
|
|
1089
|
-
let maxY = -Infinity;
|
|
1090
|
-
for (const region of graph.regions) {
|
|
1091
|
-
const jRegion = region;
|
|
1092
|
-
if (jRegion.d?.bounds) {
|
|
1093
|
-
minX = Math.min(minX, jRegion.d.bounds.minX);
|
|
1094
|
-
maxX = Math.max(maxX, jRegion.d.bounds.maxX);
|
|
1095
|
-
minY = Math.min(minY, jRegion.d.bounds.minY);
|
|
1096
|
-
maxY = Math.max(maxY, jRegion.d.bounds.maxY);
|
|
1097
|
-
} else if (jRegion.d?.center) {
|
|
1098
|
-
minX = Math.min(minX, jRegion.d.center.x);
|
|
1099
|
-
maxX = Math.max(maxX, jRegion.d.center.x);
|
|
1100
|
-
minY = Math.min(minY, jRegion.d.center.y);
|
|
1101
|
-
maxY = Math.max(maxY, jRegion.d.center.y);
|
|
1102
|
-
}
|
|
1103
|
-
}
|
|
1104
|
-
const regionCenterMap = /* @__PURE__ */ new Map();
|
|
1105
|
-
for (const region of graph.regions) {
|
|
1106
|
-
const jRegion = region;
|
|
1107
|
-
if (jRegion.d?.center) {
|
|
1108
|
-
regionCenterMap.set(region.regionId, jRegion.d.center);
|
|
1109
|
-
}
|
|
1110
|
-
}
|
|
1111
|
-
const chords = [];
|
|
1112
|
-
for (const conn of connections) {
|
|
1113
|
-
let startCenter;
|
|
1114
|
-
let endCenter;
|
|
1115
|
-
if ("startRegion" in conn && conn.startRegion) {
|
|
1116
|
-
const startRegion = conn.startRegion;
|
|
1117
|
-
const endRegion = conn.endRegion;
|
|
1118
|
-
startCenter = startRegion.d?.center;
|
|
1119
|
-
endCenter = endRegion.d?.center;
|
|
1120
|
-
} else if ("startRegionId" in conn) {
|
|
1121
|
-
startCenter = regionCenterMap.get(conn.startRegionId);
|
|
1122
|
-
endCenter = regionCenterMap.get(conn.endRegionId);
|
|
1123
|
-
}
|
|
1124
|
-
if (!startCenter || !endCenter) {
|
|
1125
|
-
continue;
|
|
1126
|
-
}
|
|
1127
|
-
const t1 = perimeterT(startCenter, minX, maxX, minY, maxY);
|
|
1128
|
-
const t2 = perimeterT(endCenter, minX, maxX, minY, maxY);
|
|
1129
|
-
chords.push([t1, t2]);
|
|
1130
|
-
}
|
|
1131
|
-
let crossings = 0;
|
|
1132
|
-
for (let i = 0; i < chords.length; i++) {
|
|
1133
|
-
for (let j = i + 1; j < chords.length; j++) {
|
|
1134
|
-
if (chordsCross(chords[i], chords[j])) {
|
|
1135
|
-
crossings++;
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
|
-
}
|
|
1139
|
-
return crossings;
|
|
1140
|
-
}
|
|
1141
|
-
|
|
1142
1155
|
// lib/JumperGraphSolver/JumperGraphSolver.ts
|
|
1143
1156
|
var JUMPER_GRAPH_SOLVER_DEFAULTS = {
|
|
1144
1157
|
portUsagePenalty: 0.034685181009478865,
|
|
@@ -1223,9 +1236,26 @@ var JumperGraphSolver = class extends HyperGraphSolver {
|
|
|
1223
1236
|
}
|
|
1224
1237
|
getRipsRequiredForPortUsage(region, port1, port2) {
|
|
1225
1238
|
const crossingAssignments = computeCrossingAssignments(region, port1, port2);
|
|
1226
|
-
|
|
1239
|
+
const conflictingAssignments = crossingAssignments.filter(
|
|
1227
1240
|
(a) => a.connection.mutuallyConnectedNetworkId !== this.currentConnection.mutuallyConnectedNetworkId
|
|
1228
1241
|
);
|
|
1242
|
+
if (!region.d.isThroughJumper) return conflictingAssignments;
|
|
1243
|
+
for (const assignment of region.assignments ?? []) {
|
|
1244
|
+
if (assignment.connection.mutuallyConnectedNetworkId === this.currentConnection.mutuallyConnectedNetworkId) {
|
|
1245
|
+
continue;
|
|
1246
|
+
}
|
|
1247
|
+
conflictingAssignments.push(assignment);
|
|
1248
|
+
}
|
|
1249
|
+
return conflictingAssignments;
|
|
1250
|
+
}
|
|
1251
|
+
isRipRequiredForPortUsage(region, _port1, _port2) {
|
|
1252
|
+
if (!region.d.isThroughJumper) return false;
|
|
1253
|
+
for (const assignment of region.assignments ?? []) {
|
|
1254
|
+
if (assignment.connection.mutuallyConnectedNetworkId !== this.currentConnection.mutuallyConnectedNetworkId) {
|
|
1255
|
+
return true;
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
return false;
|
|
1229
1259
|
}
|
|
1230
1260
|
routeSolvedHook(solvedRoute) {
|
|
1231
1261
|
}
|
|
@@ -14760,12 +14790,13 @@ function generateConvexViaTopologyRegions(opts) {
|
|
|
14760
14790
|
const obstaclePolygons = viaRegions.map((r) => ({
|
|
14761
14791
|
points: r.d.polygon
|
|
14762
14792
|
}));
|
|
14763
|
-
const
|
|
14793
|
+
const solverInput = {
|
|
14764
14794
|
bounds,
|
|
14765
14795
|
polygons: obstaclePolygons,
|
|
14766
14796
|
clearance,
|
|
14767
14797
|
concavityTolerance
|
|
14768
|
-
}
|
|
14798
|
+
};
|
|
14799
|
+
const solver = new ConvexRegionsSolver(solverInput);
|
|
14769
14800
|
solver.solve();
|
|
14770
14801
|
const solverOutput = solver.getOutput();
|
|
14771
14802
|
if (!solverOutput) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tscircuit/hypergraph",
|
|
3
3
|
"main": "dist/index.js",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.34",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"start": "cosmos",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"@biomejs/biome": "^2.3.11",
|
|
19
19
|
"@tscircuit/find-convex-regions": "^0.0.7",
|
|
20
|
+
"@tscircuit/jumper-topology-generator": "^0.0.1",
|
|
20
21
|
"@tscircuit/math-utils": "^0.0.29",
|
|
21
22
|
"@types/bun": "latest",
|
|
22
23
|
"bun-match-svg": "^0.0.15",
|