153 lines
8.0 KiB
GDScript
153 lines
8.0 KiB
GDScript
# text_tail_arrange_test —— §8.8 seam ⑩:ArrangeTextTail item 尾标去重叠 + isIn 1:1。
|
||
# boxes_overlap(isIn 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_overlap(isIn,: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 = 121;ys[1] 不变。
|
||
# 再看 i=1:此时第 1 条已在 y=121(x∈[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;与 2(100)此时已不撞(121 的框 y∈[119,137])。
|
||
# i=1:与 2(100)撞 -> 121;再与已排好的 0(121)撞 -> 121 + 21 = 142。
|
||
# i=2:0 在 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_owner(SetItemTextTailOwner, PythonTextTail.cpp:706-737)------
|
||
# 无 owner(owner_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 -> 退化")
|
||
# 有 owner:yEnd += 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")
|