132 lines
3.8 KiB
Python
132 lines
3.8 KiB
Python
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)
|