Skip to content

Commit 4f83c09

Browse files
authored
Merge pull request #1307 from Licini/tree
Merging SceneObjectNode and SceneObject
2 parents 11c50be + 96dca2a commit 4f83c09

File tree

7 files changed

+149
-295
lines changed

7 files changed

+149
-295
lines changed

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Added
1111

1212
### Changed
13-
* Changed and update the `compas_view2` examples into `compas_viewer`.
13+
14+
* Changed and updated the `compas_view2` examples into `compas_viewer`.
15+
* Changed `compas.scene.Scene` to inherent from `compas.datastructrues.Tree`.
16+
* Changed `compas.scene.SceneObject` to inherent from `compas.datastructrues.TreeNode`.
1417

1518
### Removed
1619

20+
* Removed `compas.scene.SceneObjectNode`, functionalities merged into `compas.scene.SceneObject`.
21+
* Removed `compas.scene.SceneTree`, functionalities merged into `compas.scene.Scene`.
22+
1723

1824
## [2.1.0] 2024-03-01
1925

src/compas/datastructures/tree/tree.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def __from_data__(cls, data):
7171
return node
7272

7373
def __init__(self, name=None, **kwargs):
74-
super(TreeNode, self).__init__(name=name, **kwargs)
74+
super(TreeNode, self).__init__(name=name)
7575
self.attributes = kwargs
7676
self._parent = None
7777
self._children = []

src/compas/scene/__init__.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323
from .context import register
2424

2525
from .scene import Scene
26-
from .scene import SceneObjectNode
27-
from .scene import SceneTree
2826

2927
from compas.plugins import plugin
3028
from compas.geometry import Geometry
@@ -49,8 +47,6 @@ def register_scene_objects_base():
4947
"GeometryObject",
5048
"VolMeshObject",
5149
"Scene",
52-
"SceneObjectNode",
53-
"SceneTree",
5450
"clear",
5551
"before_draw",
5652
"after_draw",

src/compas/scene/context.py

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -92,19 +92,6 @@ def register(item_type, sceneobject_type, context=None):
9292
ITEM_SCENEOBJECT[context][item_type] = sceneobject_type
9393

9494

95-
def is_viewer_open():
96-
"""Returns True if an instance of the compas_viewer is available.
97-
98-
Returns
99-
-------
100-
bool
101-
102-
"""
103-
from compas.scene import Scene
104-
105-
return Scene.viewerinstance is not None
106-
107-
10895
def detect_current_context():
10996
"""Chooses an appropriate context depending on available contexts and open instances. with the following priority:
11097
1. Viewer
@@ -119,8 +106,6 @@ def detect_current_context():
119106
120107
"""
121108

122-
if is_viewer_open():
123-
return "Viewer"
124109
if compas.is_grasshopper():
125110
return "Grasshopper"
126111
if compas.is_rhino():

src/compas/scene/scene.py

Lines changed: 33 additions & 197 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
from compas.data import Data
1+
import compas.datastructures # noqa: F401
2+
import compas.geometry # noqa: F401
23
from compas.datastructures import Tree
34
from compas.datastructures import TreeNode
45

@@ -9,174 +10,7 @@
910
from .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

Comments
 (0)