22 HighDensityIntraNodeRoute ,
33 NodeWithPortPoints ,
44} from "lib/types/high-density-types"
5+ import { pointToSegmentDistance } from "@tscircuit/math-utils"
56import { CachedIntraNodeRouteSolver } from "../HighDensitySolver/CachedIntraNodeRouteSolver"
67import { IntraNodeRouteSolver } from "../HighDensitySolver/IntraNodeSolver"
78import {
@@ -324,6 +325,20 @@ export class HyperSingleIntraNodeSolver extends HyperParameterSupervisorSolver<
324325 } else {
325326 routes = solver . solver . solvedRoutes
326327 }
328+
329+ const invalidConnectionName = getFirstConnectionWithUncoveredPortPoint (
330+ routes ,
331+ this . nodeWithPortPoints ,
332+ )
333+ if ( invalidConnectionName ) {
334+ solver . solver . solved = false
335+ solver . solver . failed = true
336+ solver . solver . error = `Solver returned partial intra-node routing for connection "${ invalidConnectionName } " in node "${ this . nodeWithPortPoints . capacityMeshNodeId } "`
337+ this . solved = false
338+ this . winningSolver = undefined
339+ return
340+ }
341+
327342 this . solvedRoutes = routes . map ( ( route ) => {
328343 const matchingPortPoint = this . nodeWithPortPoints . portPoints . find (
329344 ( p ) => p . connectionName === route . connectionName ,
@@ -338,3 +353,66 @@ export class HyperSingleIntraNodeSolver extends HyperParameterSupervisorSolver<
338353 } )
339354 }
340355}
356+
357+ const isSamePoint3 = (
358+ a : { x : number ; y : number ; z : number } ,
359+ b : { x : number ; y : number ; z : number } ,
360+ epsilon = 1e-6 ,
361+ ) =>
362+ Math . abs ( a . x - b . x ) <= epsilon &&
363+ Math . abs ( a . y - b . y ) <= epsilon &&
364+ a . z === b . z
365+
366+ const doesRouteCoverPoint = (
367+ route : Array < { x : number ; y : number ; z : number } > ,
368+ point : { x : number ; y : number ; z : number } ,
369+ ) => {
370+ for ( const routePoint of route ) {
371+ if ( isSamePoint3 ( routePoint , point ) ) return true
372+ }
373+
374+ for ( let i = 0 ; i < route . length - 1 ; i ++ ) {
375+ const A = route [ i ]
376+ const B = route [ i + 1 ]
377+ if ( A . z !== point . z || B . z !== point . z ) continue
378+ if ( pointToSegmentDistance ( point , A , B ) <= 1e-6 ) return true
379+ }
380+
381+ return false
382+ }
383+
384+ const getFirstConnectionWithUncoveredPortPoint = (
385+ routes : HighDensityIntraNodeRoute [ ] ,
386+ nodeWithPortPoints : NodeWithPortPoints ,
387+ ) => {
388+ const routesByConnection = new Map < string , HighDensityIntraNodeRoute [ ] > ( )
389+ for ( const route of routes ) {
390+ if ( ! routesByConnection . has ( route . connectionName ) ) {
391+ routesByConnection . set ( route . connectionName , [ ] )
392+ }
393+ routesByConnection . get ( route . connectionName ) ! . push ( route )
394+ }
395+
396+ const portPointsByConnection = new Map <
397+ string ,
398+ Array < { x : number ; y : number ; z : number } >
399+ > ( )
400+ for ( const portPoint of nodeWithPortPoints . portPoints ) {
401+ if ( ! portPointsByConnection . has ( portPoint . connectionName ) ) {
402+ portPointsByConnection . set ( portPoint . connectionName , [ ] )
403+ }
404+ portPointsByConnection . get ( portPoint . connectionName ) ! . push ( portPoint )
405+ }
406+
407+ for ( const [ connectionName , points ] of portPointsByConnection ) {
408+ const connectionRoutes = routesByConnection . get ( connectionName ) ?? [ ]
409+ const coversAllPoints = points . every ( ( point ) =>
410+ connectionRoutes . some ( ( route ) => doesRouteCoverPoint ( route . route , point ) ) ,
411+ )
412+ if ( ! coversAllPoints ) {
413+ return connectionName
414+ }
415+ }
416+
417+ return null
418+ }
0 commit comments