Inject geometry
A powerful feature of the Treble SDK is its ability to generate and inject geometries to existing models. This can be useful for parametric studies of geometries, programmatic furnishing of rooms, or to simply enable a modular workflow, where single componsents can be easily reused and adapted for different projects.
This is enabled via few key components,
GeometryDefinition
- A mutable definition of a geometry object, this consists of a base room geometry, either uploaded or generated (see Create Room) and a collection ofGeometryComponent
objects.GeometryComponent
- A geometry component is a 'small' component (such as chairs, desks, etc.) that can be added to a GeometryDefinition to create a more detailed model.GeometryComponentLibrary
- A library of geometry components provided by the SDK.GeometryComponentGenerator
- Can be used to create simple geometry components such as boxes, planes, triangles and loudspeakers.
Geometry components can be injected into GeometryDefinition
objects to form furnished room models.
Utility classes
Note that this functionality relies heavily on various treble_tsdk.utility_classes
for representing geometric quantities and transformations, these are available through either the treble_namespace
or they can be explicitly imported via utility_classes
:
from treble_tsdk import tsdk_namespace as treble
# Define some utility class instances
vector = treble.Point3d(1,0,0)
rotation = treble.Rotation(90,0,0)
translation = treble.Translation(vector,rotation)
# Explicit import
from treble_tsdk.utility_classes import (
Point3d,
Vector3d,
Transform3d,
Rotation,
BoundingBox,
)
Point3d and Vector3d are internally identical, differing only in their semantic usage to distinguish between positional coordinates and directional vectors.
Component Library
The Treble SDK provides a library of geometry components that can be easily retrieved and visualized. This section demonstrates how to access and display these components. We can retrieve a table geometry component from the library and visualize it via:
# Initiate instance of SDK
from treble_tsdk import tsdk_namespace as treble
from treble_tsdk import display_data as dd # for clean display
tsdk = treble.TSDK()
dd.display(tsdk.geometry_component_library.get_groups_with_count())
This displays the resulting table, which lists the different categories and the count of available components for each.
Table: Categories of objects available via Treble SDK at the time of writing this documentation page.
Subsequently, we can query the library by:
# Example:
table_gc_list = tsdk.geometry_component_library.query(group='table')
gc = table_gc_list[0] # GeometryComponent instance
This way we have a GeometryComponent
object which we can inject into a GeometryDefinition
, see Managing Geometry Components.
Component generators
The Component Generator class provides several methods to generate geometry components directly in the treble SDK. These can simply be accessed either via the TSDK namespace, or an explicit import:
# Access via SDK namespace
from treble_tsdk import tsdk_namespace as treble
treble.GeometryComponentGenerator
# Explicit import
from treble_tsdk.geometry.generator import GeometryComponentGenerator
create_triangle
Triangles can be defined via three Point3d
objects, each representing a unique vertex. Here point0
acts as the reference point for translations, and rotations.
# Example:
triangle = GeometryComponentGenerator.create_triangle(
Point3d(0, 0, 0),
Point3d(1, 0, 0),
Point3d(0, 1, 0),
layer_name="my_triangle",
)
create_plane
Creates a 2D rectangle centered in the -plane via length
and width
.
# Example:
plane = GeometryComponentGenerator.create_plane(
length=2
width=1
layer_name="my_plane",
)
create_box
Boxes can be defined through use of treble_tsdk.utility_classes.BoundingBox
, which takes two Point3d
objects, min
and max
, or the minimum and maximum points of the box respectively.
# Example:
box = GeometryComponentGenerator.create_box(
BoundingBox(
Point3d(0, 0, 0),
Point3d(1, 0, 0),
),
layer_name="my_box",
)
create_loudspeaker
Loudspeakers can be defined via their width
, height
and depth
to control the shape of the box enclosure. To place the membrane the parameters membrane_diameter
and membrane_center_height
are used. The center of the membrane is placed at the origin.
# Example:
speaker = GeometryComponentGenerator.create_loudspeaker(
width=0.2,
height=0.4,
depth=0.3,
membrane_diameter=0.1,
membrane_height=0.1,
membrane_resolution=12, # default value
membrane_layer_name="my_membrane",
enclosure_layer_name="my_enclosure"
)
Managing Geometry Components
To manage components within a GeometryDefinition
several methods are provided. Below we assume an existing geometry definition named geo_def
, see see Create Room for further details, or refer to Example below.
add_geometry_component
Adds a geometry component to the model with a specified transformation.
# Example:
geo_def.add_geometry_component(
"name",
geo_component,
Transform3d(Vector3d(3, 3, 0.5), Rotation(45, 0, 0))
)
remove_geometry_component
Removes a specified component from the model, keeping the scene clean and adaptable.
# Example:
geo_def.remove_geometry_component("name")
get_geometry_component_transform
Retrieves a component’s position and rotation for analysis or modification.
# Example:
geo_def.get_geometry_component_transform("name") # Transform3d class instance
set_geometry_component_transform
Updates a component’s position and rotation to refine spatial placement.
# Example:
geo_def.set_geometry_component_transform("name", Transform3d(Vector3d(4, 4, 0.5), Rotation(90, 0, 0)))
set_geometry_component_rotation
Adjusts the rotation of a component without changing its position.
# Example:
geo_def.set_geometry_component_rotation("name", Rotation(135, 0, 0))
move_geometry_component
Moves a component by a given vector without redefining its transformation.
# Example:
geo_def.move_geometry_component("my_box", Vector3d(1, 1, 0))
Automatic Placement of Components
GeometryComponentPlacement
objects define how a group of components are arranged within a GeometryDefinition
. This ensures efficient positioning while maintaining constraints like orientation, spacing, and alignment. By using component placements, we can automate room setups, enforce design rules, and easily create different layout variations.
add_geometry_component_placement
Adds a component placement definition to determine how components are positioned within the geometry.
# Example:
placements = treble.GeometryComponentPlacement(
components=tsdk.geometry_component_library.query(group="table"),
preferred_count=3,
rotation_settings=treble.ComponentAnglePool([0, 90, 180, 270])
)
geo_def.add_geometry_component_placement(placements)
remove_geometry_component_placement
Removes a specified component placement from the model.
# Example:
geo_def.remove_geometry_component_placement(placements)
get_geometry_component_placements
Retrieves a list of current component placements for analysis or modification.
# Example:
geo_def.get_geometry_component_placements() # Returns a list of GeometryComponentPlacement instances
set_geometry_component_placement
Updates a component placement definition to refine spatial arrangements.
# Example:
geo_def.set_geometry_component_placement(
placements,
treble.GeometryComponentPlacement(
components=tsdk.geometry_component_library.query(group="chair"),
preferred_count=10,
rotation_settings=treble.ComponentAnglePool([0, 45, 90, 135, 180, 225, 270, 315])
)
)
Populating and Visualizing the Room
Once the placements are defined, the room can be populated and visualized. Rerunning this will generate different layouts.
# Clear existing components
geo_def.clear_geometry_components()
# Populate the room
geo_def.populate_with_geometry_components(
components=placements,
selection_algorithm=treble.ComponentSelectionAlgorithm.random,
)
# Visualize the populated room
geo_def.plot()
Selection Algorithms
Different selection algorithms are available to control how components are placed:
random
: Randomly selects components for placement.ordered_single
: Places one instance of each component sequentially.ordered_all
: Places all instances of a component before moving to the next.
Example: Generating a Furnished Room
To begin, we must import the required libraries, initialize an instance of TSDK, and load create a new project.
from treble_tsdk import tsdk_namespace as treble
from treble_tsdk.utility_classes import (
Transform3d,
Vector3d,
Rotation,
Point3d,
BoundingBox,
)
from treble_tsdk import display_data as dd
tsdk = treble.TSDK()
p = tsdk.get_or_create_project("my_geometry_test_project")
Create a Model and Add Geometry
Next, we generate a T-shaped room and visualize its structure.
geo_def = treble.GeometryDefinitionGenerator.create_T_shaped_room(
a_side=6,
b_side=2,
c_side=2,
d_side=2,
height_z=2.5,
)
geo_def.plot()

Add Geometry Components
We query the component library for tables, and choose the first component from the resulting list,
gc = tsdk.geometry_component_library.query(group='table')[0]
gc.plot()

Now, we place multiple tables in the room at specific positions and orientations.
geo_def.add_geometry_component(
"my_table", gc, Transform3d(Vector3d(1, 1, 0), Rotation(0, 0, 0))
)
geo_def.add_geometry_component(
"my_table2", gc, Transform3d(Vector3d(5, 1, 0), Rotation(0, 0, 0))
)
geo_def.add_geometry_component(
"my_table3", gc, Transform3d(Vector3d(3, 1, 0), Rotation(0, 0, 0))
)
geo_def.plot()

Add a Box and Loudspeaker
We create a box, place it inside the room.
box = treble.GeometryComponentGenerator.create_box(
BoundingBox(Point3d(-0.5, 0.5, -0.5), Point3d(0.5, -0.5, 0.5))
)
geo_def.add_geometry_component(
"name", box, Transform3d(Vector3d(3, 3, 0.5), Rotation(45, 0, 0))
)
geo_def.plot()

Next, we position a loudspeaker on top.
speaker = treble.GeometryComponentGenerator.create_loudspeaker(
width=0.2, height=0.3, depth=0.5, membrane_diameter=0.1, membrane_center_height=0.1
)
geo_def.add_geometry_component(
"my_speaker", speaker, Transform3d(Vector3d(3, 3, 1.1), Rotation(-90, 0, 0))
)
geo_def.plot()

Finalizing for Simulation
Once the geometry is finalized, we can add the model a project.
model = p.add_model(f'my_model', geo_def)
model.as_live_model_status()
This model is now ready for acoustic simulations.