Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merging SceneObjectNode and SceneObject #1307

Merged
merged 14 commits into from
Mar 25, 2024
Merged

Conversation

Licini
Copy link
Contributor

@Licini Licini commented Mar 2, 2024

The relation between SceneObjectNode and SceneObject was too convoluted. This PR merge them into one by having SceneObject inherent from TreeNode. This simplifies a lot on operations to access parent/ children object or a tree that an object is attachted too. While the most-outer level user APIs stays untouched. This should also make it easier from creating a compas_model object.

from compas.scene import Scene
from compas.geometry import Box
from compas.geometry import Sphere
from compas.geometry import Cylinder
from compas.geometry import Frame
from compas.geometry import Sphere



box = Box.from_width_height_depth(1, 1, 1)
cylinder = Cylinder(1, 1, Frame.worldXY())
sphere = Sphere(1)

scene = Scene()
scene.clear()

obj = scene.add(box).add(cylinder).add(sphere)

scene.print_hierarchy()


print(obj.tree)
└── <TreeNode: ROOT>
    └── <GeometryObject: Box>
        └── <GeometryObject: Cylinder>
            └── <GeometryObject: Sphere>
<Tree with 4 nodes>

What type of change is this?

  • Bug fix in a backwards-compatible manner.
  • New feature in a backwards-compatible manner.
  • Breaking change: bug fix or new feature that involve incompatible API changes.
  • Other (e.g. doc update, configuration, etc)

Checklist

Put an x in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code.

  • I added a line to the CHANGELOG.md file in the Unreleased section under the most fitting heading (e.g. Added, Changed, Removed).
  • I ran all tests on my computer and it's all green (i.e. invoke test).
  • I ran lint on my computer and there are no errors (i.e. invoke lint).
  • I added new functions/classes and made them available on a second-level import, e.g. compas.datastructures.Mesh.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have added necessary documentation (if appropriate)

@tomvanmele
Copy link
Member

tomvanmele commented Mar 2, 2024

i don't think this helps with the model problem. from an item you can access the parent node and from the parent node you can reach the tree. but you still can't reach the scene from the tree.

perhaps it would make sense to make Scene a subclass from Tree? might feel more logical since a scene object is a tree node. the problem of reaching the scene is them immediately solved.

else:
raise ValueError("Cannot add items to a scene object without a node.")
sceneobject = SceneObject(item, **kwargs)
super().add(sceneobject)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't work in IronPython...

Comment on lines 118 to 124
parent = parent or self.tree.root

if isinstance(item, SceneObject):
sceneobject = item
else:
sceneobject = SceneObject(item, context=self.context, **kwargs)
self.tree.add(sceneobject, parent=parent)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

before, the problem was here. this might work now for the model...

@tomvanmele
Copy link
Member

i added a few changes that make the scene work for recursive addition of objects in, for example a model.
added the type annotations for debugging.
we can remove them again...

@tomvanmele
Copy link
Member

i removed viewer detection and the viewer instance attribute on the scene. as explained, i think we should rather do the opposite...

@Licini
Copy link
Contributor Author

Licini commented Mar 12, 2024

i don't think this helps with the model problem. from an item you can access the parent node and from the parent node you can reach the tree. but you still can't reach the scene from the tree.

perhaps it would make sense to make Scene a subclass from Tree? might feel more logical since a scene object is a tree node. the problem of reaching the scene is them immediately solved.

I also think making Scene inherent from Tree is a good idea. Especially when SceneObject is the node. Will give this a try now on this branch

@Licini Licini requested a review from tomvanmele March 12, 2024 15:46
@Licini
Copy link
Contributor Author

Licini commented Mar 12, 2024

@tomvanmele

  1. How about now? Scene is now inheriting directly from Tree.
  2. Regarding documenting the kwargs. Should we also explicitly write all of them out then pass on to super init, so it can be suggested pylance? For example:
def __init__(kwag_x=None, kwag_y=None):
    super(XXX, self).__init__(kwag_x=kwag_x, kwag_y=kwag_y)

@tomvanmele
Copy link
Member

regarding**kwargs...

in my opinion this should only be used when additional named arguments can be expected that are not known to the current class and need to be passed on to the class ancestors. arguments that are expected and used in the current scope should always be listed, processed, and documented explicitly...

what i think we should most certainly NOT do is the following:

def __init__(self, **kwargs):
    super().__init__(**kwargs)
    self.a = kwargs.get('a')
    self.b = kwargs.get('b')

i would also vote for using ONLY named arguments in __init__ functions in the future, because passing of arguments to parent classes is complicated when there is a mixture of positional and named arguments...

src/compas/scene/sceneobject.py Outdated Show resolved Hide resolved
tests/compas/scene/test_scene.py Outdated Show resolved Hide resolved

def test_sceneobject_auto_context_discovery_no_context(mocker):
mocker.patch("compas.scene.context.is_viewer_open", return_value=False)
# mocker.patch("compas.scene.context.is_viewer_open", return_value=False)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

src/compas/scene/sceneobject.py Outdated Show resolved Hide resolved
src/compas/scene/sceneobject.py Outdated Show resolved Hide resolved
@Licini
Copy link
Contributor Author

Licini commented Mar 14, 2024

regarding**kwargs...

in my opinion this should only be used when additional named arguments can be expected that are not known to the current class and need to be passed on to the class ancestors. arguments that are expected and used in the current scope should always be listed, processed, and documented explicitly...

what i think we should most certainly NOT do is the following:

def __init__(self, **kwargs):
    super().__init__(**kwargs)
    self.a = kwargs.get('a')
    self.b = kwargs.get('b')

i would also vote for using ONLY named arguments in __init__ functions in the future, because passing of arguments to parent classes is complicated when there is a mixture of positional and named arguments...

Sounds good, will make everything named argument in the scope of this PR and make a separate one after for rest of places. And will fix all the docs and remove the code commented out

@Licini
Copy link
Contributor Author

Licini commented Mar 15, 2024

@tomvanmele cleaned up, shall we merge?

@Licini
Copy link
Contributor Author

Licini commented Mar 25, 2024

@tomvanmele let's merge this?

@tomvanmele tomvanmele merged commit 4f83c09 into compas-dev:main Mar 25, 2024
11 checks passed
ZacZhangzhuo added a commit to compas-dev/compas_viewer that referenced this pull request Mar 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants