File size: 3,831 Bytes
96d4c08
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f2b4b4e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e8d38ed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
from buddy_fusion.assembler import bbox, assemble_part

# A 2x2x2 cube centered at origin, sitting on the ground.
CUBE = [{"x": 0, "y": 0, "z": 0, "w": 2, "h": 2, "d": 2, "color": "#888888"}]


def test_bbox_center_x_bottom_y():
    minx, maxx, miny, maxy, minz, maxz = bbox(CUBE)
    assert (minx, maxx) == (-1, 1)
    assert (miny, maxy) == (0, 2)
    assert (minz, maxz) == (-1, 1)


def test_assemble_appends_and_keeps_original():
    out = assemble_part(CUBE, "horns", "top", 1, None)
    assert out[: len(CUBE)] == CUBE          # original preserved, prepended
    assert len(out) > len(CUBE)              # part boxes appended


def test_top_anchor_sits_on_top():
    out = assemble_part(CUBE, "horns", "top", 1, None)
    added = out[len(CUBE):]
    assert min(b["y"] for b in added) >= 2   # at or above the creature's max-y


def test_symmetric_part_is_mirrored():
    out = assemble_part(CUBE, "horns", "top", 1, None)
    added = out[len(CUBE):]
    xs = {b["x"] for b in added}
    assert any(x < 0 for x in xs) and any(x > 0 for x in xs)  # both sides present


def test_scale_enlarges_part_footprint():
    small = assemble_part(CUBE, "house", "rear", 1, None)[len(CUBE):]
    big = assemble_part(CUBE, "house", "rear", 2, None)[len(CUBE):]
    assert max(b["w"] for b in big) >= max(b["w"] for b in small)


def test_color_override_recolors_added_boxes():
    out = assemble_part(CUBE, "house", "rear", 1, "#ff0000")
    added = out[len(CUBE):]
    assert all(b["color"] == "#ff0000" for b in added)


def test_unknown_part_returns_original_unchanged():
    assert assemble_part(CUBE, "nope", "top", 1, None) == CUBE


def _cell_count(boxes):
    return sum(b["w"] * b["h"] * b["d"] for b in boxes)


def test_float_scale_grows_cell_count():
    one = assemble_part(CUBE, "house", "rear", 1.0, None)[len(CUBE):]
    big = assemble_part(CUBE, "house", "rear", 1.5, None)[len(CUBE):]
    assert _cell_count(big) > _cell_count(one)


def test_count_distributes_more_instances():
    one = assemble_part(CUBE, "tail", "rear", 1, None, count=1)[len(CUBE):]
    three = assemble_part(CUBE, "tail", "rear", 1, None, count=3)[len(CUBE):]
    assert _cell_count(three) > _cell_count(one) * 2  # roughly 3x the geometry


def test_rotation_preserves_cell_count():
    base = assemble_part(CUBE, "horns", "top", 1, None)[len(CUBE):]
    rot = assemble_part(CUBE, "horns", "top", 1, None, rotation=("y", 1))[len(CUBE):]
    assert _cell_count(rot) == _cell_count(base)  # rotation moves cells, never drops them


BIG = [{"x": 0, "y": 0, "z": 0, "w": 6, "h": 6, "d": 6, "color": "#caa06f"}]


def test_repeated_add_accumulates_not_stacks():
    once = assemble_part(BIG, "wing_bird", "left", 1, None)
    twice = assemble_part(once, "wing_bird", "left", 1, None)
    p1 = [b for b in once if b.get("_part") == "wing_bird"]
    p2 = [b for b in twice if b.get("_part") == "wing_bird"]
    assert p1[0]["_pc"] == 1 and p2[0]["_pc"] == 2          # instance count accumulates
    assert _cell_count(p2) == 2 * _cell_count(p1)           # two instances, not one piled twice
    # the second add re-distributes along z (front-back), not the same spot
    assert len({b["z"] for b in p2}) > len({b["z"] for b in p1})


def test_symmetric_part_straddles_both_faces():
    out = assemble_part(BIG, "wing_bird", "left", 1, None)
    added = [b for b in out if b.get("_part") == "wing_bird"]
    assert any(b["x"] < 0 for b in added) and any(b["x"] > 0 for b in added)  # both sides


def test_distribution_hugs_body_extent():
    # four instances stay within (roughly) the body's z footprint, not flung far out
    out = assemble_part(BIG, "wing_bird", "left", 1, None, count=4)
    zs = [b["z"] for b in out if b.get("_part") == "wing_bird"]
    assert min(zs) >= -6 and max(zs) <= 6  # body z is -3..3; parts fan within a tight margin