import copy import math import ezdxf from ezdxf.math import UCS from type3d import Vector3D import numpy as np import transformation from typing import List, Union, Tuple 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") class Line: def __init__( self, msp, start_p: Vector3D, end_p: Vector3D, tension_k: float, n_point: int, ): self._msp = msp 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,draw=False)->List: 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轴的角度,画弧垂。先沿Z轴旋转到xz平面的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 if draw: msp = self._msp msp.add_polyline3d(points) return points def sag(self,draw=False): 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 p_sag_points = [ [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], ] # 旋转前的值 sag_points = rotation.rotate(p_sag_points) sag_value = start_p.z + middle_span * height / span - middle_z if draw: msp = self._msp msp.add_polyline3d(sag_points) draw_text(msp, f'sag {sag_value}', sag_points[1]) return sag_points def swing(self, angel,draw=False)->List: if not self._points: self.curve() 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) if draw: msp = self._msp msp.add_polyline3d(swing_point) 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 doc.styles.new("TXT", dxfattribs={"font": "romans.shx"}) def draw(self, points): msp = self.msp msp.add_polyline3d(points) def save(self, file_path): doc = self._doc doc.saveas(file_path) 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