// Package quality evaluates completed TALA layouts. It reads layoutgraph's // positioned graph model without mutating it; lower scores are better.
package quality import ( ) // EvaluateWithArea returns the human-facing layout score and the graph area // separately. Area is a strict tie-breaker: encoding it into the float score // made 100 smaller than 99 (0.1 versus 0.99) and could outweigh real layout // differences. func ( context.Context, *layoutgraph.Graph) (float64, float64, error) { , , , := evaluateWithAreaLimit(, , maxEvaluationWorkUnits) return , , } func evaluateWithAreaLimit( context.Context, *layoutgraph.Graph, int64) (float64, float64, int64, error) { if == nil { return 0, 0, 0, fmt.Errorf("cannot evaluate a nil graph") } // Keep this preflight at the quality boundary so candidate evaluation and // direct internal callers receive the same resource bounds. // It runs before label-overlap scratch slices and maps are constructed. if := layoutgraph.ValidatePositionedGraph(, "Evaluate", ); != nil { return 0, 0, 0, } , := newEvaluationWorkGuard(, ) if != nil { return 0, 0, 0, } := 0.0 for , := range .Edges { if := .Step(); != nil { return 0, 0, .Used(), } if .From.Cluster != nil || .To.Cluster != nil { continue } := float64(max(0, len(.Points)-2)) += * 0.5 for := 0; < len(.Points)-1; ++ { if := .Step(); != nil { return 0, 0, .Used(), } := .Points[] := .Points[+1] // Extra penalty for diagonals if .X != .X && .Y != .Y { += 3 } } } , := countNonSharedCrossings(.Edges, ) if != nil { return 0, 0, .Used(), } += float64() , := scoreExistingLabelPlacements(, ) if != nil { return 0, 0, .Used(), } += 1.0 - if := chargeEvaluationAreaWork(, ); != nil { return 0, 0, .Used(), } := .Area() if := .Finish(); != nil { return 0, 0, .Used(), } return , , .Used(), nil }