CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-klayout

KLayout is a high performance layout viewer and editor that supports GDS and OASIS files and more formats

Pending
Overview
Eval results
Files

transformations.mddocs/

Layout Transformations and Coordinates

Geometric transformations including rotation, mirroring, scaling, and translation operations for precise layout manipulation and coordinate system conversions in IC design workflows.

Capabilities

Basic Transformations

class Trans:
    def __init__(self, rotation: int = 0, mirror: bool = False, displacement: Point = None):
        """
        Create an integer coordinate transformation.
        
        Parameters:
        - rotation: Rotation in 90-degree increments (0, 1, 2, 3)
        - mirror: Mirror across X-axis before rotation
        - displacement: Translation vector
        """
    
    @property
    def rot(self) -> int:
        """Get rotation value (0-3 for 0°, 90°, 180°, 270°)."""
    
    @property
    def is_mirror(self) -> bool:
        """Check if transformation includes mirroring."""
    
    @property
    def disp(self) -> Point:
        """Get displacement vector."""
    
    def inverted(self) -> Trans:
        """Return the inverse transformation."""
    
    def __mul__(self, other: Trans) -> Trans:
        """Combine transformations (self * other)."""
    
    def transform_point(self, point: Point) -> Point:
        """Transform a point."""
    
    def transform_box(self, box: Box) -> Box:
        """Transform a bounding box."""

class DTrans:
    def __init__(self, rotation: int = 0, mirror: bool = False, displacement: DPoint = None):
        """Create a double precision transformation."""
    
    @property
    def rot(self) -> int:
        """Get rotation value."""
    
    @property
    def is_mirror(self) -> bool:
        """Check if transformation includes mirroring."""
    
    @property
    def disp(self) -> DPoint:
        """Get displacement vector."""

Complex Transformations with Scaling

class CplxTrans:
    def __init__(self, mag: float = 1.0, rotation: float = 0.0, mirror: bool = False, displacement: DPoint = None):
        """
        Create a complex transformation with scaling and arbitrary rotation.
        
        Parameters:
        - mag: Magnification factor
        - rotation: Rotation angle in degrees
        - mirror: Mirror across X-axis before rotation
        - displacement: Translation vector
        """
    
    @property
    def mag(self) -> float:
        """Get magnification factor."""
    
    @property
    def angle(self) -> float:
        """Get rotation angle in degrees."""
    
    @property
    def is_mirror(self) -> bool:
        """Check if transformation includes mirroring."""
    
    @property
    def disp(self) -> DPoint:
        """Get displacement vector."""
    
    def inverted(self) -> CplxTrans:
        """Return the inverse transformation."""
    
    def __mul__(self, other: CplxTrans) -> CplxTrans:
        """Combine complex transformations."""
    
    def transform_point(self, point: DPoint) -> DPoint:
        """Transform a double precision point."""
    
    def transform_box(self, box: DBox) -> DBox:
        """Transform a double precision bounding box."""

class ICplxTrans:
    def __init__(self, mag: float = 1.0, rotation: float = 0.0, mirror: bool = False, displacement: Point = None):
        """Create an integer complex transformation."""
    
    def to_trans(self) -> Trans:
        """Convert to simple transformation (if no scaling)."""

class DCplxTrans:
    def __init__(self, mag: float = 1.0, rotation: float = 0.0, mirror: bool = False, displacement: DPoint = None):
        """Create a double precision complex transformation."""

Matrix Transformations

class Matrix2d:
    def __init__(self, m11: float = 1.0, m12: float = 0.0, m21: float = 0.0, m22: float = 1.0):
        """
        Create a 2x2 transformation matrix.
        
        Parameters:
        - m11, m12, m21, m22: Matrix elements
        """
    
    def determinant(self) -> float:
        """Calculate matrix determinant."""
    
    def inverted(self) -> Matrix2d:
        """Return inverted matrix."""
    
    def __mul__(self, other: Matrix2d) -> Matrix2d:
        """Matrix multiplication."""
    
    def transform_point(self, point: DPoint) -> DPoint:
        """Transform a point using the matrix."""

class Matrix3d:
    def __init__(self):
        """Create a 3x3 transformation matrix."""
    
    def translate(self, dx: float, dy: float) -> Matrix3d:
        """Add translation to the transformation."""
    
    def rotate(self, angle: float) -> Matrix3d:
        """Add rotation to the transformation (in radians)."""
    
    def scale(self, sx: float, sy: float = None) -> Matrix3d:
        """
        Add scaling to the transformation.
        
        Parameters:
        - sx: X scale factor
        - sy: Y scale factor (defaults to sx if not provided)
        """
    
    def shear(self, shx: float, shy: float) -> Matrix3d:
        """Add shear transformation."""
    
    def inverted(self) -> Matrix3d:
        """Return inverted matrix."""
    
    def transform_point(self, point: DPoint) -> DPoint:
        """Transform a point."""

Coordinate System Utilities

def coord_from_dbu(coord_dbu: int, dbu: float) -> float:
    """
    Convert coordinate from database units to user units.
    
    Parameters:
    - coord_dbu: Coordinate in database units
    - dbu: Database unit in user units
    
    Returns:
    float: Coordinate in user units
    """

def coord_to_dbu(coord: float, dbu: float) -> int:
    """
    Convert coordinate from user units to database units.
    
    Parameters:
    - coord: Coordinate in user units
    - dbu: Database unit in user units
    
    Returns:
    int: Coordinate in database units
    """

class Layout:
    @property
    def dbu(self) -> float:
        """Get database unit in micrometers."""
    
    def set_dbu(self, dbu: float) -> None:
        """Set database unit."""
    
    def scale_and_snap(self, layout_target: Layout, cell_mapping, layers, factor: float) -> None:
        """Scale layout and snap to grid."""

Usage Examples

Basic Transformations

import klayout.db as db

# Create basic transformations
trans1 = db.Trans(1, False, db.Point(100, 200))  # 90° rotation + translation
trans2 = db.Trans(0, True, db.Point(0, 0))       # Mirror only
trans3 = db.Trans(db.Point(50, 75))              # Translation only

# Apply transformations to shapes
original_box = db.Box(0, 0, 100, 50)
rotated_box = trans1.transform_box(original_box)
mirrored_box = trans2.transform_box(original_box)

# Combine transformations
combined = trans1 * trans2  # Apply trans2, then trans1

print(f"Original: {original_box}")
print(f"Rotated: {rotated_box}")
print(f"Combined transformation: {combined}")

Complex Transformations with Scaling

import klayout.db as db
import math

# Create complex transformation
angle = 45.0  # 45 degrees
scale = 1.5   # 150% scaling
displacement = db.DPoint(100.0, 200.0)

ctrans = db.CplxTrans(scale, angle, False, displacement)

# Transform double precision shapes
dbox = db.DBox(0.0, 0.0, 10.0, 5.0)
transformed_dbox = ctrans.transform_box(dbox)

print(f"Original: {dbox}")
print(f"Transformed: {transformed_dbox}")
print(f"Scale: {ctrans.mag}, Angle: {ctrans.angle}°")

Matrix-Based Transformations

import klayout.db as db
import math

# Create transformation using matrices
matrix = db.Matrix3d()
matrix.rotate(math.pi / 4)  # 45 degrees in radians
matrix.scale(2.0, 1.5)      # Scale X by 2, Y by 1.5
matrix.translate(100.0, 50.0)

# Apply to points
points = [db.DPoint(0, 0), db.DPoint(10, 0), db.DPoint(10, 10), db.DPoint(0, 10)]
transformed_points = [matrix.transform_point(p) for p in points]

print("Original points:", points)
print("Transformed points:", transformed_points)

Cell Instance Transformations

import klayout.db as db

layout = db.Layout()
top_cell = layout.create_cell("TOP")
sub_cell = layout.create_cell("SUB")

# Add content to subcell
layer = layout.layer(db.LayerInfo(1, 0))
sub_cell.shapes(layer).insert(db.Box(0, 0, 100, 100))

# Create instances with various transformations
transformations = [
    db.Trans(0, False, db.Point(0, 0)),      # Original position
    db.Trans(1, False, db.Point(200, 0)),    # 90° rotation
    db.Trans(2, False, db.Point(200, 200)),  # 180° rotation
    db.Trans(3, False, db.Point(0, 200)),    # 270° rotation
    db.Trans(0, True, db.Point(400, 0)),     # Mirrored
]

for i, trans in enumerate(transformations):
    instance = db.CellInstArray(sub_cell.cell_index, trans)
    top_cell.insert(instance)

layout.write("transformed_instances.gds")

Coordinate System Conversion

import klayout.db as db

layout = db.Layout()
print(f"Default DBU: {layout.dbu} micrometers")

# Work with different coordinate systems
# Coordinates in micrometers
user_coord = 10.5  # 10.5 μm

# Convert to database units
dbu_coord = db.coord_to_dbu(user_coord, layout.dbu)
print(f"{user_coord} μm = {dbu_coord} DBU")

# Convert back to user units
recovered_coord = db.coord_from_dbu(dbu_coord, layout.dbu)
print(f"{dbu_coord} DBU = {recovered_coord} μm")

# Create shapes using converted coordinates
box_in_um = db.Box(
    db.coord_to_dbu(0.0, layout.dbu),
    db.coord_to_dbu(0.0, layout.dbu),
    db.coord_to_dbu(10.5, layout.dbu),
    db.coord_to_dbu(5.25, layout.dbu)
)

cell = layout.create_cell("TOP")
layer = layout.layer(db.LayerInfo(1, 0))
cell.shapes(layer).insert(box_in_um)

Advanced Transformation Chains

import klayout.db as db

# Create a chain of transformations
base_trans = db.Trans(db.Point(100, 100))  # Base translation
rotate_90 = db.Trans(1, False, db.Point(0, 0))  # 90° rotation
mirror_x = db.Trans(0, True, db.Point(0, 0))   # Mirror

# Build transformation chain
step1 = base_trans * rotate_90
step2 = step1 * mirror_x

# Apply to create pattern
layout = db.Layout()
cell = layout.create_cell("PATTERN")
layer = layout.layer(db.LayerInfo(1, 0))

# Original shape
original = db.Box(0, 0, 50, 25)
cell.shapes(layer).insert(original)

# Transformed copies
cell.shapes(layer).insert(step1.transform_box(original))
cell.shapes(layer).insert(step2.transform_box(original))

# Verify inverse transformations
inverse_step2 = step2.inverted()
recovered = inverse_step2.transform_box(step2.transform_box(original))
print(f"Original: {original}")
print(f"Recovered: {recovered}")
print(f"Match: {original == recovered}")

layout.write("transformation_chain.gds")

Working with Arbitrary Angles

import klayout.db as db
import math

# For arbitrary angles, use CplxTrans
angles = [15, 30, 45, 60, 75]  # Degrees
center = db.DPoint(50, 50)

layout = db.Layout()
cell = layout.create_cell("ROTATIONS")
layer = layout.layer(db.LayerInfo(1, 0))

# Create base shape
base_points = [
    db.Point(0, 0), db.Point(20, 0), 
    db.Point(20, 10), db.Point(0, 10)
]
base_polygon = db.Polygon(base_points)

for angle in angles:
    # Create transformation: translate to origin, rotate, translate back
    to_origin = db.CplxTrans(1.0, 0.0, False, db.DPoint(-center.x, -center.y))
    rotate = db.CplxTrans(1.0, angle, False, db.DPoint(0, 0))
    from_origin = db.CplxTrans(1.0, 0.0, False, center)
    
    # Combine transformations
    full_trans = from_origin * rotate * to_origin
    
    # Convert to integer transformation for polygon
    # (Note: This approximates arbitrary angles to nearest valid Trans rotation)
    # For exact arbitrary angles, work with DPolygon instead
    approx_trans = db.ICplxTrans(full_trans).to_trans()
    
    rotated_polygon = base_polygon.transformed(approx_trans)
    cell.shapes(layer).insert(rotated_polygon)

layout.write("arbitrary_rotations.gds")

Install with Tessl CLI

npx tessl i tessl/pypi-klayout

docs

database-operations.md

file-io.md

hierarchical-design.md

index.md

layout-viewer.md

shape-operations.md

transformations.md

verification.md

tile.json