22from typing import Generator
33from typing import Iterator
44from typing import Optional
5+ from typing import Type
56from typing import TypeVar
67from typing import Union
78
1213from compas_model .elements import Group
1314from compas_model .interactions import Contact
1415from compas_model .materials import Material
16+ from compas_model .modifiers import Modifier
1517
1618from .bvh import ElementBVH
1719from .bvh import ElementOBBNode
@@ -120,9 +122,9 @@ def __init__(self, name=None):
120122 self ._tree = ElementTree ()
121123 self ._graph = InteractionGraph ()
122124 self ._graph .update_default_node_attributes (element = None )
123- # type of contacts is list[Contacts]
125+ self . _graph . update_default_edge_attributes ( modifiers = None )
124126 self ._graph .update_default_edge_attributes (contacts = None )
125- # computed
127+
126128 self ._bvh = None
127129 self ._kdtree = None
128130
@@ -297,7 +299,7 @@ def remove_element(self, element: Element) -> None:
297299 if guid not in self ._elements :
298300 raise Exception ("Element not in the model." )
299301
300- self ._elements [guid ].is_dirty = True
302+ # self._elements[guid].is_dirty = True
301303
302304 del self ._elements [guid ]
303305
@@ -457,6 +459,15 @@ def add_interaction(self, a: Element, b: Element) -> tuple[int, int]:
457459 Exception
458460 If one or both of the elements are not in the graph.
459461
462+ Notes
463+ -----
464+ In future implementations, adding an interaction should implicitly take care of adding modifiers
465+ onto the interaction edges, based on the registered modifiers of the source nodes.
466+
467+ In the current implementation, modifiers have to be added explicitly using :meth:`add_modifiers`.
468+ This method will add an interaction edge from the source of the modifier to its target if needed
469+ and store the modifier object on it.
470+
460471 """
461472 node_a = a .graphnode
462473 node_b = b .graphnode
@@ -467,9 +478,17 @@ def add_interaction(self, a: Element, b: Element) -> tuple[int, int]:
467478 if not self .graph .has_node (node_a ) or not self .graph .has_node (node_b ):
468479 raise Exception ("Something went wrong: the elements are not in the interaction graph." )
469480
470- edge = self ._graph .add_edge (node_a , node_b )
481+ edge = self .graph .add_edge (node_a , node_b )
471482
472- self ._elements [str (b .guid )].is_dirty = True
483+ # modifiers = []
484+ # if a.modifiers:
485+ # for modifiertype in a.modifiers:
486+ # # modifiertype.applies_to
487+ # # modifiers.append()
488+ # pass
489+
490+ # if modifiers:
491+ # self.graph.edge_attribute(edge, name="modifiers", value=modifiers)
473492
474493 return edge
475494
@@ -486,8 +505,8 @@ def remove_interaction(self, a: Element, b: Element) -> None:
486505 None
487506
488507 """
489- elements = list (self .elements )
490- elements [b .graphnode ].is_dirty = True
508+ # elements = list(self.elements)
509+ # elements[b.graphnode].is_dirty = True
491510
492511 edge = a .graphnode , b .graphnode
493512 if self .graph .has_edge (edge ):
@@ -521,6 +540,50 @@ def has_interaction(self, a: Element, b: Element) -> bool:
521540 result = self .graph .has_edge (edge )
522541 return result
523542
543+ # =============================================================================
544+ # Modifiers (temp)
545+ # =============================================================================
546+
547+ def add_modifier (
548+ self ,
549+ source : Element ,
550+ target : Element ,
551+ modifiertype : Type [Modifier ],
552+ ) -> list [Modifier ]:
553+ """Add a modifier between two elements, with one the source of the modifier and the other the target.
554+
555+ Parameters
556+ ----------
557+ source : :class:`compas_model.elements.Element`
558+ The source element.
559+ target : :class:`compas_model.elements.Element`
560+ The target element.
561+ modifiertype : Type[:class:`compas_model.modifiers.Modifier`]
562+ The type of modifier.
563+
564+ Returns
565+ -------
566+ list[Modifier]
567+ All modifiers stored on the interaction edge between source and target.
568+
569+ Notes
570+ -----
571+ This element should implement the protocol specified by the modifier.
572+ The methods of the source element defined by the protocol are used to compute the tools involved in the modification.
573+ The tools are used by the modifier to apply the modification to the model geometry of the target element.
574+
575+ The modifier defines the protocol for the modification.
576+ The protocol should be implemented by the source element.
577+ The protocol methods of the source element are used to compute the modification tool.
578+ The modifier applies the modification to the target using this tool.
579+
580+ """
581+ edge = self .add_interaction (source , target )
582+ modifiers = self .graph .edge_attribute (edge , name = "modifiers" ) or []
583+ modifiers .append (modifiertype (source ))
584+ self .graph .edge_attribute (edge , name = "modifiers" , value = modifiers )
585+ return modifiers
586+
524587 # =============================================================================
525588 # Compute
526589 # =============================================================================
@@ -571,6 +634,14 @@ def compute_kdtree(self) -> KDTree:
571634 def compute_contacts (self , tolerance = 1e-6 , minimum_area = 1e-2 ) -> None :
572635 """Compute the contacts between the block elements of this model.
573636
637+ Computing contacts is done independently of the edges of the interaction graph.
638+ If contacts are found between two elements with an existing edge, the contacts attribute of the edge will be replaced.
639+ If there is no pre-existing edge, one will be added.
640+ No element pairs are excluded in the search based on the existence of an edge between their nodes in the interaction graph.
641+
642+ The search is conducted entirely based on the BVH of the elements contained in the model.
643+ It is a spatial search that creates topological connections between elements based on their geometrical interaction.
644+
574645 Parameters
575646 ----------
576647 tolerance : float, optional
@@ -592,6 +663,7 @@ def compute_contacts(self, tolerance=1e-6, minimum_area=1e-2) -> None:
592663 contacts = element .contacts (nbr , tolerance = tolerance , minimum_area = minimum_area )
593664 if contacts :
594665 self .graph .add_edge (u , v , contacts = contacts )
666+
595667 else :
596668 edge = (u , v ) if self .graph .has_edge ((u , v )) else (v , u )
597669 contacts = self .graph .edge_attribute (edge , name = "contacts" )
0 commit comments