Skip to content

Commit 61ee0aa

Browse files
committed
some convenience methods on the model
1 parent 7b52c65 commit 61ee0aa

File tree

2 files changed

+109
-0
lines changed

2 files changed

+109
-0
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
* Added `Model.has_element_with_name`.
1313
* Added `Model.find_element_with_name`.
14+
* Added `Model.find_element_with_name_or_fail`.
15+
* Added `Model.find_all_elements_of_type`.
16+
* Added `Model.remove_elements_of_type`.
17+
* Added `Model.add_or_get_material`.
1418

1519
### Changed
1620

src/compas_model/models/model.py

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ class ModelError(Exception):
2727
pass
2828

2929

30+
class ModelElementNotFound(ModelError):
31+
pass
32+
33+
3034
class Model(Datastructure):
3135
"""Class representing a general model of hierarchically organised elements, with interactions.
3236
@@ -252,6 +256,44 @@ def add_element(
252256
element.model = self
253257
return element
254258

259+
def add_elements(
260+
self,
261+
elements: list[Union[Element, ElementType]],
262+
parent: Optional[Element] = None,
263+
material: Optional[Material] = None,
264+
) -> list[Union[Element, ElementType]]:
265+
"""Add a list of elements to the model.
266+
267+
Parameters
268+
----------
269+
elements : list[:class:`Element`]
270+
The elements to add.
271+
parent : :class:`Element`, optional
272+
The parent element of the elements.
273+
If ``None``, the elements will be added directly under the root element.
274+
material : :class:`Material`, optional
275+
A material to assign to the elements.
276+
Note that the material should have already been added to the model before it can be assigned.
277+
278+
Returns
279+
-------
280+
list[:class:`Element`]
281+
The list of elements added to the model.
282+
283+
Raises
284+
------
285+
ValueError
286+
If the parent node is not a GroupNode.
287+
ValueError
288+
If a material is provided that is not part of the model.
289+
290+
"""
291+
# try
292+
# roll back if not all were added
293+
for element in elements:
294+
self.add_element(element, parent, material)
295+
return elements
296+
255297
def remove_element(self, element: Element) -> None:
256298
"""Remove an element from the model.
257299
@@ -322,6 +364,50 @@ def find_element_with_name(self, name: str) -> Optional[Element]:
322364
if element.name == name:
323365
return element
324366

367+
def find_element_with_name_or_fail(self, name: str) -> Element:
368+
element = self.find_element_with_name(name)
369+
if not element:
370+
raise ModelElementNotFound
371+
return element
372+
373+
def find_all_elements_of_type(self, elementtype: Type[Element]) -> list[Element]:
374+
"""Find all model elements of a given type.
375+
376+
Parameters
377+
----------
378+
elementtype : Type[:class:`Element`]
379+
The type of element.
380+
381+
Returns
382+
-------
383+
list[:class:`Element`]
384+
385+
"""
386+
elements = []
387+
for element in self.elements():
388+
if isinstance(element, elementtype):
389+
elements.append(element)
390+
return elements
391+
392+
def remove_elements_of_type(self, elementtype: Type[Element]) -> list[Element]:
393+
"""Remove all model elements of a given type.
394+
395+
Parameters
396+
----------
397+
elementtype : Type[:class:`Element`]
398+
The type of element.
399+
400+
Returns
401+
-------
402+
list[:class:`Element`]
403+
The removed elements.
404+
405+
"""
406+
elements = self.find_all_elements_of_type(elementtype)
407+
for element in elements:
408+
self.remove_element(element)
409+
return elements
410+
325411
# =============================================================================
326412
# Groups
327413
# =============================================================================
@@ -393,6 +479,25 @@ def has_material(self, material: Material) -> bool:
393479
guid = str(material.guid)
394480
return guid in self._materials
395481

482+
def add_or_get_material(self, material: Material) -> Material:
483+
"""Add a material to the model or retrieve an existing instance of the same type.
484+
485+
Parameters
486+
----------
487+
material : :class:`Material`
488+
A material.
489+
490+
Returns
491+
-------
492+
:class:`Material`
493+
494+
"""
495+
for existing in self.materials():
496+
if isinstance(existing, type(material)):
497+
return existing
498+
self.add_material(material)
499+
return material
500+
396501
def assign_material(
397502
self,
398503
material: Material,

0 commit comments

Comments
 (0)