@tscircuit/hypergraph 0.0.35 → 0.0.37

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +61 -215
  2. package/dist/index.js +282 -231
  3. package/package.json +3 -2
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { BaseSolver } from '@tscircuit/solver-utils';
2
2
  import { Matrix } from 'transformation-matrix';
3
- import { GraphicsObject } from 'graphics-debug';
3
+ import { GraphicsObject, Point } from 'graphics-debug';
4
4
 
5
5
  type PortId = string;
6
6
  type GraphEdgeId = string;
@@ -766,48 +766,24 @@ var routeSegments = [
766
766
  y: 0.582296
767
767
  },
768
768
  {
769
- x: 1.31705,
770
- y: 0.74908
769
+ x: 1.712721,
770
+ y: 0.811183
771
771
  },
772
772
  {
773
- x: 1.425309,
774
- y: 0.74908
773
+ x: 1.712721,
774
+ y: 1.542957
775
775
  },
776
776
  {
777
- x: 1.762721,
778
- y: 1.086492
777
+ x: 0.920111,
778
+ y: 2.335567
779
779
  },
780
780
  {
781
- x: 1.762721,
782
- y: 1.563668
783
- },
784
- {
785
- x: 1.425309,
786
- y: 1.90108
787
- },
788
- {
789
- x: 1.266397,
790
- y: 1.90108
791
- },
792
- {
793
- x: 0.781911,
794
- y: 2.385567
795
- },
796
- {
797
- x: 0.013957,
798
- y: 2.385567
799
- },
800
- {
801
- x: -0.753066,
802
- y: 1.618543
803
- },
804
- {
805
- x: -0.753066,
806
- y: 1.360375
781
+ x: 0.034666,
782
+ y: 2.335566
807
783
  },
808
784
  {
809
785
  x: -0.703066,
810
- y: 1.310375
786
+ y: 1.597834
811
787
  },
812
788
  {
813
789
  x: -0.703066,
@@ -830,32 +806,20 @@ var routeSegments = [
830
806
  y: -1.893395
831
807
  },
832
808
  {
833
- x: -2.2,
834
- y: -1.4
835
- },
836
- {
837
- x: -2.2,
838
- y: 0.903041
809
+ x: -2.10103,
810
+ y: -1.49897
839
811
  },
840
812
  {
841
- x: -1.603041,
842
- y: 1.5
813
+ x: -2.10103,
814
+ y: 1.002011
843
815
  },
844
816
  {
845
- x: -1.516757,
846
- y: 1.5
817
+ x: -1.708294,
818
+ y: 1.394747
847
819
  },
848
820
  {
849
- x: -1.430473,
850
- y: 1.586284
851
- },
852
- {
853
- x: -0.978975,
854
- y: 1.586284
855
- },
856
- {
857
- x: -0.703066,
858
- y: 1.310375
821
+ x: -0.897813,
822
+ y: 1.394747
859
823
  },
860
824
  {
861
825
  x: -0.703066,
@@ -865,81 +829,37 @@ var routeSegments = [
865
829
  },
866
830
  {
867
831
  routeId: "Net5:route_0",
868
- fromPort: "a3797f13-73f9-48c3-a448-bea3980cdd65",
869
- toPort: "b0c56bb1-ea80-4154-9bb7-cb0fd760de8f",
832
+ fromPort: "4e57cee8-0910-4c83-9ec1-1ed2c9d16dcc",
833
+ toPort: "a3797f13-73f9-48c3-a448-bea3980cdd65",
870
834
  layer: "bottom",
871
835
  segments: [
872
836
  {
873
- x: -1.115754,
874
- y: -0.799377
875
- },
876
- {
877
- x: -0.764375,
878
- y: -0.447998
879
- },
880
- {
881
- x: -0.636191,
882
- y: -0.447998
883
- },
884
- {
885
- x: -0.368136,
886
- y: -0.179943
887
- },
888
- {
889
- x: -0.368136,
890
- y: -0.178529
891
- },
892
- {
893
- x: 0.556834,
894
- y: 0.746441
837
+ x: 1.268717,
838
+ y: -1.698536
895
839
  },
896
840
  {
897
- x: 0.397934,
898
- y: 0.905341
841
+ x: 0.369558,
842
+ y: -0.799377
899
843
  },
900
844
  {
901
- x: 0.397934,
902
- y: 1.458567
845
+ x: -1.115754,
846
+ y: -0.799377
903
847
  }
904
848
  ]
905
849
  },
906
850
  {
907
851
  routeId: "Net5:route_1",
908
- fromPort: "4e57cee8-0910-4c83-9ec1-1ed2c9d16dcc",
852
+ fromPort: "a3797f13-73f9-48c3-a448-bea3980cdd65",
909
853
  toPort: "b0c56bb1-ea80-4154-9bb7-cb0fd760de8f",
910
854
  layer: "bottom",
911
855
  segments: [
912
856
  {
913
- x: 1.268717,
914
- y: -1.698536
915
- },
916
- {
917
- x: 1.405649,
918
- y: -1.561604
919
- },
920
- {
921
- x: 1.393076,
922
- y: -1.561604
923
- },
924
- {
925
- x: 1.055664,
926
- y: -1.224192
927
- },
928
- {
929
- x: 1.055664,
930
- y: -0.905992
931
- },
932
- {
933
- x: 0.556834,
934
- y: -0.407162
935
- },
936
- {
937
- x: 0.556834,
938
- y: 0.746441
857
+ x: -1.115754,
858
+ y: -0.799377
939
859
  },
940
860
  {
941
861
  x: 0.397934,
942
- y: 0.905341
862
+ y: 0.714311
943
863
  },
944
864
  {
945
865
  x: 0.397934,
@@ -997,28 +917,16 @@ var routeSegments = [
997
917
  x: 0.159346,
998
918
  y: 2.034567
999
919
  },
1000
- {
1001
- x: 0.06239,
1002
- y: 1.93761
1003
- },
1004
920
  {
1005
921
  x: -0.178066,
1006
922
  y: 1.697155
1007
923
  },
1008
924
  {
1009
925
  x: -0.178066,
1010
- y: 0.824715
1011
- },
1012
- {
1013
- x: -1.042874,
1014
- y: -0.040093
1015
- },
1016
- {
1017
- x: -1.169705,
1018
- y: -0.040093
926
+ y: 0.981123
1019
927
  },
1020
928
  {
1021
- x: -1.209798,
929
+ x: -1.159189,
1022
930
  y: 0
1023
931
  },
1024
932
  {
@@ -1038,69 +946,25 @@ var routeSegments = [
1038
946
  y: -0.164505
1039
947
  },
1040
948
  {
1041
- x: 1.562188,
1042
- y: -0.173664
1043
- },
1044
- {
1045
- x: 1.634312,
1046
- y: -0.173664
1047
- },
1048
- {
1049
- x: 2.207664,
1050
- y: -0.747016
1051
- },
1052
- {
1053
- x: 2.207664,
1054
- y: -1.224192
1055
- },
1056
- {
1057
- x: 1.870252,
1058
- y: -1.561604
949
+ x: 1.565592,
950
+ y: -0.164505
1059
951
  },
1060
952
  {
1061
- x: 1.844717,
1062
- y: -1.561604
953
+ x: 2.181408,
954
+ y: -0.780321
1063
955
  },
1064
956
  {
1065
- x: 1.844717,
1066
- y: -1.937124
957
+ x: 2.181408,
958
+ y: -1.600433
1067
959
  },
1068
960
  {
1069
961
  x: 1.507305,
1070
962
  y: -2.274536
1071
963
  },
1072
964
  {
1073
- x: 1.030129,
965
+ x: 0.630282,
1074
966
  y: -2.274536
1075
967
  },
1076
- {
1077
- x: 0.692717,
1078
- y: -1.937124
1079
- },
1080
- {
1081
- x: 0.692717,
1082
- y: -1.739534
1083
- },
1084
- {
1085
- x: 0.475553,
1086
- y: -1.739534
1087
- },
1088
- {
1089
- x: 0.470734,
1090
- y: -1.744353
1091
- },
1092
- {
1093
- x: 0.455647,
1094
- y: -1.744353
1095
- },
1096
- {
1097
- x: 0.30246,
1098
- y: -1.89754
1099
- },
1100
- {
1101
- x: 0.253286,
1102
- y: -1.89754
1103
- },
1104
968
  {
1105
969
  x: 0.222457,
1106
970
  y: -1.866711
@@ -1118,23 +982,15 @@ var routeSegments = [
1118
982
  y: -1.866711
1119
983
  },
1120
984
  {
1121
- x: 0.208345,
985
+ x: 0.137528,
1122
986
  y: -1.866711
1123
987
  },
1124
988
  {
1125
- x: 0.2,
1126
- y: -1.858366
1127
- },
1128
- {
1129
- x: 0.2,
1130
- y: -1.2
1131
- },
1132
- {
1133
- x: -0.701789,
1134
- y: -1.2
989
+ x: -0.329183,
990
+ y: -1.4
1135
991
  },
1136
992
  {
1137
- x: -0.869184,
993
+ x: -0.361788,
1138
994
  y: -1.367395
1139
995
  },
1140
996
  {
@@ -1142,28 +998,16 @@ var routeSegments = [
1142
998
  y: -1.367395
1143
999
  },
1144
1000
  {
1145
- x: -1.025859,
1146
- y: -1.375377
1147
- },
1148
- {
1149
- x: -1.354342,
1150
- y: -1.375377
1151
- },
1152
- {
1153
- x: -1.529719,
1154
- y: -1.2
1001
+ x: -1.237643,
1002
+ y: -1.587161
1155
1003
  },
1156
1004
  {
1157
- x: -1.636994,
1158
- y: -1.2
1159
- },
1160
- {
1161
- x: -1.718497,
1162
- y: -1.118497
1005
+ x: -1.587161,
1006
+ y: -1.587161
1163
1007
  },
1164
1008
  {
1165
1009
  x: -1.8,
1166
- y: -1.2
1010
+ y: -1.374322
1167
1011
  },
1168
1012
  {
1169
1013
  x: -1.8,
@@ -1175,19 +1019,11 @@ var routeSegments = [
1175
1019
  },
1176
1020
  {
1177
1021
  x: -1.80003,
1178
- y: -0.559789
1179
- },
1180
- {
1181
- x: -1.8,
1182
- y: -0.559759
1183
- },
1184
- {
1185
- x: -1.8,
1186
- y: 0.877363
1022
+ y: -0.6
1187
1023
  },
1188
1024
  {
1189
- x: -1.614161,
1190
- y: 1.063202
1025
+ x: -1.80003,
1026
+ y: 0.488423
1191
1027
  },
1192
1028
  {
1193
1029
  x: -1.419706,
@@ -1201,6 +1037,11 @@ var viaTile = {
1201
1037
  routeSegments: routeSegments
1202
1038
  };
1203
1039
 
1040
+ type ResolvedRouteLineSegment = {
1041
+ points: Point[];
1042
+ layer: "top" | "bottom";
1043
+ };
1044
+
1204
1045
  declare const VIA_GRAPH_SOLVER_DEFAULTS: {
1205
1046
  portUsagePenalty: number;
1206
1047
  portUsagePenaltySq: number;
@@ -1260,6 +1101,11 @@ declare class ViaGraphSolver extends HyperGraphSolver<JRegion, JPort> {
1260
1101
  computeIncreasedRegionCostIfPortsAreUsed(region: JRegion, port1: JPort, port2: JPort): number;
1261
1102
  getRipsRequiredForPortUsage(region: JRegion, port1: JPort, port2: JPort): RegionPortAssignment[];
1262
1103
  routeSolvedHook(solvedRoute: SolvedRoute): void;
1104
+ getSolvedRoutePoints(solvedRoute: SolvedRoute): Array<{
1105
+ x: number;
1106
+ y: number;
1107
+ }>;
1108
+ getSolvedRouteLineSegments(solvedRoute: SolvedRoute): ResolvedRouteLineSegment[];
1263
1109
  routeStartedHook(connection: Connection): void;
1264
1110
  visualize(): GraphicsObject;
1265
1111
  }
package/dist/index.js CHANGED
@@ -3883,48 +3883,24 @@ var via_tile_default = {
3883
3883
  y: 0.582296
3884
3884
  },
3885
3885
  {
3886
- x: 1.31705,
3887
- y: 0.74908
3886
+ x: 1.712721,
3887
+ y: 0.811183
3888
3888
  },
3889
3889
  {
3890
- x: 1.425309,
3891
- y: 0.74908
3890
+ x: 1.712721,
3891
+ y: 1.542957
3892
3892
  },
3893
3893
  {
3894
- x: 1.762721,
3895
- y: 1.086492
3894
+ x: 0.920111,
3895
+ y: 2.335567
3896
3896
  },
3897
3897
  {
3898
- x: 1.762721,
3899
- y: 1.563668
3900
- },
3901
- {
3902
- x: 1.425309,
3903
- y: 1.90108
3904
- },
3905
- {
3906
- x: 1.266397,
3907
- y: 1.90108
3908
- },
3909
- {
3910
- x: 0.781911,
3911
- y: 2.385567
3912
- },
3913
- {
3914
- x: 0.013957,
3915
- y: 2.385567
3916
- },
3917
- {
3918
- x: -0.753066,
3919
- y: 1.618543
3920
- },
3921
- {
3922
- x: -0.753066,
3923
- y: 1.360375
3898
+ x: 0.034666,
3899
+ y: 2.335566
3924
3900
  },
3925
3901
  {
3926
3902
  x: -0.703066,
3927
- y: 1.310375
3903
+ y: 1.597834
3928
3904
  },
3929
3905
  {
3930
3906
  x: -0.703066,
@@ -3947,32 +3923,20 @@ var via_tile_default = {
3947
3923
  y: -1.893395
3948
3924
  },
3949
3925
  {
3950
- x: -2.2,
3951
- y: -1.4
3952
- },
3953
- {
3954
- x: -2.2,
3955
- y: 0.903041
3956
- },
3957
- {
3958
- x: -1.603041,
3959
- y: 1.5
3926
+ x: -2.10103,
3927
+ y: -1.49897
3960
3928
  },
3961
3929
  {
3962
- x: -1.516757,
3963
- y: 1.5
3930
+ x: -2.10103,
3931
+ y: 1.002011
3964
3932
  },
3965
3933
  {
3966
- x: -1.430473,
3967
- y: 1.586284
3934
+ x: -1.708294,
3935
+ y: 1.394747
3968
3936
  },
3969
3937
  {
3970
- x: -0.978975,
3971
- y: 1.586284
3972
- },
3973
- {
3974
- x: -0.703066,
3975
- y: 1.310375
3938
+ x: -0.897813,
3939
+ y: 1.394747
3976
3940
  },
3977
3941
  {
3978
3942
  x: -0.703066,
@@ -3982,81 +3946,37 @@ var via_tile_default = {
3982
3946
  },
3983
3947
  {
3984
3948
  routeId: "Net5:route_0",
3985
- fromPort: "a3797f13-73f9-48c3-a448-bea3980cdd65",
3986
- toPort: "b0c56bb1-ea80-4154-9bb7-cb0fd760de8f",
3949
+ fromPort: "4e57cee8-0910-4c83-9ec1-1ed2c9d16dcc",
3950
+ toPort: "a3797f13-73f9-48c3-a448-bea3980cdd65",
3987
3951
  layer: "bottom",
3988
3952
  segments: [
3989
3953
  {
3990
- x: -1.115754,
3991
- y: -0.799377
3992
- },
3993
- {
3994
- x: -0.764375,
3995
- y: -0.447998
3996
- },
3997
- {
3998
- x: -0.636191,
3999
- y: -0.447998
4000
- },
4001
- {
4002
- x: -0.368136,
4003
- y: -0.179943
4004
- },
4005
- {
4006
- x: -0.368136,
4007
- y: -0.178529
4008
- },
4009
- {
4010
- x: 0.556834,
4011
- y: 0.746441
3954
+ x: 1.268717,
3955
+ y: -1.698536
4012
3956
  },
4013
3957
  {
4014
- x: 0.397934,
4015
- y: 0.905341
3958
+ x: 0.369558,
3959
+ y: -0.799377
4016
3960
  },
4017
3961
  {
4018
- x: 0.397934,
4019
- y: 1.458567
3962
+ x: -1.115754,
3963
+ y: -0.799377
4020
3964
  }
4021
3965
  ]
4022
3966
  },
4023
3967
  {
4024
3968
  routeId: "Net5:route_1",
4025
- fromPort: "4e57cee8-0910-4c83-9ec1-1ed2c9d16dcc",
3969
+ fromPort: "a3797f13-73f9-48c3-a448-bea3980cdd65",
4026
3970
  toPort: "b0c56bb1-ea80-4154-9bb7-cb0fd760de8f",
4027
3971
  layer: "bottom",
4028
3972
  segments: [
4029
3973
  {
4030
- x: 1.268717,
4031
- y: -1.698536
4032
- },
4033
- {
4034
- x: 1.405649,
4035
- y: -1.561604
4036
- },
4037
- {
4038
- x: 1.393076,
4039
- y: -1.561604
4040
- },
4041
- {
4042
- x: 1.055664,
4043
- y: -1.224192
4044
- },
4045
- {
4046
- x: 1.055664,
4047
- y: -0.905992
4048
- },
4049
- {
4050
- x: 0.556834,
4051
- y: -0.407162
4052
- },
4053
- {
4054
- x: 0.556834,
4055
- y: 0.746441
3974
+ x: -1.115754,
3975
+ y: -0.799377
4056
3976
  },
4057
3977
  {
4058
3978
  x: 0.397934,
4059
- y: 0.905341
3979
+ y: 0.714311
4060
3980
  },
4061
3981
  {
4062
3982
  x: 0.397934,
@@ -4114,28 +4034,16 @@ var via_tile_default = {
4114
4034
  x: 0.159346,
4115
4035
  y: 2.034567
4116
4036
  },
4117
- {
4118
- x: 0.06239,
4119
- y: 1.93761
4120
- },
4121
4037
  {
4122
4038
  x: -0.178066,
4123
4039
  y: 1.697155
4124
4040
  },
4125
4041
  {
4126
4042
  x: -0.178066,
4127
- y: 0.824715
4128
- },
4129
- {
4130
- x: -1.042874,
4131
- y: -0.040093
4132
- },
4133
- {
4134
- x: -1.169705,
4135
- y: -0.040093
4043
+ y: 0.981123
4136
4044
  },
4137
4045
  {
4138
- x: -1.209798,
4046
+ x: -1.159189,
4139
4047
  y: 0
4140
4048
  },
4141
4049
  {
@@ -4155,69 +4063,25 @@ var via_tile_default = {
4155
4063
  y: -0.164505
4156
4064
  },
4157
4065
  {
4158
- x: 1.562188,
4159
- y: -0.173664
4160
- },
4161
- {
4162
- x: 1.634312,
4163
- y: -0.173664
4164
- },
4165
- {
4166
- x: 2.207664,
4167
- y: -0.747016
4168
- },
4169
- {
4170
- x: 2.207664,
4171
- y: -1.224192
4172
- },
4173
- {
4174
- x: 1.870252,
4175
- y: -1.561604
4066
+ x: 1.565592,
4067
+ y: -0.164505
4176
4068
  },
4177
4069
  {
4178
- x: 1.844717,
4179
- y: -1.561604
4070
+ x: 2.181408,
4071
+ y: -0.780321
4180
4072
  },
4181
4073
  {
4182
- x: 1.844717,
4183
- y: -1.937124
4074
+ x: 2.181408,
4075
+ y: -1.600433
4184
4076
  },
4185
4077
  {
4186
4078
  x: 1.507305,
4187
4079
  y: -2.274536
4188
4080
  },
4189
4081
  {
4190
- x: 1.030129,
4082
+ x: 0.630282,
4191
4083
  y: -2.274536
4192
4084
  },
4193
- {
4194
- x: 0.692717,
4195
- y: -1.937124
4196
- },
4197
- {
4198
- x: 0.692717,
4199
- y: -1.739534
4200
- },
4201
- {
4202
- x: 0.475553,
4203
- y: -1.739534
4204
- },
4205
- {
4206
- x: 0.470734,
4207
- y: -1.744353
4208
- },
4209
- {
4210
- x: 0.455647,
4211
- y: -1.744353
4212
- },
4213
- {
4214
- x: 0.30246,
4215
- y: -1.89754
4216
- },
4217
- {
4218
- x: 0.253286,
4219
- y: -1.89754
4220
- },
4221
4085
  {
4222
4086
  x: 0.222457,
4223
4087
  y: -1.866711
@@ -4235,23 +4099,15 @@ var via_tile_default = {
4235
4099
  y: -1.866711
4236
4100
  },
4237
4101
  {
4238
- x: 0.208345,
4102
+ x: 0.137528,
4239
4103
  y: -1.866711
4240
4104
  },
4241
4105
  {
4242
- x: 0.2,
4243
- y: -1.858366
4244
- },
4245
- {
4246
- x: 0.2,
4247
- y: -1.2
4248
- },
4249
- {
4250
- x: -0.701789,
4251
- y: -1.2
4106
+ x: -0.329183,
4107
+ y: -1.4
4252
4108
  },
4253
4109
  {
4254
- x: -0.869184,
4110
+ x: -0.361788,
4255
4111
  y: -1.367395
4256
4112
  },
4257
4113
  {
@@ -4259,28 +4115,16 @@ var via_tile_default = {
4259
4115
  y: -1.367395
4260
4116
  },
4261
4117
  {
4262
- x: -1.025859,
4263
- y: -1.375377
4264
- },
4265
- {
4266
- x: -1.354342,
4267
- y: -1.375377
4268
- },
4269
- {
4270
- x: -1.529719,
4271
- y: -1.2
4272
- },
4273
- {
4274
- x: -1.636994,
4275
- y: -1.2
4118
+ x: -1.237643,
4119
+ y: -1.587161
4276
4120
  },
4277
4121
  {
4278
- x: -1.718497,
4279
- y: -1.118497
4122
+ x: -1.587161,
4123
+ y: -1.587161
4280
4124
  },
4281
4125
  {
4282
4126
  x: -1.8,
4283
- y: -1.2
4127
+ y: -1.374322
4284
4128
  },
4285
4129
  {
4286
4130
  x: -1.8,
@@ -4292,19 +4136,11 @@ var via_tile_default = {
4292
4136
  },
4293
4137
  {
4294
4138
  x: -1.80003,
4295
- y: -0.559789
4139
+ y: -0.6
4296
4140
  },
4297
4141
  {
4298
- x: -1.8,
4299
- y: -0.559759
4300
- },
4301
- {
4302
- x: -1.8,
4303
- y: 0.877363
4304
- },
4305
- {
4306
- x: -1.614161,
4307
- y: 1.063202
4142
+ x: -1.80003,
4143
+ y: 0.488423
4308
4144
  },
4309
4145
  {
4310
4146
  x: -1.419706,
@@ -5274,6 +5110,147 @@ function computeCrossingAssignmentsForPolygon(region, port1, port2) {
5274
5110
  return crossingAssignments;
5275
5111
  }
5276
5112
 
5113
+ // lib/ViaGraphSolver/resolveSolvedRoutePoints.ts
5114
+ var POINT_EPSILON = 1e-6;
5115
+ function arePointsEqual(a, b) {
5116
+ return Math.abs(a.x - b.x) <= POINT_EPSILON && Math.abs(a.y - b.y) <= POINT_EPSILON;
5117
+ }
5118
+ function appendPoint(points, point2) {
5119
+ const lastPoint = points[points.length - 1];
5120
+ if (lastPoint && arePointsEqual(lastPoint, point2)) return;
5121
+ points.push(point2);
5122
+ }
5123
+ function findNearestVia(vias, point2) {
5124
+ let bestVia = null;
5125
+ let bestDistance = Infinity;
5126
+ for (const via of vias) {
5127
+ const dx = via.position.x - point2.x;
5128
+ const dy = via.position.y - point2.y;
5129
+ const distance3 = Math.hypot(dx, dy);
5130
+ if (distance3 < bestDistance) {
5131
+ bestDistance = distance3;
5132
+ bestVia = via;
5133
+ }
5134
+ }
5135
+ return bestVia;
5136
+ }
5137
+ function parseViaRegionNetName(regionId) {
5138
+ const marker = ":v:";
5139
+ const markerIndex = regionId.lastIndexOf(marker);
5140
+ if (markerIndex !== -1) {
5141
+ return regionId.slice(markerIndex + marker.length);
5142
+ }
5143
+ const lastColonIndex = regionId.lastIndexOf(":");
5144
+ if (lastColonIndex === -1) return regionId;
5145
+ return regionId.slice(lastColonIndex + 1);
5146
+ }
5147
+ function parseViaRegionTilePrefix(regionId) {
5148
+ const marker = ":v:";
5149
+ const markerIndex = regionId.lastIndexOf(marker);
5150
+ if (markerIndex <= 0) return null;
5151
+ return regionId.slice(0, markerIndex);
5152
+ }
5153
+ function getBottomRouteSegmentsForVias(viaTile, vias) {
5154
+ const viaIdSet = new Set(vias.map((via) => via.viaId));
5155
+ return viaTile.routeSegments.filter(
5156
+ (routeSegment) => routeSegment.layer === "bottom" && viaIdSet.has(routeSegment.fromPort) && viaIdSet.has(routeSegment.toPort) && routeSegment.segments.length >= 2
5157
+ );
5158
+ }
5159
+ function selectViasForTraversedRegion(viaTile, viaRegion) {
5160
+ const netName = parseViaRegionNetName(viaRegion.regionId);
5161
+ if (!netName) return [];
5162
+ const viasForNet = viaTile.viasByNet[netName];
5163
+ if (!viasForNet || viasForNet.length === 0) return [];
5164
+ const tilePrefix = parseViaRegionTilePrefix(viaRegion.regionId);
5165
+ if (!tilePrefix) return viasForNet;
5166
+ const tileScopedVias = viasForNet.filter(
5167
+ (via) => via.viaId.startsWith(`${tilePrefix}:`)
5168
+ );
5169
+ return tileScopedVias.length > 0 ? tileScopedVias : viasForNet;
5170
+ }
5171
+ function normalizeSegmentPoints(points) {
5172
+ const normalized = [];
5173
+ for (const point2 of points) appendPoint(normalized, point2);
5174
+ return normalized;
5175
+ }
5176
+ function appendLineSegment(lineSegments, points, layer) {
5177
+ const normalized = normalizeSegmentPoints(points);
5178
+ if (normalized.length < 2) return;
5179
+ const lastLine = lineSegments[lineSegments.length - 1];
5180
+ if (!lastLine || lastLine.layer !== layer) {
5181
+ lineSegments.push({ points: normalized, layer });
5182
+ return;
5183
+ }
5184
+ const lastPoint = lastLine.points[lastLine.points.length - 1];
5185
+ const firstPoint = normalized[0];
5186
+ if (!lastPoint || !firstPoint || !arePointsEqual(lastPoint, firstPoint)) {
5187
+ lineSegments.push({ points: normalized, layer });
5188
+ return;
5189
+ }
5190
+ const continuation = normalized.slice(1);
5191
+ for (const point2 of continuation) {
5192
+ appendPoint(lastLine.points, point2);
5193
+ }
5194
+ }
5195
+ function flattenLineSegments(lineSegments) {
5196
+ const points = [];
5197
+ for (const lineSegment of lineSegments) {
5198
+ for (const point2 of lineSegment.points) {
5199
+ appendPoint(points, point2);
5200
+ }
5201
+ }
5202
+ return points;
5203
+ }
5204
+ function resolveSolvedRouteLineSegments(solvedRoute, viaTile) {
5205
+ if (solvedRoute.path.length === 0) return [];
5206
+ const path = solvedRoute.path;
5207
+ const lineSegments = [];
5208
+ const drawnViaRegionIds = /* @__PURE__ */ new Set();
5209
+ for (let index = 1; index < path.length; index++) {
5210
+ const previousCandidate = path[index - 1];
5211
+ const currentCandidate = path[index];
5212
+ const previousPoint = {
5213
+ x: previousCandidate.port.d.x,
5214
+ y: previousCandidate.port.d.y
5215
+ };
5216
+ const currentPoint = {
5217
+ x: currentCandidate.port.d.x,
5218
+ y: currentCandidate.port.d.y
5219
+ };
5220
+ const traversedRegion = currentCandidate.lastRegion;
5221
+ const isViaRegionTraversal = !!viaTile && !!traversedRegion?.d?.isViaRegion;
5222
+ if (!isViaRegionTraversal) {
5223
+ appendLineSegment(lineSegments, [previousPoint, currentPoint], "top");
5224
+ continue;
5225
+ }
5226
+ const viasForRegion = selectViasForTraversedRegion(viaTile, traversedRegion);
5227
+ if (viasForRegion.length === 0) continue;
5228
+ const entryVia = findNearestVia(viasForRegion, previousPoint);
5229
+ const exitVia = findNearestVia(viasForRegion, currentPoint);
5230
+ if (entryVia) {
5231
+ appendLineSegment(lineSegments, [previousPoint, entryVia.position], "top");
5232
+ }
5233
+ const bottomRouteSegments = getBottomRouteSegmentsForVias(
5234
+ viaTile,
5235
+ viasForRegion
5236
+ );
5237
+ if (bottomRouteSegments.length > 0 && !drawnViaRegionIds.has(traversedRegion.regionId)) {
5238
+ drawnViaRegionIds.add(traversedRegion.regionId);
5239
+ for (const routeSegment of bottomRouteSegments) {
5240
+ appendLineSegment(lineSegments, routeSegment.segments, "bottom");
5241
+ }
5242
+ }
5243
+ if (exitVia) {
5244
+ appendLineSegment(lineSegments, [exitVia.position, currentPoint], "top");
5245
+ }
5246
+ }
5247
+ return lineSegments;
5248
+ }
5249
+ function resolveSolvedRoutePoints(solvedRoute, viaTile) {
5250
+ const lineSegments = resolveSolvedRouteLineSegments(solvedRoute, viaTile);
5251
+ return flattenLineSegments(lineSegments);
5252
+ }
5253
+
5277
5254
  // lib/ViaGraphSolver/visualizeViaGraphSolver.ts
5278
5255
  var getConnectionColor2 = (connectionId, alpha = 0.8) => {
5279
5256
  let hash = 0;
@@ -5301,6 +5278,8 @@ var NET_COLOR_PALETTE = [
5301
5278
  "rgba(230, 126, 34, 0.35)"
5302
5279
  // dark orange
5303
5280
  ];
5281
+ var BOTTOM_LAYER_TRACE_COLOR = "rgba(52, 152, 219, 0.95)";
5282
+ var BOTTOM_LAYER_TRACE_DASH = "3 2";
5304
5283
  var visualizeViaGraphSolver = (solver) => {
5305
5284
  const graph = {
5306
5285
  regions: solver.graph.regions,
@@ -5380,15 +5359,13 @@ var visualizeViaGraphSolver = (solver) => {
5380
5359
  const connectionColor = getConnectionColor2(
5381
5360
  solvedRoute.connection.connectionId
5382
5361
  );
5383
- const pathPoints = [];
5384
- for (const candidate of solvedRoute.path) {
5385
- const port = candidate.port;
5386
- pathPoints.push({ x: port.d.x, y: port.d.y });
5387
- }
5388
- if (pathPoints.length > 0) {
5362
+ const lineSegments = solver.getSolvedRouteLineSegments(solvedRoute);
5363
+ for (const lineSegment of lineSegments) {
5364
+ const isBottomLayer = lineSegment.layer === "bottom";
5389
5365
  graphics.lines.push({
5390
- points: pathPoints,
5391
- strokeColor: connectionColor
5366
+ points: lineSegment.points,
5367
+ strokeColor: isBottomLayer ? BOTTOM_LAYER_TRACE_COLOR : connectionColor,
5368
+ ...isBottomLayer ? { strokeDash: BOTTOM_LAYER_TRACE_DASH } : {}
5392
5369
  });
5393
5370
  }
5394
5371
  }
@@ -5560,6 +5537,12 @@ var ViaGraphSolver = class extends HyperGraphSolver {
5560
5537
  }
5561
5538
  routeSolvedHook(solvedRoute) {
5562
5539
  }
5540
+ getSolvedRoutePoints(solvedRoute) {
5541
+ return resolveSolvedRoutePoints(solvedRoute, this.viaTile);
5542
+ }
5543
+ getSolvedRouteLineSegments(solvedRoute) {
5544
+ return resolveSolvedRouteLineSegments(solvedRoute, this.viaTile);
5545
+ }
5563
5546
  routeStartedHook(connection) {
5564
5547
  }
5565
5548
  visualize() {
@@ -14860,6 +14843,35 @@ function centroid(points) {
14860
14843
  }
14861
14844
  return { x: cx / points.length, y: cy / points.length };
14862
14845
  }
14846
+ function classifySideFromBounds(point2, bounds) {
14847
+ const distances = {
14848
+ left: Math.abs(point2.x - bounds.minX),
14849
+ right: Math.abs(point2.x - bounds.maxX),
14850
+ bottom: Math.abs(point2.y - bounds.minY),
14851
+ top: Math.abs(point2.y - bounds.maxY)
14852
+ };
14853
+ let bestSide = "left";
14854
+ let bestDistance = distances.left;
14855
+ for (const side of ["right", "bottom", "top"]) {
14856
+ if (distances[side] < bestDistance) {
14857
+ bestSide = side;
14858
+ bestDistance = distances[side];
14859
+ }
14860
+ }
14861
+ return bestSide;
14862
+ }
14863
+ function toCandidateKey(regionId, point2) {
14864
+ return `${regionId}:${point2.x.toFixed(6)},${point2.y.toFixed(6)}`;
14865
+ }
14866
+ function compareCandidateQuality(a, b) {
14867
+ if (Math.abs(a.primaryDistance - b.primaryDistance) > 1e-6) {
14868
+ return b.primaryDistance - a.primaryDistance;
14869
+ }
14870
+ if (Math.abs(a.orthDistance - b.orthDistance) > 1e-6) {
14871
+ return a.orthDistance - b.orthDistance;
14872
+ }
14873
+ return a.key < b.key ? -1 : a.key > b.key ? 1 : 0;
14874
+ }
14863
14875
  function createRegionFromPolygon(regionId, polygon2, opts) {
14864
14876
  const bounds = boundsFromPolygon(polygon2);
14865
14877
  return {
@@ -15048,6 +15060,8 @@ function generateConvexViaTopologyRegions(opts) {
15048
15060
  }
15049
15061
  }
15050
15062
  for (const viaRegion of viaRegions) {
15063
+ const viaCenter = viaRegion.d.center;
15064
+ const candidates = [];
15051
15065
  for (const convexRegion of convexRegions) {
15052
15066
  const sharedEdges = findSharedEdges(
15053
15067
  viaRegion.d.polygon,
@@ -15057,18 +15071,55 @@ function generateConvexViaTopologyRegions(opts) {
15057
15071
  for (const edge of sharedEdges) {
15058
15072
  const portPositions = createPortsAlongEdge(edge, portPitch);
15059
15073
  for (const pos of portPositions) {
15060
- const port = {
15061
- portId: `via-convex:${viaRegion.regionId}-${convexRegion.regionId}:${portIdCounter++}`,
15062
- region1: viaRegion,
15063
- region2: convexRegion,
15064
- d: { x: pos.x, y: pos.y }
15065
- };
15066
- viaRegion.ports.push(port);
15067
- convexRegion.ports.push(port);
15068
- allPorts.push(port);
15074
+ const dx = pos.x - viaCenter.x;
15075
+ const dy = pos.y - viaCenter.y;
15076
+ const side = classifySideFromBounds(pos, viaRegion.d.bounds);
15077
+ const primaryDistance = side === "left" || side === "right" ? Math.abs(dx) : Math.abs(dy);
15078
+ const orthDistance = side === "left" || side === "right" ? Math.abs(dy) : Math.abs(dx);
15079
+ candidates.push({
15080
+ convexRegion,
15081
+ position: pos,
15082
+ side,
15083
+ primaryDistance,
15084
+ orthDistance,
15085
+ key: toCandidateKey(convexRegion.regionId, pos)
15086
+ });
15069
15087
  }
15070
15088
  }
15071
15089
  }
15090
+ if (candidates.length === 0) continue;
15091
+ const selectedCandidates = [];
15092
+ const selectedKeys = /* @__PURE__ */ new Set();
15093
+ const addCandidate = (candidate) => {
15094
+ if (!candidate) return;
15095
+ if (selectedKeys.has(candidate.key)) return;
15096
+ selectedCandidates.push(candidate);
15097
+ selectedKeys.add(candidate.key);
15098
+ };
15099
+ for (const side of ["top", "bottom", "left", "right"]) {
15100
+ const sideCandidate = [...candidates].filter((candidate) => candidate.side === side).sort(compareCandidateQuality)[0];
15101
+ addCandidate(sideCandidate);
15102
+ }
15103
+ if (selectedCandidates.length < 4) {
15104
+ for (const candidate of [...candidates].sort(compareCandidateQuality)) {
15105
+ addCandidate(candidate);
15106
+ if (selectedCandidates.length >= 4) break;
15107
+ }
15108
+ }
15109
+ for (const selectedCandidate of selectedCandidates.slice(0, 4)) {
15110
+ const port = {
15111
+ portId: `via-convex:${viaRegion.regionId}-${selectedCandidate.convexRegion.regionId}:${portIdCounter++}`,
15112
+ region1: viaRegion,
15113
+ region2: selectedCandidate.convexRegion,
15114
+ d: {
15115
+ x: selectedCandidate.position.x,
15116
+ y: selectedCandidate.position.y
15117
+ }
15118
+ };
15119
+ viaRegion.ports.push(port);
15120
+ selectedCandidate.convexRegion.ports.push(port);
15121
+ allPorts.push(port);
15122
+ }
15072
15123
  }
15073
15124
  return {
15074
15125
  regions: allRegions,
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.35",
4
+ "version": "0.0.37",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "start": "cosmos",
@@ -17,7 +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.2",
20
+ "@tscircuit/jumper-topology-generator": "^0.0.4",
21
21
  "@tscircuit/math-utils": "^0.0.29",
22
22
  "@types/bun": "latest",
23
23
  "bun-match-svg": "^0.0.15",
@@ -31,6 +31,7 @@
31
31
  "typescript": "^5"
32
32
  },
33
33
  "dependencies": {
34
+ "@tscircuit/hypergraph": "^0.0.35",
34
35
  "@tscircuit/solver-utils": "^0.0.14"
35
36
  }
36
37
  }