package routing
import "sort"
type ovgEdgeSet struct {
horizontalEdges map [float64 ][]OVGEdge
verticalEdges map [float64 ][]OVGEdge
horizontals []float64
verticals []float64
edges map [OVGEdge ]struct {}
}
func newOvgEdgeSet() *ovgEdgeSet {
return &ovgEdgeSet {
horizontalEdges : make (map [float64 ][]OVGEdge , 16 ),
verticalEdges : make (map [float64 ][]OVGEdge , 16 ),
horizontals : make ([]float64 , 0 , 16 ),
verticals : make ([]float64 , 0 , 16 ),
edges : make (map [OVGEdge ]struct {}, 16 ),
}
}
func (set *ovgEdgeSet ) insertSortedFloat64 (slice *[]float64 , val float64 ) {
i := sort .SearchFloat64s (*slice , val )
if i < len (*slice ) && (*slice )[i ] == val {
return
}
*slice = append (*slice , 0 )
copy ((*slice )[i +1 :], (*slice )[i :])
(*slice )[i ] = val
}
func (set *ovgEdgeSet ) insertSortedEdge (edges *[]OVGEdge , edge OVGEdge , isVertical bool ) {
getMinCoord := func (e OVGEdge ) float64 {
if isVertical {
if e .From .Y < e .To .Y {
return e .From .Y
}
return e .To .Y
} else {
if e .From .X < e .To .X {
return e .From .X
}
return e .To .X
}
}
edgeMinCoord := getMinCoord (edge )
i := sort .Search (len (*edges ), func (j int ) bool {
return getMinCoord ((*edges )[j ]) >= edgeMinCoord
})
*edges = append (*edges , OVGEdge {})
copy ((*edges )[i +1 :], (*edges )[i :])
(*edges )[i ] = edge
}
func (set *ovgEdgeSet ) add (edge *OVGEdge ) {
if _ , exists := set .edges [*edge ]; exists {
return
}
set .edges [*edge ] = struct {}{}
if edge .isVertical () {
if _ , exists := set .verticalEdges [edge .From .X ]; !exists {
set .verticalEdges [edge .From .X ] = make ([]OVGEdge , 0 , 16 )
set .insertSortedFloat64 (&set .verticals , edge .From .X )
}
edges := set .verticalEdges [edge .From .X ]
set .insertSortedEdge (&edges , *edge , true )
set .verticalEdges [edge .From .X ] = edges
} else if edge .isHorizontal () {
if _ , exists := set .horizontalEdges [edge .From .Y ]; !exists {
set .horizontalEdges [edge .From .Y ] = make ([]OVGEdge , 0 , 16 )
set .insertSortedFloat64 (&set .horizontals , edge .From .Y )
}
edges := set .horizontalEdges [edge .From .Y ]
set .insertSortedEdge (&edges , *edge , false )
set .horizontalEdges [edge .From .Y ] = edges
}
}
func (set *ovgEdgeSet ) addGuarded (edge *OVGEdge , guard workBudget ) error {
if err := guard .step (); err != nil {
return err
}
if _ , exists := set .edges [*edge ]; exists {
return nil
}
if edge .isVertical () {
if _ , exists := set .verticalEdges [edge .From .X ]; !exists {
if err := guard .add (uint64 (len (set .verticals )) + 1 ); err != nil {
return err
}
}
if err := guard .add (uint64 (len (set .verticalEdges [edge .From .X ])) + 1 ); err != nil {
return err
}
} else if edge .isHorizontal () {
if _ , exists := set .horizontalEdges [edge .From .Y ]; !exists {
if err := guard .add (uint64 (len (set .horizontals )) + 1 ); err != nil {
return err
}
}
if err := guard .add (uint64 (len (set .horizontalEdges [edge .From .Y ])) + 1 ); err != nil {
return err
}
}
set .add (edge )
return guard .check ()
}
func (set *ovgEdgeSet ) intersectsWithGuarded (edge *OVGEdge , guard workBudget ) (bool , error ) {
return set .intersectsWithChecked (edge , guard )
}
func (set *ovgEdgeSet ) intersectsWithChecked (edge *OVGEdge , guard workBudget ) (bool , error ) {
step := func () error {
if guard == nil {
return nil
}
return guard .step ()
}
if edge .isHorizontal () {
minX , maxX := edge .From .X , edge .To .X
if maxX < minX {
minX , maxX = maxX , minX
}
for _ , e := range set .horizontalEdges [edge .From .Y ] {
if err := step (); err != nil {
return false , err
}
if e .From .X < e .To .X {
if maxX <= e .From .X {
break
}
if e .To .X <= minX {
continue
}
} else {
if maxX <= e .To .X {
break
}
if e .From .X <= minX {
continue
}
}
if !edge .sharePoints (e ) {
return true , nil
}
}
y := edge .From .Y
start := sort .Search (len (set .verticals ), func (i int ) bool { return !(set .verticals [i ] < minX ) })
if err := chargeSkippedRouteWork (guard , start ); err != nil {
return false , err
}
for _ , lineCoordinate := range set .verticals [start :] {
if err := step (); err != nil {
return false , err
}
if lineCoordinate < minX {
continue
}
if maxX < lineCoordinate {
break
}
for _ , e := range set .verticalEdges [lineCoordinate ] {
if err := step (); err != nil {
return false , err
}
if e .From .Y < e .To .Y {
if y < e .From .Y {
break
}
if e .To .Y < y {
continue
}
} else {
if y < e .To .Y {
break
}
if e .From .Y < y {
continue
}
}
if !edge .sharePoints (e ) {
return true , nil
}
}
}
} else if edge .isVertical () {
minY , maxY := edge .From .Y , edge .To .Y
if maxY < minY {
minY , maxY = maxY , minY
}
for _ , e := range set .verticalEdges [edge .From .X ] {
if err := step (); err != nil {
return false , err
}
if e .From .Y < e .To .Y {
if maxY <= e .From .Y {
break
}
if e .To .Y <= minY {
continue
}
} else {
if maxY <= e .To .Y {
break
}
if e .From .Y <= minY {
continue
}
}
if !edge .sharePoints (e ) {
return true , nil
}
}
x := edge .From .X
start := sort .Search (len (set .horizontals ), func (i int ) bool { return !(set .horizontals [i ] < minY ) })
if err := chargeSkippedRouteWork (guard , start ); err != nil {
return false , err
}
for _ , lineCoordinate := range set .horizontals [start :] {
if err := step (); err != nil {
return false , err
}
if lineCoordinate < minY {
continue
}
if maxY < lineCoordinate {
break
}
for _ , e := range set .horizontalEdges [lineCoordinate ] {
if err := step (); err != nil {
return false , err
}
if e .From .X < e .To .X {
if x < e .From .X {
break
}
if e .To .X < x {
continue
}
} else {
if x < e .To .X {
break
}
if e .From .X < x {
continue
}
}
if !edge .sharePoints (e ) {
return true , nil
}
}
}
}
return false , nil
}
func (set *ovgEdgeSet ) overlappingEdgesGuarded (edge *OVGEdge , guard workBudget ) ([]OVGEdge , error ) {
return set .overlappingEdgesChecked (edge , guard )
}
func (set *ovgEdgeSet ) overlappingEdgesChecked (edge *OVGEdge , guard workBudget ) ([]OVGEdge , error ) {
var overlapping []OVGEdge
var maybeOverlap []OVGEdge
if edge .isVertical () {
maybeOverlap = set .verticalEdges [edge .From .X ]
} else if edge .isHorizontal () {
maybeOverlap = set .horizontalEdges [edge .From .Y ]
}
for _ , e := range maybeOverlap {
if guard != nil {
if err := guard .step (); err != nil {
return nil , err
}
}
if intersects (edge .From .Point , edge .To .Point , e .From .Point , e .To .Point ) {
overlapping = append (overlapping , e )
}
}
return overlapping , nil
}
The pages are generated with Golds v0.8.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .