2021-06-04 18:02:24 +08:00
|
|
|
|
import copy
|
|
|
|
|
|
import math
|
|
|
|
|
|
import ezdxf
|
2021-06-04 23:20:32 +08:00
|
|
|
|
from ezdxf.math import UCS
|
|
|
|
|
|
|
2021-06-04 18:02:24 +08:00
|
|
|
|
from type3d import Vector3D
|
|
|
|
|
|
import numpy as np
|
|
|
|
|
|
import transformation
|
|
|
|
|
|
from typing import List, Union, Tuple
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-06-04 23:20:32 +08:00
|
|
|
|
def draw_text(msp, text, text_point):
|
|
|
|
|
|
text_entity = msp.add_text(
|
|
|
|
|
|
text=text,
|
|
|
|
|
|
dxfattribs={
|
|
|
|
|
|
# text rotation angle in degrees in OCS
|
|
|
|
|
|
"thickness": 0.333,
|
|
|
|
|
|
"color": 1,
|
|
|
|
|
|
"style": "TXT",
|
|
|
|
|
|
"height": 2,
|
|
|
|
|
|
},
|
|
|
|
|
|
)
|
|
|
|
|
|
# set text position in OCS
|
|
|
|
|
|
text_entity.set_pos(text_point, align="MIDDLE_CENTER")
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-06-04 18:02:24 +08:00
|
|
|
|
class Line:
|
|
|
|
|
|
def __init__(
|
|
|
|
|
|
self,
|
2021-06-04 23:20:32 +08:00
|
|
|
|
msp,
|
2021-06-04 18:02:24 +08:00
|
|
|
|
start_p: Vector3D,
|
|
|
|
|
|
end_p: Vector3D,
|
|
|
|
|
|
tension_k: float,
|
|
|
|
|
|
n_point: int,
|
|
|
|
|
|
):
|
2021-06-04 23:20:32 +08:00
|
|
|
|
self._msp = msp
|
2021-06-04 18:02:24 +08:00
|
|
|
|
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
|
|
|
|
|
|
|
2023-12-05 01:32:19 +08:00
|
|
|
|
def curve(self,draw=False)->List:
|
2021-06-04 18:02:24 +08:00
|
|
|
|
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
|
|
|
|
|
|
)
|
2023-12-05 01:32:19 +08:00
|
|
|
|
# 计算与X轴的角度,画弧垂。先沿Z轴旋转到xz平面的x正半轴上。
|
2021-06-04 18:02:24 +08:00
|
|
|
|
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]))
|
2023-12-05 01:32:19 +08:00
|
|
|
|
# 绕起点,在Z轴方向旋转
|
2021-06-04 18:02:24 +08:00
|
|
|
|
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
|
2023-12-05 01:32:19 +08:00
|
|
|
|
if draw:
|
|
|
|
|
|
msp = self._msp
|
|
|
|
|
|
msp.add_polyline3d(points)
|
2021-06-04 18:02:24 +08:00
|
|
|
|
return points
|
|
|
|
|
|
|
2023-12-05 01:32:19 +08:00
|
|
|
|
def sag(self,draw=False):
|
2021-06-04 18:02:24 +08:00
|
|
|
|
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
|
2021-06-04 23:20:32 +08:00
|
|
|
|
p_sag_points = [
|
|
|
|
|
|
[start_p.x, start_p.y, start_p.z],
|
2021-06-04 18:02:24 +08:00
|
|
|
|
[
|
2021-06-04 23:20:32 +08:00
|
|
|
|
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],
|
|
|
|
|
|
] # 旋转前的值
|
|
|
|
|
|
sag_points = rotation.rotate(p_sag_points)
|
|
|
|
|
|
sag_value = start_p.z + middle_span * height / span - middle_z
|
2023-12-05 01:32:19 +08:00
|
|
|
|
if draw:
|
|
|
|
|
|
msp = self._msp
|
|
|
|
|
|
msp.add_polyline3d(sag_points)
|
|
|
|
|
|
draw_text(msp, f'sag {sag_value}', sag_points[1])
|
2021-06-04 18:02:24 +08:00
|
|
|
|
return sag_points
|
|
|
|
|
|
|
2023-12-05 01:32:19 +08:00
|
|
|
|
def swing(self, angel,draw=False)->List:
|
2021-06-04 23:20:32 +08:00
|
|
|
|
if not self._points:
|
|
|
|
|
|
self.curve()
|
2021-06-04 18:02:24 +08:00
|
|
|
|
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)
|
2023-12-05 01:32:19 +08:00
|
|
|
|
if draw:
|
|
|
|
|
|
msp = self._msp
|
|
|
|
|
|
msp.add_polyline3d(swing_point)
|
2021-06-04 18:02:24 +08:00
|
|
|
|
return swing_point
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Canvas:
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
|
self._doc = None
|
2021-06-04 23:20:32 +08:00
|
|
|
|
self.msp = None
|
2021-06-04 18:02:24 +08:00
|
|
|
|
|
|
|
|
|
|
def init_canvas(self):
|
|
|
|
|
|
doc = ezdxf.new()
|
|
|
|
|
|
self._doc = doc
|
|
|
|
|
|
msp = doc.modelspace()
|
2021-06-04 23:20:32 +08:00
|
|
|
|
self.msp = msp
|
|
|
|
|
|
doc.styles.new("TXT", dxfattribs={"font": "romans.shx"})
|
2021-06-04 18:02:24 +08:00
|
|
|
|
|
|
|
|
|
|
def draw(self, points):
|
2021-06-04 23:20:32 +08:00
|
|
|
|
msp = self.msp
|
2021-06-04 18:02:24 +08:00
|
|
|
|
msp.add_polyline3d(points)
|
|
|
|
|
|
|
|
|
|
|
|
def save(self, file_path):
|
|
|
|
|
|
doc = self._doc
|
|
|
|
|
|
doc.saveas(file_path)
|
2021-06-04 23:20:32 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Ruler:
|
|
|
|
|
|
def __init__(self, curve_points1: List, curve_points2: List):
|
|
|
|
|
|
self._curve_points1 = curve_points1
|
|
|
|
|
|
self._curve_points2 = curve_points2
|
|
|
|
|
|
|
|
|
|
|
|
def closest_distance(self):
|
|
|
|
|
|
curve_points1 = self._curve_points1
|
|
|
|
|
|
curve_points2 = self._curve_points2
|
|
|
|
|
|
closest = 999999999999
|
|
|
|
|
|
closest_poc1 = 0
|
|
|
|
|
|
closest_poc2 = 0
|
|
|
|
|
|
for foo in range(len(curve_points1)):
|
|
|
|
|
|
poc1 = curve_points1[foo] # point of curve 1
|
|
|
|
|
|
for bar in range(len(curve_points2)):
|
|
|
|
|
|
poc2 = curve_points2[bar]
|
|
|
|
|
|
distance = np.sum(np.power((np.array(poc1) - np.array(poc2)), 2)) ** 0.5
|
|
|
|
|
|
if distance < closest:
|
|
|
|
|
|
closest_poc1 = poc1
|
|
|
|
|
|
closest_poc2 = poc2
|
|
|
|
|
|
closest = distance
|
|
|
|
|
|
return closest, closest_poc1, closest_poc2
|