def circle(count, radius=1, elevation=0, close=False): """ Create polygon vertices for a circle with *radius* and *count* corners, *elevation* is the z-axis for all vertices. Args: count: count of polygon vertices radius: circle radius elevation: z axis for all vertices close: yields first vertex also as last vertex if True. Returns: yields Vector() objects in counter clockwise orientation """ radius = float(radius) delta = 2. * pi / count alpha = 0. for index in range(count): x = cos(alpha) * radius y = sin(alpha) * radius yield Vector(x, y, elevation) alpha += delta if close: yield Vector(radius, 0, elevation)
def test_arbitrary_ucs(): origin = Vector(3, 3, 3) ux = Vector(1, 2, 0) def_point_in_xy_plane = Vector(3, 10, 4) uz = ux.cross(def_point_in_xy_plane - origin) ucs = UCS(origin=origin, ux=ux, uz=uz) def_point_in_ucs = ucs.from_wcs(def_point_in_xy_plane) assert def_point_in_ucs.z == 0 assert ucs.to_wcs(def_point_in_ucs) == def_point_in_xy_plane assert ucs.is_cartesian is True
def test_rotation(): # normalization is not necessary ux = Vector(1, 2, 0) # only cartesian coord systems work uy = ux.rot_z_deg(90) ucs = UCS(ux=ux, uy=uy) assert ucs.ux == ux.normalize() assert ucs.uy == uy.normalize() assert ucs.uz == (0, 0, 1) assert ucs.is_cartesian is True
def test_cylinder(): mesh = cylinder(12) assert len(mesh.faces) == 14 # 1x bottom, 1x top, 12x side assert len(mesh.vertices) == 24 # 12x bottom, 12x top mesh = cylinder(count=12, radius=3, top_radius=2, top_center=(1, 0, 3), caps=False) assert len(mesh.faces) == 12 assert len(mesh.vertices) == 24 assert Vector(3, 0, 3) in mesh.vertices assert Vector(-1, 0, 3) in mesh.vertices
def test_arc_from_2p_radius(): p1 = (2, 1) p2 = (0, 3) radius = 2 arc = Arc.from_2p_radius(start_point=p1, end_point=p2, radius=radius) assert almost_equal_points(arc.center, Vector(0, 1)) assert equals_almost(arc.radius, radius) assert equals_almost(arc.start_angle, 0) assert equals_almost(arc.end_angle, 90) arc = Arc.from_2p_radius(start_point=p2, end_point=p1, radius=radius) assert almost_equal_points(arc.center, Vector(2, 3)) assert equals_almost(arc.radius, radius) assert equals_almost(arc.start_angle, 180) assert equals_almost(arc.end_angle, -90)
def ellipse(count, rx=1, ry=1, start_param=0, end_param=2 * pi, elevation=0): """ Create polygon vertices for an ellipse with *rx* as x-axis radius and *ry* for y-axis radius with *count* vertices, *elevation* is the z-axis for all vertices. The ellipse goes from *start_param* to *end_param* in counter clockwise orientation. Args: count: count of polygon vertices rx: ellipse x-axis radius ry: ellipse y-axis radius start_param: start of ellipse in range 0 .. 2*pi end_param: end of ellipse in range 0 .. 2*pi elevation: z-axis for all vertices Returns: yields Vector() objects """ rx = float(rx) ry = float(ry) start_param = float(start_param) end_param = float(end_param) count = int(count) delta = (end_param - start_param) / (count - 1) for param in range(count): alpha = start_param + param * delta yield Vector(cos(alpha) * rx, sin(alpha) * ry, elevation)
def tangent(self, t): """ Get tangent at distance t as Vector() object. """ angle = t**2 / (2. * self.curvature_powers[2]) return Vector.from_rad_angle(angle)
def spline_insert_knot(): dwg = ezdxf.new('R2000') ezdxf.setup_linetypes(dwg) msp = dwg.modelspace() def add_spline(control_points, color=3, knots=None): msp.add_polyline2d(control_points, dxfattribs={ 'color': color, 'linetype': 'DASHED' }) msp.add_open_spline(control_points, degree=3, knots=knots, dxfattribs={'color': color}) control_points = Vector.list([(0, 0), (10, 20), (30, 10), (40, 10), (50, 0), (60, 20), (70, 50), (80, 70)]) add_spline(control_points, color=3, knots=None) bspline = BSpline(control_points, order=4) bspline.insert_knot(bspline.max_t / 2) add_spline(bspline.control_points, color=4, knots=bspline.knot_values()) if dwg.validate(): dwg.saveas("Spline_R2000_spline_insert_knot.dxf")
def test_arc_from_2p_angle_simple(): p1 = (2, 1) p2 = (0, 3) angle = 90 arc = Arc.from_2p_angle(start_point=p1, end_point=p2, angle=angle) assert almost_equal_points(arc.center, Vector(0, 1)) assert equals_almost(arc.radius, 2) assert equals_almost(arc.start_angle, 0) assert equals_almost(arc.end_angle, 90) arc = Arc.from_2p_angle(start_point=p2, end_point=p1, angle=angle) assert almost_equal_points(arc.center, Vector(2, 3)) assert equals_almost(arc.radius, 2) assert equals_almost(arc.start_angle, 180) assert equals_almost(arc.end_angle, -90)
def reset_boundary_path(self): lower_left_corner = (-.5, -.5) upper_right_corner = Vector(self.dxf.image_size) + lower_left_corner self._set_path_tags([lower_left_corner, upper_right_corner[:2]]) self.set_flag_state(Image.USE_CLIPPING_BOUNDARY, state=False) self.dxf.clipping = 0 self.dxf.clipping_boundary_type = 1
def approximate(self, length, segments): """ Approximate curve of length with line segments. Generates segments+1 vertices as Vector() objects. """ delta_l = float(length) / float(segments) yield Vector(0, 0) for index in range(1, segments + 1): yield self.point(delta_l * index)
def extrude(profile, path, close=True): """ Extrude a profile polygon along a path polyline, vertices of profile should be in counter clockwise order. Args: profile: sweeping profile as list of (x, y, z) tuples in counter clock wise order path: extrusion path as list of (x, y, z) tuples close: close profile polygon if True Returns: MeshVertexMerger() """ def add_hull(bottom_profile, top_profile): prev_bottom = bottom_profile[0] prev_top = top_profile[0] for bottom, top in zip(bottom_profile[1:], top_profile[1:]): face = (prev_bottom, bottom, top, prev_top ) # counter clock wise: normals outwards mesh.faces.append(face) prev_bottom = bottom prev_top = top mesh = MeshVertexMerger() if close: profile = close_polygon(profile) profile = [Vector(p) for p in profile] path = [Vector(p) for p in path] start_point = path[0] bottom_indices = mesh.add_vertices(profile) # base profile for target_point in path[1:]: translation_vector = target_point - start_point # profile will just be translated profile = [vec + translation_vector for vec in profile] top_indices = mesh.add_vertices(profile) add_hull(bottom_indices, top_indices) bottom_indices = top_indices start_point = target_point return mesh
def translate(vertices, vec=(0, 0, 1)): """ Simple translation, faster than a Matrix44 transformation. Args: vertices: list of vertices vec: translation vector Returns: yields transformed vertices """ vec = Vector(vec) for p in vertices: yield vec + p
def test_spatial_arc_from_3p(): start_point_wcs = Vector(0, 1, 0) end_point_wcs = Vector(1, 0, 0) def_point_wcs = Vector(0, 0, 1) ucs = UCS.from_x_axis_and_point_in_xy(origin=def_point_wcs, axis=end_point_wcs - def_point_wcs, point=start_point_wcs) start_point_ucs = ucs.from_wcs(start_point_wcs) end_point_ucs = ucs.from_wcs(end_point_wcs) def_point_ucs = Vector(0, 0) arc = Arc.from_3p(start_point_ucs, end_point_ucs, def_point_ucs) dwg = ezdxf.new('R12') msp = dwg.modelspace() dxf_arc = arc.add_to_layout(msp, ucs) assert dxf_arc.dxftype() == 'ARC' assert equals_almost(dxf_arc.dxf.radius, 0.81649658) assert equals_almost(dxf_arc.dxf.start_angle, -30.) assert equals_almost(dxf_arc.dxf.end_angle, -150.) assert almost_equal_points(dxf_arc.dxf.extrusion, (0.57735027, 0.57735027, 0.57735027))
def circle(count, radius=1.0, z=0., close=False): """ Create polygon vertices for a circle with *radius* and *count* corners at *z* height. Args: count: polygon corners radius: circle radius z: z axis value close: yields first vertex also as last vertex if True. Returns: yields Vector() objects in count clockwise orientation """ delta = 2. * pi / count alpha = 0. for index in range(count): x = cos(alpha) * radius y = sin(alpha) * radius yield Vector(x, y, z) alpha += delta if close: yield Vector(radius, 0, z)
def point(self, t): """ Get point at distance t as Vector(). """ def term(powerL, powerA, const): return t ** powerL / (const * self.powersA[powerA]) if t not in self._cache: y = term(3, 2, 6.) - term(7, 6, 336.) + term(11, 10, 42240.) - \ term(15, 14, 9676800.) + term(19, 18, 3530096640.) x = t - term(5, 4, 40.) + term(9, 8, 3456.) - term(13, 12, 599040.) + \ term(17, 16, 175472640.) self._cache[t] = Vector(x, y) return self._cache[t]
def rotation_form(count, profile, angle=2 * pi, axis=(1, 0, 0)): """ Mesh by rotating a profile around an axis. Args: count: count of rotated profiles profile: profile to rotate as list of vertices angle: rotation angle in radians axis: rotation axis Returns: MeshVertexMerger() """ if count < 3: raise ValueError('count >= 2') delta = float(angle) / count m = Matrix44.axis_rotate(Vector(axis), delta) profile = [Vector(p) for p in profile] profiles = [profile] for _ in range(int(count)): profile = m.transform_vectors(profile) profiles.append(profile) mesh = from_profiles_linear(profiles, close=False, caps=False) return mesh
def test_basis_vector_N_ip(): degree = 3 fit_points = Vector.list(POINTS2) # data points D n = len(fit_points) - 1 t_vector = list(uniform_t_vector(fit_points)) knots = list(control_frame_knots(n, degree, t_vector)) should_count = len(fit_points) - 2 # target control point count h = should_count - 1 spline = Basis(knots, order=degree + 1, count=len(fit_points)) matrix_N = [spline.basis(t) for t in t_vector] for k in range(1, n): basis_vector = bspline_basis_vector(u=t_vector[k], count=len(fit_points), degree=degree, knots=knots) for i in range(1, h): assert is_close(matrix_N[k][i], basis_vector[i])
def add_image(self, image_def, insert, size_in_units, rotation=0., dxfattribs=None): def to_vector(units_per_pixel, angle_in_rad): x = math.cos(angle_in_rad) * units_per_pixel y = math.sin(angle_in_rad) * units_per_pixel return round(x, 6), round( y, 6), 0 # supports only images in the xy-plane if self.dxfversion < 'AC1015': raise DXFVersionError('IMAGE requires DXF version R2000+') dxfattribs = copy_attribs(dxfattribs) x_pixels, y_pixels = image_def.dxf.image_size x_units, y_units = size_in_units x_units_per_pixel = x_units / x_pixels y_units_per_pixel = y_units / y_pixels x_angle_rad = math.radians(rotation) y_angle_rad = x_angle_rad + (math.pi / 2.) dxfattribs['insert'] = Vector(insert) dxfattribs['u_pixel'] = to_vector(x_units_per_pixel, x_angle_rad) dxfattribs['v_pixel'] = to_vector(y_units_per_pixel, y_angle_rad) dxfattribs['image_def'] = image_def.dxf.handle dxfattribs['image_size'] = image_def.dxf.image_size image = self.build_and_add_entity('IMAGE', dxfattribs) if self.drawing is not None: image_def_reactor = self.drawing.objects.add_image_def_reactor( image.dxf.handle) reactor_handle = image_def_reactor.dxf.handle image.dxf.image_def_reactor = reactor_handle image_def.append_reactor_handle(reactor_handle) return image
def spline_control_frame_approximation(): dwg = ezdxf.new('R2000') ezdxf.setup_linetypes(dwg) fit_points = Vector.list([(0, 0), (10, 20), (30, 10), (40, 10), (50, 0), (60, 20), (70, 50), (80, 70), (65, 75)]) msp = dwg.modelspace() msp.add_polyline2d(fit_points, dxfattribs={'color': 2, 'linetype': 'DOT2'}) spline = bspline_control_frame_approx(fit_points, count=7, degree=3, method='uniform') msp.add_polyline2d(spline.control_points, dxfattribs={ 'color': 3, 'linetype': 'DASHED' }) msp.add_open_spline(spline.control_points, degree=spline.degree, dxfattribs={'color': 3}) msp.add_spline(fit_points, degree=3, dxfattribs={'color': 1}) if dwg.validate(): dwg.saveas("Spline_R2000_spline_control_frame_approximation.dxf")
def draw(points, extrusion=None): dxfattribs = {'color': 1} if extrusion is not None: ocs = OCS(extrusion) points = ocs.points_from_wcs(points) dxfattribs['extrusion'] = extrusion for point in points: msp.add_circle(radius=0.1, center=point, dxfattribs=dxfattribs) base_spline_points = [(8.55, 2.96), (8.55, -.03), (2.75, -.03), (2.76, 3.05), (4.29, 1.78), (6.79, 3.05)] spline_points = [Vector(p) for p in base_spline_points] # open quadratic b-spline draw(spline_points) msp.add_text("Open Quadratic R12Spline", dxfattribs={ 'height': .1 }).set_pos(spline_points[0]) R12Spline(spline_points, degree=2, closed=False).render(msp, segments=SEGMENTS, dxfattribs={'color': 3}) if dwg.dxfversion > 'AC1009': msp.add_open_spline(control_points=spline_points, degree=2, dxfattribs={'color': 4}) # open cubic b-spline spline_points = next_frame.transform_vectors(spline_points)
def random_pos(lower_left=(0, 0), upper_right=(100, 100)): x0, y0 = lower_left x1, y1 = upper_right x = random_in_range(x0, x1) y = random_in_range(y0, y1) return Vector(x, y)
dwg = ezdxf.new('R2010') msp = dwg.modelspace() # include-start 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), # shortcut end_angle=ucs.to_ocs_angle_deg(270), # shortcut dxfattribs={ 'extrusion': ucs.uz, 'color': 2, }) center = ucs.to_wcs((0, 0)) msp.add_line( start=center, end=ucs.to_wcs(Vector.from_deg_angle(45)), dxfattribs={'color': 2}, ) msp.add_line( start=center, end=ucs.to_wcs(Vector.from_deg_angle(270)), dxfattribs={'color': 2}, ) # include-end ucs.render_axis(msp) dwg.saveas('ocs_arc.dxf')
# Copyright (c) 2018 Manfred Moitzi # License: MIT License from __future__ import unicode_literals import ezdxf from ezdxf.algebra import Vector, Arc, UCS dwg = ezdxf.new('R2000') modelspace = dwg.modelspace() # create a 2D arcs in xy-plane delta = 30 for count in range(12): modelspace.add_arc(center=(0, 0), radius=10+count, start_angle=count*delta, end_angle=(count+1)*delta) # create a 3D arc from 3 points in WCS start_point_wcs = Vector(3, 0, 0) end_point_wcs = Vector(0, 3, 0) def_point_wcs = Vector(0, 0, 3) # create UCS ucs = UCS.from_x_axis_and_point_in_xy(origin=def_point_wcs, axis=start_point_wcs-def_point_wcs, point=end_point_wcs) start_point_ucs = ucs.from_wcs(start_point_wcs) end_point_ucs = ucs.from_wcs(end_point_wcs) def_point_ucs = Vector(0, 0) # origin of UCS # create arc in the xy-plane of the UCS arc = Arc.from_3p(start_point_ucs, end_point_ucs, def_point_ucs) arc.add_to_layout(modelspace, ucs, dxfattribs={'color': 1}) # red arc arc = Arc.from_3p(end_point_ucs, start_point_ucs, def_point_ucs) arc.add_to_layout(modelspace, ucs, dxfattribs={'color': 2}) # yellow arc
# License: MIT License # include-start import ezdxf from ezdxf.algebra import UCS, Vector dwg = ezdxf.new('R2010') msp = dwg.modelspace() # thickness for text works only with shx fonts not with true type fonts dwg.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 = Vector.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': 2, 'style': 'TXT', }) # set text position in OCS text.set_pos(ucs.to_ocs((0, 0, 0)), align='MIDDLE_CENTER')
next_frame = Matrix44.translate(0, 7, 0) NAME = 'r12spline.dxf' SEGMENTS = 40 dwg = ezdxf.new('R12') msp = dwg.modelspace() def draw(points): for point in points: msp.add_circle(radius=0.1, center=point, dxfattribs={'color': 1}) spline_points = [ Vector(p) for p in [(8.55, 2.96), (8.55, -.03), (2.75, -.03), (2.76, 3.05), (4.29, 1.78), (6.79, 3.05)] ] # open quadratic b-spline draw(spline_points) msp.add_text("Open Quadratic R12Spline", dxfattribs={ 'height': .1 }).set_pos(spline_points[0]) R12Spline(spline_points, degree=2, closed=False).render(msp, segments=SEGMENTS, dxfattribs={'color': 3}) if dwg.dxfversion > 'AC1009': msp.add_open_spline(control_points=spline_points,
from ezdxf.algebra import Vector, Matrix44 next_frame = Matrix44.translate(0, 5, 0) right_frame = Matrix44.translate(10, 0, 0) NAME = 'spline.dxf' dwg = ezdxf.new('R2000') msp = dwg.modelspace() def draw(points): for point in points: msp.add_circle(radius=0.1, center=point, dxfattribs={'color': 1}) spline_points = Vector.list([(1., 1.), (2.5, 3.), (4.5, 2.), (6.5, 4.)]) # fit points draw(spline_points) Spline(spline_points).render_as_fit_points( msp, method='distance', dxfattribs={'color': 2}) # curve with definition points as fit points Spline(spline_points).render_as_fit_points(msp, method='uniform', dxfattribs={'color': 3}) Spline(spline_points).render_as_fit_points(msp, method='centripetal', dxfattribs={'color': 4}) # distance ^ 1/2 Spline(spline_points).render_as_fit_points(msp, method='centripetal',
import ezdxf from ezdxf.algebra import Vector, UCS dwg = ezdxf.new('R2010') msp = dwg.modelspace() # center point 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 = [Vector.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( # LWPOLYLINE point format: (x, y, [start_width, [end_width, [bulge]]]) # the z-axis would be start_width, so remove it points=[p[:2] for p in ocs_points], dxfattribs={ 'elevation': elevation, 'extrusion': ucs.uz, 'closed': True,