def make_hatches_from_str(s: str, font: fonts.FontFace, size: float = 1.0, align: str = 'LEFT', length: float = 0, segments: int = 4, dxfattribs: Dict = None, m: Matrix44 = None) -> List[Hatch]: """ Convert a single line string `s` into a list of virtual :class:`~ezdxf.entities.Hatch` entities. The text `size` is the height of the uppercase letter "X" (cap height). The paths are aligned about the insertion point at (0, 0). The HATCH entities are aligned to this insertion point. BASELINE means the bottom of the letter "X". Args: s: text to convert font: font face definition size: text size (cap height) in drawing units align: alignment as string, default is "LEFT" length: target length for the "ALIGNED" and "FIT" alignments segments: minimal segment count per Bézier curve dxfattribs: additional DXF attributes m: transformation :class:`~ezdxf.math.Matrix44` """ font_properties, font_measurements = _get_font_data(font) # scale cap_height for 1 drawing unit! scaled_size = size / font_measurements.cap_height scaled_fm = font_measurements.scale_from_baseline(scaled_size) paths = _str_to_paths(s, font_properties, scaled_size) # HATCH is an OCS entity, transforming just the polyline paths # is not correct! The Hatch has to be created in the xy-plane! hatches = [] dxfattribs = dxfattribs or dict() dxfattribs.setdefault('solid_fill', 1) dxfattribs.setdefault('pattern_name', 'SOLID') dxfattribs.setdefault('color', 7) for contour, holes in group_contour_and_holes(paths): hatch = Hatch.new(dxfattribs=dxfattribs) # Vec2 removes the z-axis, which would be interpreted as bulge value! hatch.paths.add_polyline_path( Vec2.generate(contour.flattening(1, segments=segments)), flags=1) for hole in holes: hatch.paths.add_polyline_path( Vec2.generate(hole.flattening(1, segments=segments)), flags=0) hatches.append(hatch) halign, valign = const.TEXT_ALIGN_FLAGS[align.upper()] bbox = path.bbox(paths, precise=False) matrix = get_alignment_transformation(scaled_fm, bbox, halign, valign) if m is not None: matrix *= m # Transform HATCH entities as a unit: return [hatch.transform(matrix) for hatch in hatches]
def test_polyline_path_transform_interface(m44): hatch = Hatch.new() vertices = list(box(1.0, 2.0)) path = hatch.paths.add_polyline_path(vertices) hatch.transform(m44) chk = m44.transform_vertices(vertices) for v, c in zip(path.vertices, chk): assert c.isclose(v)
def closed_edge_hatch(request): _hatch = Hatch.new() _path = _hatch.paths.add_edge_path() if request.param == "arc": _path.add_arc((0, 0), radius=1, start_angle=0, end_angle=360, ccw=1) elif request.param == "ellipse": _path.add_ellipse( (0, 0), major_axis=(5, 0), ratio=0.2, start_angle=0, end_angle=360 ) return _hatch
def test_upright_hatch_with_polyline_path(): hatch = Hatch.new(dxfattribs={ "elevation": (0, 0, 4), "extrusion": (0, 0, -1), }) hatch.paths.add_polyline_path([(x, y, b) for x, y, s, e, b in POLYLINE_POINTS]) p0 = path.make_path(hatch) assert p0.has_curves is True upright(hatch) assert hatch.dxf.extrusion.isclose(Z_AXIS) p1 = path.make_path(hatch) assert path.have_close_control_vertices(p0, p1)
def test_edge_path_transform_interface(m44): hatch = Hatch.new() path = hatch.paths.add_edge_path() path.add_line((0, 0), (10, 0)) path.add_arc((10, 5), radius=5, start_angle=270, end_angle=450, ccw=1) path.add_ellipse( (5, 10), major_axis=(5, 0), ratio=0.2, start_angle=0, end_angle=180 ) spline = path.add_spline( [(1, 1), (2, 2), (3, 3), (4, 4)], degree=3, periodic=1 ) # the following values do not represent a mathematically valid spline spline.control_points = [(1, 1), (2, 2), (3, 3), (4, 4)] spline.knot_values = [1, 2, 3, 4, 5, 6] spline.weights = [4, 3, 2, 1] spline.start_tangent = (10, 1) spline.end_tangent = (2, 20) chk = list( m44.transform_vertices( [ Vec3(0, 0), Vec3(10, 0), Vec3(10, 5), Vec3(5, 10), Vec3(1, 1), Vec3(2, 2), Vec3(3, 3), Vec3(4, 4), ] ) ) hatch.transform(m44) line = path.edges[0] assert chk[0].isclose(line.start) assert chk[1].isclose(line.end) arc = path.edges[1] assert chk[2].isclose(arc.center) ellipse = path.edges[2] assert chk[3].isclose(ellipse.center) spline = path.edges[3] for c, v in zip(chk[4:], spline.control_points): assert c.isclose(v) for c, v in zip(chk[4:], spline.fit_points): assert c.isclose(v) assert m44.transform_direction((10, 1, 0)).isclose(spline.start_tangent) assert m44.transform_direction((2, 20, 0)).isclose(spline.end_tangent)
def _hatch_converter(paths: Iterable[Path], add_boundary: Callable[[Hatch, Path, int], None], extrusion: 'Vertex' = Z_AXIS, dxfattribs: Optional[Dict] = None) -> Iterable[Hatch]: if isinstance(paths, Path): paths = [paths] else: paths = list(paths) if len(paths) == 0: return [] extrusion = Vec3(extrusion) reference_point = paths[0].start dxfattribs = dxfattribs or dict() if not extrusion.isclose(Z_AXIS): ocs, elevation = _get_ocs(extrusion, reference_point) paths = tools.transform_paths_to_ocs(paths, ocs) dxfattribs['elevation'] = Vec3(0, 0, elevation) dxfattribs['extrusion'] = extrusion elif reference_point.z != 0: dxfattribs['elevation'] = Vec3(0, 0, reference_point.z) dxfattribs.setdefault('solid_fill', 1) dxfattribs.setdefault('pattern_name', 'SOLID') dxfattribs.setdefault('color', const.BYLAYER) for group in group_paths(paths): if len(group) == 0: continue hatch = Hatch.new(dxfattribs=dxfattribs) external = group[0] external.close() add_boundary(hatch, external, 1) for hole in group[1:]: hole.close() add_boundary(hatch, hole, 0) yield hatch
def all_edge_types_hatch(elevation, extrusion): hatch = Hatch.new(dxfattribs={ "layer": "original", "color": 2, "elevation": (0.0, 0.0, elevation), "extrusion": extrusion, "pattern_name": "SOLID", "solid_fill": 1, "associative": 0, "hatch_style": 0, "pattern_type": 1, }, ) # edge-path contains all supported edge types: ep = hatch.paths.add_edge_path(flags=1) ep.add_arc( # clockwise oriented ARC center=(0.0, 13.0), radius=3.0, start_angle=-90.0, end_angle=90.0, ccw=False, ) ep.add_ellipse( # clockwise oriented ELLIPSE center=(0.0, 5.0), major_axis=(0.0, 5.0), ratio=0.6, start_angle=180.0, end_angle=360.0, ccw=False, ) ep.add_line((0.0, 0.0), (10.0, 0.0)) # LINE ep.add_ellipse( # counter-clockwise oriented ELLIPSE center=(10.0, 5.0), major_axis=(0.0, -5.0), ratio=0.6, start_angle=0.0, end_angle=180.0, ccw=True, ) ep.add_arc( # counter-clockwise oriented ARC center=(10.0, 13.0), radius=3.0, start_angle=270.0, end_angle=450.0, ccw=True, ) ep.add_spline( # SPLINE control_points=[ Vec2(10.0, 16.0), Vec2(9.028174684192452, 16.0), Vec2(6.824943218065775, 12.14285714285714), Vec2(3.175056781934232, 19.85714285714287), Vec2(0.9718253158075516, 16.0), Vec2(0, 16.0), ], knot_values=[ 0.0, 0.0, 0.0, 0.0, 2.91547594742265, 8.746427842267952, 11.6619037896906, 11.6619037896906, 11.6619037896906, 11.6619037896906, ], degree=3, periodic=0, ) return hatch
def hatch(self): return Hatch.new(dxfattribs={ "elevation": (0, 0, 4), "extrusion": (0, 0, -1), })
def hatch(): return Hatch.new()
def test_full_circle_edge_scaling(): _hatch = Hatch.new() _path = _hatch.paths.add_edge_path() _arc = _path.add_arc((0, 0), radius=1, start_angle=0, end_angle=360, ccw=1) _hatch.transform(Matrix44.scale(0.5, 0.5, 0.5)) assert _arc.radius == pytest.approx(0.5)