import os import time class ObjectFactory: """Scene object and sample panel factory methods.""" def __init__(self, app): self.app = app def __getattr__(self, name): return getattr(self.app, name) def __setattr__(self, name, value): if name == "app" or name in self.__dict__ or hasattr(type(self), name): object.__setattr__(self, name, value) else: setattr(self.app, name, value) def createEmptyObject(self): """创建空对象""" try: from panda3d.core import NodePath # 创建一个空节点 empty_node = NodePath("EmptyObject") empty_node.reparentTo(self.render) empty_node.setPos(0, 0, 0) # 添加到场景管理器 if hasattr(self, 'scene_manager') and self.scene_manager: self.scene_manager.models.append(empty_node) # 更新场景树 if hasattr(self, 'updateSceneTree'): self.updateSceneTree() print("✓ 空对象创建成功") return empty_node except Exception as e: print(f"✗ 创建空对象失败: {e}") return None def create3DText(self, pos=(0, 0, 0), text="3D Text", scale=1.0): """创建3D文本""" try: from panda3d.core import TextNode, NodePath # 创建文本节点 text_node = TextNode("3DText") text_node.setText(text) text_node.setAlign(TextNode.ACenter) text_node.setTextColor(1, 1, 1, 1) # 白色 # 设置中文字体 chinese_font = self._get_chinese_font() if chinese_font: text_node.setFont(chinese_font) # 创建节点路径并设置位置 text_np = NodePath(text_node) text_np.reparentTo(self.render) text_np.setPos(pos) text_np.setScale(scale) # 添加到场景管理器 if hasattr(self, 'scene_manager') and self.scene_manager: self.scene_manager.models.append(text_np) # 更新场景树 if hasattr(self, 'updateSceneTree'): self.updateSceneTree() print(f"✓ 3D文本创建成功: {text}") return text_np except Exception as e: print(f"✗ 创建3D文本失败: {e}") return None def create3DImage(self, pos=(0, 0, 0), image_path="", size=(1, 1)): """创建3D图片""" try: from panda3d.core import CardMaker, NodePath if not image_path or not os.path.exists(image_path): print("✗ 图片文件不存在") return None # 创建卡片几何体 card_maker = CardMaker("3DImage") card_maker.setFrame(-size[0]/2, size[0]/2, -size[1]/2, size[1]/2) card = card_maker.generate() # 创建节点路径 image_np = NodePath(card) image_np.reparentTo(self.render) image_np.setPos(pos) # 加载纹理 from panda3d.core import Texture, Filename tex = self.loader.loadTexture(Filename.fromOsSpecific(image_path)) if tex: image_np.setTexture(tex, 1) else: print("✗ 加载纹理失败") image_np.removeNode() return None # 添加到场景管理器 if hasattr(self, 'scene_manager') and self.scene_manager: self.scene_manager.models.append(image_np) # 更新场景树 if hasattr(self, 'updateSceneTree'): self.updateSceneTree() print(f"✓ 3D图片创建成功: {os.path.basename(image_path)}") return image_np except Exception as e: print(f"✗ 创建3D图片失败: {e}") return None def createCube(self, pos=(0, 0, 0), size=1.0): """创建立方体""" try: # 尝试使用Panda3D的内置几何体 from panda3d.core import NodePath, GeomNode, Geom, GeomVertexFormat, GeomVertexData, GeomVertexWriter, GeomTriangles, GeomPoints from panda3d.core import Vec3, Vec4, RenderState, ShadeModelAttrib # 创建顶点数据格式 format = GeomVertexFormat.getV3n3cpt2() vdata = GeomVertexData('cube', format, Geom.UHStatic) vdata.setNumRows(24) vertex = GeomVertexWriter(vdata, 'vertex') normal = GeomVertexWriter(vdata, 'normal') color = GeomVertexWriter(vdata, 'color') # 立方体的8个顶点 s = size / 2 vertices = [ (-s, -s, -s), (s, -s, -s), (s, s, -s), (-s, s, -s), # 底面 (-s, -s, s), (s, -s, s), (s, s, s), (-s, s, s) # 顶面 ] # 立方体的6个面,每个面4个顶点 faces = [ (0, 1, 2, 3), # 底面 (4, 7, 6, 5), # 顶面 (0, 4, 5, 1), # 前面 (2, 6, 7, 3), # 后面 (0, 3, 7, 4), # 左面 (1, 5, 6, 2) # 右面 ] # 法线 normals = [ (0, 0, -1), (0, 0, 1), (0, -1, 0), (0, 1, 0), (-1, 0, 0), (1, 0, 0) ] # 添加顶点数据 for face_idx, face in enumerate(faces): n = normals[face_idx] for vertex_idx in face: v = vertices[vertex_idx] vertex.addData3f(*v) normal.addData3f(*n) color.addData4f(0.8, 0.8, 0.8, 1.0) # 灰色 # 创建几何体 geom = Geom(vdata) # 添加三角形 for face_idx in range(6): base = face_idx * 4 # 每个面分成2个三角形 tri = GeomTriangles(Geom.UHStatic) tri.addConsecutiveVertices(base, 3) tri.closePrimitive() tri2 = GeomTriangles(Geom.UHStatic) tri2.addVertices(base + 2, base + 3, base) tri2.closePrimitive() geom.addPrimitive(tri) geom.addPrimitive(tri2) # 创建节点 geom_node = GeomNode('cube') geom_node.addGeom(geom) cube = NodePath(geom_node) cube.reparentTo(self.render) cube.setPos(pos) # 设置渲染状态 state = RenderState.make(ShadeModelAttrib.make(ShadeModelAttrib.MSmooth)) cube.set_state(state) # 添加到场景管理器 if hasattr(self, 'scene_manager') and self.scene_manager: self.scene_manager.models.append(cube) # 更新场景树 if hasattr(self, 'updateSceneTree'): self.updateSceneTree() print("✓ 立方体创建成功") return cube except Exception as e: print(f"✗ 创建立方体失败: {e}") return None def createSphere(self, pos=(0, 0, 0), radius=1.0): """创建球体""" try: from panda3d.core import CardMaker, NodePath # 创建一个简单的球体(使用多个卡片近似) sphere_root = NodePath("Sphere") # 创建球体的多个面来近似球形 num_segments = 6 for i in range(num_segments): angle1 = (i / num_segments) * 360 # 创建球体片段 segment_maker = CardMaker(f"SphereSegment{i}") segment_maker.setFrame(-radius, radius, -radius, radius) segment = NodePath(segment_maker.generate()) segment.reparentTo(sphere_root) # 设置位置和旋转来形成球体 segment.setPos(0, 0, 0) segment.setH(angle1) segment.setP(angle1/2) # 倾斜角度 segment.setScale(radius) # 设置颜色 from panda3d.core import Vec4 sphere_root.setColor(Vec4(0.8, 0.6, 0.4, 1.0)) # 棕色 sphere_root.reparentTo(self.render) sphere_root.setPos(pos) # 添加到场景管理器 if hasattr(self, 'scene_manager') and self.scene_manager: self.scene_manager.models.append(sphere_root) # 更新场景树 if hasattr(self, 'updateSceneTree'): self.updateSceneTree() print("✓ 球体创建成功") return sphere_root except Exception as e: print(f"✗ 创建球体失败: {e}") return None def createCylinder(self, pos=(0, 0, 0), radius=1.0, height=2.0): """创建圆柱体""" try: import math from panda3d.core import CardMaker, NodePath # 创建圆柱体 cylinder_root = NodePath("Cylinder") # 创建圆柱体的多个侧面 num_segments = 12 for i in range(num_segments): angle1 = (i / num_segments) * 360 angle2 = ((i + 1) / num_segments) * 360 # 计算圆柱体侧面的位置 x1 = radius * math.cos(math.radians(angle1)) y1 = radius * math.sin(math.radians(angle1)) # 创建圆柱体侧面 segment_maker = CardMaker(f"CylinderSegment{i}") segment = NodePath(segment_maker.generate()) segment.reparentTo(cylinder_root) # 设置位置和旋转 segment.setPos(x1, y1, 0) segment.setH(angle1) segment.setScale(0.5, height, 1) # 调整宽度和高度 # 设置颜色 from panda3d.core import Vec4 cylinder_root.setColor(Vec4(0.4, 0.8, 0.4, 1.0)) # 绿色 cylinder_root.reparentTo(self.render) cylinder_root.setPos(pos) # 添加到场景管理器 if hasattr(self, 'scene_manager') and self.scene_manager: self.scene_manager.models.append(cylinder_root) # 更新场景树 if hasattr(self, 'updateSceneTree'): self.updateSceneTree() print("✓ 圆柱体创建成功") return cylinder_root except Exception as e: print(f"✗ 创建圆柱体失败: {e}") return None def createPlane(self, pos=(0, 0, 0), size=(1, 1)): """创建平面""" try: from panda3d.core import CardMaker, NodePath # 创建平面 card_maker = CardMaker("Plane") card_maker.setFrame(-size[0]/2, size[0]/2, -size[1]/2, size[1]/2) plane = NodePath(card_maker.generate()) plane.reparentTo(self.render) plane.setPos(pos) # 添加到场景管理器 if hasattr(self, 'scene_manager') and self.scene_manager: self.scene_manager.models.append(plane) # 更新场景树 if hasattr(self, 'updateSceneTree'): self.updateSceneTree() print("✓ 平面创建成功") return plane except Exception as e: print(f"✗ 创建平面失败: {e}") return None def create2DSamplePanel(self): """创建2D示例面板""" try: from core.InfoPanelManager import createSampleInfoPanel result = createSampleInfoPanel(self.render) return result except Exception as e: print(f"创建2D示例面板失败: {e}") return None def create3DSamplePanel(self): """创建3D实例面板""" try: if hasattr(self, 'info_panel_manager') and self.info_panel_manager: # 创建3D信息面板 panel_id = f"3d_sample_{int(time.time())}" result = self.info_panel_manager.create3DInfoPanel( panel_id=panel_id, position=(0, 0, 2), size=(1.0, 0.6), bg_color=(0.15, 0.25, 0.35, 0.95), border_color=(0.3, 0.5, 0.7, 1.0), title_color=(0.7, 0.9, 1.0, 1.0), content_color=(0.95, 0.95, 0.95, 1.0) ) # 添加示例内容 if result: sample_data = { "标题": "3D信息面板", "状态": "运行中", "创建时间": time.strftime("%Y-%m-%d %H:%M:%S"), "位置": f"X:0, Y:0, Z:2" } self.info_panel_manager.updatePanelContent(panel_id, content=sample_data) return result return None except Exception as e: print(f"创建3D示例面板失败: {e}") return None def createWebPanel(self, url="https://www.example.com"): """创建Web面板""" try: if hasattr(self, 'info_panel_manager') and self.info_panel_manager: panel_id = f"web_panel_{int(time.time())}" result = self.info_panel_manager.createHTTPInfoPanel( panel_id=panel_id, url=url, position=(0.8, 0.0), size=(0.35, 0.4), update_interval=5.0 # 每5秒更新一次 ) return result return None except Exception as e: print(f"创建Web面板失败: {e}") return None # ==================== GUI创建方法 ====================