Transforms¶
All entities support non-destructive transforms — rotation and scale are stored as numbers and applied at render time via SVG transform, not baked into geometry. Transforms preserve relative bindings: rotating or scaling an entity that tracks a container-relative position does not destroy that binding.
See also
For hands-on transform examples, see Transforms and Layout.
Entity ¶
Bases: ABC
Base class for all drawable objects in PyFreeform.
Entities are objects with identity - they can be moved, connected, and tracked. Unlike raw primitives, entities maintain relationships with other entities.
Attributes:
| Name | Type | Description |
|---|---|---|
position |
Coord
|
Current position (center point for most entities) |
surface |
Surface | None
|
The surface containing this entity (Cell, Scene, or CellGroup) |
connections |
Collection[Connection]
|
Connections involving this entity |
Subclasses must implement
anchor(name): Return anchor point by nameanchor_names: Property listing available anchor namesto_svg(): Render to SVG element string
Initialize entity at position.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
float
|
Initial x coordinate. |
0
|
y
|
float
|
Initial y coordinate. |
0
|
z_index
|
int
|
Layer ordering (higher = on top). Default 0. |
0
|
rotation
property
writable
¶
Rotation angle in degrees (accumulated, non-destructive).
scale_factor
property
writable
¶
Scale factor (accumulated, non-destructive). Default 1.0.
rotation_center
property
¶
rotation_center: Coord
The center point for rotation and scaling transforms.
Default: entity position. Override for entities where the natural pivot differs (e.g., Rect center, Polygon centroid).
rotate ¶
rotate(angle: float, origin: CoordLike | None = None) -> Entity
Rotate entity by angle degrees.
Without origin, rotates in place. With origin, also moves the entity around that point (like orbiting).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
angle
|
float
|
Rotation in degrees (counterclockwise). |
required |
origin
|
CoordLike | None
|
Point to rotate around. If |
None
|
Returns:
| Type | Description |
|---|---|
Entity
|
self, for method chaining. |
scale ¶
scale(factor: float, origin: CoordLike | None = None) -> Entity
Scale entity by factor.
Without origin, scales around the entity's natural center. With origin, also moves the entity toward/away from that point.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
factor
|
float
|
Scale multiplier (1.0 = no change, 2.0 = double). |
required |
origin
|
CoordLike | None
|
Point to scale around. If |
None
|
Returns:
| Type | Description |
|---|---|
Entity
|
self, for method chaining. |
fit_within ¶
fit_within(target: Entity | tuple[float, float, float, float], scale: float = 1.0, recenter: bool = True, *, at: RelCoordLike | None = None, visual: bool = True, rotate: bool = False, match_aspect: bool = False) -> Entity
Scale and position entity to fit within another entity's inner bounds.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target
|
Entity | tuple[float, float, float, float]
|
Entity (uses inner_bounds()) or raw (min_x, min_y, max_x, max_y) tuple. |
required |
scale
|
float
|
Fraction of target inner bounds to fill (0.0-1.0]. |
1.0
|
recenter
|
bool
|
If True, center entity within target after scaling.
Ignored when |
True
|
at
|
RelCoordLike | None
|
Optional relative position (rx, ry) within the target's inner bounds, where (0,0) is top-left and (1,1) is bottom-right. Available space is constrained by the nearest edges so the entity never overflows. |
None
|
visual
|
bool
|
If True (default), include stroke width when measuring bounds so stroked entities don't overflow after fitting. Set to False for pure geometric fitting. |
True
|
rotate
|
bool
|
If True, find the rotation angle that maximizes how much of the target space the entity fills before scaling. |
False
|
match_aspect
|
bool
|
If True, rotate the entity so its bounding box
aspect ratio matches the target's. Mutually
exclusive with |
False
|
Returns:
| Type | Description |
|---|---|
Entity
|
self, for method chaining. |
fit_to_surface ¶
fit_to_surface(scale: float = 1.0, recenter: bool = True, *, at: RelCoordLike | None = None, visual: bool = True, rotate: bool = False, match_aspect: bool = False) -> Entity
Automatically scale and position entity to fit within its surface bounds.
Convenience wrapper around :meth:fit_within that uses the
containing surface as the target region.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scale
|
float
|
Fraction of available space to fill (0.0-1.0). 1.0 = fill entire surface, 0.85 = use 85%. |
1.0
|
recenter
|
bool
|
If True, center entity in surface after scaling.
Ignored when |
True
|
at
|
RelCoordLike | None
|
RelCoordLike within the surface as (rx, ry) fractions. Constrains fitting to the space available at that point so the entity doesn't overflow. (0.5, 0.5) uses the full surface (default). |
None
|
visual
|
bool
|
If True (default), include stroke width in bounds measurement so stroked shapes don't overflow. |
True
|
rotate
|
bool
|
If True, auto-rotate to maximize surface coverage. |
False
|
match_aspect
|
bool
|
If True, rotate to match the surface's aspect ratio.
Mutually exclusive with |
False
|
Returns:
| Type | Description |
|---|---|
Entity
|
self, for method chaining |
Raises:
| Type | Description |
|---|---|
ValueError
|
If entity has no surface, scale is out of range,
or both |
TypeError
|
If |
Model-space vs world-space
- Model-space properties (
.radius,.width,.end,.vertices) are unchanged by transforms - World-space methods (
anchor(),bounds(),point_at()) apply rotation and scale automatically - SVG output uses model-space coordinates with a
transformattribute
Per-Entity Pivot Points¶
Each entity type defines its own natural rotation_center:
| Entity | Pivot |
|---|---|
| Dot, Ellipse, Text | Center (position) |
| Rect | Center of rectangle |
| Line, Curve | Chord midpoint (start → end) |
| Polygon | Centroid of vertices |
| Path | Bezier midpoint at t=0.5 |
| EntityGroup | Accumulates in <g> transform (children unchanged) |
Text fit_to_surface
For Text entities, fit_to_surface(fraction) adjusts font size (up or down) to fill the surface. Compare with add_text(fit=True) which only shrinks.