or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

database-operations.mdfile-io.mdhierarchical-design.mdindex.mdlayout-viewer.mdshape-operations.mdtransformations.mdverification.md

shape-operations.mddocs/

0

# Shape Collections and Boolean Operations

1

2

Advanced geometric operations including boolean operations (AND, OR, XOR, NOT), sizing, merging, and comprehensive region analysis for layout verification and processing.

3

4

## Capabilities

5

6

### Region Operations

7

8

The Region class provides powerful bulk operations on collections of polygons, essential for design rule checking and layout processing.

9

10

```python { .api }

11

class Region:

12

def __init__(self, shapes=None):

13

"""

14

Create a region from shapes or empty region.

15

16

Parameters:

17

- shapes: Initial shapes (Polygon, Box, or iterable of shapes)

18

"""

19

20

def insert(self, shape) -> None:

21

"""

22

Insert a shape into the region.

23

24

Parameters:

25

- shape: Polygon, Box, or other geometric shape

26

"""

27

28

def __and__(self, other: Region) -> Region:

29

"""Boolean AND operation (intersection)."""

30

31

def __or__(self, other: Region) -> Region:

32

"""Boolean OR operation (union)."""

33

34

def __xor__(self, other: Region) -> Region:

35

"""Boolean XOR operation (exclusive or)."""

36

37

def __sub__(self, other: Region) -> Region:

38

"""Boolean subtraction (difference)."""

39

40

def sized(self, dx: int, dy: int = None) -> Region:

41

"""

42

Size operation (grow/shrink polygons).

43

44

Parameters:

45

- dx: X sizing amount (positive to grow)

46

- dy: Y sizing amount (defaults to dx)

47

48

Returns:

49

Region: Sized region

50

"""

51

52

def merged(self) -> Region:

53

"""Merge overlapping and touching polygons."""

54

55

def smoothed(self, d: int) -> Region:

56

"""

57

Smooth region by removing small notches and gaps.

58

59

Parameters:

60

- d: Smoothing distance

61

"""

62

63

def rounded_corners(self, radius_inner: int, radius_outer: int, num_points: int) -> Region:

64

"""

65

Round corners of polygons.

66

67

Parameters:

68

- radius_inner: Inner corner radius

69

- radius_outer: Outer corner radius

70

- num_points: Points per quarter circle

71

"""

72

73

def area(self) -> int:

74

"""Calculate total area of all polygons."""

75

76

def perimeter(self) -> int:

77

"""Calculate total perimeter of all polygons."""

78

79

def bbox(self) -> Box:

80

"""Get bounding box of entire region."""

81

82

def is_empty(self) -> bool:

83

"""Check if region contains no shapes."""

84

85

def count(self) -> int:

86

"""Get number of polygons in region."""

87

88

def each(self):

89

"""Iterate over polygons in region."""

90

91

def select_interacting(self, other: Region) -> Region:

92

"""Select polygons that interact with other region."""

93

94

def select_not_interacting(self, other: Region) -> Region:

95

"""Select polygons that don't interact with other region."""

96

97

def select_overlapping(self, other: Region) -> Region:

98

"""Select polygons that overlap with other region."""

99

100

def select_not_overlapping(self, other: Region) -> Region:

101

"""Select polygons that don't overlap with other region."""

102

103

def width_check(self, d: int) -> EdgePairs:

104

"""

105

Check for width violations.

106

107

Parameters:

108

- d: Minimum width

109

110

Returns:

111

EdgePairs: Width violation edge pairs

112

"""

113

114

def space_check(self, d: int) -> EdgePairs:

115

"""

116

Check for spacing violations.

117

118

Parameters:

119

- d: Minimum spacing

120

121

Returns:

122

EdgePairs: Spacing violation edge pairs

123

"""

124

```

125

126

### Edge Collections

127

128

```python { .api }

129

class Edges:

130

def __init__(self, shapes=None):

131

"""

132

Create edge collection from shapes.

133

134

Parameters:

135

- shapes: Initial shapes or edges

136

"""

137

138

def insert(self, edge: Edge) -> None:

139

"""Insert an edge into the collection."""

140

141

def merged(self) -> Edges:

142

"""Merge connected and overlapping edges."""

143

144

def extended(self, ext_begin: int, ext_end: int) -> Edges:

145

"""

146

Extend edges at both ends.

147

148

Parameters:

149

- ext_begin: Extension at beginning

150

- ext_end: Extension at end

151

"""

152

153

def length(self) -> int:

154

"""Get total length of all edges."""

155

156

def bbox(self) -> Box:

157

"""Get bounding box of all edges."""

158

159

def each(self):

160

"""Iterate over edges."""

161

162

def with_length(self, min_length: int, max_length: int = None) -> Edges:

163

"""

164

Select edges within length range.

165

166

Parameters:

167

- min_length: Minimum length

168

- max_length: Maximum length (unlimited if None)

169

"""

170

171

def with_angle(self, min_angle: float, max_angle: float) -> Edges:

172

"""Select edges within angle range (in degrees)."""

173

```

174

175

### Edge Pairs (for DRC Results)

176

177

```python { .api }

178

class EdgePairs:

179

def __init__(self):

180

"""Create empty edge pair collection."""

181

182

def insert(self, edge1: Edge, edge2: Edge) -> None:

183

"""

184

Insert an edge pair.

185

186

Parameters:

187

- edge1: First edge

188

- edge2: Second edge

189

"""

190

191

def count(self) -> int:

192

"""Get number of edge pairs."""

193

194

def each(self):

195

"""Iterate over edge pairs."""

196

197

def polygons(self, enlargement: int = 0) -> Region:

198

"""

199

Convert edge pairs to polygons for visualization.

200

201

Parameters:

202

- enlargement: Polygon enlargement around edges

203

204

Returns:

205

Region: Region representing the edge pairs

206

"""

207

208

def first_edges(self) -> Edges:

209

"""Get collection of first edges from all pairs."""

210

211

def second_edges(self) -> Edges:

212

"""Get collection of second edges from all pairs."""

213

```

214

215

### Text Collections

216

217

```python { .api }

218

class Texts:

219

def __init__(self, shapes=None):

220

"""Create text collection."""

221

222

def insert(self, text: Text) -> None:

223

"""Insert a text object."""

224

225

def each(self):

226

"""Iterate over text objects."""

227

228

def count(self) -> int:

229

"""Get number of text objects."""

230

231

def bbox(self) -> Box:

232

"""Get bounding box of all texts."""

233

234

def with_text(self, pattern: str) -> Texts:

235

"""

236

Select texts matching pattern.

237

238

Parameters:

239

- pattern: Text pattern to match

240

"""

241

```

242

243

### Deep Region Operations

244

245

```python { .api }

246

class DeepShapes:

247

"""Deep shapes for hierarchical operations."""

248

249

def region(self, layer: int) -> Region:

250

"""Get region for layer with hierarchy flattening."""

251

252

def edges(self, layer: int) -> Edges:

253

"""Get edges for layer with hierarchy flattening."""

254

```

255

256

## Usage Examples

257

258

### Basic Boolean Operations

259

260

```python

261

import klayout.db as db

262

263

# Create two regions

264

region1 = db.Region()

265

region1.insert(db.Box(0, 0, 100, 100))

266

region1.insert(db.Box(50, 50, 150, 150))

267

268

region2 = db.Region()

269

region2.insert(db.Box(25, 25, 75, 75))

270

region2.insert(db.Box(125, 25, 175, 75))

271

272

# Boolean operations

273

intersection = region1 & region2 # AND

274

union = region1 | region2 # OR

275

difference = region1 - region2 # SUBTRACT

276

symmetric_diff = region1 ^ region2 # XOR

277

278

print(f"Region1 area: {region1.area()}")

279

print(f"Region2 area: {region2.area()}")

280

print(f"Intersection area: {intersection.area()}")

281

print(f"Union area: {union.area()}")

282

```

283

284

### Sizing and Merging Operations

285

286

```python

287

import klayout.db as db

288

289

# Create region with overlapping shapes

290

region = db.Region()

291

region.insert(db.Box(0, 0, 50, 50))

292

region.insert(db.Box(40, 0, 90, 50))

293

region.insert(db.Box(80, 0, 130, 50))

294

295

print(f"Original polygon count: {region.count()}")

296

297

# Merge overlapping polygons

298

merged = region.merged()

299

print(f"After merge: {merged.count()}")

300

301

# Size operations

302

grown = merged.sized(10) # Grow by 10 units

303

shrunk = merged.sized(-5) # Shrink by 5 units

304

asymmetric = merged.sized(10, 5) # Grow 10 in X, 5 in Y

305

306

print(f"Original area: {merged.area()}")

307

print(f"Grown area: {grown.area()}")

308

print(f"Shrunk area: {shrunk.area()}")

309

```

310

311

### Design Rule Checking

312

313

```python

314

import klayout.db as db

315

316

# Load layout

317

layout = db.Layout()

318

layout.read("design.gds")

319

320

# Get shapes on metal layer

321

metal_layer = layout.layer(db.LayerInfo(1, 0))

322

metal_region = db.Region()

323

324

for cell in layout.each_cell():

325

if cell:

326

for shape in cell.shapes(metal_layer).each():

327

metal_region.insert(shape.polygon)

328

329

# Perform DRC checks

330

min_width = 100 # 100 nm minimum width

331

min_space = 120 # 120 nm minimum spacing

332

333

# Width check

334

width_violations = metal_region.width_check(min_width)

335

print(f"Width violations: {width_violations.count()}")

336

337

# Space check

338

space_violations = metal_region.space_check(min_space)

339

print(f"Space violations: {space_violations.count()}")

340

341

# Create error layer for violations

342

if width_violations.count() > 0:

343

error_region = width_violations.polygons(50) # 50nm marker around violations

344

# Insert error_region into layout for visualization

345

```

346

347

### Advanced Shape Selection

348

349

```python

350

import klayout.db as db

351

352

# Create test regions

353

shapes = db.Region()

354

shapes.insert(db.Box(0, 0, 100, 100)) # Large square

355

shapes.insert(db.Box(200, 0, 250, 250)) # Tall rectangle

356

shapes.insert(db.Box(300, 0, 400, 50)) # Wide rectangle

357

358

reference = db.Region()

359

reference.insert(db.Box(50, 50, 150, 150)) # Overlapping area

360

361

# Selection operations

362

interacting = shapes.select_interacting(reference)

363

print(f"Shapes interacting with reference: {interacting.count()}")

364

365

not_interacting = shapes.select_not_interacting(reference)

366

print(f"Shapes not interacting: {not_interacting.count()}")

367

368

overlapping = shapes.select_overlapping(reference)

369

print(f"Shapes overlapping reference: {overlapping.count()}")

370

371

# Area-based selection

372

large_shapes = db.Region()

373

for poly in shapes.each():

374

if poly.area() > 5000: # Only shapes larger than 5000 sq units

375

large_shapes.insert(poly)

376

377

print(f"Large shapes: {large_shapes.count()}")

378

```

379

380

### Working with Edges

381

382

```python

383

import klayout.db as db

384

385

# Create region and extract edges

386

region = db.Region()

387

region.insert(db.Box(0, 0, 100, 200))

388

region.insert(db.Box(100, 0, 200, 100))

389

390

# Get all edges

391

all_edges = region.edges()

392

print(f"Total edges: {all_edges.count()}")

393

print(f"Total edge length: {all_edges.length()}")

394

395

# Filter edges by length

396

long_edges = all_edges.with_length(100, None) # Edges >= 100 units

397

short_edges = all_edges.with_length(0, 99) # Edges < 100 units

398

399

print(f"Long edges: {long_edges.count()}")

400

print(f"Short edges: {short_edges.count()}")

401

402

# Filter by angle (horizontal and vertical)

403

horizontal = all_edges.with_angle(-1, 1) # ~0 degrees

404

vertical = all_edges.with_angle(89, 91) # ~90 degrees

405

406

print(f"Horizontal edges: {horizontal.count()}")

407

print(f"Vertical edges: {vertical.count()}")

408

```

409

410

### Corner Rounding and Smoothing

411

412

```python

413

import klayout.db as db

414

415

# Create region with sharp corners

416

region = db.Region()

417

# Create L-shaped polygon with sharp internal corner

418

points = [

419

db.Point(0, 0), db.Point(100, 0), db.Point(100, 50),

420

db.Point(50, 50), db.Point(50, 100), db.Point(0, 100)

421

]

422

region.insert(db.Polygon(points))

423

424

# Round corners

425

rounded = region.rounded_corners(

426

radius_inner=10, # Inner corner radius

427

radius_outer=15, # Outer corner radius

428

num_points=16 # Points per quarter circle

429

)

430

431

# Smooth small features

432

smoothed = region.smoothed(5) # Remove features smaller than 5 units

433

434

print(f"Original vertices: {sum(1 for _ in region.each())}")

435

print(f"After rounding: {sum(1 for _ in rounded.each())}")

436

```

437

438

### Hierarchical Processing

439

440

```python

441

import klayout.db as db

442

443

# Load hierarchical layout

444

layout = db.Layout()

445

layout.read("hierarchical_design.gds")

446

447

# Process specific layer across hierarchy

448

layer = layout.layer(db.LayerInfo(1, 0))

449

450

# Option 1: Flatten and process

451

flattened_region = db.Region()

452

for cell in layout.each_cell():

453

if cell:

454

# Get shapes with hierarchy context

455

shapes = cell.shapes(layer)

456

for shape in shapes.each():

457

flattened_region.insert(shape.polygon)

458

459

# Option 2: Use deep shapes (preserves hierarchy)

460

if hasattr(layout, 'top_cell') and layout.top_cell():

461

deep_shapes = db.DeepShapes(layout.top_cell())

462

hierarchical_region = deep_shapes.region(layer)

463

464

# Process while maintaining hierarchy information

465

processed = hierarchical_region.sized(10).merged()

466

```

467

468

### Complex DRC Rule Implementation

469

470

```python

471

import klayout.db as db

472

473

def check_enclosure_rule(inner_layer: db.Region, outer_layer: db.Region,

474

min_enclosure: int) -> db.EdgePairs:

475

"""

476

Check enclosure rule: outer_layer must enclose inner_layer by min_enclosure.

477

478

Parameters:

479

- inner_layer: Region that should be enclosed

480

- outer_layer: Region that should provide enclosure

481

- min_enclosure: Minimum enclosure distance

482

483

Returns:

484

EdgePairs: Enclosure violations

485

"""

486

# Areas where inner extends beyond outer (not enclosed)

487

not_enclosed = inner_layer - outer_layer

488

489

# Areas where enclosure is insufficient

490

grown_inner = inner_layer.sized(min_enclosure)

491

insufficient_enclosure = grown_inner - outer_layer

492

493

# Convert violations to edge pairs for reporting

494

violations = db.EdgePairs()

495

496

# Process each violation area

497

for poly in insufficient_enclosure.each():

498

# Find nearest edges between inner and outer

499

inner_edges = inner_layer.edges()

500

outer_edges = outer_layer.edges()

501

502

# This is simplified - real implementation would find closest edge pairs

503

# For each inner edge, find closest outer edge and check distance

504

505

return violations

506

507

# Example usage

508

via_layer = db.Region()

509

metal_layer = db.Region()

510

511

# Load actual shapes...

512

# via_layer.insert(...)

513

# metal_layer.insert(...)

514

515

enclosure_violations = check_enclosure_rule(via_layer, metal_layer, 50)

516

print(f"Enclosure violations: {enclosure_violations.count()}")

517

```