Skip to content

Commit

Permalink
Merge branch 'main' into rhino_brep_trimmed
Browse files Browse the repository at this point in the history
  • Loading branch information
chenkasirer authored Mar 28, 2024
2 parents 08b4e99 + 4f83c09 commit 1ca1cc1
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 294 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed
* Changed and update the `compas_view2` examples into `compas_viewer`.
* Changed and updated the `compas_view2` examples into `compas_viewer`.
* Changed `compas.scene.Scene` to inherent from `compas.datastructrues.Tree`.
* Changed `compas.scene.SceneObject` to inherent from `compas.datastructrues.TreeNode`.
* `RhinoBrep.trimmed` returns single result or raises `BrepTrimmingError` instead of returning a list.

### Removed

* Removed `compas.scene.SceneObjectNode`, functionalities merged into `compas.scene.SceneObject`.
* Removed `compas.scene.SceneTree`, functionalities merged into `compas.scene.Scene`.


## [2.1.0] 2024-03-01

Expand Down
2 changes: 1 addition & 1 deletion src/compas/datastructures/tree/tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def __from_data__(cls, data):
return node

def __init__(self, name=None, **kwargs):
super(TreeNode, self).__init__(name=name, **kwargs)
super(TreeNode, self).__init__(name=name)
self.attributes = kwargs
self._parent = None
self._children = []
Expand Down
4 changes: 0 additions & 4 deletions src/compas/scene/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
from .context import register

from .scene import Scene
from .scene import SceneObjectNode
from .scene import SceneTree

from compas.plugins import plugin
from compas.geometry import Geometry
Expand All @@ -49,8 +47,6 @@ def register_scene_objects_base():
"GeometryObject",
"VolMeshObject",
"Scene",
"SceneObjectNode",
"SceneTree",
"clear",
"before_draw",
"after_draw",
Expand Down
15 changes: 0 additions & 15 deletions src/compas/scene/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,19 +92,6 @@ def register(item_type, sceneobject_type, context=None):
ITEM_SCENEOBJECT[context][item_type] = sceneobject_type


def is_viewer_open():
"""Returns True if an instance of the compas_viewer is available.
Returns
-------
bool
"""
from compas.scene import Scene

return Scene.viewerinstance is not None


def detect_current_context():
"""Chooses an appropriate context depending on available contexts and open instances. with the following priority:
1. Viewer
Expand All @@ -119,8 +106,6 @@ def detect_current_context():
"""

if is_viewer_open():
return "Viewer"
if compas.is_grasshopper():
return "Grasshopper"
if compas.is_rhino():
Expand Down
230 changes: 33 additions & 197 deletions src/compas/scene/scene.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from compas.data import Data
import compas.datastructures # noqa: F401
import compas.geometry # noqa: F401
from compas.datastructures import Tree
from compas.datastructures import TreeNode

Expand All @@ -9,174 +10,7 @@
from .sceneobject import SceneObject


class SceneObjectNode(TreeNode):
"""A node representing a scene object in a scene tree. The SceneObjectNode should only be used internally by the SceneTree.
Parameters
----------
object : :class:`compas.scene.SceneObject`
The scene object associated with the node.
Attributes
----------
name : str
The name of the node, same as the underlying scene object.
object : :class:`compas.scene.SceneObject`
The scene object associated with the node.
parentobject : :class:`compas.scene.SceneObject`
The scene object associated with the parent node.
childobjects : list[:class:`compas.scene.SceneObject`]
The scene objects associated with the child nodes.
"""

@property
def __data__(self):
return {
"item": str(self.object.item.guid),
"settings": self.object.settings,
"children": [child.__data__ for child in self.children],
}

@classmethod
def __from_data__(cls, data):
raise TypeError("SceneObjectNode cannot be created from data. Use Scene.__from_data__ instead.")

def __init__(self, sceneobject, name=None):
super(SceneObjectNode, self).__init__(name=name)
self.object = sceneobject

@property
def name(self):
if self.object:
return self.object.name

@property
def parentobject(self):
if self.parent and isinstance(self.parent, SceneObjectNode):
return self.parent.object
return None

@property
def childobjects(self):
return [child.object for child in self.children]

def add_item(self, item, **kwargs):
"""Add an child item to the node.
Parameters
----------
item : :class:`compas.data.Data`
The item to add.
**kwargs : dict
Additional keyword arguments to create the scene object for the item.
Returns
-------
:class:`compas.scene.SceneObject`
The scene object associated with the item.
"""
sceneobject = SceneObject(item, **kwargs)
node = SceneObjectNode(sceneobject)
self.add(node)
sceneobject._node = node # type: ignore
return sceneobject


class SceneTree(Tree):
"""A tree structure for storing the hierarchy of scene objects in a scene. The SceneTree should only be used internally by the Scene.
Parameters
----------
name : str, optional
The name of the tree.
Attributes
----------
objects : list[:class:`compas.scene.SceneObject`]
All scene objects in the scene tree.
"""

@classmethod
def __from_data__(cls, data):
raise TypeError("SceneTree cannot be created from data. Use Scene.__from_data__ instead.")

def __init__(self, name=None):
super(SceneTree, self).__init__(name=name)
root = TreeNode(name="root")
self.add(root)

@property
def objects(self):
return [node.object for node in self.nodes if isinstance(node, SceneObjectNode)]

def add_object(self, sceneobject, parent=None):
"""Add a scene object to the tree.
Parameters
----------
sceneobject : :class:`compas.scene.SceneObject`
The scene object to add.
parent : :class:`compas.scene.SceneObject`, optional
The parent scene object.
Returns
-------
:class:`compas.scene.SceneObjectNode`
The node associated with the scene object.
"""
node = SceneObjectNode(sceneobject)
if parent is None:
self.add(node, parent=self.root)
else:
parent_node = self.get_node_from_object(parent)
self.add(node, parent=parent_node)

sceneobject._node = node
return node

def remove_object(self, sceneobject):
"""Remove a scene object from the tree.
Parameters
----------
sceneobject : :class:`compas.scene.SceneObject`
The scene object to remove.
"""
node = self.get_node_from_object(sceneobject)
self.remove(node)

def get_node_from_object(self, sceneobject):
"""Get the node associated with a scene object.
Parameters
----------
sceneobject : :class:`compas.scene.SceneObject`
The scene object.
Returns
-------
:class:`compas.scene.SceneObjectNode`
The node associated with the scene object.
Raises
------
ValueError
If the scene object is not in the scene tree.
"""
for node in self.nodes:
if isinstance(node, SceneObjectNode):
if node.object is sceneobject:
return node
raise ValueError("Scene object not in scene tree")


class Scene(Data):
class Scene(Tree):
"""A scene is a container for hierarchical scene objects which are to be visualised in a given context.
Parameters
Expand Down Expand Up @@ -204,19 +38,19 @@ class Scene(Data):
"""

viewerinstance = None

@property
def __data__(self):
# type: () -> dict
items = {str(object.item.guid): object.item for object in self.objects}
return {
"name": self.name,
"tree": self.tree.__data__,
"root": self.root.__data__, # type: ignore
"items": list(items.values()),
}

@classmethod
def __from_data__(cls, data):
# type: (dict) -> Scene
scene = cls(data["name"])
items = {str(item.guid): item for item in data["items"]}

Expand All @@ -227,24 +61,25 @@ def add(node, parent, items):
sceneobject = parent.add(items[guid], **settings)
add(child_node, sceneobject, items)

add(data["tree"]["root"], scene, items)
add(data["root"], scene, items)

return scene

def __init__(self, name=None, context=None):
super(Scene, self).__init__(name)
self._tree = SceneTree("Scene")
def __init__(self, name="Scene", context=None):
# type: (str | "Scene", str | None) -> None
super(Scene, self).__init__(name=name)
super(Scene, self).add(TreeNode(name="ROOT"))
self.context = context or detect_current_context()

@property
def tree(self):
return self._tree

@property
def objects(self):
return self.tree.objects
# type: () -> list[SceneObject]
# this is flagged by the type checker
# because the tree returns nodes of type TreeNode
return [node for node in self.nodes if not node.is_root] # type: ignore

def add(self, item, parent=None, **kwargs):
# type: (compas.geometry.Geometry | compas.datastructures.Datastructure, SceneObject | TreeNode | None, dict) -> SceneObject
"""Add an item to the scene.
Parameters
Expand All @@ -261,26 +96,31 @@ def add(self, item, parent=None, **kwargs):
:class:`compas.scene.SceneObject`
The scene object associated with the item.
"""
sceneobject = SceneObject(item, context=self.context, **kwargs)
self.tree.add_object(sceneobject, parent=parent)
return sceneobject

def remove(self, sceneobject):
"""Remove a scene object from the scene.

Parameters
----------
sceneobject : :class:`compas.scene.SceneObject`
The scene object to remove.
parent = parent or self.root

"""
self.tree.remove_object(sceneobject)
if isinstance(item, SceneObject):
sceneobject = item
else:
if "context" in kwargs:
if kwargs["context"] != self.context:
raise Exception(
"Object context should be the same as scene context: {} != {}".format(
kwargs["context"], self.context
)
)
del kwargs["context"] # otherwist the SceneObject receives "context" twice, which results in an error
sceneobject = SceneObject(item, context=self.context, **kwargs) # type: ignore
super(Scene, self).add(sceneobject, parent=parent)
return sceneobject

def clear(self):
# type: () -> None
"""Clear the current context of the scene."""
clear()

def clear_objects(self):
# type: () -> None
"""Clear all objects inside the scene."""
guids = []
for sceneobject in self.objects:
Expand All @@ -306,7 +146,3 @@ def draw(self):
after_draw(drawn_objects)

return drawn_objects

def print_hierarchy(self):
"""Print the hierarchy of the scene."""
self.tree.print_hierarchy()
Loading

0 comments on commit 1ca1cc1

Please sign in to comment.