0
# Path Processing
1
2
Vector path representation and manipulation for advanced geometric operations. The path system provides unified handling of complex geometric shapes with support for conversion between different representations.
3
4
## Capabilities
5
6
### Path Representation
7
8
Core path representation with vertices and drawing commands for complex geometric shapes.
9
10
```python { .api }
11
class Path:
12
"""Vector path with vertices and drawing commands"""
13
14
def __init__(self, start = None): ...
15
16
@property
17
def start(self) -> Vec3:
18
"""Path start point"""
19
20
@property
21
def end(self) -> Vec3:
22
"""Path end point"""
23
24
@property
25
def vertices(self) -> List[Vec3]:
26
"""All path vertices"""
27
28
@property
29
def commands(self):
30
"""Path command sequence"""
31
32
@property
33
def is_closed(self) -> bool:
34
"""True if path forms a closed loop"""
35
36
def line_to(self, location) -> 'Path':
37
"""Add line segment to location"""
38
39
def curve3_to(self, location, ctrl) -> 'Path':
40
"""Add quadratic Bézier curve"""
41
42
def curve4_to(self, location, ctrl1, ctrl2) -> 'Path':
43
"""Add cubic Bézier curve"""
44
45
def close(self) -> 'Path':
46
"""Close path with line to start"""
47
48
def close_sub_path(self) -> 'Path':
49
"""Close current sub-path"""
50
51
def move_to(self, location) -> 'Path':
52
"""Start new sub-path at location"""
53
54
def transform(self, matrix: Matrix44) -> 'Path':
55
"""Transform all vertices by matrix"""
56
57
def reversed(self) -> 'Path':
58
"""Return path with reversed direction"""
59
60
def clockwise(self) -> 'Path':
61
"""Return path with clockwise orientation"""
62
63
def counter_clockwise(self) -> 'Path':
64
"""Return path with counter-clockwise orientation"""
65
66
def approximate(self, segments: int = 20) -> List[Vec3]:
67
"""Approximate path with line segments"""
68
69
def flattening(self, distance: float) -> List[Vec3]:
70
"""Flatten path to vertices within distance tolerance"""
71
72
class Command(Enum):
73
"""Path command types"""
74
LINE_TO = 1
75
CURVE3_TO = 2 # Quadratic Bézier
76
CURVE4_TO = 3 # Cubic Bézier
77
MOVE_TO = 4
78
```
79
80
Usage examples:
81
```python
82
from ezdxf.path import Path
83
from ezdxf.math import Vec3
84
85
# Create a complex path
86
path = Path(Vec3(0, 0))
87
path.line_to((10, 0))
88
path.curve4_to((20, 10), (12, -5), (18, 15)) # Cubic Bézier
89
path.line_to((0, 10))
90
path.close()
91
92
# Transform path
93
from ezdxf.math import Matrix44
94
matrix = Matrix44.scale(2, 2, 1)
95
scaled_path = path.transform(matrix)
96
97
# Convert to line segments
98
vertices = path.approximate(segments=50)
99
polyline = msp.add_lwpolyline(vertices)
100
```
101
102
### Path Creation from Entities
103
104
Convert DXF entities to path representations for unified geometric processing.
105
106
```python { .api }
107
def make_path(entity) -> Path:
108
"""
109
Convert DXF entity to path representation.
110
111
Parameters:
112
- entity: DXF entity (LINE, ARC, CIRCLE, ELLIPSE, SPLINE, LWPOLYLINE, etc.)
113
114
Returns:
115
Path: Vector path representation
116
"""
117
118
def from_vertices(vertices, close: bool = False) -> Path:
119
"""Create path from vertex sequence"""
120
121
def from_hatch(hatch) -> List[Path]:
122
"""
123
Create paths from hatch boundary definitions.
124
125
Parameters:
126
- hatch: HATCH entity
127
128
Returns:
129
List[Path]: Boundary paths (exterior and holes)
130
"""
131
132
def from_hatch_boundary_path(boundary_path) -> Path:
133
"""Create path from single hatch boundary path"""
134
```
135
136
Usage examples:
137
```python
138
from ezdxf.path import make_path, from_vertices
139
from ezdxf.math import Vec3
140
141
# Convert entities to paths
142
line_entity = msp.add_line((0, 0), (10, 10))
143
line_path = make_path(line_entity)
144
145
circle_entity = msp.add_circle((5, 5), 3)
146
circle_path = make_path(circle_entity) # Closed circular path
147
148
spline_entity = msp.add_spline([(0, 0), (5, 10), (10, 0)])
149
spline_path = make_path(spline_entity)
150
151
# Create path from vertices
152
vertices = [Vec3(0, 0), Vec3(5, 10), Vec3(10, 5), Vec3(15, 0)]
153
vertex_path = from_vertices(vertices, close=True)
154
155
# Extract paths from hatch
156
hatch = msp.add_hatch()
157
# ... configure hatch boundaries ...
158
hatch_paths = from_hatch(hatch)
159
```
160
161
### Path to Entity Conversion
162
163
Convert paths back to DXF entities in various formats.
164
165
```python { .api }
166
def to_lines(paths) -> List[Line]:
167
"""Convert paths to LINE entities"""
168
169
def to_polylines2d(paths, *, close: bool = True, max_flattening_distance: float = 0.01,
170
dxfattribs: dict = None) -> List[Polyline]:
171
"""Convert paths to 2D POLYLINE entities"""
172
173
def to_polylines3d(paths, *, close: bool = True, max_flattening_distance: float = 0.01,
174
dxfattribs: dict = None) -> List[Polyline]:
175
"""Convert paths to 3D POLYLINE entities"""
176
177
def to_lwpolylines(paths, *, close: bool = True, max_flattening_distance: float = 0.01,
178
dxfattribs: dict = None) -> List[LWPolyline]:
179
"""Convert paths to LWPOLYLINE entities"""
180
181
def to_hatches(paths, *, edge_path: bool = True, max_flattening_distance: float = 0.01,
182
dxfattribs: dict = None) -> List[Hatch]:
183
"""Convert paths to HATCH entities"""
184
185
def to_mpolygons(paths, *, max_flattening_distance: float = 0.01,
186
dxfattribs: dict = None) -> List[MPolygon]:
187
"""Convert paths to MPOLYGON entities"""
188
189
def to_bsplines_and_vertices(paths, *, g1_tol: float = 1e-4, max_flattening_distance: float = 0.01,
190
dxfattribs: dict = None) -> List:
191
"""Convert paths to B-splines and vertices"""
192
193
def to_splines_and_polylines(paths, *, g1_tol: float = 1e-4, max_flattening_distance: float = 0.01,
194
dxfattribs: dict = None) -> List:
195
"""Convert paths to splines and polylines"""
196
```
197
198
Usage examples:
199
```python
200
from ezdxf.path import to_lwpolylines, to_hatches, to_splines_and_polylines
201
202
# Convert paths to different entity types
203
paths = [circle_path, spline_path, vertex_path]
204
205
# Convert to lightweight polylines
206
lwpolylines = to_lwpolylines(paths, close=True, dxfattribs={'layer': 'PATHS'})
207
for poly in lwpolylines:
208
msp.add_entity(poly)
209
210
# Convert to hatches with solid fill
211
hatches = to_hatches(paths, dxfattribs={'color': 1})
212
for hatch in hatches:
213
hatch.set_solid_fill()
214
msp.add_entity(hatch)
215
216
# Convert to splines where possible, polylines elsewhere
217
entities = to_splines_and_polylines(paths, g1_tol=1e-3)
218
for entity in entities:
219
msp.add_entity(entity)
220
```
221
222
### Path Shape Generators
223
224
Generate paths for common geometric shapes and patterns.
225
226
```python { .api }
227
def unit_circle(start_angle: float = 0, end_angle: float = 360,
228
segments: int = None) -> Path:
229
"""
230
Create circular path with unit radius.
231
232
Parameters:
233
- start_angle: start angle in degrees
234
- end_angle: end angle in degrees
235
- segments: number of line segments (auto if None)
236
237
Returns:
238
Path: Circular path
239
"""
240
241
def elliptic_transformation(path: Path, center, rx: float, ry: float,
242
start_angle: float = 0) -> Path:
243
"""Transform unit circle path to ellipse"""
244
245
def rect(width: float = 1, height: float = 1, center: bool = True) -> Path:
246
"""Create rectangular path"""
247
248
def wedge(start_angle: float, end_angle: float, radius: float = 1) -> Path:
249
"""Create wedge-shaped path (pie slice)"""
250
251
def star(count: int, r1: float, r2: float, rotation: float = 0) -> Path:
252
"""Create star-shaped path with alternating radii"""
253
254
def gear(count: int, top_width: float, bottom_width: float, height: float,
255
outside_radius: float = 1) -> Path:
256
"""Create gear-shaped path"""
257
258
def ngon(count: int, radius: float = 1, rotation: float = 0,
259
center: bool = True) -> Path:
260
"""Create regular polygon path"""
261
262
def helix(radius: float, pitch: float, turns: float, ccw: bool = True) -> Path:
263
"""Create helical path"""
264
```
265
266
Usage examples:
267
```python
268
from ezdxf.path.shapes import unit_circle, rect, star, ngon
269
from ezdxf.math import Vec3
270
import math
271
272
# Create basic shapes
273
circle = unit_circle(0, 360, segments=32) # Full circle
274
arc = unit_circle(45, 135, segments=16) # Quarter arc
275
276
# Transform to ellipse
277
ellipse = elliptic_transformation(circle, Vec3(10, 5), rx=8, ry=4)
278
279
# Create rectangle
280
rectangle = rect(width=10, height=6, center=True)
281
282
# Create star shape
283
star_path = star(count=6, r1=5, r2=2.5, rotation=math.pi/6)
284
285
# Create regular polygon
286
hexagon = ngon(count=6, radius=4)
287
288
# Convert to entities
289
for path in [ellipse, rectangle, star_path, hexagon]:
290
entities = to_lwpolylines([path], close=True)
291
for entity in entities:
292
msp.add_entity(entity)
293
```
294
295
### Path Tools and Utilities
296
297
Utility functions for path analysis, transformation, and processing.
298
299
```python { .api }
300
def bbox(paths) -> tuple:
301
"""
302
Calculate bounding box of paths.
303
304
Parameters:
305
- paths: sequence of Path objects
306
307
Returns:
308
tuple: (min_x, min_y, max_x, max_y) bounding box
309
"""
310
311
def precise_bbox(paths) -> tuple:
312
"""Calculate precise bounding box including curve control points"""
313
314
def fit_paths_into_box(paths, size, uniform: bool = True, source_box = None):
315
"""
316
Scale paths to fit within specified box.
317
318
Parameters:
319
- paths: sequence of Path objects
320
- size: target box size (width, height)
321
- uniform: maintain aspect ratio
322
- source_box: explicit source bounding box
323
324
Returns:
325
List[Path]: Scaled paths
326
"""
327
328
def transform_paths(paths, matrix: Matrix44):
329
"""Transform paths by transformation matrix"""
330
331
def transform_paths_to_ocs(paths, ocs):
332
"""Transform paths to Object Coordinate System"""
333
334
def reverse_paths(paths):
335
"""Reverse direction of all paths"""
336
337
def clockwise_paths(paths):
338
"""Ensure all paths have clockwise orientation"""
339
340
def counter_clockwise_paths(paths):
341
"""Ensure all paths have counter-clockwise orientation"""
342
```
343
344
Usage examples:
345
```python
346
from ezdxf.path.tools import bbox, fit_paths_into_box, transform_paths
347
from ezdxf.math import Matrix44
348
349
# Calculate bounding box
350
paths = [circle_path, star_path, hexagon]
351
min_x, min_y, max_x, max_y = bbox(paths)
352
print(f"Bounding box: ({min_x}, {min_y}) to ({max_x}, {max_y})")
353
354
# Fit paths into specific size
355
target_size = (100, 80) # 100 units wide, 80 units tall
356
fitted_paths = fit_paths_into_box(paths, target_size, uniform=True)
357
358
# Transform paths
359
rotation = Matrix44.z_rotate(math.radians(30))
360
translation = Matrix44.translate(50, 50, 0)
361
combined = translation @ rotation
362
transformed_paths = transform_paths(paths, combined)
363
```
364
365
### Path Nesting and Structure
366
367
Advanced path organization for complex polygon structures with holes and islands.
368
369
```python { .api }
370
def make_polygon_structure(paths):
371
"""
372
Create hierarchical polygon structure from paths.
373
374
Parameters:
375
- paths: sequence of closed Path objects
376
377
Returns:
378
List: Nested polygon structure with exterior and holes
379
"""
380
381
def winding_deconstruction(polygons):
382
"""Apply winding rules to polygon structure"""
383
384
def group_paths(paths):
385
"""Group related paths by proximity and containment"""
386
387
def flatten_polygons(polygons):
388
"""Flatten polygon hierarchy to simple path list"""
389
390
class PolygonStructure:
391
"""Hierarchical polygon representation with holes"""
392
393
def __init__(self, exterior: Path, holes: List[Path] = None): ...
394
395
@property
396
def exterior(self) -> Path:
397
"""Exterior boundary path"""
398
399
@property
400
def holes(self) -> List[Path]:
401
"""Interior hole paths"""
402
403
def add_hole(self, hole: Path): ...
404
def remove_hole(self, hole: Path): ...
405
406
def area(self) -> float:
407
"""Calculate polygon area (exterior minus holes)"""
408
409
def contains_point(self, point) -> bool:
410
"""Test if point is inside polygon"""
411
```
412
413
### Path Rendering Functions
414
415
Specialized rendering functions for different entity types.
416
417
```python { .api }
418
def render_lines(layout, paths, *, dxfattribs: dict = None): ...
419
def render_lwpolylines(layout, paths, *, close: bool = True, dxfattribs: dict = None): ...
420
def render_splines(layout, paths, *, degree: int = 3, dxfattribs: dict = None): ...
421
def render_hatches(layout, paths, *, pattern: str = 'SOLID', dxfattribs: dict = None): ...
422
423
def add_bezier4p(path: Path, start, ctrl1, ctrl2, end): ...
424
def add_bezier3p(path: Path, start, ctrl, end): ...
425
def add_ellipse(path: Path, center, rx: float, ry: float, start_param: float = 0,
426
end_param: float = 2*math.pi): ...
427
```
428
429
## Path Command Classes
430
431
```python { .api }
432
class LineTo:
433
"""Line command for paths"""
434
def __init__(self, end: Vec3): ...
435
436
class Curve3To:
437
"""Quadratic Bézier curve command"""
438
def __init__(self, end: Vec3, ctrl: Vec3): ...
439
440
class Curve4To:
441
"""Cubic Bézier curve command"""
442
def __init__(self, end: Vec3, ctrl1: Vec3, ctrl2: Vec3): ...
443
444
class MoveTo:
445
"""Move command for starting new sub-paths"""
446
def __init__(self, end: Vec3): ...
447
448
# Type aliases
449
AnyCurve = Union[Curve3To, Curve4To]
450
PathElement = Union[LineTo, Curve3To, Curve4To, MoveTo]
451
```
452
453
Complete usage example:
454
```python
455
import ezdxf
456
from ezdxf.path import Path, make_path, to_lwpolylines
457
from ezdxf.path.shapes import unit_circle, star, rect
458
from ezdxf.path.tools import bbox, fit_paths_into_box
459
from ezdxf.math import Vec3, Matrix44
460
import math
461
462
# Create document
463
doc = ezdxf.new()
464
msp = doc.modelspace()
465
466
# Create various paths
467
circle = unit_circle(segments=24)
468
star_path = star(count=5, r1=4, r2=2)
469
rectangle = rect(width=6, height=4)
470
471
# Position paths
472
circle = circle.transform(Matrix44.translate(0, 0, 0))
473
star_path = star_path.transform(Matrix44.translate(10, 0, 0))
474
rectangle = rectangle.transform(Matrix44.translate(20, 0, 0))
475
476
# Combine and process
477
all_paths = [circle, star_path, rectangle]
478
479
# Fit to standard size
480
fitted_paths = fit_paths_into_box(all_paths, (50, 30), uniform=True)
481
482
# Convert to entities and add to layout
483
entities = to_lwpolylines(fitted_paths, close=True, dxfattribs={'layer': 'PATHS'})
484
for entity in entities:
485
msp.add_entity(entity)
486
487
# Save document
488
doc.saveas('path_processing_example.dxf')
489
```