Exemple #1
0
def add_lines(msp, center: Vec3, radius: float, start_angle: float,
              end_angle: float):
    attribs = {"color": 7}
    start_point = center + Vec3.from_deg_angle(start_angle) * radius
    end_point = center + Vec3.from_deg_angle(end_angle) * radius
    msp.add_line(center, start_point, dxfattribs=attribs)
    msp.add_line(center, end_point, dxfattribs=attribs)
Exemple #2
0
    def transform(self, m: Matrix44) -> 'Text':
        """ Transform TEXT entity by transformation matrix `m` inplace.

        .. versionadded:: 0.13

        """
        dxf = self.dxf
        if not dxf.hasattr('align_point'):
            dxf.align_point = dxf.insert
        ocs = OCSTransform(self.dxf.extrusion, m)
        dxf.insert = ocs.transform_vertex(dxf.insert)
        dxf.align_point = ocs.transform_vertex(dxf.align_point)
        old_rotation = dxf.rotation
        new_rotation = ocs.transform_deg_angle(old_rotation)
        x_scale = ocs.transform_length(Vec3.from_deg_angle(old_rotation))
        y_scale = ocs.transform_length(
            Vec3.from_deg_angle(old_rotation + 90.0))

        if not ocs.scale_uniform:
            oblique_vec = Vec3.from_deg_angle(
                old_rotation + 90.0 - dxf.oblique)
            new_oblique_deg = new_rotation + 90.0 - ocs.transform_direction(
                oblique_vec).angle_deg
            dxf.oblique = new_oblique_deg
            y_scale *= math.cos(math.radians(new_oblique_deg))

        dxf.width *= x_scale / y_scale
        dxf.height *= y_scale
        dxf.rotation = new_rotation

        if dxf.hasattr('thickness'):  # can be negative
            dxf.thickness = ocs.transform_length((0, 0, dxf.thickness),
                                                 reflection=dxf.thickness)
        dxf.extrusion = ocs.new_extrusion
        return self
    def add_axis(attribs: Dict, m: Matrix44 = None):
        start = -X_AXIS * arrow_length / 2
        end = X_AXIS * arrow_length / 2
        leg1 = Vec3.from_deg_angle(180 - leg_angle) * leg_length
        leg2 = Vec3.from_deg_angle(180 + leg_angle) * leg_length

        lines = [
            block.add_line(start, end, dxfattribs=attribs),
            block.add_line(end, end + leg1, dxfattribs=attribs),
            block.add_line(end, end + leg2, dxfattribs=attribs),
        ]
        if m is not None:
            for line in lines:
                line.transform(m)
Exemple #4
0
def usr_location_relative(angle: float, rotation: float = None):
    doc = ezdxf.new(DXFVERSION, setup=True)
    msp = doc.modelspace()
    x_dist = 10
    radius = 3.0
    distance = 1.0
    for dimtad, y_dist, leader in [
        [0, 0, False],
        [0, 10, True],
        [4, 20, True],
    ]:
        for count in range(8):
            center = Vec3(x_dist * count, y_dist)
            main_angle = 45.0 * count
            dim = add_arc_dim(
                msp,
                center=center,
                angle=main_angle,
                delta=angle / 2.0,
                radius=radius,
                distance=distance,
                text_rotation=rotation,
                override={"dimtad": dimtad},
            )
            # user location relative to center of dimension line:
            usr_location = Vec3.from_deg_angle(main_angle, 2.0)
            dim.set_location(usr_location, leader=leader, relative=True)
            dim.render(discard=BRICSCAD)

    doc.set_modelspace_vport(height=100, center=(x_dist * 4, 40))
    rstr = ""
    if rotation is not None:
        rstr = f"rot_{rotation}_"
    doc.saveas(OUTDIR / f"dim_arc_usr_loc_relative_{rstr}_{DXFVERSION}.dxf")
Exemple #5
0
    def transform(self, m: Matrix44) -> 'MText':
        """ Transform the MTEXT entity by transformation matrix `m` inplace. """
        dxf = self.dxf
        old_extrusion = Vec3(dxf.extrusion)
        new_extrusion, _ = transform_extrusion(old_extrusion, m)

        if dxf.hasattr('rotation') and not dxf.hasattr('text_direction'):
            # MTEXT is not an OCS entity, but I don't know how else to convert
            # a rotation angle for an entity just defined by an extrusion vector.
            # It's correct for the most common case: extrusion=(0, 0, 1)
            ocs = OCS(old_extrusion)
            dxf.text_direction = ocs.to_wcs(Vec3.from_deg_angle(dxf.rotation))

        dxf.discard('rotation')

        old_text_direction = Vec3(dxf.text_direction)
        new_text_direction = m.transform_direction(old_text_direction)

        old_char_height_vec = old_extrusion.cross(
            old_text_direction).normalize(dxf.char_height)
        new_char_height_vec = m.transform_direction(old_char_height_vec)
        oblique = new_text_direction.angle_between(new_char_height_vec)
        dxf.char_height = new_char_height_vec.magnitude * math.sin(oblique)

        if dxf.hasattr('width'):
            width_vec = old_text_direction.normalize(dxf.width)
            dxf.width = m.transform_direction(width_vec).magnitude

        dxf.insert = m.transform(dxf.insert)
        dxf.text_direction = new_text_direction
        dxf.extrusion = new_extrusion
        return self
    def test_reflections(self, s, e, rotation, sx, sy):
        m = Matrix44.chain(
            Matrix44.scale(sx, sy, 1),
            Matrix44.z_rotate(rotation),
        )
        expected_start = m.transform(Vec3.from_deg_angle(s))
        expected_end = m.transform(Vec3.from_deg_angle(e))
        expected_angle_span = arc_angle_span_deg(s, e)

        ocs = OCSTransform(Z_AXIS, m)
        new_s, new_e = ocs.transform_ccw_arc_angles_deg(s, e)
        wcs_start = ocs.new_ocs.to_wcs(Vec3.from_deg_angle(new_s))
        wcs_end = ocs.new_ocs.to_wcs(Vec3.from_deg_angle(new_e))
        assert arc_angle_span_deg(new_s, new_e) == pytest.approx(
            expected_angle_span
        )
        assert wcs_start.isclose(expected_start)
        assert wcs_end.isclose(expected_end)
 def add_dim(x, y, radius, dimtad):
     center = Vec3(x, y)
     msp.add_circle((x, y), radius=3)
     dim_location = center + Vec3.from_deg_angle(angle, radius)
     dim = msp.add_diameter_dim(center=(x, y), radius=3, location=dim_location, dimstyle='EZ_RADIUS',
                                override={
                                    'dimtad': dimtad,
                                })
     dim.render(discard=BRICSCAD)
Exemple #8
0
    def to_ocs_angle_deg(self, angle: float) -> float:
        """
        Transforms `angle` from current UCS to the parent coordinate system (most likely the WCS) including
        the transformation to the OCS established by the extrusion vector :attr:`UCS.uz`.

        Args:
            angle: in UCS in degrees

        """
        return self.ucs_direction_to_ocs_direction(Vec3.from_deg_angle(angle)).angle_deg
def add_dim_user(msp, x, y, distance, override):
    center = Vec3(x, y)
    msp.add_circle(center, radius=RADIUS)
    location = center + Vec3.from_deg_angle(45, distance)
    add_mark(msp, location)
    dim = msp.add_radius_dim(center=center,
                             radius=RADIUS,
                             location=location,
                             dimstyle='EZ_RADIUS',
                             override=override)
    dim.render()
Exemple #10
0
    def vertices(self, angles: Iterable[float]) -> Iterable[Vec3]:
        """ Yields vertices of the circle for iterable `angles` in WCS.

        Args:
            angles: iterable of angles in OCS as degrees, angle goes counter
                clockwise around the extrusion vector, ocs x-axis = 0 deg.

        """
        ocs = self.ocs()
        for angle in angles:
            v = Vec3.from_deg_angle(angle, self.dxf.radius) + self.dxf.center
            yield ocs.to_wcs(v)
Exemple #11
0
    def vertices(self, angles: Iterable[float]) -> Iterable[Vec3]:
        """Yields vertices of the circle for iterable `angles` in WCS.

        Args:
            angles: iterable of angles in OCS as degrees, angle goes counter
                clockwise around the extrusion vector, OCS x-axis = 0 deg.

        """
        ocs = self.ocs()
        radius: float = abs(self.dxf.radius)  # AutoCAD ignores the sign too
        center = Vec3(self.dxf.center)
        for angle in angles:
            yield ocs.to_wcs(Vec3.from_deg_angle(angle, radius) + center)
Exemple #12
0
 def add_dim(x, y, radius, dimtad):
     center = Vec3(x, y)
     msp.add_circle((x, y), radius=3)
     dim_location = center + Vec3.from_deg_angle(angle, radius)
     dim = msp.add_radius_dim(
         center=(x, y),
         radius=3,
         location=dim_location,
         dimstyle='EZ_RADIUS',
         override={
             'dimtad': dimtad,
             'dimtih': 1,  # force text inside horizontal
         })
     dim.render(discard=BRICSCAD)
Exemple #13
0
def arc_3p_default(distance: float = 2.0):
    doc = ezdxf.new(DXFVERSION, setup=True)
    msp = doc.modelspace()
    radius = 5
    data = [
        [Vec3(0, 0), 60, 120],
        [Vec3(10, 0), 300, 240],
        [Vec3(20, 0), 240, 300],
    ]
    for dimtad, offset in [(1, (0, 20)), (0, (0, 0)), (4, (0, -20))]:
        for center, start_angle, end_angle in data:
            center += Vec3(offset)
            dir1 = Vec3.from_deg_angle(start_angle)
            dir2 = Vec3.from_deg_angle(end_angle)

            # calculate defpoints from parameters of the "cra" example:
            p1 = center + dir1 * radius
            p2 = center + dir2 * radius
            base = center + dir1.lerp(dir2) * (radius + distance)

            add_lines(msp, center, radius, start_angle, end_angle)
            add_arc(msp, center, radius, start_angle, end_angle)
            msp.add_arc_dim_3p(
                base,
                center,
                p1,
                p2,
                override={
                    "dimtad": dimtad,
                    "dimtxt": 1,
                    "dimasz": 1,
                    "dimgap": 0.25,
                },
            ).render(discard=BRICSCAD)

    doc.set_modelspace_vport(height=70)
    doc.saveas(OUTDIR / f"dim_arc_3p_{DXFVERSION}.dxf")
Exemple #14
0
    def get_text_direction(self) -> Vec3:
        """Returns the horizontal text direction as :class:`~ezdxf.math.Vec3`
        object, even if only the text rotation is defined.

        """
        dxf = self.dxf
        # "text_direction" has higher priority than "rotation"
        if dxf.hasattr("text_direction"):
            return dxf.text_direction
        if dxf.hasattr("rotation"):
            # MTEXT is not an OCS entity, but I don't know how else to convert
            # a rotation angle for an entity just defined by an extrusion vector.
            # It's correct for the most common case: extrusion=(0, 0, 1)
            return OCS(dxf.extrusion).to_wcs(Vec3.from_deg_angle(dxf.rotation))
        return X_AXIS
 def add_dim(x, y, radius, dimtad):
     center = Vec3(x, y)
     msp.add_circle((x, y), radius=3)
     dim_location = center + Vec3.from_deg_angle(angle, radius)
     dim = msp.add_radius_dim(
         center=(x, y),
         radius=3,
         location=dim_location,
         dimstyle="EZ_RADIUS",
         override={
             "dimtad": dimtad,
             "dimtoh": 1,  # force text outside horizontal
         },
     )
     dim.render(discard=BRICSCAD)
Exemple #16
0
        def get_ucs() -> UCS:
            """ Create local coordinate system:
            origin = insertion point
            z-axis = extrusion vector
            x-axis = text_direction or text rotation, text rotation requires
                extrusion vector == (0, 0, 1) or treatment like an OCS?

            """
            origin = mtext.dxf.insert
            z_axis = mtext.dxf.extrusion  # default is Z_AXIS
            x_axis = X_AXIS
            if mtext.dxf.hasattr('text_direction'):
                x_axis = mtext.dxf.text_direction
            elif mtext.dxf.hasattr('rotation'):
                # TODO: what if extrusion vector is not (0, 0, 1)
                x_axis = Vec3.from_deg_angle(mtext.dxf.rotation)
                z_axis = Z_AXIS
            return UCS(origin=origin, ux=x_axis, uz=z_axis)
Exemple #17
0
    def _create_linked_columns(self) -> None:
        """ Create linked MTEXT columns for DXF versions before R2018. """
        # creates virtual MTEXT entities
        dxf = self.dxf
        attribs = self.dxfattribs(drop={'handle', 'owner'})
        doc = self.doc
        cols = self._columns

        insert = dxf.get('insert', Vec3())
        default_direction = Vec3.from_deg_angle(dxf.get('rotation', 0))
        text_direction = Vec3(dxf.get('text_direction', default_direction))
        offset = text_direction.normalize(cols.width + cols.gutter_width)
        linked_columns = cols.linked_columns
        for _ in range(cols.count - 1):
            insert += offset
            column = MText.new(dxfattribs=attribs, doc=doc)
            column.dxf.insert = insert
            linked_columns.append(column)
Exemple #18
0
def ordinate_ucs(
    filename: str,
    rotate: float = 30.0,
):
    doc = ezdxf.new(DXFVERSION, setup=True)
    dimstyle = doc.dimstyles.duplicate_entry("EZDXF", "ORD_CENTER")
    dimstyle.dxf.dimtad = 0
    msp = doc.modelspace()

    for origin in [Vec3(5, 20), Vec3(0, 0), Vec3(-5, -20)]:
        ucs = UCS(origin, ux=Vec3.from_deg_angle(rotate), uz=(0, 0, 1))
        msp.add_ordinate_x_dim(feature_location=(3, 2),
                               offset=(1, 2),
                               dimstyle="ORD_CENTER").render(ucs=ucs)
        msp.add_ordinate_y_dim(feature_location=(3, 2),
                               offset=(1, -2),
                               dimstyle="ORD_CENTER").render(ucs=ucs)

    doc.set_modelspace_vport(height=70)
    doc.saveas(OUTDIR / f"{filename}_{DXFVERSION}.dxf")
Exemple #19
0
import ezdxf
from ezdxf.math import UCS, Vec3
from pathlib import Path

OUT_DIR = Path('~/Desktop/Outbox').expanduser()

doc = ezdxf.new('R2010')
msp = doc.modelspace()

# Thickness for text works only with shx fonts not with true type fonts
doc.styles.new('TXT', dxfattribs={'font': 'romans.shx'})

ucs = UCS(origin=(0, 2, 2), ux=(1, 0, 0), uz=(0, 1, 1))
# calculation of text direction as angle in OCS:
# convert text rotation in degree into a vector in UCS
text_direction = Vec3.from_deg_angle(-45)
# transform vector into OCS and get angle of vector in xy-plane
rotation = ucs.to_ocs(text_direction).angle_deg

text = msp.add_text(
    text="TEXT",
    dxfattribs={
        # text rotation angle in degrees in OCS
        'rotation': rotation,
        'extrusion': ucs.uz,
        'thickness': .333,
        'color': 1,
        'style': 'TXT',
    })
# set text position in OCS
text.set_pos(ucs.to_ocs((0, 0, 0)), align='MIDDLE_CENTER')
Exemple #20
0
from pathlib import Path

OUT_DIR = Path('~/Desktop/Outbox').expanduser()

doc = ezdxf.new('R2010')
msp = doc.modelspace()

ucs = UCS(origin=(0, 2, 2), ux=(1, 0, 0), uz=(0, 1, 1))
msp.add_arc(center=ucs.to_ocs((0, 0)),
            radius=1,
            start_angle=ucs.to_ocs_angle_deg(45),
            end_angle=ucs.to_ocs_angle_deg(270),
            dxfattribs={
                'extrusion': ucs.uz,
                'color': 1,
            })
center = ucs.to_wcs((0, 0))
msp.add_line(
    start=center,
    end=ucs.to_wcs(Vec3.from_deg_angle(45)),
    dxfattribs={'color': 1},
)
msp.add_line(
    start=center,
    end=ucs.to_wcs(Vec3.from_deg_angle(270)),
    dxfattribs={'color': 1},
)

ucs.render_axis(msp)
doc.saveas(OUT_DIR / 'ocs_arc.dxf')
# Create a special DIMSTYLE for "vertical" centered measurement text:
dimstyle = doc.dimstyles.duplicate_entry("EZDXF", "ORD_CENTER")
dimstyle.dxf.dimtad = 0  # "vertical" centered measurement text

# Add a rectangle: width=4, height = 2.5, lower left corner is WCS(x=2, y=3),
# rotated about 30 degrees:
origin = Vec3(2, 3)
msp.add_lwpolyline(forms.translate(forms.rotate(forms.box(4, 2.5), 30),
                                   origin),
                   close=True)

# Define the rotated local render UCS.
# The origin is the lower-left corner of the rectangle and the axis are
# aligned to the rectangle edges:
# The y-axis "uy" is calculated automatically by the right-hand rule.
ucs = UCS(origin, ux=Vec3.from_deg_angle(30), uz=(0, 0, 1))

# Add a x-type ordinate DIMENSION with local feature locations:
# the origin is now the origin of the UCS, which is (0, 0) the default value of
# "origin" and the feature coordinates are located in the UCS:
msp.add_ordinate_x_dim(
    # lower left corner
    feature_location=(0, 0),  # feature location in the UCS
    offset=(0.25, -2),  # # leader with a "knee"
    dimstyle="ORD_CENTER",
).render(ucs=ucs)  # Important when using a render UCS!
msp.add_ordinate_x_dim(
    # lower right corner
    feature_location=(4, 0),  # feature location in the UCS
    offset=(0.25, -2),  # leader with a "knee"
    dimstyle="ORD_CENTER",
Exemple #22
0
START_ANGLE = 45
END_ANGLE = 270

msp.add_arc(
    center=CENTER,
    radius=1,
    start_angle=START_ANGLE,
    end_angle=END_ANGLE,
    dxfattribs={
        'color': 6
    },
).transform(ucs.matrix)

msp.add_line(
    start=CENTER,
    end=Vec3.from_deg_angle(START_ANGLE),
    dxfattribs={
        'color': 6
    },
).transform(ucs.matrix)

msp.add_line(
    start=CENTER,
    end=Vec3.from_deg_angle(END_ANGLE),
    dxfattribs={
        'color': 6
    },
).transform(ucs.matrix)

ucs.render_axis(msp)
doc.saveas(OUT_DIR / 'ucs_arc.dxf')
                        })

zoom.extents(msp)
doc.saveas(DIR / 'concept-0-fit-points-only.dxf')

# ------------------------------------------------------------------------------
# SPLINE from fit points WITH given end tangents.
# ------------------------------------------------------------------------------

# 2. Store fit points, start- and end tangent values in DXF file:
doc, msp = setup()
# Tangent estimation method: "Total Chord Length",
# returns sum of chords for m1 and m2
m1, m2 = estimate_end_tangent_magnitude(points, method='chord')
# Multiply tangent vectors by total chord length for global interpolation:
start_tangent = Vec3.from_deg_angle(100) * m1
end_tangent = Vec3.from_deg_angle(-100) * m2
# Interpolate control vertices from fit points and end derivatives as constraints
s = global_bspline_interpolation(points,
                                 degree=3,
                                 tangents=(start_tangent, end_tangent))
msp.add_spline(dxfattribs={
    'color': 4,
    'layer': 'Global Interpolation'
}).apply_construction_tool(s)

# Result matches the BricsCAD interpolation if fit points, start- and end
# tangents are stored explicit in the DXF file.
spline = msp.add_spline(points,
                        degree=3,
                        dxfattribs={
Exemple #24
0
OUT_DIR = Path('~/Desktop/Outbox').expanduser()

doc = ezdxf.new('R2010')
msp = doc.modelspace()

# The center of the pentagon should be (0, 2, 2), and the shape is
# rotated around x-axis about 45 degree, to accomplish this I use an
# UCS with z-axis (0, 1, 1) and an x-axis parallel to WCS x-axis.
ucs = UCS(
    origin=(0, 2, 2),  # center of pentagon
    ux=(1, 0, 0),  # x-axis parallel to WCS x-axis
    uz=(0, 1, 1),  # z-axis
)
# calculating corner points in local (UCS) coordinates
points = [Vec3.from_deg_angle((360 / 5) * n) for n in range(5)]
# converting UCS into OCS coordinates
ocs_points = list(ucs.points_to_ocs(points))

# LWPOLYLINE accepts only 2D points and has an separated DXF attribute elevation.
# All points have the same z-axis (elevation) in OCS!
elevation = ocs_points[0].z

msp.add_lwpolyline(
    points=ocs_points,
    format='xy',  # ignore z-axis
    dxfattribs={
        'elevation': elevation,
        'extrusion': ucs.uz,
        'closed': True,
        'color': 1,