compas_tf.model
¤
Classes¤
TFModel
¤
A :class:compas_tf.base_model.BaseModel whose geometry survives serialization.
Two additions, matching the ones on :class:compas_tf.element.TFElement:
- :meth:
bakewalks the model and computes every element's geometry once. After thatcompas.json_dump(model, path)writes a file thatcompas.json_loadbrings back with the booleans already applied to the base geometry - no boolean backend needed, and no wait. - :meth:
get_brepconverts the whole model into one Brep compound of solid, coplanar-merged parts (and :meth:to_stepwrites it out).
Serialization itself is inherited: Model.__data__ already carries the
elements, the tree and the interaction graph, and every compas_tf element
puts its baked geometry in its own __data__.
Attributes¤
is_baked
property
¤
is_baked: bool
True if every geometry-carrying element has geometry stored on it.
Methods:¤
bake
¤
Compute every element's default geometry once, and store it on the elements.
Elements that are not compas_tf elements are still given their
modelgeometry, which is what the viewer and the Brep/STEP export
read - they just cannot carry extra variants.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
modelgeometry
|
bool
|
Also bake the model-space geometry of every element. |
True
|
Returns:
| Type | Description |
|---|---|
class:`TFModel`
|
Self, so it chains. |
brep_meshes
¤
The model-space mesh of every element - what :meth:get_brep converts.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
variant
|
str
|
A baked variant key to convert instead of the finished geometry. Elements that do not carry it are skipped - including any element that is not a compas_tf element, since only those hold variants. |
None
|
clear_contacts
¤
clear_contacts() -> TFModel
Drop every contact stored on the interaction graph, keeping the edges.
Contact searches never remove a contact - they only fill in edges that
have none (see :meth:compute_contacts). So a model loaded from file
keeps whatever contacts were computed when it was written, and a fresh
search has to start from a clean graph to report only its own result.
compute_bvh
¤
Bounding-volume hierarchy over the geometry elements only.
Model.compute_bvh feeds self.elements() to the BVH, which
includes the :class:Groups. A Group carries no geometry, so its
compute_aabb is the base-class raise NotImplementedError - and
the BVH asks every element for its aabb. Any model built with
:meth:merge therefore has groups in it and cannot build a BVH at all,
which makes compute_contacts() fail outright.
compute_contacts_between_groups never hit this because it builds its
own BVH from the participating elements, skipping groups explicitly.
Filtering here fixes plain compute_contacts() the same way.
compute_contacts
¤
compute_contacts(tolerance: float = 1e-06, minimum_area: float = 0.01, contacttype: type[Contact] = Contact, contactmethod: Callable | None = None) -> None
Compute the contacts between the geometry elements of this model.
Overridden only to iterate :meth:geometry_elements instead of
elements(): a :class:Group has no geometry, so asking the BVH
for its neighbours calls the base-class compute_aabb and raises
NotImplementedError. See :meth:compute_bvh for the same fix on the
other side. Body otherwise verbatim from compas_model.
Computing contacts is done independently of the edges of the interaction graph. If contacts are found between two elements with an existing edge, the contacts attribute of the edge will be replaced. If there is no pre-existing edge, one will be added. No element pairs are excluded in the search based on the existence of an edge between their nodes in the interaction graph.
The search is conducted entirely based on the BVH of the elements contained in the model. It is a spatial search that creates topological connections between elements based on their geometrical interaction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tolerance
|
float
|
The distance tolerance. |
1e-06
|
minimum_area
|
float
|
The minimum contact size. |
0.01
|
contacttype
|
type[Contact]
|
The contact class to use for the generated contacts. |
Contact
|
contactmethod
|
Callable | None
|
What detects the contacts of one candidate pair, called as
|
None
|
compute_contacts_brep
¤
compute_contacts_brep(tolerance: float = 1e-06, minimum_area: float = 0.1, groups: list[str] | None = None, groups_b: list[str] | None = None, contacttype: type[Contact] = Contact, clear: bool = False, **kwargs)
Contacts on Brep faces rather than mesh faces - one polygon per interface.
The same spatial search as :meth:compute_contacts, with
:class:compas_tf.contacts.BrepContacts doing the detection: the BVH
still prunes on the mesh AABBs, but each surviving pair is converted to a
solid Brep with its coplanar faces merged (element.get_brep()) and
intersected face against face. A boolean-triangulated interface therefore
comes back as ONE contact carrying its hole loops, instead of one contact
per triangle - see :mod:compas_tf.contacts for the numbers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tolerance
|
float
|
The distance tolerance. |
1e-06
|
minimum_area
|
float
|
The minimum contact size. The 1e-2 default of the mesh search is below the noise of a merged Brep face; 1.0 mm2 is a sane floor for this model. |
0.1
|
groups
|
list[str]
|
Restrict the search to these named groups, as in
:meth: |
None
|
groups_b
|
list[str]
|
The second side of a two-sided group query. Requires |
None
|
contacttype
|
type[:class:`compas_model.interactions.Contact`]
|
The contact class to instantiate. |
Contact
|
clear
|
bool
|
Clear the contacts already on the graph first, so the result holds
only what this search found. See :meth: |
False
|
**kwargs
|
Forwarded to :class: |
{}
|
Returns:
| Type | Description |
|---|---|
class:`compas_tf.contacts.BrepContacts`
|
The detector, holding the Brep cache it built ( |
contact_adjacency
¤
contact_breps
¤
contact_breps() -> list
One planar-face Brep per contact, named contact_<i>__<a>__<b>.
Boundary loop only - holes are dropped, since a contact written this way
is a surface for inspection, not a solid. The name is for use in memory:
STEP does not carry it (see :meth:contacts_to_json).
contact_pairs
¤
contact_pairs() -> Iterator
(index, element_a, element_b, contact) for every contact.
The order is the one :meth:contacts yields, and it is what makes the
adjacency sidecar work - see :meth:contacts_to_json. Everything that
writes contacts out goes through here, so the indices always agree.
contacts_to_json
¤
Write the contact adjacency beside the contact STEP.
Record i describes face i of the file
:meth:contacts_to_step wrote, which is the only way to know which two
elements a face in that file joins.
contacts_to_step
¤
Write the contacts to their own STEP file, one face each.
Separate from :meth:to_step on purpose: that file is the shop's, and a
reader splits it with .solids, which would drop loose faces.
The faces carry no adjacency - STEP drops the per-shape name (a
round-trip through to_step / from_step returns them all as
OCCBrepFace, and from_step_with_attributes collapses the
compound into one unnamed entry). What it does preserve is the ORDER, so
pair the file with :meth:contacts_to_json and match on index.
element_breps
¤
One solid, coplanar-merged Brep per element, named after the element.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
variant
|
str
|
A baked variant key to convert instead of each element's finished geometry. Elements that do not carry it are skipped - including any element that is not a compas_tf element, since only those can hold variants. |
None
|
cache
|
dict[int, :class:`compas_occt.brep.OCCBrep`]
|
Already-converted Breps keyed by |
None
|
**kwargs
|
Forwarded to :meth: |
{}
|
Returns:
| Type | Description |
|---|---|
list[:class:`compas_occt.brep.OCCBrep`]
|
|
from_model
classmethod
¤
Re-wrap a plain model as a :class:TFModel.
Accepts a :class:compas_model.models.Model too - only __data__ is
read, and that is the same on both.
The elements are shared, not copied - the tree and the interaction graph
are rebuilt around them by Model.__from_data__.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
:class:`compas_tf.base_model.BaseModel` or :class:`compas_model.models.Model`
|
|
required |
name
|
str
|
|
None
|
Returns:
| Type | Description |
|---|---|
class:`TFModel`
|
|
geometry_elements
¤
geometry_elements() -> Iterator
Every element in the model that carries geometry (groups excluded).
to_step
¤
to_step(path: str, author: str = 'compas_tf', variant: str | None = None, cache: dict | None = None, **kwargs) -> str
Write the whole model to a STEP file, one solid per element.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str
|
Destination |
required |
author
|
str
|
Author recorded in the STEP header. |
'compas_tf'
|
variant
|
str
|
A baked variant key to write instead of the finished geometry (see
:meth: |
None
|
cache
|
dict[int, :class:`compas_occt.brep.OCCBrep`]
|
Already-converted Breps to reuse - see :meth: |
None
|
**kwargs
|
Forwarded to :meth: |
{}
|
Returns:
| Type | Description |
|---|---|
str
|
The path written. |