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

item as kwarg #1353

Merged
merged 18 commits into from
Jun 11, 2024
Merged

item as kwarg #1353

merged 18 commits into from
Jun 11, 2024

Conversation

Licini
Copy link
Contributor

@Licini Licini commented May 13, 2024

In SceneObject init, changing the item to be a kwarg. This will be very helpful in handling complicated multi-inheritance situations, in places like Viewer, where this is becoming very tricky.

@Licini Licini marked this pull request as draft May 22, 2024 16:55
@Licini
Copy link
Contributor Author

Licini commented May 22, 2024

@tomvanmele @gonzalocasas @chenkasirer Hey guys, I expanded this PR a bit to make a rather big update to clean up how data items are assigned to SceneObjects.

Previously, in SceneObject class __init__, we accept the geometry/datastructrue item as the first positional argument, in form of:

class SceneObject:
    def __init__(self, item, **kwargs):
        self.item=item
        ...

Then its subclasses like MeshObject we add on top:

class MeshObject(SceneObject):
    def __init__(self, mesh, **kwargs):
        super().init(item=mesh, **kwargs)
        self.mesh=mesh
        ...

Meanwhile we also created general sceneobject class for different context like RhinoSceneObject and BlenderSceneObject where their __init__ does not take positional arguments, only keyword arguments:

class RhinoSceneObject(SceneObject):
    def __init__(self, **kwargs):
        super().init(**kwargs)
        ...

At last we need to make specific sceneobject for context such as MeshObject for Rhino, which looks like:

class MeshObject(RhinoSceneObject, BaseMeshObject):
    def __init__(self, mesh, **kwargs):
        super().init(mesh=mesh, **kwargs)
        ...

Especially for the last one which involves multi-inheritance, it becomes very difficult to know how to pass in data item to the super init function, whether as positional or kwargs. And it is very often we encounter error of conflicted args or kwargs while extending further these classes.

So the idea here is to remove all this complexity. We do not use positional arguments at all. And we only catch item as kwarg ONCE at the root SceneObject class. And if we need alias such as MeshObject.mesh, we make it a property that fetches self.item, which is the "single source of truth".

I didn't do it for all, just few of them as a demonstration how it can look like. Please let me know if you guys think this is the good direction, then I will apply the same to all rest of SceneObject classes.

Comment on lines 44 to 53
def __init__(self, pointcolor=None, linecolor=None, surfacecolor=None, pointsize=1.0, linewidth=1.0, show_points=False, show_lines=True, show_surfaces=True, **kwargs):
super(GeometryObject, self).__init__(**kwargs)
self.pointcolor = pointcolor or self.color
self.linecolor = linecolor or self.color
self.surfacecolor = surfacecolor or self.color
self.pointsize = pointsize
self.linewidth = linewidth
self.show_points = show_points
self.show_lines = show_lines
self.show_surfaces = show_surfaces
Copy link
Contributor Author

Choose a reason for hiding this comment

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

So after adjustment, any __init__ of subclasses should only care about additional parameters that its parent classes do not have, the data item will be passed along automatically within **kwargs and eventualy received by the root __init__ of SceneObject

Comment on lines 55 to 57
@property
def geometry(self):
return self.item
Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we need alias we create a property that points to self.item instead of creating another attribute.

Comment on lines 65 to 83
@graph.setter
def graph(self, graph):
Copy link
Contributor Author

@Licini Licini May 22, 2024

Choose a reason for hiding this comment

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

These setters I removed for now, because item in SceneObject is currently read-only

"""A scene object for drawing a RhinoBrep.

Parameters
----------
brep : :class:`compas_rhino.geometry.RhinoBrep`
The Brep to draw.

"""

def __init__(self, brep, **kwargs):
super(RhinoBrepObject, self).__init__(geometry=brep, **kwargs)
"""A scene object for drawing a RhinoBrep."""
Copy link
Contributor Author

@Licini Licini May 22, 2024

Choose a reason for hiding this comment

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

In many cases the __init__ function of subclass can be entirely omitted, because the don't do anything else than passing in the positional argument using a different name.

@Licini Licini requested a review from tomvanmele May 22, 2024 17:46
@tomvanmele tomvanmele marked this pull request as ready for review May 23, 2024 10:13
src/compas/scene/graphobject.py Outdated Show resolved Hide resolved
src/compas/scene/meshobject.py Outdated Show resolved Hide resolved
src/compas/scene/volmeshobject.py Outdated Show resolved Hide resolved
@Licini Licini requested a review from tomvanmele June 10, 2024 16:37
@@ -120,7 +140,7 @@ def draw_vertices(self) -> List[bpy.types.Object]:
for vertex in vertices:
name = f"{self.mesh.name}.vertex.{vertex}"
color = self.vertexcolor[vertex]
point = self.vertex_xyz[vertex]
point = self.mesh.vertex_coordinates(vertex)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I did this here because the update_object will apply transformation afterwards. If using vertex_xyz, the transformation will be applied twice, similar changes are done for both BlenderMeshObject and BlenderVolmeshObjectr

@Licini
Copy link
Contributor Author

Licini commented Jun 10, 2024

@tomvanmele Ok this one is done and ready. Could you take a look again?
I know it's a lot files but all following same pattern.

Copy link
Member

@tomvanmele tomvanmele left a comment

Choose a reason for hiding this comment

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

LGTM. just a few notes/reminders

  • show_wires (Blender) is actually the same as show_lines. show_wires is a better name in my opinion
  • disjoint (Rhino) and not shade_smooth (Blender) are the same
  • Frame, Plane, Shape, Curve, Surface should have dedicated base classes
  • points of Line, Polyline, Polygon, Polyhedron, Curve, Surface are in fact "control points" and should perhaps have a dedicated color attribute for when they are turned "on".

src/compas/scene/geometryobject.py Outdated Show resolved Hide resolved
src/compas/scene/geometryobject.py Outdated Show resolved Hide resolved
src/compas/scene/volmeshobject.py Outdated Show resolved Hide resolved

def __init__(self, circle: Circle, **kwargs: Any):
super().__init__(geometry=circle, **kwargs)
"""Scene object for drawing circles in Blender."""

def draw(self, color: Optional[Color] = None, collection: Optional[str] = None) -> list[bpy.types.Object]:
Copy link
Member

Choose a reason for hiding this comment

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

here we should also remove the parameters, but this can be in the next PR

@@ -153,7 +173,7 @@ def draw_edges(self) -> List[bpy.types.Object]:
for u, v in edges:
name = f"{self.mesh.name}.edge.{u}-{v}"
color = self.edgecolor[u, v]
curve = conversions.line_to_blender_curve(Line(self.vertex_xyz[u], self.vertex_xyz[v]))
curve = conversions.line_to_blender_curve(Line(self.mesh.vertex_coordinates(u), self.mesh.vertex_coordinates(v)))
Copy link
Member

Choose a reason for hiding this comment

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

why do you change this back? vertex_xyz are the cached coordinates...

@@ -177,7 +197,7 @@ def draw_faces(self) -> List[bpy.types.Object]:
for face in faces:
name = f"{self.mesh.name}.face.{face}"
color = self.facecolor[face]
points = [self.vertex_xyz[vertex] for vertex in self.mesh.face_vertices(face)]
points = [self.mesh.vertex_coordinates(vertex) for vertex in self.mesh.face_vertices(face)]
Copy link
Member

Choose a reason for hiding this comment

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

same here

@@ -152,7 +171,7 @@ def draw_edges(self) -> List[bpy.types.Object]:
for u, v in edges:
name = f"{self.volmesh.name}.edge.{u}-{v}"
color = self.edgecolor[u, v]
curve = conversions.line_to_blender_curve(Line(self.vertex_xyz[u], self.vertex_xyz[v]))
curve = conversions.line_to_blender_curve(Line(self.volmesh.vertex_coordinates(u), self.volmesh.vertex_coordinates(v)))
Copy link
Member

Choose a reason for hiding this comment

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

why do you change this back?

@tomvanmele
Copy link
Member

the revert of using self.vertex_xyz is not correct in my opinion...

@Licini
Copy link
Contributor Author

Licini commented Jun 11, 2024

the revert of using self.vertex_xyz is not correct in my opinion...

This was because the update_object that is called later inside these function will apply the transformation again. So the object will be transformed twice:

from compas.scene import Scene
from compas.datastructures import Graph

from compas.geometry import Translation


graph = Graph.from_nodes_and_edges([(0, 0, 0), (0, -1.5, 0), (-1, 1, 0), (1, 1, 0)], [(0, 1), (0, 2), (0, 3)])



scene = Scene()

obj = scene.add(graph, nodesize=0.2)
obj.transformation = Translation.from_vector([10, 0, 0])
scene.draw()

See in picture it is moved 20 instead of 10
image

@@ -78,7 +78,7 @@ def __init__(
cellcolor=None,
vertexsize=1.0,
edgewidth=1.0,
**kwargs, # fmt: skip
**kwargs, # fmt: skip
Copy link
Member

Choose a reason for hiding this comment

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

this is only useful if you remove the comma after **kwargs

@tomvanmele tomvanmele merged commit 9856318 into main Jun 11, 2024
15 checks passed
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