def create_doc(filename, content_creator): print(f"start DXF document: {filename}") doc = ezdxf.new(dxfversion='R2004') for name in LAYERS: doc.layers.new(name) doc.styles.new(ATTRIBS, dxfattribs={'font': 'OpenSansCondensed-Light.ttf'}) content_creator(doc) msp = doc.modelspace() print("exploding ...") ts = perf_counter() explode(msp) print(f"... required {perf_counter()-ts:.2f}s") print("zooming ...") ts = perf_counter() if EXPLODE_CONTENT: # processing only LINE entities is much faster: zoom.objects(msp, doc.modelspace().query('LINE')) else: zoom.extents(msp) print(f"... required {perf_counter()-ts:.2f}s") print("saving ...") ts = perf_counter() doc.saveas(filename) print(f"... required {perf_counter()-ts:.2f}s") print(f"saved DXF document: {filename}\n")
def scene1(filename): doc = ezdxf.new('R2010', setup=True) msp = doc.modelspace() ucs = UCS() angle = math.pi / 12 # 15 degree for ix in range(X_COUNT): for iy in range(Y_COUNT): ucs.moveto((ix * DX, iy * DY, 0)) ucs.render_axis(msp, length=1) add_circle(msp, ucs) # add_ocs_circle(msp, ucs) # add_ocs_arc(msp, ucs) # add_text(msp, ucs) add_mtext(msp, ucs) add_ellipse(msp, ucs) # add_solid(msp, ucs) add_trace(msp, ucs) # add_3dface(msp, ucs) # add_lwpolyline(msp, ucs) ucs = ucs.rotate_local_z(angle) ucs = UCS().rotate_local_x(ix * angle) zoom.extents(msp) doc.saveas(filename)
def create_mpolygon_with_bulge(dxfversion="R2000"): doc = ezdxf.new(dxfversion) msp = doc.modelspace() mpolygon = msp.add_mpolygon(color=1, fill_color=5) mpolygon.paths.add_polyline_path([(0, 0), (0, 3, 0.5), (3, 6), (6, 6), (6, 3), (3, 0)]) zoom.extents(msp) doc.saveas(DIR / f"simple_mpolygon_with_bulge_{dxfversion}.dxf")
def using_hatch_style(): def place_square_1(hatch, x, y): def shift(point): return x + point[0], y + point[1] # outer loop - flags = 1 (external) default value hatch.paths.add_polyline_path( map(shift, [(0, 0), (8, 0), (8, 8), (0, 8)])) # first inner loop - flags = 16 (outermost) hatch.paths.add_polyline_path( map(shift, [(2, 2), (7, 2), (7, 7), (2, 7)]), flags=const.BOUNDARY_PATH_OUTERMOST, ) # any further inner loops - flags = 0 (default) hatch.paths.add_polyline_path( map(shift, [(4, 4), (6, 4), (6, 6), (4, 6)]), flags=const.BOUNDARY_PATH_DEFAULT, ) def place_square_2(hatch, x, y): def shift(point): return x + point[0], y + point[1] # outer loop - flags = 1 (external) default value hatch.paths.add_polyline_path( map(shift, [(0, 0), (8, 0), (8, 8), (0, 8)])) # partly 1. inner loop - flags = 16 (outermost) hatch.paths.add_polyline_path( map(shift, [(3, 1), (7, 1), (7, 5), (3, 5)]), flags=const.BOUNDARY_PATH_OUTERMOST, ) # partly 1. inner loop - flags = 16 (outermost) hatch.paths.add_polyline_path( map(shift, [(1, 3), (5, 3), (5, 7), (1, 7)]), flags=const.BOUNDARY_PATH_OUTERMOST, ) doc = ezdxf.new("R2010") # create a new DXF drawing (AutoCAD 2010) msp = doc.modelspace() # we are working in model space # first create DXF hatch entities hatch_style_0 = msp.add_hatch(color=3, dxfattribs={"hatch_style": 0}) hatch_style_1 = msp.add_hatch(color=3, dxfattribs={"hatch_style": 1}) hatch_style_2 = msp.add_hatch(color=3, dxfattribs={"hatch_style": 2}) # then insert path elements to define the hatch boundaries place_square_1(hatch_style_0, 0, 0) place_square_1(hatch_style_1, 10, 0) place_square_1(hatch_style_2, 20, 0) # first create DXF hatch entities hatch_style_0b = msp.add_hatch(color=4, dxfattribs={"hatch_style": 0}) hatch_style_1b = msp.add_hatch(color=4, dxfattribs={"hatch_style": 1}) hatch_style_2b = msp.add_hatch(color=4, dxfattribs={"hatch_style": 2}) # then insert path elements to define the hatch boundaries place_square_2(hatch_style_0b, 0, 10) place_square_2(hatch_style_1b, 10, 10) place_square_2(hatch_style_2b, 20, 10) zoom.extents(msp) doc.saveas(DIR / "hatch_styles_examples.dxf") # save DXF drawing
def create_solid_polyline_hatch(): doc = ezdxf.new("R2010") # create a new DXF drawing (AutoCAD 2010) msp = doc.modelspace() # we are working in model space hatch = msp.add_hatch(color=2) # by default a SOLID fill # if only 1 path - flags = 1 (external) by default hatch.paths.add_polyline_path([(0, 0), (0, 3), (3, 6), (6, 6), (6, 3), (3, 0)]) zoom.extents(msp) doc.saveas(DIR / "hatch_solid_polyline.dxf") # save DXF drawing
def create_simple_pattern_filled_mpolygon(dxfversion="R2000"): doc = ezdxf.new(dxfversion) msp = doc.modelspace() mpolygon = msp.add_mpolygon() mpolygon.set_pattern_fill("ANSI33", color=7, scale=0.01) mpolygon.paths.add_polyline_path([(0, 0), (0, 3), (3, 6), (6, 6), (6, 3), (3, 0)]) zoom.extents(msp) doc.saveas(DIR / f"simple_pattern_filled_mpolygon_{dxfversion}.dxf")
def create_simple_solid_rgb_filled_mpolygon(dxfversion="R2000"): doc = ezdxf.new(dxfversion) msp = doc.modelspace() mpolygon = msp.add_mpolygon(color=1, fill_color=5) mpolygon.paths.add_polyline_path([(0, 0), (0, 3), (3, 6), (6, 6), (6, 3), (3, 0)]) mpolygon.set_solid_fill(rgb=(60, 180, 60)) # overrides fill_color! zoom.extents(msp) doc.saveas(DIR / f"simple_solid_rgb_filled_mpolygon_{dxfversion}.dxf")
def explode_mtext(doc, filename, destroy=False): msp = doc.modelspace() with MTextExplode(msp) as xpl: for mtext in msp.query("MTEXT"): xpl.explode(mtext, destroy=destroy) if mtext.is_alive: mtext.dxf.layer = "SOURCE" zoom.extents(msp) doc.saveas(DIR / filename)
def explode_mtext(doc, destroy=True): msp = doc.modelspace() xpl = MTextExplode(msp) for mtext in msp.query("MTEXT"): xpl.explode(mtext, destroy=destroy) xpl.finalize() if mtext.is_alive: mtext.dxf.layer = "SOURCE" zoom.extents(msp) return doc
def create_pattern_fill_hatch_with_bgcolor(): doc = ezdxf.new("R2010") # create a new DXF drawing (AutoCAD 2010) msp = doc.modelspace() # we are working in model space hatch = msp.add_hatch() # by default a SOLID fill hatch.set_pattern_fill("ANSI33", color=7, scale=0.01) # if only 1 path - flags = 1 (external) by default hatch.paths.add_polyline_path([(0, 0), (0, 3), (3, 6), (6, 6), (6, 3), (3, 0)]) hatch.bgcolor = (100, 200, 100) zoom.extents(msp) doc.saveas(DIR / "hatch_pattern_fill_with_bgcolor.dxf") # save DXF drawing
def explode_mtext_to_block(doc, filename, destroy=False): msp = doc.modelspace() blk = doc.blocks.new("EXPLODE") with MTextExplode(blk) as xpl: for mtext in msp.query("MTEXT"): xpl.explode(mtext, destroy=destroy) if mtext.is_alive: mtext.dxf.layer = "SOURCE" msp.add_blockref("EXPLODE", (0, 0)) zoom.extents(msp) doc.saveas(DIR / filename)
def create_pattern_filled_mpolygon_with_bgcolor(): doc = ezdxf.new("R2010") msp = doc.modelspace() # This is not supported by TrueView/BricsCAD! # TrueView doesn't show this MPOLYGON at all! mpolygon = msp.add_mpolygon() mpolygon.set_pattern_fill("ANSI33", color=7, scale=0.01) mpolygon.paths.add_polyline_path([(0, 0), (0, 3), (3, 6), (6, 6), (6, 3), (3, 0)]) mpolygon.bgcolor = (100, 200, 100) zoom.extents(msp) doc.saveas(DIR / f"simple_pattern_filled_mpolygon_with_bgcolor_{dxfversion}.dxf")
def create_doc(dxfversion): doc = ezdxf.new(dxfversion, setup=True) msp = doc.modelspace() msp.add_circle(center=(0, 0), radius=1.5, dxfattribs={ 'layer': 'test', 'linetype': 'DASHED', }) zoom.extents(msp, factor=1.1) filename = DIR / f'{doc.acad_release}.dxf' doc.saveas(filename) print("drawing '%s' created.\n" % filename)
def main(filename: str, n: int, d: int) -> None: doc = ezdxf.new() doc.layers.new('PETALS', dxfattribs={'color': 1}) doc.layers.new('NET', dxfattribs={'color': 5}) msp = doc.modelspace() msp.add_lwpolyline(maurer_rose(n, 1, 250), close=True, dxfattribs={'layer': 'PETALS'}) msp.add_lwpolyline(maurer_rose(n, d, 250), close=True, dxfattribs={'layer': 'NET'}) zoom.extents(msp) doc.saveas(filename)
def new_doc(content: str, width: float = 30): doc = ezdxf.new(setup=True) msp = doc.modelspace() mtext = msp.add_mtext(content, dxfattribs={ "layer": "MTEXT_EXPLODE", "width": width, "char_height": 1, "color": 7, "style": "OpenSans", "line_spacing_style": ezdxf.const.MTEXT_EXACT }) mtext.set_bg_color(None, text_frame=True) zoom.extents(msp) return doc
def main(filename: str, n: int, d: int) -> None: doc = ezdxf.new() doc.layers.add("PETALS", color=1) doc.layers.add("NET", color=5) msp = doc.modelspace() msp.add_lwpolyline(maurer_rose(n, 1, 250), close=True, dxfattribs={"layer": "PETALS"}) msp.add_lwpolyline(maurer_rose(n, d, 250), close=True, dxfattribs={"layer": "NET"}) zoom.extents(msp) doc.saveas(filename)
def create_doc(dxfversion): doc = ezdxf.new(dxfversion, setup=True) msp = doc.modelspace() msp.add_circle( center=(0, 0), radius=1.5, dxfattribs={ "layer": "test", "linetype": "DASHED", }, ) zoom.extents(msp, factor=1.1) filename = DIR / f"{doc.acad_release}.dxf" doc.saveas(filename) print("drawing '%s' created.\n" % filename)
def scene2(filename): doc = ezdxf.new('R2010', setup=True) msp = doc.modelspace() delta = 6 for z in range(-2, 3): for y in range(-2, 3): for x in range(-2, 3): cx = x * delta cy = y * delta cz = z * delta ucs = UCS(origin=(cx, cy, cz)).rotate_local_z( math.radians(45)).rotate_local_x(math.radians(30)) add_excentric_text(msp, ucs, location=Vec3(1, 2, 3), text=f'Hallo\n(x={cx}, y={cy}, z={cz})') zoom.extents(msp) doc.saveas(filename)
def using_hatch_with_spline_edge(): doc = ezdxf.new("R2010") # create a new DXF drawing (AutoCAD 2010) msp = doc.modelspace() # we are working in model space # draw outline fitpoints = [(8, 0, 0), (10, 2, 0), (6, 6, 0), (8, 8, 0)] msp.add_line((8, 8), (0, 8)) msp.add_line((0, 8), (0, 0)) msp.add_line((0, 0), (8, 0)) # use spline with control points created by ezdxf # Don't know how AutoCAD calculates control points from fit points msp.add_spline_control_frame(fit_points=fitpoints) # next create DXF hatch entities hatch = msp.add_hatch(color=3) # if only 1 path - flags = 1 (external) by default path = hatch.paths.add_edge_path() # create a new edge path path.add_line((8, 8), (0, 8)) path.add_line((0, 8), (0, 0)) path.add_line((0, 0), (8, 0)) path.add_spline_control_frame(fit_points=fitpoints) zoom.extents(msp) doc.saveas(DIR / "hatch_with_spline_edge.dxf") # save DXF drawing
# create the target box: msp.add_lwpolyline([(0, 0), (sx, 0), (sx, sy), (0, sy)], close=True, dxfattribs={'color': 1}) # convert text string into path objects: text_as_paths = text2path.make_paths_from_str("Squeeze Me", ff) # fit text paths into a given box size by scaling, does not move the path objects: # uniform=True, keeps the text aspect ratio # uniform=False, scales the text to touch all 4 sides of the box final_paths = path.fit_paths_into_box(text_as_paths, size=(sx, sy, 0), uniform=False) # mirror text along x-axis final_paths = path.transform_paths(final_paths, Matrix44.scale(-1, 1, 1)) # move bottom/left corner to (0, 0) if required: bbox = path.bbox(final_paths) dx, dy, dz = -bbox.extmin final_paths = path.transform_paths(final_paths, Matrix44.translate(dx, dy, dz)) path.render_lwpolylines(msp, final_paths, distance=0.01, dxfattribs={'color': 2}) zoom.extents(msp) doc.saveas(DIR / 'SqeezeMe.dxf')
"GASLEITUNG2", dxfattribs={ "description": "Gasleitung2 ----GAS----GAS----GAS----GAS----GAS----GAS--", "length": 1, # required for complex line types # line type definition in acadlt.lin: "pattern": 'A,.5,-.2,["GAS",STANDARD,S=.1,U=0.0,X=-0.1,Y=-.05],-.25', }, ) # shapes only work if the ltypeshp.shx and the DXF file are in the same directory doc.linetypes.new( "GRENZE2", dxfattribs={ "description": "Grenze eckig ----[]-----[]----[]-----[]----[]--", "length": 1.45, # required for complex line types # line type definition in acadlt.lin: # A,.25,-.1,[BOX,ltypeshp.shx,x=-.1,s=.1],-.1,1 # replacing BOX by shape index 132 (got index from an AutoCAD file), ezdxf # can't get shape index from ltypeshp.shx "pattern": "A,.25,-.1,[132,ltypeshp.shx,x=-.1,s=.1],-.1,1", }, ) msp = doc.modelspace() msp.add_line((0, 0), (100, 0), dxfattribs={"linetype": "GASLEITUNG2"}) msp.add_line((0, 50), (100, 50), dxfattribs={"linetype": "GRENZE2"}) zoom.extents(msp, 1.1) doc.saveas(FILENAME)
def using_hatch_style(): def place_square_1(hatch, x, y): def shift(point): return x + point[0], y + point[1] # outer loop - flags = 1 (external) default value hatch.paths.add_polyline_path( map(shift, [(0, 0), (8, 0), (8, 8), (0, 8)])) # first inner loop - flags = 16 (outermost) hatch.paths.add_polyline_path( map(shift, [(2, 2), (7, 2), (7, 7), (2, 7)]), flags=const.BOUNDARY_PATH_OUTERMOST, ) # any further inner loops - flags = 0 (default) hatch.paths.add_polyline_path( map(shift, [(4, 4), (6, 4), (6, 6), (4, 6)]), flags=const.BOUNDARY_PATH_DEFAULT, ) def place_square_2(hatch, x, y): def shift(point): return x + point[0], y + point[1] # outer loop - flags = 1 (external) default value hatch.paths.add_polyline_path( map(shift, [(0, 0), (8, 0), (8, 8), (0, 8)])) # partly 1. inner loop - flags = 16 (outermost) hatch.paths.add_polyline_path( map(shift, [(3, 1), (7, 1), (7, 5), (3, 5)]), flags=const.BOUNDARY_PATH_OUTERMOST, ) # partly 1. inner loop - flags = 16 (outermost) hatch.paths.add_polyline_path( map(shift, [(1, 3), (5, 3), (5, 7), (1, 7)]), flags=const.BOUNDARY_PATH_OUTERMOST, ) doc = ezdxf.new("R2010") msp = doc.modelspace() # The hatch style tag, group code 75, is not supported for the MPOLYGON # entity by Autodesk products! # This example remains as it is, maybe I find a solution for this issue in # the future. # first create MPOLYGON entities hatch_style_0 = msp.add_mpolygon(color=3, fill_color=1, dxfattribs={"hatch_style": 0}) hatch_style_1 = msp.add_mpolygon(color=3, fill_color=1, dxfattribs={"hatch_style": 1}) hatch_style_2 = msp.add_mpolygon(color=3, fill_color=1, dxfattribs={"hatch_style": 2}) # then insert path elements to define the MPOLYGON boundaries place_square_1(hatch_style_0, 0, 0) place_square_1(hatch_style_1, 10, 0) place_square_1(hatch_style_2, 20, 0) # first create DXF mpolygon entities hatch_style_0b = msp.add_mpolygon(color=4, fill_color=2, dxfattribs={"hatch_style": 0}) hatch_style_1b = msp.add_mpolygon(color=4, fill_color=2, dxfattribs={"hatch_style": 1}) hatch_style_2b = msp.add_mpolygon(color=4, fill_color=2, dxfattribs={"hatch_style": 2}) # then insert path elements to define the MPOLYGON boundaries place_square_2(hatch_style_0b, 0, 10) place_square_2(hatch_style_1b, 10, 10) place_square_2(hatch_style_2b, 20, 10) zoom.extents(msp) doc.saveas(DIR / "mpolygon_with_hatch_styles.dxf") # save DXF drawing
def create_doc(filename: str, dxfversion: str): def add_mtext_columns(msp): insert = Vec3(0, 0, 0) attribs = { 'layer': 'STATIC', 'char_height': 1, 'insert': insert, } content = [ " ".join(lorem_ipsum(50)), " ".join(lorem_ipsum(100)), " ".join(lorem_ipsum(70)) ] # Create 3 static columns, the content if each column is # clearly defined: [content0, content1, content2, ...] # The height of the columns is defined by their content, ezdxf adds # an automatic column switch `\N` (R2018) between the parts. # The height argument should as big as the tallest column needs to be, # this value also determines the total height of the MTEXT entity. # # This is the simplest way to define columns without the need to render # the content to determine the required column heights. mtext = msp.add_mtext_static_columns(content, width=20, gutter_width=1, height=100, dxfattribs=attribs) insert += Vec3(mtext.columns.total_width + 5, 0, 0) attribs['layer'] = 'DYNAMIC' attribs['insert'] = insert content = " ".join(lorem_ipsum(300)) # Create as much columns as needed for the given common fixed height: # Easy for R2018, very hard for <R2018 # Passing count is required to calculate the correct total width. # The get the correct column count requires an exact MTEXT rendering # like AutoCAD/BricsCAD, which does not exist yet, but is planned for # the future. # DO NOT USE THIS INTERFACE IN PRODUCTION CODE! mtext = msp.add_mtext_dynamic_auto_height_columns(content, width=20, gutter_width=1, height=50, count=3, dxfattribs=attribs) insert += Vec3(mtext.columns.total_width + 5, 0, 0) attribs['insert'] = insert # Create 3 columns with given individual column heights, # the last column height is required but ignored and therefore 0, # because the last column contains as much of the remaining content # as needed. # Easy for R2018, very hard for <R2018 msp.add_mtext_dynamic_manual_height_columns(content, width=20, gutter_width=1, heights=[20, 30, 0], dxfattribs=attribs) doc = ezdxf.new(dxfversion=dxfversion) msp = doc.modelspace() add_mtext_columns(msp) zoom.extents(msp) doc.saveas(filename) print(f"created {filename}")
def save(name): zoom.extents(msp, factor=1.1) doc.saveas(DIR / name)
def using_hatch_style_with_edge_path(): def add_edge_path(paths, vertices, flags=1): path = paths.add_edge_path(flags) # create a new edge path first_point = next(vertices) # store first point for closing path last_point = first_point for next_point in vertices: path.add_line(last_point, next_point) # add lines to edge path last_point = next_point path.add_line(last_point, first_point) # close path def place_square_1(hatch, x, y): def shift(point): return x + point[0], y + point[1] # outer loop - flags=1 (external) default value add_edge_path( hatch.paths, map(shift, [(0, 0), (12.5, 0), (12.5, 12.5), (0, 12.5)]), ) # first inner loop - flags=16 (outermost) add_edge_path( hatch.paths, map(shift, [(2.5, 2.5), (10, 2.5), (10, 10), (2.5, 10)]), flags=const.BOUNDARY_PATH_OUTERMOST, ) # any inner loop - flags=0 (default) add_edge_path( hatch.paths, map(shift, [(5, 5), (7.5, 5), (7.5, 7.5), (5, 7.5)]), flags=const.BOUNDARY_PATH_DEFAULT, ) def place_square_2(hatch, x, y): def shift(point): return x + point[0], y + point[1] add_edge_path(hatch.paths, map(shift, [(0, 0), (0, 8), (8, 8), (8, 0)])) # 1. path add_edge_path( hatch.paths, map(shift, [(3, 1), (7, 1), (7, 5), (3, 5)]), flags=const.BOUNDARY_PATH_OUTERMOST, ) add_edge_path( hatch.paths, map(shift, [(1, 3), (5, 3), (5, 7), (1, 7)]), flags=const.BOUNDARY_PATH_OUTERMOST, ) doc = ezdxf.new("R2010") # create a new DXF drawing (AutoCAD 2010) msp = doc.modelspace() # we are working in model space # first create DXF hatch entities hatch_style_0 = msp.add_hatch(color=3, dxfattribs={"hatch_style": 0}) hatch_style_1 = msp.add_hatch(color=3, dxfattribs={"hatch_style": 1}) hatch_style_2 = msp.add_hatch(color=3, dxfattribs={"hatch_style": 2}) # then insert path elements to define the hatch boundaries place_square_1(hatch_style_0, 0, 0) place_square_1(hatch_style_1, 15, 0) place_square_1(hatch_style_2, 30, 0) # first create DXF hatch entities hatch_style_0b = msp.add_hatch(color=4, dxfattribs={"hatch_style": 0}) hatch_style_1b = msp.add_hatch(color=4, dxfattribs={"hatch_style": 1}) hatch_style_2b = msp.add_hatch(color=4, dxfattribs={"hatch_style": 2}) # then insert path elements to define the hatch boundaries place_square_2(hatch_style_0b, 0, 15) place_square_2(hatch_style_1b, 15, 15) place_square_2(hatch_style_2b, 30, 15) zoom.extents(msp) doc.saveas(DIR / "hatch_styles_examples_with_edge_path.dxf") # save DXF drawing
def test_zoom_extents(self, msp): zoom.extents(msp) vp = msp.doc.viewports.get("*Active")[0] assert vp.dxf.center == (0, 0) # 2:1 = 200 / 2 = 100 == height assert vp.dxf.height == 100
def test_zoom_extents(self, psp): zoom.extents(psp) vp = psp.main_viewport() assert vp.dxf.center == (205, 155) assert vp.dxf.width == 400 assert vp.dxf.height == 300
def test_zoom_extents_factor_2(self, msp): zoom.extents(msp, factor=2) vp = msp.doc.viewports.get('*Active')[0] assert vp.dxf.center == (0, 0) # 2:1 = 200 / 2 = 100 * 2 == height assert vp.dxf.height == 200
def test_zoom_extents_factor_2(self, psp): zoom.extents(psp, factor=2) vp = psp.main_viewport() assert vp.dxf.center == (205, 155) assert vp.dxf.width == 800 assert vp.dxf.height == 600
# License: MIT License import pathlib import ezdxf from ezdxf import disassemble, zoom from ezdxf.tools import fonts DIR = pathlib.Path('~/Desktop/Outbox').expanduser() fonts.load() FILES = [ 'text_fonts.dxf', 'text_oblique_rotate.dxf', 'text_mirror_true_type_font.dxf', 'text_stacked_shx_font.dxf', ] for filename in FILES: print(f"Processing: {filename}") doc = ezdxf.readfile( pathlib.Path(__file__).parent.parent / 'examples_dxf' / filename) msp = doc.modelspace() # required to switch layer on/off doc.layers.new('TEXT_FRAME', dxfattribs={'color': 6}) for frame in disassemble.to_primitives(msp.query('TEXT')): msp.add_lwpolyline(frame.vertices(), close=True, dxfattribs={'layer': 'TEXT_FRAME'}) zoom.extents(msp, factor=1.1) doc.saveas(DIR / filename)