Files
mtgodot-poc/project/text_tail_arrange_test.gd
T

153 lines
8.0 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# text_tail_arrange_test —— §8.8 seam ⑩:ArrangeTextTail item 尾标去重叠 + isIn 1:1。
# boxes_overlapisIn AABB,含边界)、box_* 四边(-w/2-2 / w/2+2 / -2 / h)、
# arrange_item_tails(单条不动 / 两条不叠不动 / 两条叠 -> 后者顶到前者框底下 /
# 级联下推 / 病态全同位收敛在 MAX_ITERS 内)、
# item_box_with_owner(增量 125:无 owner 退化 / 有 owner -> h += ownerH + 4、
# owner 更宽时 w = ownerW - 2 使 box_end_x == ownerW/2 + 1)。
# godot --headless --path project --script text_tail_arrange_test.gd
# 退出码 0 = 全过。
extends SceneTree
const TextTailArrange = preload("res://text_tail_arrange.gd")
var _fail := 0
func _ck(c: bool, m: String) -> void:
if not c:
_fail += 1
printerr("FAIL: " + m)
func _feq(a: float, b: float, m: String) -> void:
_ck(absf(a - b) < 0.0001, "%s (got %f want %f)" % [m, a, b])
func _init() -> void:
_run()
if _fail == 0:
print("PASS: text_tail_arrange_test (§8.8 seam ⑩ ArrangeTextTail item 尾标去重叠 + isIn 1:1)")
quit(0)
else:
printerr("%d check(s) failed" % _fail)
quit(1)
func _run() -> void:
# --- 0. 常量 -------------------------------------------------------------
_feq(TextTailArrange.PUSH_GAP, 5.0, "PUSH_GAP = yTemp = 5:164")
_feq(TextTailArrange.MAX_ITERS, 20.0, "MAX_ITERS = LimitCount 上限 20:176")
# --- 1. 框四边(PythonTextTail.cpp:810-813----------------------------
_feq(TextTailArrange.box_start_x(40.0), -40.0 / 2.0 - 2.0, "xStart = -w/2 - 2 = -22")
_feq(TextTailArrange.box_end_x(40.0), 40.0 / 2.0 + 2.0, "xEnd = w/2 + 2 = 22")
_feq(TextTailArrange.box_start_y(), -2.0, "yStart = -2")
_feq(TextTailArrange.box_end_y(16.0), 16.0, "yEnd = h = 16")
# --- 2. boxes_overlapisIn:489-507-------------------------------
var a := {"x": 100.0, "y": 100.0, "w": 40.0, "h": 16.0} # x∈[78,122] y∈[98,116]
var b_hit := {"x": 110.0, "y": 105.0, "w": 40.0, "h": 16.0} # x∈[88,132] y∈[103,121]
_ck(TextTailArrange.boxes_overlap(a, b_hit), "x、y 都交叠 -> 相交")
_ck(TextTailArrange.boxes_overlap(b_hit, a), "isIn 对称")
# 边界相接:inclusive <= / >= -> 视为相交
var b_edge := {"x": 100.0 + 44.0, "y": 100.0, "w": 40.0, "h": 16.0} # x1T = 144-22 = 122 == x2S
_ck(TextTailArrange.boxes_overlap(a, b_edge), "边界相接(x2S == x1T)含边界 -> 相交")
# x 完全分离
var b_farx := {"x": 100.0 + 45.0, "y": 100.0, "w": 40.0, "h": 16.0} # x1T = 145-22 = 123 > 122
_ck(not TextTailArrange.boxes_overlap(a, b_farx), "x 分离 -> 不相交")
# y 完全分离
var b_fary := {"x": 100.0, "y": 100.0 + 40.0, "w": 40.0, "h": 16.0} # y1T = 140-2 = 138 > 116
_ck(not TextTailArrange.boxes_overlap(a, b_fary), "y 分离 -> 不相交")
# --- 3. arrange_item_tails ---------------------------------------------
# 单条:不动
var one := [{"x": 100.0, "y": 100.0, "w": 40.0, "h": 16.0}]
_feq(TextTailArrange.arrange_item_tails(one)[0], 100.0, "单条 -> y 不变")
# 两条不叠:都不动
var two_far := [
{"x": 100.0, "y": 100.0, "w": 40.0, "h": 16.0},
{"x": 100.0, "y": 300.0, "w": 40.0, "h": 16.0},
]
var r_far := TextTailArrange.arrange_item_tails(two_far)
_feq(r_far[0], 100.0, "不叠 -> 第 1 条不变")
_feq(r_far[1], 300.0, "不叠 -> 第 2 条不变")
# 两条叠:外层先处理 i=0 —— 与 j=1 相交,把「自己」(第 1 条)顶到第 2 条框底下。
# ys[0] = ys[1] + yEnd(第2条=16) + PUSH_GAP(5) = 100 + 16 + 5 = 121ys[1] 不变。
# 再看 i=1:此时第 1 条已在 y=121x∈[78,122] y∈[119,137]),第 2 条 y=100
# y∈[98,116])——115? 119 > 116 -> 不再相交,第 2 条不动。
var two_hit := [
{"x": 100.0, "y": 100.0, "w": 40.0, "h": 16.0},
{"x": 100.0, "y": 100.0, "w": 40.0, "h": 16.0},
]
var r_hit := TextTailArrange.arrange_item_tails(two_hit)
_feq(r_hit[0], 100.0 + 16.0 + 5.0, "两条同位 -> 第 1 条被顶到 121")
_feq(r_hit[1], 100.0, "两条同位 -> 第 2 条留原位")
_ck(not TextTailArrange.boxes_overlap(
{"x": 100.0, "y": r_hit[0], "w": 40.0, "h": 16.0},
{"x": 100.0, "y": r_hit[1], "w": 40.0, "h": 16.0}),
"排布后两框不再相交")
# 三条同位。逐条各自移动自己(参考端每个 pInsert 只改自己的 y):
# i=0:与 1 撞 -> ys[0] = 100 + 16 + 5 = 121;与 2100)此时已不撞(121 的框 y∈[119,137])。
# i=1:与 2100)撞 -> 121;再与已排好的 0121)撞 -> 121 + 21 = 142。
# i=20 在 121、1 在 142,都在 100 上方(y 更大 = 屏幕更下),100 的槽已空出 -> 第 3 条不动。
# 结果 [121, 142, 100]:三框互不相交(100→[98,116]、121→[119,137]、142→[140,158])。
var three := [
{"x": 100.0, "y": 100.0, "w": 40.0, "h": 16.0},
{"x": 100.0, "y": 100.0, "w": 40.0, "h": 16.0},
{"x": 100.0, "y": 100.0, "w": 40.0, "h": 16.0},
]
var r3 := TextTailArrange.arrange_item_tails(three)
_feq(r3[0], 121.0, "三条同位 -> 第 1 条 121")
_feq(r3[1], 142.0, "三条同位 -> 第 2 条 142")
_feq(r3[2], 100.0, "三条同位 -> 第 3 条留原位(前两条已让开)")
# 两两不再相交
for p in [[0, 1], [0, 2], [1, 2]]:
_ck(not TextTailArrange.boxes_overlap(
{"x": 100.0, "y": r3[p[0]], "w": 40.0, "h": 16.0},
{"x": 100.0, "y": r3[p[1]], "w": 40.0, "h": 16.0}),
"三条排布后 %d/%d 不相交" % p)
# 病态:很多条全同位 —— 单条被下推次数封顶 MAX_ITERS,函数必然返回(不死循环)。
var many: Array = []
for k in 40:
many.append({"x": 0.0, "y": 0.0, "w": 30.0, "h": 12.0})
var rm := TextTailArrange.arrange_item_tails(many)
_ck(rm.size() == 40, "40 条全同位 -> 正常返回 40 个 y(未死循环)")
# 第 1 条只需 1 次下推就让开其余全部(它们都还在 y=0):0 + 12 + 5 = 17。
_feq(rm[0], 17.0, "第 1 条一次下推到 17")
# 靠后的条目下推次数封顶 MAX_ITERS:每次至多 +12 + 5= 17 -> <= 340。
for k in 40:
_ck(rm[k] <= (12.0 + 5.0) * TextTailArrange.MAX_ITERS + 0.001,
"第 %d 条下推量不超过 MAX_ITERS * (h + gap) = 340" % (k + 1))
# --- 4. 列表顺序即 m_ItemTextTailList 顺序:靠前的先让位(各自移动自己)-------
var ordered := [
{"x": 50.0, "y": 200.0, "w": 20.0, "h": 10.0},
{"x": 50.0, "y": 203.0, "w": 20.0, "h": 10.0},
]
var ro := TextTailArrange.arrange_item_tails(ordered)
_ck(ro[0] > ro[1], "靠前的条目被顶到靠后条目下方(参考端各 pInsert 移动自己)")
_feq(ro[1], 203.0, "靠后的条目保持原位")
# --- 5. item_box_with_ownerSetItemTextTailOwner, PythonTextTail.cpp:706-737------
# 无 ownerowner_w / owner_h <= 0-> 退化为纯名字框
var b0 := TextTailArrange.item_box_with_owner(40.0, 16.0)
_feq(b0["w"], 40.0, "无 owner -> w = name_w")
_feq(b0["h"], 16.0, "无 owner -> h = name_h")
_feq(TextTailArrange.item_box_with_owner(40.0, 16.0, 0.0, 12.0)["h"], 16.0, "owner_w<=0 -> 退化")
_feq(TextTailArrange.item_box_with_owner(40.0, 16.0, 30.0, 0.0)["h"], 16.0, "owner_h<=0 -> 退化")
# 有 owneryEnd += ownerH + 4:735
var bo := TextTailArrange.item_box_with_owner(40.0, 16.0, 30.0, 12.0)
_feq(bo["h"], 16.0 + 12.0 + 4.0, "有 owner -> h = name_h + owner_h + 4 = 32")
_feq(bo["w"], 40.0, "owner 比名字窄 -> w 仍 = name_w")
_feq(TextTailArrange.box_end_x(bo["w"]), 40.0 / 2.0 + 2.0, "owner 窄 -> box_end_x(w) == nameW/2 + 2")
# owner 比名字宽 -> box_end_x 收进 fMAX(nameW/2+2, ownerW/2+1):737-> w = owner_w - 2
var bw := TextTailArrange.item_box_with_owner(20.0, 16.0, 50.0, 12.0)
_feq(bw["w"], 50.0 - 2.0, "owner 更宽 -> w = owner_w - 2 = 48")
_feq(TextTailArrange.box_end_x(bw["w"]), 50.0 / 2.0 + 1.0, "-> box_end_x(w) == ownerW/2 + 1(参考 :737 fMAX")
# 顶到带 owner 的框底下时 push = yEnd + PUSH_GAP
var stacked := [
{"x": 0.0, "y": 0.0, "w": 20.0, "h": 16.0},
{"x": 0.0, "y": 0.0, "w": bo["w"], "h": bo["h"]},
]
_feq(TextTailArrange.arrange_item_tails(stacked)[0], bo["h"] + TextTailArrange.PUSH_GAP,
"靠前条被顶到带 owner 框底下 = (name_h + owner_h + 4) + PUSH_GAP = 37")