#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 测试脚本:验证子节点的选择框和坐标轴跟随父模型移动 """ import sys import os sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) from main import MyWorld from panda3d.core import Vec3, Point3, CardMaker, GeomNode from direct.task.TaskManagerGlobal import taskMgr import time def getWorldCenter(nodePath, render): """获取节点在世界坐标系中的边界框中心""" minPoint = Point3() maxPoint = Point3() if nodePath.calcTightBounds(minPoint, maxPoint, render): return Point3((minPoint.x + maxPoint.x) * 0.5, (minPoint.y + maxPoint.y) * 0.5, (minPoint.z + maxPoint.z) * 0.5) return Point3(0, 0, 0) def test_selection_follow(): """测试子节点选择框和坐标轴跟随父模型移动""" print("=== 测试子节点选择框和坐标轴跟随 ===") # 创建世界 world = MyWorld() # 创建主父节点 parent = world.render.attachNewNode("parent_model") # 创建子节点1 - 一个简单的几何体 cm1 = CardMaker("child1_card") cm1.setFrame(-1, 1, -1, 1) child1 = parent.attachNewNode(cm1.generate()) child1.setName("child1") child1.setPos(2, 0, 0) # 相对于父节点的位置 child1.setColor(1, 0, 0, 1) # 红色 # 创建子节点2 - 另一个几何体 cm2 = CardMaker("child2_card") cm2.setFrame(-0.5, 0.5, -0.5, 0.5) child2 = parent.attachNewNode(cm2.generate()) child2.setName("child2") child2.setPos(-2, 0, 1) # 相对于父节点的位置 child2.setColor(0, 1, 0, 1) # 绿色 # 设置父节点的初始位置 parent.setPos(0, 0, 0) # 将父节点添加到模型列表(这样它可以被选择) world.models.append(parent) world.models.append(child1) world.models.append(child2) print(f"创建了父节点: {parent.getName()}") print(f"创建了子节点1: {child1.getName()}, 位置: {child1.getPos()}") print(f"创建了子节点2: {child2.getName()}, 位置: {child2.getPos()}") # 选择子节点1 print("\n--- 选择子节点1 ---") world.selection.updateSelection(child1) print(f"子节点1的相对边界框: {child1.getBounds()}") # 获取移动后的世界边界框 minPoint = Point3() maxPoint = Point3() if child1.calcTightBounds(minPoint, maxPoint, world.render): print(f"子节点1的世界边界框: min={minPoint}, max={maxPoint}") else: print("子节点1无法计算世界边界框") # 移动父节点 print("\n--- 移动父节点到新位置 ---") new_parent_pos = Vec3(5, 3, 2) parent.setPos(new_parent_pos) print(f"父节点新位置: {parent.getPos()}") print(f"子节点1的相对边界框: {child1.getBounds()}") # 获取移动后的世界边界框 minPoint = Point3() maxPoint = Point3() if child1.calcTightBounds(minPoint, maxPoint, world.render): print(f"子节点1的世界边界框: min={minPoint}, max={maxPoint}") else: print("子节点1无法计算世界边界框") # 等待一帧,让更新任务运行 def check_after_move(task): print("\n--- 检查移动后的状态 ---") # 检查选择框是否跟随 if world.selection.selectionBox: # 获取选择框目标的世界边界框 minPoint = Point3() maxPoint = Point3() if world.selection.selectionBoxTarget.calcTightBounds(minPoint, maxPoint, world.render): print(f"选择框目标的世界边界框: min={minPoint}, max={maxPoint}") print(f"选择框是否存在: {world.selection.selectionBox is not None}") # 检查坐标轴是否跟随 if world.selection.gizmo: gizmo_pos = world.selection.gizmo.getPos() print(f"坐标轴位置: {gizmo_pos}") # 验证坐标轴是否在正确的位置 expected_center = getWorldCenter(child1, world.render) print(f"期望的坐标轴位置: {expected_center}") # 计算位置差异 diff = (gizmo_pos - expected_center).length() print(f"坐标轴位置差异: {diff}") if diff < 0.1: # 允许小的浮点误差 print("✓ 坐标轴正确跟随了父模型移动") else: print("✗ 坐标轴没有正确跟随父模型移动") # 再次移动父节点测试 print("\n--- 再次移动父节点 ---") another_pos = Vec3(-3, -2, 1) parent.setPos(another_pos) print(f"父节点再次移动到: {another_pos}") # 等待另一帧 def final_check(task): print("\n--- 最终检查 ---") if world.selection.gizmo: final_gizmo_pos = world.selection.gizmo.getPos() final_expected_center = getWorldCenter(child1, world.render) final_diff = (final_gizmo_pos - final_expected_center).length() print(f"最终坐标轴位置: {final_gizmo_pos}") print(f"最终期望位置: {final_expected_center}") print(f"最终位置差异: {final_diff}") if final_diff < 0.1: print("✓ 测试通过:坐标轴正确跟随父模型移动") else: print("✗ 测试失败:坐标轴没有正确跟随") # 测试选择其他子节点 print("\n--- 测试选择子节点2 ---") world.selection.updateSelection(child2) def check_child2(task): if world.selection.gizmo: child2_gizmo_pos = world.selection.gizmo.getPos() child2_expected_center = getWorldCenter(child2, world.render) child2_diff = (child2_gizmo_pos - child2_expected_center).length() print(f"子节点2坐标轴位置: {child2_gizmo_pos}") print(f"子节点2期望位置: {child2_expected_center}") print(f"子节点2位置差异: {child2_diff}") if child2_diff < 0.1: print("✓ 子节点2坐标轴位置正确") else: print("✗ 子节点2坐标轴位置错误") print("\n=== 测试完成 ===") return task.done taskMgr.doMethodLater(0.1, check_child2, "check_child2") return task.done taskMgr.doMethodLater(0.1, final_check, "final_check") return task.done taskMgr.doMethodLater(0.1, check_after_move, "check_after_move") # 运行测试 print("\n开始运行测试...") world.run() if __name__ == "__main__": test_selection_follow()