EG/ui/panels/object_factory.py
2026-02-25 11:49:31 +08:00

407 lines
14 KiB
Python
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.

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创建方法 ====================