def update(self) -> None: if not self._tainted: return center = self.center w2 = Vec2.from_deg_angle(self._angle, self._width / 2.0) h2 = Vec2.from_deg_angle(self._angle + 90, self._height / 2.0) self._corners = ( center - w2 - h2, # lower left center + w2 - h2, # lower right center + w2 + h2, # upper right center - w2 + h2, # upper left ) self._tainted = False
def get_user_defined_text_location(self) -> Vec2: """Returns text midpoint for user defined dimension location.""" measurement = self.measurement assert isinstance(measurement.user_location, Vec2) text_outside_horiz = ( measurement.text_is_outside and measurement.text_outside_horizontal ) text_inside_horiz = ( measurement.text_is_inside and measurement.text_inside_horizontal ) if text_outside_horiz or text_inside_horiz: hdist = self._total_text_width / 2.0 if ( measurement.vertical_placement == 0 ): # shift text horizontal if vertical centered hdist += self.arrows.arrow_size if measurement.user_location.x <= self.point_on_circle.x: hdist = -hdist vdist = measurement.text_vertical_distance() return measurement.user_location + Vec2((hdist, vdist)) else: text_normal_vec = Vec2.from_deg_angle( measurement.text_rotation ).orthogonal() return ( measurement.user_location + text_normal_vec * measurement.text_vertical_distance() )
def get_default_text_location(self) -> Vec2: """Returns default text midpoint based on `text_valign` and `text_outside` """ measurement = self.measurement if measurement.text_is_outside and measurement.text_outside_horizontal: hdist = self._total_text_width / 2.0 if ( measurement.vertical_placement == 0 ): # shift text horizontal if vertical centered hdist += self.arrows.arrow_size angle = self.dim_line_angle % 360.0 # normalize 0 .. 360 if 90.0 < angle <= 270.0: hdist = -hdist return self.outside_default_defpoint + Vec2( (hdist, measurement.text_vertical_distance()) ) text_direction = Vec2.from_deg_angle(measurement.text_rotation) vertical_direction = text_direction.orthogonal(ccw=True) vertical_distance = measurement.text_vertical_distance() if measurement.text_is_inside: hdist = (self.radius - self.arrows.arrow_size) / 2.0 text_midpoint = self.center + (self.dim_line_vec * hdist) else: hdist = ( self._total_text_width / 2.0 + self.arrows.arrow_size + measurement.text_gap ) text_midpoint = self.point_on_circle + (self.dim_line_vec * hdist) return text_midpoint + (vertical_direction * vertical_distance)
def extension_line_points(self, start: Vec2, end: Vec2, text_above_extline=False) -> Tuple[Vec2, Vec2]: """ Adjust start and end point of extension line by dimension variables DIMEXE, DIMEXO, DIMEXFIX, DIMEXLEN. Args: start: start point of extension line (measurement point) end: end point at dimension line text_above_extline: True if text is above and aligned with extension line Returns: adjusted start and end point """ if start == end: direction = Vec2.from_deg_angle(self.ext_line_angle) else: direction = (end - start).normalize() if self.ext_line_fixed: start = end - (direction * self.ext_line_length) else: start = start + direction * self.ext_line_offset extension = self.ext_line_extension if text_above_extline: extension += self.dim_text_width end = end + direction * extension return start, end
def connection_point(arrow_name: str, insert: 'Vertex', scale: float = 1, rotation: float = 0) -> Vec2: insert = Vec2(insert) if arrow_name in _Arrows.ORIGIN_ZERO: return insert else: return insert - Vec2.from_deg_angle(rotation, scale)
def connection_point(arrow_name: str, insert: Vertex, scale: float = 1.0, rotation: float = 0.0) -> Vec2: """Returns the connection point for `arrow_name`. """ insert = Vec2(insert) if ARROWS.arrow_name(arrow_name) in _Arrows.ORIGIN_ZERO: return insert else: return insert - Vec2.from_deg_angle(rotation, scale)
def get_default_text_location(self) -> Vec2: """ Returns default text midpoint based on `self.text_valign` and `self.text_outside` """ if self.text_outside and self.text_outside_horizontal: return super().get_default_text_location() text_direction = Vec2.from_deg_angle(self.text_rotation) vertical_direction = text_direction.orthogonal(ccw=True) vertical_distance = self.text_vertical_distance() if self.text_inside: text_midpoint = self.center else: hdist = self.dim_text_width / 2. + self.arrow_size + self.text_gap text_midpoint = self.point_on_circle + (self.dim_line_vec * hdist) return text_midpoint + (vertical_direction * vertical_distance)
def vertices(self, a: Iterable[float]) -> Iterable[Vec2]: """ Yields vertices on arc for angles in iterable `a` in WCS as location vectors. Args: a: angles in the range from 0 to 360 in degrees, arc goes counter clockwise around the z-axis, WCS x-axis = 0 deg. """ center = self.center radius = self.radius for angle in a: yield center + Vec2.from_deg_angle(angle, radius)
def get_user_defined_text_location(self) -> Vec2: """ Returns text midpoint for user defined dimension location. """ text_outside_horiz = self.text_outside and self.text_outside_horizontal text_inside_horiz = self.text_inside and self.text_inside_horizontal if text_outside_horiz or text_inside_horiz: hdist = self.dim_text_width / 2 if self.vertical_placement == 0: # shift text horizontal if vertical centered hdist += self.arrow_size if self.user_location.x <= self.point_on_circle.x: hdist = -hdist vdist = self.text_vertical_distance() return self.user_location + Vec2((hdist, vdist)) else: text_normal_vec = Vec2.from_deg_angle(self.text_rotation).orthogonal() return self.user_location + text_normal_vec * self.text_vertical_distance()
def default_text_location(self) -> Vec2: """Calculate default text location in UCS based on `self.text_halign`, `self.text_valign` and `self.text_outside` """ start = self.dim_line_start end = self.dim_line_end measurement = self.measurement halign = measurement.text_halign # positions the text above and aligned with the first/second extension line ext_lines = self.extension_lines if halign in (3, 4): # horizontal location hdist = measurement.text_gap + measurement.text_height / 2.0 hvec = self.dim_line_vec * hdist location = (start if halign == 3 else end) - hvec # vertical location vdist = ext_lines.extension_above + self._total_text_width / 2.0 location += Vec2.from_deg_angle( self.ext_line_angle).normalize(vdist) else: # relocate outside text to center location if measurement.text_is_outside: halign = 0 if halign == 0: location = self.dim_line_center # center of dimension line else: hdist = (self._total_text_width / 2.0 + self.arrows.arrow_size + measurement.text_gap) if (halign == 1 ): # positions the text next to the first extension line location = start + (self.dim_line_vec * hdist) else: # positions the text next to the second extension line location = end - (self.dim_line_vec * hdist) if measurement.text_is_outside: # move text up vdist = (ext_lines.extension_above + measurement.text_gap + measurement.text_height / 2.0) else: # distance from extension line to text midpoint vdist = measurement.text_vertical_distance() location += self.dim_line_vec.orthogonal().normalize(vdist) return location
def add_text(self, text: str, pos: Vector, rotation: float, dxfattribs: dict = None) -> None: """ Add TEXT (DXF R12) or MTEXT (DXF R2000+) entity to the dimension BLOCK. Args: text: text as string pos: insertion location in UCS rotation: rotation angle in degrees in UCS (x-axis is 0 degrees) dxfattribs: additional or overridden DXF attributes """ attribs = self.default_attributes() attribs['style'] = self.text_style_name attribs['color'] = self.text_color if self.requires_extrusion: attribs['extrusion'] = self.ucs.uz if self.supports_dxf_r2000: text_direction = self.ucs.to_wcs( Vec2.from_deg_angle(rotation)) - self.ucs.origin attribs['text_direction'] = text_direction attribs['char_height'] = self.text_height attribs['insert'] = self.wcs(pos) attribs['attachment_point'] = self.text_attachment_point if self.supports_dxf_r2007: if self.text_fill: attribs['box_fill_scale'] = self.text_box_fill_scale attribs['bg_fill_color'] = self.text_fill_color attribs['bg_fill'] = 3 if self.text_fill == 1 else 1 if dxfattribs: attribs.update(dxfattribs) self.block.add_mtext(text, dxfattribs=attribs) else: attribs['rotation'] = self.ucs.to_ocs_angle_deg(rotation) attribs['height'] = self.text_height if dxfattribs: attribs.update(dxfattribs) dxftext = self.block.add_text(text, dxfattribs=attribs) dxftext.set_pos(self.ocs(pos), align='MIDDLE_CENTER')
def quick_mtext_horizontal(name: str): doc = ezdxf.new(DXFVERSION, setup=True) mleaderstyle = doc.mleader_styles.duplicate_entry("Standard", "EZDXF") mleaderstyle.set_mtext_style("OpenSans") # type: ignore msp = doc.modelspace() target_point = Vec2(40, 15) msp.add_circle( target_point, radius=0.5, dxfattribs=GfxAttribs(color=colors.RED) ) for angle in [45, 135, 225, -45]: ml_builder = msp.add_multileader_mtext("EZDXF") ml_builder.quick_leader( "Line1\nLine2", target=target_point, segment1=Vec2.from_deg_angle(angle, 14), ) doc.set_modelspace_vport(60, center=(10, 5)) doc.saveas(OUTDIR / f"{name}_{DXFVERSION}.dxf")
def get_default_text_location(self) -> Vec2: """ Returns default text midpoint based on `self.text_valign` and `self.text_outside` """ if self.text_outside and self.text_outside_horizontal: hdist = self.dim_text_width / 2. if self.vertical_placement == 0: # shift text horizontal if vertical centered hdist += self.arrow_size angle = self.dim_line_angle % 360. # normalize 0 .. 360 if 90 < angle <= 270: hdist = -hdist return self.outside_default_defpoint + Vec2((hdist, self.text_vertical_distance())) text_direction = Vec2.from_deg_angle(self.text_rotation) vertical_direction = text_direction.orthogonal(ccw=True) vertical_distance = self.text_vertical_distance() if self.text_inside: hdist = (self.measurement - self.arrow_size) / 2 text_midpoint = self.center + (self.dim_line_vec * hdist) else: hdist = self.dim_text_width / 2. + self.arrow_size + self.text_gap text_midpoint = self.point_on_circle + (self.dim_line_vec * hdist) return text_midpoint + (vertical_direction * vertical_distance)
def single_triangle(pos, rotation, fill): if not hasattr(single_triangle, "counter"): single_triangle.counter = 0 single_triangle.counter += 1 block_name = "triangle" + str(single_triangle.counter) shape_test = doc.blocks.new(name=block_name) points = [Vec2.from_deg_angle((360 / 3) * n) for n in range(3)] points.append(points[0]) if (fill): hatch = shape_test.add_hatch(color=1) hatch.paths.add_polyline_path(points) else: points.append(points[0]) shape_test.add_lwpolyline(points, dxfattribs={'color': 1}) msp.add_blockref(block_name, pos, dxfattribs={ 'rotation': rotation, 'xscale': 9, 'yscale': 9 })
def start_point(self) -> 'Vec2': """ start point of arc as :class:`Vec2`. """ return self.center + Vec2.from_deg_angle(self.start_angle, self.radius)
def sort_projected_points(points: Iterable['Vertex'], angle: float = 0) -> List[Vec2]: direction = Vec2.from_deg_angle(angle) projected_vectors = [(direction.project(Vec2(p)), p) for p in points] return [p for projection, p in sorted(projected_vectors)]
def end_point(self) -> 'Vec2': """ end point of arc as :class:`Vec2`. """ return self.center + Vec2.from_deg_angle(self.end_angle, self.radius)