0
# Layout Transformations and Coordinates
1
2
Geometric transformations including rotation, mirroring, scaling, and translation operations for precise layout manipulation and coordinate system conversions in IC design workflows.
3
4
## Capabilities
5
6
### Basic Transformations
7
8
```python { .api }
9
class Trans:
10
def __init__(self, rotation: int = 0, mirror: bool = False, displacement: Point = None):
11
"""
12
Create an integer coordinate transformation.
13
14
Parameters:
15
- rotation: Rotation in 90-degree increments (0, 1, 2, 3)
16
- mirror: Mirror across X-axis before rotation
17
- displacement: Translation vector
18
"""
19
20
@property
21
def rot(self) -> int:
22
"""Get rotation value (0-3 for 0°, 90°, 180°, 270°)."""
23
24
@property
25
def is_mirror(self) -> bool:
26
"""Check if transformation includes mirroring."""
27
28
@property
29
def disp(self) -> Point:
30
"""Get displacement vector."""
31
32
def inverted(self) -> Trans:
33
"""Return the inverse transformation."""
34
35
def __mul__(self, other: Trans) -> Trans:
36
"""Combine transformations (self * other)."""
37
38
def transform_point(self, point: Point) -> Point:
39
"""Transform a point."""
40
41
def transform_box(self, box: Box) -> Box:
42
"""Transform a bounding box."""
43
44
class DTrans:
45
def __init__(self, rotation: int = 0, mirror: bool = False, displacement: DPoint = None):
46
"""Create a double precision transformation."""
47
48
@property
49
def rot(self) -> int:
50
"""Get rotation value."""
51
52
@property
53
def is_mirror(self) -> bool:
54
"""Check if transformation includes mirroring."""
55
56
@property
57
def disp(self) -> DPoint:
58
"""Get displacement vector."""
59
```
60
61
### Complex Transformations with Scaling
62
63
```python { .api }
64
class CplxTrans:
65
def __init__(self, mag: float = 1.0, rotation: float = 0.0, mirror: bool = False, displacement: DPoint = None):
66
"""
67
Create a complex transformation with scaling and arbitrary rotation.
68
69
Parameters:
70
- mag: Magnification factor
71
- rotation: Rotation angle in degrees
72
- mirror: Mirror across X-axis before rotation
73
- displacement: Translation vector
74
"""
75
76
@property
77
def mag(self) -> float:
78
"""Get magnification factor."""
79
80
@property
81
def angle(self) -> float:
82
"""Get rotation angle in degrees."""
83
84
@property
85
def is_mirror(self) -> bool:
86
"""Check if transformation includes mirroring."""
87
88
@property
89
def disp(self) -> DPoint:
90
"""Get displacement vector."""
91
92
def inverted(self) -> CplxTrans:
93
"""Return the inverse transformation."""
94
95
def __mul__(self, other: CplxTrans) -> CplxTrans:
96
"""Combine complex transformations."""
97
98
def transform_point(self, point: DPoint) -> DPoint:
99
"""Transform a double precision point."""
100
101
def transform_box(self, box: DBox) -> DBox:
102
"""Transform a double precision bounding box."""
103
104
class ICplxTrans:
105
def __init__(self, mag: float = 1.0, rotation: float = 0.0, mirror: bool = False, displacement: Point = None):
106
"""Create an integer complex transformation."""
107
108
def to_trans(self) -> Trans:
109
"""Convert to simple transformation (if no scaling)."""
110
111
class DCplxTrans:
112
def __init__(self, mag: float = 1.0, rotation: float = 0.0, mirror: bool = False, displacement: DPoint = None):
113
"""Create a double precision complex transformation."""
114
```
115
116
### Matrix Transformations
117
118
```python { .api }
119
class Matrix2d:
120
def __init__(self, m11: float = 1.0, m12: float = 0.0, m21: float = 0.0, m22: float = 1.0):
121
"""
122
Create a 2x2 transformation matrix.
123
124
Parameters:
125
- m11, m12, m21, m22: Matrix elements
126
"""
127
128
def determinant(self) -> float:
129
"""Calculate matrix determinant."""
130
131
def inverted(self) -> Matrix2d:
132
"""Return inverted matrix."""
133
134
def __mul__(self, other: Matrix2d) -> Matrix2d:
135
"""Matrix multiplication."""
136
137
def transform_point(self, point: DPoint) -> DPoint:
138
"""Transform a point using the matrix."""
139
140
class Matrix3d:
141
def __init__(self):
142
"""Create a 3x3 transformation matrix."""
143
144
def translate(self, dx: float, dy: float) -> Matrix3d:
145
"""Add translation to the transformation."""
146
147
def rotate(self, angle: float) -> Matrix3d:
148
"""Add rotation to the transformation (in radians)."""
149
150
def scale(self, sx: float, sy: float = None) -> Matrix3d:
151
"""
152
Add scaling to the transformation.
153
154
Parameters:
155
- sx: X scale factor
156
- sy: Y scale factor (defaults to sx if not provided)
157
"""
158
159
def shear(self, shx: float, shy: float) -> Matrix3d:
160
"""Add shear transformation."""
161
162
def inverted(self) -> Matrix3d:
163
"""Return inverted matrix."""
164
165
def transform_point(self, point: DPoint) -> DPoint:
166
"""Transform a point."""
167
```
168
169
### Coordinate System Utilities
170
171
```python { .api }
172
def coord_from_dbu(coord_dbu: int, dbu: float) -> float:
173
"""
174
Convert coordinate from database units to user units.
175
176
Parameters:
177
- coord_dbu: Coordinate in database units
178
- dbu: Database unit in user units
179
180
Returns:
181
float: Coordinate in user units
182
"""
183
184
def coord_to_dbu(coord: float, dbu: float) -> int:
185
"""
186
Convert coordinate from user units to database units.
187
188
Parameters:
189
- coord: Coordinate in user units
190
- dbu: Database unit in user units
191
192
Returns:
193
int: Coordinate in database units
194
"""
195
196
class Layout:
197
@property
198
def dbu(self) -> float:
199
"""Get database unit in micrometers."""
200
201
def set_dbu(self, dbu: float) -> None:
202
"""Set database unit."""
203
204
def scale_and_snap(self, layout_target: Layout, cell_mapping, layers, factor: float) -> None:
205
"""Scale layout and snap to grid."""
206
```
207
208
## Usage Examples
209
210
### Basic Transformations
211
212
```python
213
import klayout.db as db
214
215
# Create basic transformations
216
trans1 = db.Trans(1, False, db.Point(100, 200)) # 90° rotation + translation
217
trans2 = db.Trans(0, True, db.Point(0, 0)) # Mirror only
218
trans3 = db.Trans(db.Point(50, 75)) # Translation only
219
220
# Apply transformations to shapes
221
original_box = db.Box(0, 0, 100, 50)
222
rotated_box = trans1.transform_box(original_box)
223
mirrored_box = trans2.transform_box(original_box)
224
225
# Combine transformations
226
combined = trans1 * trans2 # Apply trans2, then trans1
227
228
print(f"Original: {original_box}")
229
print(f"Rotated: {rotated_box}")
230
print(f"Combined transformation: {combined}")
231
```
232
233
### Complex Transformations with Scaling
234
235
```python
236
import klayout.db as db
237
import math
238
239
# Create complex transformation
240
angle = 45.0 # 45 degrees
241
scale = 1.5 # 150% scaling
242
displacement = db.DPoint(100.0, 200.0)
243
244
ctrans = db.CplxTrans(scale, angle, False, displacement)
245
246
# Transform double precision shapes
247
dbox = db.DBox(0.0, 0.0, 10.0, 5.0)
248
transformed_dbox = ctrans.transform_box(dbox)
249
250
print(f"Original: {dbox}")
251
print(f"Transformed: {transformed_dbox}")
252
print(f"Scale: {ctrans.mag}, Angle: {ctrans.angle}°")
253
```
254
255
### Matrix-Based Transformations
256
257
```python
258
import klayout.db as db
259
import math
260
261
# Create transformation using matrices
262
matrix = db.Matrix3d()
263
matrix.rotate(math.pi / 4) # 45 degrees in radians
264
matrix.scale(2.0, 1.5) # Scale X by 2, Y by 1.5
265
matrix.translate(100.0, 50.0)
266
267
# Apply to points
268
points = [db.DPoint(0, 0), db.DPoint(10, 0), db.DPoint(10, 10), db.DPoint(0, 10)]
269
transformed_points = [matrix.transform_point(p) for p in points]
270
271
print("Original points:", points)
272
print("Transformed points:", transformed_points)
273
```
274
275
### Cell Instance Transformations
276
277
```python
278
import klayout.db as db
279
280
layout = db.Layout()
281
top_cell = layout.create_cell("TOP")
282
sub_cell = layout.create_cell("SUB")
283
284
# Add content to subcell
285
layer = layout.layer(db.LayerInfo(1, 0))
286
sub_cell.shapes(layer).insert(db.Box(0, 0, 100, 100))
287
288
# Create instances with various transformations
289
transformations = [
290
db.Trans(0, False, db.Point(0, 0)), # Original position
291
db.Trans(1, False, db.Point(200, 0)), # 90° rotation
292
db.Trans(2, False, db.Point(200, 200)), # 180° rotation
293
db.Trans(3, False, db.Point(0, 200)), # 270° rotation
294
db.Trans(0, True, db.Point(400, 0)), # Mirrored
295
]
296
297
for i, trans in enumerate(transformations):
298
instance = db.CellInstArray(sub_cell.cell_index, trans)
299
top_cell.insert(instance)
300
301
layout.write("transformed_instances.gds")
302
```
303
304
### Coordinate System Conversion
305
306
```python
307
import klayout.db as db
308
309
layout = db.Layout()
310
print(f"Default DBU: {layout.dbu} micrometers")
311
312
# Work with different coordinate systems
313
# Coordinates in micrometers
314
user_coord = 10.5 # 10.5 μm
315
316
# Convert to database units
317
dbu_coord = db.coord_to_dbu(user_coord, layout.dbu)
318
print(f"{user_coord} μm = {dbu_coord} DBU")
319
320
# Convert back to user units
321
recovered_coord = db.coord_from_dbu(dbu_coord, layout.dbu)
322
print(f"{dbu_coord} DBU = {recovered_coord} μm")
323
324
# Create shapes using converted coordinates
325
box_in_um = db.Box(
326
db.coord_to_dbu(0.0, layout.dbu),
327
db.coord_to_dbu(0.0, layout.dbu),
328
db.coord_to_dbu(10.5, layout.dbu),
329
db.coord_to_dbu(5.25, layout.dbu)
330
)
331
332
cell = layout.create_cell("TOP")
333
layer = layout.layer(db.LayerInfo(1, 0))
334
cell.shapes(layer).insert(box_in_um)
335
```
336
337
### Advanced Transformation Chains
338
339
```python
340
import klayout.db as db
341
342
# Create a chain of transformations
343
base_trans = db.Trans(db.Point(100, 100)) # Base translation
344
rotate_90 = db.Trans(1, False, db.Point(0, 0)) # 90° rotation
345
mirror_x = db.Trans(0, True, db.Point(0, 0)) # Mirror
346
347
# Build transformation chain
348
step1 = base_trans * rotate_90
349
step2 = step1 * mirror_x
350
351
# Apply to create pattern
352
layout = db.Layout()
353
cell = layout.create_cell("PATTERN")
354
layer = layout.layer(db.LayerInfo(1, 0))
355
356
# Original shape
357
original = db.Box(0, 0, 50, 25)
358
cell.shapes(layer).insert(original)
359
360
# Transformed copies
361
cell.shapes(layer).insert(step1.transform_box(original))
362
cell.shapes(layer).insert(step2.transform_box(original))
363
364
# Verify inverse transformations
365
inverse_step2 = step2.inverted()
366
recovered = inverse_step2.transform_box(step2.transform_box(original))
367
print(f"Original: {original}")
368
print(f"Recovered: {recovered}")
369
print(f"Match: {original == recovered}")
370
371
layout.write("transformation_chain.gds")
372
```
373
374
### Working with Arbitrary Angles
375
376
```python
377
import klayout.db as db
378
import math
379
380
# For arbitrary angles, use CplxTrans
381
angles = [15, 30, 45, 60, 75] # Degrees
382
center = db.DPoint(50, 50)
383
384
layout = db.Layout()
385
cell = layout.create_cell("ROTATIONS")
386
layer = layout.layer(db.LayerInfo(1, 0))
387
388
# Create base shape
389
base_points = [
390
db.Point(0, 0), db.Point(20, 0),
391
db.Point(20, 10), db.Point(0, 10)
392
]
393
base_polygon = db.Polygon(base_points)
394
395
for angle in angles:
396
# Create transformation: translate to origin, rotate, translate back
397
to_origin = db.CplxTrans(1.0, 0.0, False, db.DPoint(-center.x, -center.y))
398
rotate = db.CplxTrans(1.0, angle, False, db.DPoint(0, 0))
399
from_origin = db.CplxTrans(1.0, 0.0, False, center)
400
401
# Combine transformations
402
full_trans = from_origin * rotate * to_origin
403
404
# Convert to integer transformation for polygon
405
# (Note: This approximates arbitrary angles to nearest valid Trans rotation)
406
# For exact arbitrary angles, work with DPolygon instead
407
approx_trans = db.ICplxTrans(full_trans).to_trans()
408
409
rotated_polygon = base_polygon.transformed(approx_trans)
410
cell.shapes(layer).insert(rotated_polygon)
411
412
layout.write("arbitrary_rotations.gds")
413
```