package bsp import ( "math" "testing" "bspviz/internal/geom" ) func TestStopUsesDefaults(t *testing.T) { segs := make([]geom.Seg, 13) if stop(segs, 0, Params{}) { t.Fatalf("stop should continue when using default LeafMax with 13 segs") } if !stop(segs, 33, Params{}) { t.Fatalf("stop should trigger when depth exceeds default MaxDepth") } } func TestEvalCostSplitsAndBalance(t *testing.T) { line := []geom.Seg{ {A: geom.V(-1, 1), B: geom.V(1, 1)}, {A: geom.V(-1, -1), B: geom.V(1, -1)}, {A: geom.V(-1, -1), B: geom.V(1, 1)}, } p := Params{Alpha: 10, Beta: 2, Eps: geom.EPS} splits, balance, cost := evalCost(line, geom.V(0, 0), geom.V(1, 0), p) if splits != 1 { t.Fatalf("splits=%d want 1", splits) } if balance != 0 { t.Fatalf("balance=%d want 0", balance) } if cost != 10 { t.Fatalf("cost=%v want 10", cost) } } func TestSplitAllProducesFrontAndBack(t *testing.T) { segs := []geom.Seg{{A: geom.V(-1, -1), B: geom.V(1, 1)}} left, right, splits := splitAll(segs, geom.V(0, 0), geom.V(1, 0), Params{Eps: geom.EPS}) if splits != 1 { t.Fatalf("splits=%d want 1", splits) } if len(left) != 1 || len(right) != 1 { t.Fatalf("expected split into two segments, left=%d right=%d", len(left), len(right)) } share := func(a, b geom.Vec) bool { return math.Abs(a.X-b.X) < geom.EPS && math.Abs(a.Y-b.Y) < geom.EPS } if !share(left[0].A, right[0].B) && !share(left[0].B, right[0].A) { t.Fatalf("split point mismatch") } } func TestBuildRespectsLeafAndDepth(t *testing.T) { segs := []geom.Seg{ {A: geom.V(-2, -2), B: geom.V(2, -2)}, {A: geom.V(2, -2), B: geom.V(2, 2)}, {A: geom.V(2, 2), B: geom.V(-2, 2)}, {A: geom.V(-2, 2), B: geom.V(-2, -2)}, {A: geom.V(-2, -2), B: geom.V(2, 2)}, {A: geom.V(-2, 2), B: geom.V(2, -2)}, } p := Params{LeafMax: 2, MaxDepth: 3, Seed: 1, Cands: 4, Alpha: 5, Beta: 1, Eps: geom.EPS} root := Build(segs, p) if root == nil { t.Fatalf("Build returned nil") } stats := Measure(root) if stats.MaxDepth > p.MaxDepth { t.Fatalf("MaxDepth=%d exceeds limit %d", stats.MaxDepth, p.MaxDepth) } if stats.Leaves == 0 { t.Fatalf("expected some leaves in tree") } verifyLeaves(t, root, 0, p) } func verifyLeaves(t *testing.T, n *Node, depth int, p Params) { t.Helper() if n == nil { return } if n.Leaf != nil { if depth < p.MaxDepth && len(n.Leaf.Segs) > p.LeafMax { t.Fatalf("leaf at depth %d has %d segs (limit %d)", depth, len(n.Leaf.Segs), p.LeafMax) } return } if depth >= p.MaxDepth { t.Fatalf("internal node at depth %d exceeds MaxDepth %d", depth, p.MaxDepth) } verifyLeaves(t, n.Left, depth+1, p) verifyLeaves(t, n.Right, depth+1, p) }