or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

addons.mdcolors.mddocument-operations.mdentities.mdindex.mdlayouts.mdmath.mdpath-processing.mdrendering.mdtools.md

path-processing.mddocs/

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

```