606 lines
24 KiB
Python
606 lines
24 KiB
Python
"""
|
|
流体域组件
|
|
定义流体模拟的边界和域
|
|
"""
|
|
|
|
from panda3d.core import Vec3, Point3, CollisionNode, CollisionSphere, CollisionBox
|
|
import math
|
|
|
|
class FluidDomain:
|
|
"""
|
|
流体域类
|
|
定义流体模拟的边界和域
|
|
"""
|
|
|
|
# 边界类型
|
|
BOUNDARY_BOX = "box"
|
|
BOUNDARY_SPHERE = "sphere"
|
|
BOUNDARY_CYLINDER = "cylinder"
|
|
BOUNDARY_CONE = "cone"
|
|
|
|
# 边界条件
|
|
CONDITION_CLOSED = "closed" # 封闭边界
|
|
CONDITION_OPEN = "open" # 开放边界
|
|
CONDITION_PERIODIC = "periodic" # 周期性边界
|
|
|
|
def __init__(self, min_bound, max_bound, boundary_type=BOUNDARY_BOX, boundary_condition=CONDITION_CLOSED):
|
|
"""
|
|
初始化流体域
|
|
|
|
Args:
|
|
min_bound (Point3): 最小边界点
|
|
max_bound (Point3): 最大边界点
|
|
boundary_type (str): 边界类型
|
|
boundary_condition (str): 边界条件
|
|
"""
|
|
self.min_bound = min_bound
|
|
self.max_bound = max_bound
|
|
self.size = max_bound - min_bound
|
|
self.center = (min_bound + max_bound) * 0.5
|
|
self.boundary_type = boundary_type
|
|
self.boundary_condition = boundary_condition
|
|
|
|
# 为不同边界类型计算额外参数
|
|
if boundary_type == self.BOUNDARY_SPHERE:
|
|
# 计算球体半径
|
|
self.radius = max(self.size.getX(), self.size.getY(), self.size.getZ()) / 2.0
|
|
elif boundary_type == self.BOUNDARY_CYLINDER:
|
|
# 计算圆柱体半径和高度
|
|
self.radius = max(self.size.getX(), self.size.getY()) / 2.0
|
|
self.height = self.size.getZ()
|
|
elif boundary_type == self.BOUNDARY_CONE:
|
|
# 计算圆锥体半径和高度
|
|
self.radius = max(self.size.getX(), self.size.getY()) / 2.0
|
|
self.height = self.size.getZ()
|
|
|
|
# 边界属性
|
|
self.restitution = 0.3 # 恢复系数
|
|
self.friction = 0.1 # 摩擦系数
|
|
self.surface_roughness = 0.01 # 表面粗糙度
|
|
|
|
# 碰撞检测相关
|
|
self.collision_margin = 0.05 # 碰撞边缘
|
|
self.corner_radius = 0.05 # 角点半径
|
|
|
|
# 动态边界支持
|
|
self.is_dynamic = False
|
|
self.velocity = Vec3(0, 0, 0)
|
|
self.rotation = Vec3(0, 0, 0)
|
|
|
|
# 边界厚度
|
|
self.boundary_thickness = 0.05
|
|
|
|
print(f"流体域创建完成: {min_bound} to {max_bound}, 类型: {boundary_type}, 条件: {boundary_condition}")
|
|
|
|
def update(self, dt):
|
|
"""
|
|
更新流体域状态
|
|
|
|
Args:
|
|
dt (float): 时间步长
|
|
"""
|
|
if self.is_dynamic:
|
|
# 更新动态边界的位置和旋转
|
|
self.center += self.velocity * dt
|
|
|
|
# 在这里可以添加边界旋转的逻辑
|
|
# self.rotation += self.angular_velocity * dt
|
|
|
|
def handle_particle_collision(self, particle):
|
|
"""
|
|
处理粒子与域边界的碰撞
|
|
|
|
Args:
|
|
particle: 流体粒子对象(字典格式)
|
|
"""
|
|
pos = particle['position']
|
|
|
|
if self.boundary_type == self.BOUNDARY_BOX:
|
|
self._handle_box_collision(particle)
|
|
elif self.boundary_type == self.BOUNDARY_SPHERE:
|
|
self._handle_sphere_collision(particle)
|
|
elif self.boundary_type == self.BOUNDARY_CYLINDER:
|
|
self._handle_cylinder_collision(particle)
|
|
elif self.boundary_type == self.BOUNDARY_CONE:
|
|
self._handle_cone_collision(particle)
|
|
|
|
def _handle_box_collision(self, particle):
|
|
"""
|
|
处理盒状边界碰撞
|
|
|
|
Args:
|
|
particle: 流体粒子对象
|
|
"""
|
|
pos = particle['position']
|
|
vel = particle['velocity']
|
|
|
|
# 获取边界值
|
|
min_x, max_x = self.min_bound.getX(), self.max_bound.getX()
|
|
min_y, max_y = self.min_bound.getY(), self.max_bound.getY()
|
|
min_z, max_z = self.min_bound.getZ(), self.max_bound.getZ()
|
|
|
|
# 检查X轴边界
|
|
if pos.getX() <= min_x + self.collision_margin:
|
|
pos.setX(min_x + self.collision_margin)
|
|
vel.setX(-vel.getX() * (1 - self.friction) * self.restitution)
|
|
elif pos.getX() >= max_x - self.collision_margin:
|
|
pos.setX(max_x - self.collision_margin)
|
|
vel.setX(-vel.getX() * (1 - self.friction) * self.restitution)
|
|
|
|
# 检查Y轴边界
|
|
if pos.getY() <= min_y + self.collision_margin:
|
|
pos.setY(min_y + self.collision_margin)
|
|
vel.setY(-vel.getY() * (1 - self.friction) * self.restitution)
|
|
elif pos.getY() >= max_y - self.collision_margin:
|
|
pos.setY(max_y - self.collision_margin)
|
|
vel.setY(-vel.getY() * (1 - self.friction) * self.restitution)
|
|
|
|
# 检查Z轴边界
|
|
if pos.getZ() <= min_z + self.collision_margin:
|
|
pos.setZ(min_z + self.collision_margin)
|
|
vel.setZ(-vel.getZ() * (1 - self.friction) * self.restitution)
|
|
elif pos.getZ() >= max_z - self.collision_margin:
|
|
pos.setZ(max_z - self.collision_margin)
|
|
vel.setZ(-vel.getZ() * (1 - self.friction) * self.restitution)
|
|
|
|
# 处理周期性边界条件
|
|
if self.boundary_condition == self.CONDITION_PERIODIC:
|
|
self._apply_periodic_boundary_conditions(particle)
|
|
|
|
def _handle_sphere_collision(self, particle):
|
|
"""
|
|
处理球状边界碰撞
|
|
|
|
Args:
|
|
particle: 流体粒子对象
|
|
"""
|
|
pos = particle['position']
|
|
vel = particle['velocity']
|
|
|
|
# 计算粒子到球心的距离
|
|
center_to_particle = pos - self.center
|
|
distance = center_to_particle.length()
|
|
|
|
# 检查是否超出球体边界
|
|
if distance > self.radius - self.collision_margin:
|
|
# 计算碰撞点
|
|
normal = center_to_particle.normalized()
|
|
collision_point = self.center + normal * (self.radius - self.collision_margin)
|
|
|
|
# 调整粒子位置
|
|
particle['position'] = collision_point
|
|
|
|
# 计算碰撞响应
|
|
v_normal = normal.dot(vel) * normal # 法向速度
|
|
v_tangent = vel - v_normal # 切向速度
|
|
|
|
# 应用反弹和摩擦
|
|
new_v_normal = -v_normal * self.restitution
|
|
new_v_tangent = v_tangent * (1 - self.friction)
|
|
|
|
particle['velocity'] = new_v_normal + new_v_tangent
|
|
|
|
def _handle_cylinder_collision(self, particle):
|
|
"""
|
|
处理圆柱边界碰撞
|
|
|
|
Args:
|
|
particle: 流体粒子对象
|
|
"""
|
|
pos = particle['position']
|
|
vel = particle['velocity']
|
|
|
|
# 计算在X-Y平面上到圆柱轴的距离
|
|
dx = pos.getX() - self.center.getX()
|
|
dy = pos.getY() - self.center.getY()
|
|
distance_xy = math.sqrt(dx*dx + dy*dy)
|
|
|
|
# 检查径向边界
|
|
if distance_xy > self.radius - self.collision_margin:
|
|
# 计算径向方向
|
|
radial_dir = Vec3(dx, dy, 0).normalized()
|
|
|
|
# 调整位置
|
|
new_x = self.center.getX() + radial_dir.getX() * (self.radius - self.collision_margin)
|
|
new_y = self.center.getY() + radial_dir.getY() * (self.radius - self.collision_margin)
|
|
pos.setX(new_x)
|
|
pos.setY(new_y)
|
|
|
|
# 计算碰撞响应
|
|
v_radial = radial_dir.dot(vel) * radial_dir
|
|
v_tangent = vel - v_radial
|
|
|
|
# 应用反弹和摩擦
|
|
new_v_radial = -v_radial * self.restitution
|
|
particle['velocity'] = new_v_radial + v_tangent * (1 - self.friction)
|
|
|
|
# 检查Z轴边界
|
|
min_z = self.center.getZ() - self.height/2.0
|
|
max_z = self.center.getZ() + self.height/2.0
|
|
|
|
if pos.getZ() <= min_z + self.collision_margin:
|
|
pos.setZ(min_z + self.collision_margin)
|
|
vel.setZ(-vel.getZ() * (1 - self.friction) * self.restitution)
|
|
elif pos.getZ() >= max_z - self.collision_margin:
|
|
pos.setZ(max_z - self.collision_margin)
|
|
vel.setZ(-vel.getZ() * (1 - self.friction) * self.restitution)
|
|
|
|
def _handle_cone_collision(self, particle):
|
|
"""
|
|
处理圆锥边界碰撞
|
|
|
|
Args:
|
|
particle: 流体粒子对象
|
|
"""
|
|
pos = particle['position']
|
|
vel = particle['velocity']
|
|
|
|
# 计算相对于圆锥顶点的位置
|
|
rel_pos = pos - self.center
|
|
rel_pos.setZ(rel_pos.getZ() + self.height/2) # 调整Z轴使顶点在底部
|
|
|
|
# 计算在X-Y平面上到圆锥轴的距离
|
|
distance_xy = math.sqrt(rel_pos.getX()**2 + rel_pos.getY()**2)
|
|
|
|
# 计算圆锥在当前高度的半径
|
|
cone_radius_at_height = (rel_pos.getZ() / self.height) * self.radius
|
|
|
|
# 检查是否超出圆锥边界
|
|
if distance_xy > cone_radius_at_height - self.collision_margin and rel_pos.getZ() > 0:
|
|
# 计算圆锥表面的法向量
|
|
radial_dir = Vec3(rel_pos.getX(), rel_pos.getY(), 0).normalized()
|
|
surface_normal = Vec3(
|
|
radial_dir.getX(),
|
|
radial_dir.getY(),
|
|
-self.radius / self.height # 圆锥的斜率
|
|
).normalized()
|
|
|
|
# 调整粒子位置到表面
|
|
adjusted_radius = cone_radius_at_height - self.collision_margin
|
|
particle['position'] = Point3(
|
|
self.center.getX() + radial_dir.getX() * adjusted_radius,
|
|
self.center.getY() + radial_dir.getY() * adjusted_radius,
|
|
self.center.getZ() + rel_pos.getZ() - self.height/2
|
|
)
|
|
|
|
# 计算碰撞响应
|
|
v_normal = surface_normal.dot(vel) * surface_normal
|
|
v_tangent = vel - v_normal
|
|
|
|
# 应用反弹和摩擦
|
|
new_v_normal = -v_normal * self.restitution
|
|
particle['velocity'] = new_v_normal + v_tangent * (1 - self.friction)
|
|
|
|
# 检查Z轴边界
|
|
if rel_pos.getZ() < 0: # 底部
|
|
pos.setZ(self.center.getZ() - self.height/2 + self.collision_margin)
|
|
vel.setZ(-vel.getZ() * (1 - self.friction) * self.restitution)
|
|
elif rel_pos.getZ() > self.height: # 顶部(圆锥尖端)
|
|
pos.setZ(self.center.getZ() + self.height/2 - self.collision_margin)
|
|
vel.setZ(-vel.getZ() * (1 - self.friction) * self.restitution)
|
|
|
|
def _apply_periodic_boundary_conditions(self, particle):
|
|
"""
|
|
应用周期性边界条件
|
|
|
|
Args:
|
|
particle: 流体粒子对象
|
|
"""
|
|
pos = particle['position']
|
|
|
|
# X轴周期性
|
|
if pos.getX() < self.min_bound.getX():
|
|
particle['position'].setX(self.max_bound.getX() - (self.min_bound.getX() - pos.getX()))
|
|
elif pos.getX() > self.max_bound.getX():
|
|
particle['position'].setX(self.min_bound.getX() + (pos.getX() - self.max_bound.getX()))
|
|
|
|
# Y轴周期性
|
|
if pos.getY() < self.min_bound.getY():
|
|
particle['position'].setY(self.max_bound.getY() - (self.min_bound.getY() - pos.getY()))
|
|
elif pos.getY() > self.max_bound.getY():
|
|
particle['position'].setY(self.min_bound.getY() + (pos.getY() - self.max_bound.getY()))
|
|
|
|
# Z轴周期性
|
|
if pos.getZ() < self.min_bound.getZ():
|
|
particle['position'].setZ(self.max_bound.getZ() - (self.min_bound.getZ() - pos.getZ()))
|
|
elif pos.getZ() > self.max_bound.getZ():
|
|
particle['position'].setZ(self.min_bound.getZ() + (pos.getZ() - self.max_bound.getZ()))
|
|
|
|
def is_point_inside(self, point):
|
|
"""
|
|
检查点是否在域内
|
|
|
|
Args:
|
|
point (Point3): 检查点
|
|
|
|
Returns:
|
|
bool: 是否在域内
|
|
"""
|
|
if self.boundary_type == self.BOUNDARY_BOX:
|
|
return (self.min_bound.getX() <= point.getX() <= self.max_bound.getX() and
|
|
self.min_bound.getY() <= point.getY() <= self.max_bound.getY() and
|
|
self.min_bound.getZ() <= point.getZ() <= self.max_bound.getZ())
|
|
elif self.boundary_type == self.BOUNDARY_SPHERE:
|
|
distance = (point - self.center).length()
|
|
return distance <= self.radius
|
|
elif self.boundary_type == self.BOUNDARY_CYLINDER:
|
|
dx = point.getX() - self.center.getX()
|
|
dy = point.getY() - self.center.getY()
|
|
distance_xy = math.sqrt(dx*dx + dy*dy)
|
|
z_in_range = self.center.getZ() - self.height/2 <= point.getZ() <= self.center.getZ() + self.height/2
|
|
return distance_xy <= self.radius and z_in_range
|
|
elif self.boundary_type == self.BOUNDARY_CONE:
|
|
rel_point = point - self.center
|
|
rel_point.setZ(rel_point.getZ() + self.height/2)
|
|
dx = rel_point.getX()
|
|
dy = rel_point.getY()
|
|
distance_xy = math.sqrt(dx*dx + dy*dy)
|
|
cone_radius_at_height = (rel_point.getZ() / self.height) * self.radius
|
|
return distance_xy <= cone_radius_at_height and 0 <= rel_point.getZ() <= self.height
|
|
|
|
return False # 默认返回False
|
|
|
|
def get_volume(self):
|
|
"""
|
|
计算域体积
|
|
|
|
Returns:
|
|
float: 域体积
|
|
"""
|
|
if self.boundary_type == self.BOUNDARY_BOX:
|
|
return self.size.getX() * self.size.getY() * self.size.getZ()
|
|
elif self.boundary_type == self.BOUNDARY_SPHERE:
|
|
return (4.0/3.0) * math.pi * (self.radius ** 3)
|
|
elif self.boundary_type == self.BOUNDARY_CYLINDER:
|
|
return math.pi * (self.radius ** 2) * self.height
|
|
elif self.boundary_type == self.BOUNDARY_CONE:
|
|
return (1.0/3.0) * math.pi * (self.radius ** 2) * self.height
|
|
else:
|
|
# 默认按盒状计算
|
|
return self.size.getX() * self.size.getY() * self.size.getZ()
|
|
|
|
def set_boundary_condition(self, condition):
|
|
"""
|
|
设置边界条件
|
|
|
|
Args:
|
|
condition (str): 边界条件类型
|
|
"""
|
|
self.boundary_condition = condition
|
|
|
|
def set_material_properties(self, restitution=None, friction=None, surface_roughness=None):
|
|
"""
|
|
设置边界材料属性
|
|
|
|
Args:
|
|
restitution (float): 恢复系数
|
|
friction (float): 摩擦系数
|
|
surface_roughness (float): 表面粗糙度
|
|
"""
|
|
if restitution is not None:
|
|
self.restitution = max(0.0, min(1.0, restitution))
|
|
if friction is not None:
|
|
self.friction = max(0.0, min(1.0, friction))
|
|
if surface_roughness is not None:
|
|
self.surface_roughness = max(0.0, surface_roughness)
|
|
|
|
def set_dynamic(self, is_dynamic, velocity=None, rotation=None):
|
|
"""
|
|
设置边界是否为动态
|
|
|
|
Args:
|
|
is_dynamic (bool): 是否为动态边界
|
|
velocity (Vec3): 速度
|
|
rotation (Vec3): 旋转
|
|
"""
|
|
self.is_dynamic = is_dynamic
|
|
if velocity:
|
|
self.velocity = velocity
|
|
if rotation:
|
|
self.rotation = rotation
|
|
|
|
def get_surface_area(self):
|
|
"""
|
|
计算边界表面积
|
|
|
|
Returns:
|
|
float: 表面积
|
|
"""
|
|
if self.boundary_type == self.BOUNDARY_BOX:
|
|
return 2 * (self.size.getX() * self.size.getY() +
|
|
self.size.getX() * self.size.getZ() +
|
|
self.size.getY() * self.size.getZ())
|
|
elif self.boundary_type == self.BOUNDARY_SPHERE:
|
|
return 4 * math.pi * (self.radius ** 2)
|
|
elif self.boundary_type == self.BOUNDARY_CYLINDER:
|
|
return 2 * math.pi * self.radius * (self.radius + self.height)
|
|
elif self.boundary_type == self.BOUNDARY_CONE:
|
|
slant_height = math.sqrt(self.radius**2 + self.height**2)
|
|
return math.pi * self.radius * (self.radius + slant_height)
|
|
else:
|
|
# 默认按盒状计算
|
|
return 2 * (self.size.getX() * self.size.getY() +
|
|
self.size.getX() * self.size.getZ() +
|
|
self.size.getY() * self.size.getZ())
|
|
|
|
def get_bounding_box(self):
|
|
"""
|
|
获取边界框
|
|
|
|
Returns:
|
|
tuple: (min_bound, max_bound)
|
|
"""
|
|
return (self.min_bound, self.max_bound)
|
|
|
|
def get_boundary_mesh(self):
|
|
"""
|
|
获取边界网格(用于可视化)
|
|
|
|
Returns:
|
|
dict: 包含网格顶点和面的字典
|
|
"""
|
|
if self.boundary_type == self.BOUNDARY_BOX:
|
|
return self._get_box_mesh()
|
|
elif self.boundary_type == self.BOUNDARY_SPHERE:
|
|
return self._get_sphere_mesh()
|
|
elif self.boundary_type == self.BOUNDARY_CYLINDER:
|
|
return self._get_cylinder_mesh()
|
|
elif self.boundary_type == self.BOUNDARY_CONE:
|
|
return self._get_cone_mesh()
|
|
else:
|
|
return self._get_box_mesh() # 默认返回盒状网格
|
|
|
|
def _get_box_mesh(self):
|
|
"""
|
|
获取盒状边界网格
|
|
|
|
Returns:
|
|
dict: 网格数据
|
|
"""
|
|
vertices = [
|
|
Point3(self.min_bound.getX(), self.min_bound.getY(), self.min_bound.getZ()),
|
|
Point3(self.max_bound.getX(), self.min_bound.getY(), self.min_bound.getZ()),
|
|
Point3(self.max_bound.getX(), self.max_bound.getY(), self.min_bound.getZ()),
|
|
Point3(self.min_bound.getX(), self.max_bound.getY(), self.min_bound.getZ()),
|
|
Point3(self.min_bound.getX(), self.min_bound.getY(), self.max_bound.getZ()),
|
|
Point3(self.max_bound.getX(), self.min_bound.getY(), self.max_bound.getZ()),
|
|
Point3(self.max_bound.getX(), self.max_bound.getY(), self.max_bound.getZ()),
|
|
Point3(self.min_bound.getX(), self.max_bound.getY(), self.max_bound.getZ()),
|
|
]
|
|
|
|
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], # 右面
|
|
]
|
|
|
|
return {"vertices": vertices, "faces": faces}
|
|
|
|
def _get_sphere_mesh(self, resolution=16):
|
|
"""
|
|
获取球状边界网格
|
|
|
|
Args:
|
|
resolution (int): 网格分辨率
|
|
|
|
Returns:
|
|
dict: 网格数据
|
|
"""
|
|
vertices = []
|
|
faces = []
|
|
|
|
# 生成球面顶点
|
|
for i in range(resolution + 1):
|
|
phi = math.pi * i / resolution # 0 到 π
|
|
for j in range(resolution + 1):
|
|
theta = 2 * math.pi * j / resolution # 0 到 2π
|
|
|
|
x = self.center.getX() + self.radius * math.sin(phi) * math.cos(theta)
|
|
y = self.center.getY() + self.radius * math.sin(phi) * math.sin(theta)
|
|
z = self.center.getZ() + self.radius * math.cos(phi)
|
|
|
|
vertices.append(Point3(x, y, z))
|
|
|
|
# 生成面
|
|
for i in range(resolution):
|
|
for j in range(resolution):
|
|
first = i * (resolution + 1) + j
|
|
second = first + resolution + 1
|
|
|
|
# 添加两个三角形形成一个四边形面
|
|
faces.append([first, second, first + 1])
|
|
faces.append([second, second + 1, first + 1])
|
|
|
|
return {"vertices": vertices, "faces": faces}
|
|
|
|
def _get_cylinder_mesh(self, resolution=16):
|
|
"""
|
|
获取圆柱边界网格
|
|
|
|
Args:
|
|
resolution (int): 网格分辨率
|
|
|
|
Returns:
|
|
dict: 网格数据
|
|
"""
|
|
vertices = []
|
|
faces = []
|
|
|
|
# 生成底部圆环
|
|
base_center = Point3(self.center.getX(), self.center.getY(), self.center.getZ() - self.height/2)
|
|
for i in range(resolution):
|
|
theta = 2 * math.pi * i / resolution
|
|
x = base_center.getX() + self.radius * math.cos(theta)
|
|
y = base_center.getY() + self.radius * math.sin(theta)
|
|
z = base_center.getZ()
|
|
vertices.append(Point3(x, y, z))
|
|
|
|
# 添加底部中心点
|
|
vertices.append(base_center)
|
|
|
|
# 生成顶部圆环
|
|
top_center = Point3(self.center.getX(), self.center.getY(), self.center.getZ() + self.height/2)
|
|
for i in range(resolution):
|
|
theta = 2 * math.pi * i / resolution
|
|
x = top_center.getX() + self.radius * math.cos(theta)
|
|
y = top_center.getY() + self.radius * math.sin(theta)
|
|
z = top_center.getZ()
|
|
vertices.append(Point3(x, y, z))
|
|
|
|
# 添加顶部中心点
|
|
vertices.append(top_center)
|
|
|
|
# 生成侧面
|
|
for i in range(resolution):
|
|
next_i = (i + 1) % resolution
|
|
# 底面
|
|
faces.append([i, resolution, (next_i if next_i != 0 else resolution-1)])
|
|
# 顶面
|
|
faces.append([i + resolution + 1, resolution * 2 + 1, (next_i + resolution + 1) if next_i != 0 else resolution])
|
|
# 侧面
|
|
faces.append([i, next_i, i + resolution + 1])
|
|
faces.append([next_i, next_i + resolution + 1, i + resolution + 1])
|
|
|
|
return {"vertices": vertices, "faces": faces}
|
|
|
|
def _get_cone_mesh(self, resolution=16):
|
|
"""
|
|
获取圆锥边界网格
|
|
|
|
Args:
|
|
resolution (int): 网格分辨率
|
|
|
|
Returns:
|
|
dict: 网格数据
|
|
"""
|
|
vertices = []
|
|
faces = []
|
|
|
|
# 生成底部圆环
|
|
base_center = Point3(self.center.getX(), self.center.getY(), self.center.getZ() - self.height/2)
|
|
for i in range(resolution):
|
|
theta = 2 * math.pi * i / resolution
|
|
x = base_center.getX() + self.radius * math.cos(theta)
|
|
y = base_center.getY() + self.radius * math.sin(theta)
|
|
z = base_center.getZ()
|
|
vertices.append(Point3(x, y, z))
|
|
|
|
# 添加底部中心点
|
|
vertices.append(base_center)
|
|
|
|
# 圆锥顶点
|
|
apex = Point3(self.center.getX(), self.center.getY(), self.center.getZ() + self.height/2)
|
|
vertices.append(apex)
|
|
|
|
# 生成侧面
|
|
for i in range(resolution):
|
|
next_i = (i + 1) % resolution
|
|
# 底面
|
|
faces.append([i, resolution, (next_i if next_i != 0 else resolution-1)])
|
|
# 侧面
|
|
faces.append([i, (next_i if next_i != 0 else resolution-1), resolution + 1])
|
|
|
|
return {"vertices": vertices, "faces": faces} |