姓名:卜凡
学号:2020211066
指导老师:符强
日期:2022-04-12 ~ 27
如下代码定义了表示三维坐标中的坐标点的 Point
类。它主要由 x
、 y
、 z
三个坐标构成。
技术要点:
__init__()
处,利用了可变参数 *args
和一系列参数长度和类型判断( 利用 isinstance
),实现构造函数的重载;__add__()
、减法 __sub__()
、数乘 __mul__()
及其反运算符 __rmul__()
(Python 在左操作数类型定义中找不到符合参数的运算符时,会去寻找右操作数类型中的反运算符);__str__()
以便调试;dist()
,并用除号 __truediv__()
进行运算符化。# 表示三维坐标中的点。
class Point(object):
def __init__(self, *args):
# [0 参数] 默认构造方法:x 与 y 默认值均为 0
if (len(args) == 0):
self.x = self.y = self.z = 0.0
# [1 参数] 复制构造方法
elif (len(args) == 1 and isinstance(args[0], Point)):
other = args[0];
self.x = other.x
self.y = other.y
self.z = other.z
# [1 参数] 构造方法,三参数均为同一值
elif (len(args) == 1 and isinstance(args[0], (int, float))):
value = args[0]
self.x = self.y = self.z = value
# [3 参数] 构造方法
elif (len(args) == 3 and isinstance(args[0], (int, float))
and isinstance(args[1], (int, float))
and isinstance(args[2], (int, float))):
self.x = args[0]
self.y = args[1]
self.z = args[2]
# [其他参数] 抛出异常,表示参数不合法。
else:
raise ValueError("invalid args", args)
# 重载 + 运算符:Point 之间的加法
def __add__(self, other) -> object:
return Point(self.x + other.x, self.y + other.y, self.z + other.z)
# 重载 - 运算符:Point 之间的减法
def __sub__(self, other) -> object:
return Point(self.x - other.x, self.y - other.y, self.z - other.z)
# 重载 * 运算符:Point 和实数之间的减法
def __mul__(self, num:float) -> object:
return Point(self.x * num, self.y * num, self.z * num)
# 定义反 * 运算符:同上
def __rmul__(self, num:float) -> object:
return self.__mul__(num)
# 定义字符串化方法
def __str__(self) -> str:
return "P(%.3f, %.3f, %.3f)" % (self.x, self.y, self.z)
def toTuple(self) -> T.Tuple[float, float, float]:
return (self.x, self.y, self.z)
# 定义求两 Point 之间距离的方法
def dist(self, other) -> float:
return math.sqrt((self.x - other.x) ** 2
+ (self.y - other.y) ** 2
+ (self.z - other.z) ** 2)
# 重载 / 运算符:同上
def __truediv__(self, other) -> float:
return self.dist(other)
下面部分的代码定义了表示三维坐标中的一个多边形网格的 Mesh
类。它主要由顶点坐标序列(下称 ptList
)和表示各面具有哪些顶点的下标矩阵(下称 idMatrix
)构成。
如下图是一个标准立方体的例子,其 ptList
和 idMatrix
如下代码块:
ptList = [Point(1,1,-1), Point(1,-1,-1), Point(-1,-1,-1), Point(-1,1,-1),
Point(1,1,1), Point(1,-1,1), Point(-1,-1,1), Point(-1,1,1)]
idMatrix = [[0,1,2,3], [3,2,6,7], [4,0,3,7], [4,5,1,0], [7,6,5,4], [1,5,6,2]]
技术要点:
ptList
和 idMatrix
构造的方法和复制构造的方法,都需要做深拷贝。__add__()
和 __sub__()
。render()
。利用 GL_LINE_LOOP 绘制类型进行各面线环的绘制。__str__()
以便调试。这里为了效率使用了较快的 join()
方法(见参考 [1])。# 表示多边形网格模型。注意采用的方法是 Point 列表和表示如何成面的 id 矩阵。
class Mesh(object):
# Mesh - Part.1 定义对象工作的部分
def __init__(self, *args):
# [0 参数] 默认空构造方法
if (len(args) == 0):
self.ptList = list()
self.idMatrix = list()
# [1 参数] 复制构造方法
elif (len(args) == 1 and isinstance(args[0], Mesh)):
other = args[0]
# 做深拷贝
self.ptList = [pt for pt in other.ptList]
self.idMatrix = [[index for index in faceids] for faceids in other.idMatrix]
# [2 参数] 传入点列表和 id 矩阵的构造方法
elif (len(args) == 2) and isinstance(args[0], list) \\
and (isinstance(args[0][0], Point)) \\
and (isinstance(args[1], list)) \\
and (isinstance(args[1][0], list)) \\
and (isinstance(args[1][0][0], int)):
ptList = args[0]
idMatrix = args[1]
# 做深拷贝
self.ptList = [pt for pt in ptList]
self.idMatrix = [[index for index in faceids] for faceids in idMatrix]
else:
raise ValueError("invalid args", args)
# 重载 + 运算符:ptList 中每个 Point 都对给定点做加法
def __add__(self, other:Point) -> object:
for i in range(len(self.ptList)):
self.ptList[i] = self.ptList[i] + other;
# 重载 - 运算符:ptList 中每个 Point 都对给定点做减法
def __sub__(self, other:Point) -> object:
for i in range(len(self.ptList)):
self.ptList[i] = self.ptList[i] - other;
# 定义字符串化方法
def __str__(self) -> str:
# join 是字符串化序列最高效的方法
return "M{[" + ", ".join([pt.__str__() for pt in self.ptList]) + "], [" \\
+ ", ".join("["
+ [", ".join([index for index in faceids]) for faceids in self.idMatrix]
+ "]") + "]}"
# 定义绘制方法
def render(self) -> None:
for faceids in self.idMatrix:
glBegin(GL_LINE_LOOP) # 绘制线环
for index in faceids:
glVertex3f(self.ptList[index].x, self.ptList[index].y, self.ptList[index].z)
glEnd()
# Mesh - Part.2 定义算法工作的部分(见下)