Geometry
The kipy.geometry module provides geometric types for working with positions and shapes.
from kipy.geometry import Vector2, Box2
Vector2
Represents a 2D point or vector.
Creating Vectors
from kipy.geometry import Vector2
# From millimeters (most common)
pos = Vector2.from_xy_mm(50, 25)
# From mils (1/1000 inch)
pos = Vector2.from_xy_mils(2000, 1000)
# From internal units (nanometers)
pos = Vector2(x=50000000, y=25000000)
# Zero vector
zero = Vector2.zero()
Accessing Values
pos = Vector2.from_xy_mm(50, 25)
# In internal units (nanometers)
print(pos.x, pos.y) # 50000000, 25000000
# In millimeters
print(pos.x_mm, pos.y_mm) # 50.0, 25.0
# In mils
print(pos.x_mils, pos.y_mils) # 1968.5, 984.25
Operations
a = Vector2.from_xy_mm(10, 20)
b = Vector2.from_xy_mm(5, 10)
# Addition
c = a + b # (15, 30)mm
# Subtraction
d = a - b # (5, 10)mm
# Scalar multiplication
e = a * 2 # (20, 40)mm
# Negation
f = -a # (-10, -20)mm
Distance and Magnitude
a = Vector2.from_xy_mm(0, 0)
b = Vector2.from_xy_mm(3, 4)
# Distance between points
dist = a.distance_to(b)
print(f"{dist / 1000000}mm") # 5.0mm
# Magnitude (length)
length = b.magnitude()
Comparison
a = Vector2.from_xy_mm(10, 20)
b = Vector2.from_xy_mm(10, 20)
c = Vector2.from_xy_mm(10, 21)
print(a == b) # True
print(a == c) # False
Box2
Represents an axis-aligned bounding box.
Creating Boxes
from kipy.geometry import Box2
# From position and size
box = Box2.from_pos_size(
pos=Vector2.from_xy_mm(10, 10),
size=Vector2.from_xy_mm(50, 30)
)
# From corners
box = Box2.from_corners(
min_corner=Vector2.from_xy_mm(10, 10),
max_corner=Vector2.from_xy_mm(60, 40)
)
# From center and size
box = Box2.from_center_size(
center=Vector2.from_xy_mm(35, 25),
size=Vector2.from_xy_mm(50, 30)
)
Box Properties
box = Box2.from_pos_size(
pos=Vector2.from_xy_mm(10, 10),
size=Vector2.from_xy_mm(50, 30)
)
# Position (top-left)
print(box.position.x_mm, box.position.y_mm) # 10, 10
# Size
print(box.size.x_mm, box.size.y_mm) # 50, 30
# Width and height
print(box.width, box.height) # in internal units
# Center
print(box.center.x_mm, box.center.y_mm) # 35, 25
Box Operations
# Check if point is inside
point = Vector2.from_xy_mm(30, 20)
inside = box.contains(point) # True
# Check intersection
box2 = Box2.from_pos_size(
pos=Vector2.from_xy_mm(40, 20),
size=Vector2.from_xy_mm(30, 20)
)
intersects = box.intersects(box2) # True
# Expand box
expanded = box.expand(5000000) # Expand by 5mm
# Union of boxes
union = box.union(box2)
Example: Calculate Bounding Box
from kipy import KiCad
from kipy.geometry import Vector2, Box2
kicad = KiCad()
board = kicad.get_board()
# Get all footprint positions
footprints = board.footprints.get_all()
if footprints:
# Start with first footprint position
min_x = max_x = footprints[0].position.x
min_y = max_y = footprints[0].position.y
# Find bounds
for fp in footprints:
min_x = min(min_x, fp.position.x)
max_x = max(max_x, fp.position.x)
min_y = min(min_y, fp.position.y)
max_y = max(max_y, fp.position.y)
bbox = Box2.from_corners(
Vector2(min_x, min_y),
Vector2(max_x, max_y)
)
print(f"Footprint bounds:")
print(f" Min: ({bbox.position.x_mm}, {bbox.position.y_mm})mm")
print(f" Size: ({bbox.size.x_mm}, {bbox.size.y_mm})mm")
Example: Grid Positions
from kipy.geometry import Vector2
def grid_positions(start, cols, rows, spacing_mm):
"""Generate a grid of positions."""
positions = []
for row in range(rows):
for col in range(cols):
pos = Vector2.from_xy_mm(
start.x_mm + col * spacing_mm,
start.y_mm + row * spacing_mm
)
positions.append(pos)
return positions
# Generate 3x4 grid starting at (10, 10) with 10mm spacing
start = Vector2.from_xy_mm(10, 10)
grid = grid_positions(start, cols=3, rows=4, spacing_mm=10)
for i, pos in enumerate(grid):
print(f"Position {i}: ({pos.x_mm}, {pos.y_mm})mm")
Example: Polar Coordinates
import math
from kipy.geometry import Vector2
def polar_position(center, radius_mm, angle_degrees):
"""Calculate position from polar coordinates."""
angle_rad = math.radians(angle_degrees)
x = center.x_mm + radius_mm * math.cos(angle_rad)
y = center.y_mm + radius_mm * math.sin(angle_rad)
return Vector2.from_xy_mm(x, y)
# Create circle of positions
center = Vector2.from_xy_mm(100, 100)
radius = 20
for angle in range(0, 360, 30):
pos = polar_position(center, radius, angle)
print(f"{angle}°: ({pos.x_mm:.1f}, {pos.y_mm:.1f})mm")
Unit Conversion Reference
| Unit | Multiplier to IU |
|---|---|
| 1 nm | 1 |
| 1 µm | 1,000 |
| 1 mm | 1,000,000 |
| 1 mil | 25,400 |
| 1 inch | 25,400,000 |
Internal units (IU) are nanometers in the PCB editor.