package engine
import (
"context"
"fmt"
"math/rand"
"github.com/pancsta/d2/d2layouts/d2talalayout/internal/hierarchy"
"github.com/pancsta/d2/d2layouts/d2talalayout/internal/layoutgraph"
"github.com/pancsta/d2/d2layouts/d2talalayout/internal/placement"
)
func CompoundCandidate (ctx context .Context , graph *layoutgraph .Graph ) (*layoutgraph .Graph , error ) {
if ctx == nil || graph == nil {
return nil , fmt .Errorf ("TALA compound candidate requires a context and graph" )
}
if err := ctx .Err (); err != nil {
return nil , err
}
if len (graph .Nodes ) > 128 || len (graph .Edges ) > 256 || len (graph .Containers [nil ]) < 3 || len (graph .Containers [nil ]) > 64 {
return graph , nil
}
detailed := false
for _ , node := range graph .Containers [nil ] {
detailed = detailed || node .IsContainer ()
}
if !detailed || graph .HasFixedNode () {
return graph , nil
}
candidate , err := layoutgraph .Clone (ctx , graph )
if err != nil {
return nil , err
}
changed , err := hierarchy .PlaceCompound (ctx , candidate , rand .New (rand .NewSource (0 )))
if err != nil {
return nil , err
}
if !changed {
return graph , nil
}
worseAlignment := compoundCrossAxisDetours (candidate ) > compoundCrossAxisDetours (graph )
if err := ctx .Err (); err != nil {
return nil , err
}
if worseAlignment {
return graph , nil
}
if err := reroutePlaced (ctx , candidate ); err != nil {
return nil , err
}
tl , br := candidate .BoundingBox ()
if tl != nil && br != nil && (br .X -tl .X > maxGraphSize || br .Y -tl .Y > maxGraphSize ) {
return graph , nil
}
return candidate , nil
}
func compoundCrossAxisDetours(g *layoutgraph .Graph ) int {
rootOf := make (map [*layoutgraph .Node ]*layoutgraph .Node , len (g .Nodes ))
for _ , n := range g .Nodes {
root := n
for root .Container != nil {
root = root .Container
}
rootOf [n ] = root
}
horizontal := g .Direction (nil ).IsHorizontal ()
detours := 0
for _ , edge := range g .Edges {
from , to := rootOf [edge .From ], rootOf [edge .To ]
if from == to {
continue
}
if horizontal {
if from .TopLeft .Y +from .Height < to .TopLeft .Y || to .TopLeft .Y +to .Height < from .TopLeft .Y {
detours ++
}
} else if from .TopLeft .X +from .Width < to .TopLeft .X || to .TopLeft .X +to .Width < from .TopLeft .X {
detours ++
}
}
return detours
}
func reroutePlaced(ctx context .Context , g *layoutgraph .Graph ) error {
p := newPipeline (g , 0 , false )
p .resetFullLayoutRouteState ()
stages := []func (context .Context ) error {
p .edgeRoutingStage , p .simplifyEdgeRoutes , p .swapEdgePorts ,
p .straightEdgesFallback , p .balanceEdgeSegments ,
p .fixClusterEdgeBranching , p .traceEdgesToShapeBorder ,
p .reorderDuplicates , p .placeLabels ,
}
for _ , stage := range stages {
if err := ctx .Err (); err != nil {
return err
}
if err := stage (ctx ); err != nil {
return err
}
}
if !g .HasFixedNode () {
placement .Normalize (g )
}
return ctx .Err ()
}
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 .