Geometry Builders¶
Geometry utility functions for EnergyPlus surface manipulation. For creating building zones and surfaces, see Zoning.
Quick Start¶
from idfkit import new_document
from idfkit.geometry_builders import add_shading_block
doc = new_document()
add_shading_block(doc, "Neighbour", [(30, 0), (50, 0), (50, 20), (30, 20)], height=25)
print(len(doc["Shading:Site:Detailed"])) # 5
Shading Blocks¶
add_shading_block creates Shading:Site:Detailed surfaces --
opaque boxes that cast shadows but have no thermal zones.
from idfkit import new_document
from idfkit.geometry_builders import add_shading_block
doc = new_document()
# Neighbouring building
add_shading_block(doc, "Neighbour", [(30, 0), (50, 0), (50, 20), (30, 20)], height=25)
# Elevated canopy
add_shading_block(doc, "Canopy", [(0, -3), (10, -3), (10, 0), (0, 0)], height=0.2, base_z=3)
Each call creates one wall surface per footprint edge plus a horizontal top cap.
GlobalGeometryRules Convention¶
All builder functions read the document's GlobalGeometryRules to
determine the vertex ordering convention:
starting_vertex_position-- which corner is listed first for walls (UpperLeftCorner,LowerLeftCorner, etc.)vertex_entry_direction-- winding direction (CounterclockwiseorClockwise)
new_document() pre-seeds GlobalGeometryRules with
UpperLeftCorner / Counterclockwise defaults. If a model is missing
GlobalGeometryRules (for example, some legacy inputs), the same
EnergyPlus defaults are assumed.
This means you can safely add geometry to an existing model that uses a non-default convention without having to rewrite all existing surfaces:
from idfkit import load_idf, create_block
# Model uses Clockwise vertex convention
model = load_idf("existing_building.idf")
# New surfaces will automatically use Clockwise ordering
# to match the model's GlobalGeometryRules
create_block(model, "Addition", [(20, 0), (30, 0), (30, 10), (20, 10)], floor_to_floor=3)
Wall Vertex Order by Convention¶
For a wall between footprint vertices p1 and p2 (height z_bot to z_top), viewed from outside:
| Starting Position | Counterclockwise | Clockwise |
|---|---|---|
| UpperLeftCorner | UL LL LR UR | UL UR LR LL |
| LowerLeftCorner | LL LR UR UL | LL UL UR LR |
| LowerRightCorner | LR UR UL LL | LR LL UL UR |
| UpperRightCorner | UR UL LL LR | UR LR LL UL |
Where UL = (p1, z_top), LL = (p1, z_bot), LR = (p2, z_bot), UR = (p2, z_top).
Horizontal Surfaces¶
For floors and ceilings, the winding direction is adapted so that EnergyPlus computes the correct outward normal regardless of convention:
- Floor: outward normal points down (toward ground)
- Ceiling / Roof: outward normal points up (toward sky)
Utility Functions¶
set_default_constructions¶
Assigns a placeholder construction name to any surface that lacks one:
from idfkit.geometry_builders import set_default_constructions
count = set_default_constructions(doc, "Generic Wall")
print(f"Updated {count} surfaces")
bounding_box¶
Returns the 2D axis-aligned bounding box of all
BuildingSurface:Detailed objects:
from idfkit.geometry_builders import bounding_box
bbox = bounding_box(doc)
if bbox:
(min_x, min_y), (max_x, max_y) = bbox
print(f"Footprint spans {max_x - min_x:.1f} x {max_y - min_y:.1f} m")
scale_building¶
Scales all surface vertices around an anchor point:
from idfkit.geometry_builders import scale_building
from idfkit.geometry import Vector3D
# Double the building in all directions
scale_building(doc, 2.0)
# Stretch only the X axis
scale_building(doc, (1.5, 1.0, 1.0))
# Scale around the building centroid
scale_building(doc, 0.5, anchor=Vector3D(15, 10, 0))
Horizontal Adjacency Detection¶
When building models with stacked blocks (e.g. setback towers), roof
and floor surfaces at shared elevations need to be detected, split, and
linked. The high-level link_blocks
handles this automatically, but you can use the lower-level API for
custom geometry workflows.
Detecting Adjacencies¶
detect_horizontal_adjacencies scans all BuildingSurface:Detailed
surfaces for horizontal Roof/Floor pairs at the same z-elevation with
Outdoors boundary condition, and computes their 2-D polygon
intersection:
from idfkit.geometry_builders import detect_horizontal_adjacencies
adjacencies = detect_horizontal_adjacencies(doc)
for adj in adjacencies:
print(f"Roof '{adj.roof_surface.name}' overlaps floor "
f"'{adj.floor_surface.name}' at z={adj.z} "
f"({adj.intersection_area:.1f} m²)")
Each HorizontalAdjacency record contains the roof surface, floor
surface, z-elevation, 2-D intersection polygon, and intersection area.
Splitting Surfaces¶
split_horizontal_surface creates a new surface for a 2-D region
within an existing horizontal surface. The original surface is shrunk
to the remaining area:
from idfkit.geometry_builders import split_horizontal_surface
new_surface, remaining = split_horizontal_surface(doc, adj.roof_surface, adj.intersection)
# new_surface covers the intersection region
# remaining is the original surface, now covering only the exposed area
Linking Surfaces¶
link_horizontal_surfaces sets mutual Surface boundary conditions
between a ceiling and floor:
from idfkit.geometry_builders import link_horizontal_surfaces
link_horizontal_surfaces(new_surface, adj.floor_surface)
# new_surface is now a Ceiling pointing at the floor, and vice versa
Full Example¶
from idfkit.geometry_builders import (
detect_horizontal_adjacencies,
link_horizontal_surfaces,
split_horizontal_surface,
)
adjacencies = detect_horizontal_adjacencies(doc)
for adj in adjacencies:
new_ceiling, _ = split_horizontal_surface(doc, adj.roof_surface, adj.intersection)
link_horizontal_surfaces(new_ceiling, adj.floor_surface)
API Reference¶
Geometry utility functions for EnergyPlus surface manipulation.
Provides shading block creation, default construction assignment, bounding
box queries, building scaling, horizontal adjacency detection, surface
splitting, and GlobalGeometryRules vertex-ordering helpers.
For building zone and surface creation, see zoning which provides create_block and ZonedBlock.
HorizontalAdjacency
dataclass
¶
A detected adjacency between a roof and floor surface at the same elevation.
Attributes:
| Name | Type | Description |
|---|---|---|
roof_surface |
IDFObject
|
The roof surface from the lower block. |
floor_surface |
IDFObject
|
The floor surface from the upper block. |
z |
float
|
The shared elevation in metres. |
intersection |
list[tuple[float, float]]
|
2-D polygon of the overlapping area. |
intersection_area |
float
|
Area of the overlap in square metres. |
Source code in src/idfkit/geometry_builders.py
add_shading_block(doc, name, footprint, height, base_z=0.0)
¶
Create Shading:Site:Detailed surfaces from a 2D footprint.
Creates one shading surface per footprint edge (walls) plus a horizontal top cap. No zones or thermal surfaces are created.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
doc
|
IDFDocument
|
The document to add objects to. |
required |
name
|
str
|
Base name for shading surfaces. |
required |
footprint
|
Sequence[tuple[float, float]]
|
2D footprint as |
required |
height
|
float
|
Height of the shading block in metres. |
required |
base_z
|
float
|
Z-coordinate of the block base (default |
0.0
|
Returns:
| Type | Description |
|---|---|
list[IDFObject]
|
List of created |
Raises:
| Type | Description |
|---|---|
ValueError
|
If footprint has fewer than 3 vertices or height <= 0. |
Source code in src/idfkit/geometry_builders.py
bounding_box(doc)
¶
Return the 2D axis-aligned bounding box of all building surfaces.
Scans all BuildingSurface:Detailed vertices and returns the
bounding envelope projected onto the XY plane.
Note
Only BuildingSurface:Detailed objects are considered.
Fenestration and shading surfaces are excluded because they
are either coplanar with (windows) or outside (shading) the
thermal envelope.
Returns:
| Type | Description |
|---|---|
tuple[tuple[float, float], tuple[float, float]] | None
|
|
tuple[tuple[float, float], tuple[float, float]] | None
|
surfaces with valid coordinates exist. |
Source code in src/idfkit/geometry_builders.py
detect_horizontal_adjacencies(doc)
¶
Find roof/floor surface pairs at matching elevations.
Scans all BuildingSurface:Detailed surfaces for horizontal Roof
surfaces with Outdoors boundary condition and horizontal Floor
surfaces with Outdoors boundary condition at the same elevation.
For each overlapping pair the 2-D polygon intersection is computed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
doc
|
IDFDocument
|
The document to scan. |
required |
Returns:
| Type | Description |
|---|---|
list[HorizontalAdjacency]
|
List of :class: |
list[HorizontalAdjacency]
|
overlap. |
Source code in src/idfkit/geometry_builders.py
get_geometry_convention(doc)
¶
Read the vertex ordering convention from GlobalGeometryRules.
Returns:
| Type | Description |
|---|---|
str
|
|
bool
|
|
tuple[str, bool]
|
Defaults to |
Source code in src/idfkit/geometry_builders.py
horizontal_poly(footprint, z, *, reverse)
¶
Build a horizontal polygon at height z.
When reverse is True the footprint is reversed, flipping the
polygon normal. Used to produce floor and ceiling polygons in the
correct winding for the active GlobalGeometryRules convention.
Source code in src/idfkit/geometry_builders.py
link_horizontal_surfaces(ceiling, floor)
¶
Set mutual Surface boundary conditions between ceiling and floor.
Modifies both surfaces in-place:
- The ceiling's
surface_typeis set toCeiling. - Both surfaces get
outside_boundary_condition = "Surface"pointing at each other, with sun/wind exposure set toNoSun/NoWind.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ceiling
|
IDFObject
|
The surface to designate as the ceiling. |
required |
floor
|
IDFObject
|
The surface to designate as the floor. |
required |
Source code in src/idfkit/geometry_builders.py
scale_building(doc, factor, anchor=None)
¶
Scale all surface vertices around an anchor point.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
doc
|
IDFDocument
|
The document to modify in-place. |
required |
factor
|
float | tuple[float, float, float]
|
Scale factor. A single |
required |
anchor
|
Vector3D | None
|
Point to scale around. If |
None
|
Source code in src/idfkit/geometry_builders.py
set_default_constructions(doc, construction_name='Default Construction')
¶
Assign a placeholder construction to surfaces that lack one.
Iterates all BuildingSurface:Detailed and
FenestrationSurface:Detailed objects and sets
construction_name for any whose current value is empty or None.
Does not create the Construction object itself — the caller
is responsible for ensuring it exists.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
doc
|
IDFDocument
|
The document to modify. |
required |
construction_name
|
str
|
Name of the construction to assign. |
'Default Construction'
|
Returns:
| Type | Description |
|---|---|
int
|
Number of surfaces updated. |
Source code in src/idfkit/geometry_builders.py
split_horizontal_surface(doc, surface, region)
¶
Split a horizontal surface at a 2-D region boundary.
A new surface is created for the area inside the region. The original surface is shrunk to the area outside the region (the remaining frame).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
doc
|
IDFDocument
|
The document containing the surface. |
required |
surface
|
IDFObject
|
Horizontal surface to split (floor, ceiling, or roof). |
required |
region
|
Sequence[tuple[float, float]]
|
2-D polygon defining the split region. |
required |
Returns:
| Type | Description |
|---|---|
IDFObject
|
|
IDFObject | None
|
remaining_surface is |
tuple[IDFObject, IDFObject | None]
|
surface (i.e. no remaining area). |
Source code in src/idfkit/geometry_builders.py
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 | |
See Also¶
- Zoning --
create_block,link_blocks, core-perimeter zoning, footprint helpers, and multi-zone building generation - Geometry -- Lower-level 3D primitives, coordinate transforms, and surface intersection
- Visualization -- 3D rendering of building geometry
- Thermal -- R/U-value calculations for constructions