1- from compas .data import Data
1+ import compas .datastructures # noqa: F401
2+ import compas .geometry # noqa: F401
23from compas .datastructures import Tree
34from compas .datastructures import TreeNode
45
910from .sceneobject import SceneObject
1011
1112
12- class SceneObjectNode (TreeNode ):
13- """A node representing a scene object in a scene tree. The SceneObjectNode should only be used internally by the SceneTree.
14-
15- Parameters
16- ----------
17- object : :class:`compas.scene.SceneObject`
18- The scene object associated with the node.
19-
20- Attributes
21- ----------
22- name : str
23- The name of the node, same as the underlying scene object.
24- object : :class:`compas.scene.SceneObject`
25- The scene object associated with the node.
26- parentobject : :class:`compas.scene.SceneObject`
27- The scene object associated with the parent node.
28- childobjects : list[:class:`compas.scene.SceneObject`]
29- The scene objects associated with the child nodes.
30-
31- """
32-
33- @property
34- def __data__ (self ):
35- return {
36- "item" : str (self .object .item .guid ),
37- "settings" : self .object .settings ,
38- "children" : [child .__data__ for child in self .children ],
39- }
40-
41- @classmethod
42- def __from_data__ (cls , data ):
43- raise TypeError ("SceneObjectNode cannot be created from data. Use Scene.__from_data__ instead." )
44-
45- def __init__ (self , sceneobject , name = None ):
46- super (SceneObjectNode , self ).__init__ (name = name )
47- self .object = sceneobject
48-
49- @property
50- def name (self ):
51- if self .object :
52- return self .object .name
53-
54- @property
55- def parentobject (self ):
56- if self .parent and isinstance (self .parent , SceneObjectNode ):
57- return self .parent .object
58- return None
59-
60- @property
61- def childobjects (self ):
62- return [child .object for child in self .children ]
63-
64- def add_item (self , item , ** kwargs ):
65- """Add an child item to the node.
66-
67- Parameters
68- ----------
69- item : :class:`compas.data.Data`
70- The item to add.
71- **kwargs : dict
72- Additional keyword arguments to create the scene object for the item.
73-
74- Returns
75- -------
76- :class:`compas.scene.SceneObject`
77- The scene object associated with the item.
78-
79- """
80- sceneobject = SceneObject (item , ** kwargs )
81- node = SceneObjectNode (sceneobject )
82- self .add (node )
83- sceneobject ._node = node # type: ignore
84- return sceneobject
85-
86-
87- class SceneTree (Tree ):
88- """A tree structure for storing the hierarchy of scene objects in a scene. The SceneTree should only be used internally by the Scene.
89-
90- Parameters
91- ----------
92- name : str, optional
93- The name of the tree.
94-
95- Attributes
96- ----------
97- objects : list[:class:`compas.scene.SceneObject`]
98- All scene objects in the scene tree.
99-
100- """
101-
102- @classmethod
103- def __from_data__ (cls , data ):
104- raise TypeError ("SceneTree cannot be created from data. Use Scene.__from_data__ instead." )
105-
106- def __init__ (self , name = None ):
107- super (SceneTree , self ).__init__ (name = name )
108- root = TreeNode (name = "root" )
109- self .add (root )
110-
111- @property
112- def objects (self ):
113- return [node .object for node in self .nodes if isinstance (node , SceneObjectNode )]
114-
115- def add_object (self , sceneobject , parent = None ):
116- """Add a scene object to the tree.
117-
118- Parameters
119- ----------
120- sceneobject : :class:`compas.scene.SceneObject`
121- The scene object to add.
122- parent : :class:`compas.scene.SceneObject`, optional
123- The parent scene object.
124-
125- Returns
126- -------
127- :class:`compas.scene.SceneObjectNode`
128- The node associated with the scene object.
129-
130- """
131- node = SceneObjectNode (sceneobject )
132- if parent is None :
133- self .add (node , parent = self .root )
134- else :
135- parent_node = self .get_node_from_object (parent )
136- self .add (node , parent = parent_node )
137-
138- sceneobject ._node = node
139- return node
140-
141- def remove_object (self , sceneobject ):
142- """Remove a scene object from the tree.
143-
144- Parameters
145- ----------
146- sceneobject : :class:`compas.scene.SceneObject`
147- The scene object to remove.
148-
149- """
150- node = self .get_node_from_object (sceneobject )
151- self .remove (node )
152-
153- def get_node_from_object (self , sceneobject ):
154- """Get the node associated with a scene object.
155-
156- Parameters
157- ----------
158- sceneobject : :class:`compas.scene.SceneObject`
159- The scene object.
160-
161- Returns
162- -------
163- :class:`compas.scene.SceneObjectNode`
164- The node associated with the scene object.
165-
166- Raises
167- ------
168- ValueError
169- If the scene object is not in the scene tree.
170-
171- """
172- for node in self .nodes :
173- if isinstance (node , SceneObjectNode ):
174- if node .object is sceneobject :
175- return node
176- raise ValueError ("Scene object not in scene tree" )
177-
178-
179- class Scene (Data ):
13+ class Scene (Tree ):
18014 """A scene is a container for hierarchical scene objects which are to be visualised in a given context.
18115
18216 Parameters
@@ -204,19 +38,19 @@ class Scene(Data):
20438
20539 """
20640
207- viewerinstance = None
208-
20941 @property
21042 def __data__ (self ):
43+ # type: () -> dict
21144 items = {str (object .item .guid ): object .item for object in self .objects }
21245 return {
21346 "name" : self .name ,
214- "tree " : self .tree .__data__ ,
47+ "root " : self .root .__data__ , # type: ignore
21548 "items" : list (items .values ()),
21649 }
21750
21851 @classmethod
21952 def __from_data__ (cls , data ):
53+ # type: (dict) -> Scene
22054 scene = cls (data ["name" ])
22155 items = {str (item .guid ): item for item in data ["items" ]}
22256
@@ -227,24 +61,25 @@ def add(node, parent, items):
22761 sceneobject = parent .add (items [guid ], ** settings )
22862 add (child_node , sceneobject , items )
22963
230- add (data ["tree" ][ " root" ], scene , items )
64+ add (data ["root" ], scene , items )
23165
23266 return scene
23367
234- def __init__ (self , name = None , context = None ):
235- super (Scene , self ).__init__ (name )
236- self ._tree = SceneTree ("Scene" )
68+ def __init__ (self , name = "Scene" , context = None ):
69+ # type: (str | "Scene", str | None) -> None
70+ super (Scene , self ).__init__ (name = name )
71+ super (Scene , self ).add (TreeNode (name = "ROOT" ))
23772 self .context = context or detect_current_context ()
23873
239- @property
240- def tree (self ):
241- return self ._tree
242-
24374 @property
24475 def objects (self ):
245- return self .tree .objects
76+ # type: () -> list[SceneObject]
77+ # this is flagged by the type checker
78+ # because the tree returns nodes of type TreeNode
79+ return [node for node in self .nodes if not node .is_root ] # type: ignore
24680
24781 def add (self , item , parent = None , ** kwargs ):
82+ # type: (compas.geometry.Geometry | compas.datastructures.Datastructure, SceneObject | TreeNode | None, dict) -> SceneObject
24883 """Add an item to the scene.
24984
25085 Parameters
@@ -261,26 +96,31 @@ def add(self, item, parent=None, **kwargs):
26196 :class:`compas.scene.SceneObject`
26297 The scene object associated with the item.
26398 """
264- sceneobject = SceneObject (item , context = self .context , ** kwargs )
265- self .tree .add_object (sceneobject , parent = parent )
266- return sceneobject
267-
268- def remove (self , sceneobject ):
269- """Remove a scene object from the scene.
27099
271- Parameters
272- ----------
273- sceneobject : :class:`compas.scene.SceneObject`
274- The scene object to remove.
100+ parent = parent or self .root
275101
276- """
277- self .tree .remove_object (sceneobject )
102+ if isinstance (item , SceneObject ):
103+ sceneobject = item
104+ else :
105+ if "context" in kwargs :
106+ if kwargs ["context" ] != self .context :
107+ raise Exception (
108+ "Object context should be the same as scene context: {} != {}" .format (
109+ kwargs ["context" ], self .context
110+ )
111+ )
112+ del kwargs ["context" ] # otherwist the SceneObject receives "context" twice, which results in an error
113+ sceneobject = SceneObject (item , context = self .context , ** kwargs ) # type: ignore
114+ super (Scene , self ).add (sceneobject , parent = parent )
115+ return sceneobject
278116
279117 def clear (self ):
118+ # type: () -> None
280119 """Clear the current context of the scene."""
281120 clear ()
282121
283122 def clear_objects (self ):
123+ # type: () -> None
284124 """Clear all objects inside the scene."""
285125 guids = []
286126 for sceneobject in self .objects :
@@ -306,7 +146,3 @@ def draw(self):
306146 after_draw (drawn_objects )
307147
308148 return drawn_objects
309-
310- def print_hierarchy (self ):
311- """Print the hierarchy of the scene."""
312- self .tree .print_hierarchy ()
0 commit comments