parent
edc09e5c61
commit
ef683999b4
|
|
@ -1,2 +1,3 @@
|
||||||
.idea
|
.idea
|
||||||
__pycache__
|
__pycache__
|
||||||
|
*.dxf
|
||||||
131
graphic.py
131
graphic.py
|
|
@ -0,0 +1,131 @@
|
||||||
|
import copy
|
||||||
|
import math
|
||||||
|
import ezdxf
|
||||||
|
from type3d import Vector3D
|
||||||
|
import numpy as np
|
||||||
|
import transformation
|
||||||
|
from typing import List, Union, Tuple
|
||||||
|
|
||||||
|
|
||||||
|
class Line:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
start_p: Vector3D,
|
||||||
|
end_p: Vector3D,
|
||||||
|
tension_k: float,
|
||||||
|
n_point: int,
|
||||||
|
):
|
||||||
|
self._start_p: Vector3D = start_p
|
||||||
|
self._end_p: Vector3D = end_p
|
||||||
|
self._tension_k: float = tension_k
|
||||||
|
self._n_point: int = n_point
|
||||||
|
self._span = 0
|
||||||
|
self._points = None
|
||||||
|
self._rotation = None
|
||||||
|
|
||||||
|
def curve(self):
|
||||||
|
if self._points:
|
||||||
|
return self._points
|
||||||
|
start_p = self._start_p
|
||||||
|
end_p = self._end_p
|
||||||
|
tension_k = self._tension_k
|
||||||
|
n_point = self._n_point
|
||||||
|
# 右手坐标系,Z朝上
|
||||||
|
line = Vector3D(end_p.x, end_p.y, end_p.z) - Vector3D(
|
||||||
|
start_p.x, start_p.y, start_p.z
|
||||||
|
)
|
||||||
|
# 计算与X轴的角度
|
||||||
|
xy_project = copy.deepcopy(line) # 投影到xy平面上
|
||||||
|
xy_project.z = 0
|
||||||
|
x_abs_angel = xy_project.angle_to(Vector3D(1, 0, 0))
|
||||||
|
x_angel = x_abs_angel * np.sign(xy_project.y)
|
||||||
|
height = end_p.z - start_p.z
|
||||||
|
span: float = abs(xy_project)
|
||||||
|
self._span = span
|
||||||
|
span_l = np.linspace(0, span, n_point) # 档距
|
||||||
|
z_points: Tuple[float] = (
|
||||||
|
start_p.z
|
||||||
|
+ span_l * height / span
|
||||||
|
- span_l * (span - span_l) * tension_k / math.cos(math.atan(height / span))
|
||||||
|
)
|
||||||
|
p_points: List[
|
||||||
|
Union[List[float, float, float], Tuple[float, float, float]]
|
||||||
|
] = list() # 未旋转之前的伪坐标
|
||||||
|
for foo in range(len(span_l)):
|
||||||
|
p_points.append((span_l[foo] + start_p.x, start_p.y, z_points[foo]))
|
||||||
|
# 绕Z轴旋转
|
||||||
|
rotation = transformation.Rotation(
|
||||||
|
x_angel,
|
||||||
|
[start_p.x, start_p.y, start_p.z],
|
||||||
|
[start_p.x, start_p.y, start_p.z + 1],
|
||||||
|
)
|
||||||
|
self._rotation = rotation
|
||||||
|
points = rotation.rotate(
|
||||||
|
p_points,
|
||||||
|
)
|
||||||
|
self._points = points
|
||||||
|
return points
|
||||||
|
|
||||||
|
def sag(self):
|
||||||
|
# msp.add_polyline3d(
|
||||||
|
# [(start_p.x, start_p.y, start_p.z), (end_p.x, end_p.y, end_p.z)]
|
||||||
|
# )
|
||||||
|
start_p = self._start_p
|
||||||
|
end_p = self._end_p
|
||||||
|
span = self._span
|
||||||
|
height = end_p.z - start_p.z
|
||||||
|
middle_span = span / 2
|
||||||
|
points = self._points
|
||||||
|
n_point = self._n_point
|
||||||
|
middle_z = points[int(n_point / 2)][2]
|
||||||
|
rotation = self._rotation
|
||||||
|
sag_points = rotation.rotate(
|
||||||
|
[
|
||||||
|
[start_p.x, start_p.y, start_p.z],
|
||||||
|
[
|
||||||
|
middle_span + start_p.x,
|
||||||
|
start_p.y,
|
||||||
|
start_p.z + middle_span * height / span,
|
||||||
|
],
|
||||||
|
[middle_span + start_p.x, start_p.y, middle_z],
|
||||||
|
[
|
||||||
|
middle_span + start_p.x,
|
||||||
|
start_p.y,
|
||||||
|
start_p.z + middle_span * height / span,
|
||||||
|
],
|
||||||
|
[start_p.x + span, start_p.y, end_p.z],
|
||||||
|
]
|
||||||
|
)
|
||||||
|
return sag_points
|
||||||
|
|
||||||
|
def swing(self, angel):
|
||||||
|
points = self._points
|
||||||
|
start_p = self._start_p
|
||||||
|
end_p = self._end_p
|
||||||
|
swing_rotation = transformation.Rotation(
|
||||||
|
angel,
|
||||||
|
[start_p.x, start_p.y, start_p.z],
|
||||||
|
[end_p.x, end_p.y, end_p.z],
|
||||||
|
)
|
||||||
|
swing_point = swing_rotation.rotate(points)
|
||||||
|
return swing_point
|
||||||
|
|
||||||
|
|
||||||
|
class Canvas:
|
||||||
|
def __init__(self):
|
||||||
|
self._doc = None
|
||||||
|
self._msp = None
|
||||||
|
|
||||||
|
def init_canvas(self):
|
||||||
|
doc = ezdxf.new()
|
||||||
|
self._doc = doc
|
||||||
|
msp = doc.modelspace()
|
||||||
|
self._msp = msp
|
||||||
|
|
||||||
|
def draw(self, points):
|
||||||
|
msp = self._msp
|
||||||
|
msp.add_polyline3d(points)
|
||||||
|
|
||||||
|
def save(self, file_path):
|
||||||
|
doc = self._doc
|
||||||
|
doc.saveas(file_path)
|
||||||
16
main.py
16
main.py
|
|
@ -1,9 +1,13 @@
|
||||||
import math
|
import math
|
||||||
from transformation import rotation
|
|
||||||
import numpy as np
|
from graphic import Canvas, Line
|
||||||
|
from type3d import Vector3D
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
t = rotation(
|
canvas = Canvas()
|
||||||
45 / 180 * math.pi, np.array([0, 0, 1]), np.array([[1, 1, 0], [2, 3, 4]])
|
canvas.init_canvas()
|
||||||
)
|
line = Line(Vector3D(20, 30, 0), Vector3D(400, 100, 1), 0.3 * 1e-3, 400)
|
||||||
print(t)
|
canvas.draw(line.curve())
|
||||||
|
canvas.draw(line.sag())
|
||||||
|
canvas.draw(line.swing(80/180*math.pi))
|
||||||
|
canvas.save("lwpolyline1.dxf")
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from math import cos, sin
|
from math import cos, sin
|
||||||
|
from typing import List, Union, Tuple
|
||||||
|
|
||||||
|
|
||||||
def create_rx(unit_axis: np.ndarray) -> np.ndarray:
|
def create_rx(unit_axis: np.ndarray) -> np.ndarray:
|
||||||
|
|
@ -32,16 +33,41 @@ def create_t(axis: np.ndarray) -> np.ndarray:
|
||||||
return np.array([[1, 0, 0, -x1], [0, 1, 0, -y1], [0, 0, 1, -z1], [0, 0, 0, 1]])
|
return np.array([[1, 0, 0, -x1], [0, 1, 0, -y1], [0, 0, 1, -z1], [0, 0, 0, 1]])
|
||||||
|
|
||||||
|
|
||||||
def rotation(angel: float, axis: np.ndarray, points: np.ndarray):
|
def rotation_matrix(
|
||||||
|
angel: float, axis_start: np.ndarray, axis_end: np.ndarray
|
||||||
|
) -> np.ndarray:
|
||||||
# 依据《计算机图形学》第4版 9.28公式
|
# 依据《计算机图形学》第4版 9.28公式
|
||||||
|
axis = axis_end - axis_start
|
||||||
unit_axis = axis / np.linalg.norm(axis)
|
unit_axis = axis / np.linalg.norm(axis)
|
||||||
rz = create_rz(angel)
|
rz = create_rz(angel)
|
||||||
rx = create_rx(unit_axis)
|
rx = create_rx(unit_axis)
|
||||||
ry = create_ry(unit_axis)
|
ry = create_ry(unit_axis)
|
||||||
t = create_t(axis)
|
t = create_t(axis_start)
|
||||||
t_i = np.linalg.inv(t)
|
t_i = np.linalg.inv(t)
|
||||||
rx_i = np.linalg.inv(rx)
|
rx_i = np.linalg.inv(rx)
|
||||||
ry_i = np.linalg.inv(ry)
|
ry_i = np.linalg.inv(ry)
|
||||||
r_transform = t_i.dot(rx_i.dot(ry_i.dot(rz.dot(ry.dot(rx.dot(t))))))
|
r_transform = t_i @ rx_i @ ry_i @ rz @ ry @ rx @ t
|
||||||
expand_point = np.concatenate((points, np.ones((points.shape[0], 1))), axis=1)
|
return r_transform
|
||||||
return r_transform.dot(expand_point.T)
|
|
||||||
|
|
||||||
|
def rotation(
|
||||||
|
angel: float, axis_start: np.ndarray, axis_end: np.ndarray, points: np.ndarray
|
||||||
|
) -> np.ndarray:
|
||||||
|
_rotation = Rotation(angel, axis_start.tolist(), axis_end.tolist())
|
||||||
|
return _rotation.rotate(points.tolist())
|
||||||
|
|
||||||
|
|
||||||
|
class Rotation:
|
||||||
|
def __init__(self, angel: float, axis_start: List[float], axis_end: List[float]):
|
||||||
|
self._r_transform = rotation_matrix(
|
||||||
|
angel, np.array(axis_start), np.array(axis_end)
|
||||||
|
)
|
||||||
|
|
||||||
|
def rotate(self, points: List[Union[List[float], Tuple[float]]])->List:
|
||||||
|
np_points = np.array(points)
|
||||||
|
r_transform = self._r_transform
|
||||||
|
expand_point = np.concatenate(
|
||||||
|
(np_points, np.ones((np_points.shape[0], 1))), axis=1
|
||||||
|
)
|
||||||
|
transformed_points = r_transform @ expand_point.T
|
||||||
|
return transformed_points[:-1, :].T.tolist()
|
||||||
|
|
|
||||||
23
type3d.py
23
type3d.py
|
|
@ -1,5 +1,22 @@
|
||||||
|
import math
|
||||||
|
|
||||||
|
|
||||||
class Vector3D:
|
class Vector3D:
|
||||||
def __init__(self, x, y, z):
|
def __init__(self, x, y, z):
|
||||||
self.x = x
|
self.x:float = x
|
||||||
self.y = y
|
self.y:float = y
|
||||||
self.z = z
|
self.z:float = z
|
||||||
|
|
||||||
|
def __sub__(self, other):
|
||||||
|
return Vector3D(self.x - other.x, self.y - other.y, self.z - other.z)
|
||||||
|
|
||||||
|
def __abs__(self) -> float:
|
||||||
|
return (self.x ** 2 + self.y ** 2 + self.z ** 2) ** 0.5
|
||||||
|
|
||||||
|
# 计算两向量间夹角
|
||||||
|
def angle_to(self, other):
|
||||||
|
return math.acos(
|
||||||
|
abs(self.x * other.x + self.y * other.y + self.z * other.z)
|
||||||
|
/ abs(self)
|
||||||
|
/ abs(other)
|
||||||
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue