marcomusy / vedo

A python module for scientific analysis of 3D data based on VTK and Numpy
https://vedo.embl.es
MIT License
2.02k stars 264 forks source link

Group objects #1164

Closed smoothumut closed 1 month ago

smoothumut commented 1 month ago

Hi Marco again : )

I am also using Group in my codes I have also noticed that in newer versions the Group object doesnt have any property in order to get the vedo objects in it. I have been using GetParts() for the previous versions but in newer versions GetParts() bring the vtkOpenGLActors which we cannot reach the vedo objects through actor. Yes we can actually, but it would need an unnecessary work around.

So I have added objects property in Group vedo object as I show below. It worked in my cases but I might oversee the effects or miss somethings.

    #################################################
    class Group(vtki.vtkPropAssembly):
        """Form groups of generic objects (not necessarily meshes)."""

        def __init__(self, objects=()):
            """Form groups of generic objects (not necessarily meshes)."""
            super().__init__()

            self.objects = []  ## I have added

            if isinstance(objects, dict):
                for name in objects:
                    objects[name].name = name
                self.objects = list(objects.values())
            elif isinstance(objects, list):  ## I have added
                self.objects = objects  ## I have added

            self.actor = self

            self.name = "Group"
            self.filename = ""
            self.trail = None
            self.trail_points = []
            self.trail_segment_size = 0
            self.trail_offset = None
            self.shadows = []
            self.info = {}
            self.rendered_at = set()
            self.scalarbar = None

            for a in vedo.utils.flatten(objects):
                if a:
                    self.AddPart(a.actor)

            self.PickableOff()

        def __str__(self):
            """Print info about Group object."""
            module = self.__class__.__module__
            name = self.__class__.__name__
            out = vedo.printc(
                f"{module}.{name} at ({hex(id(self))})".ljust(75),
                bold=True, invert=True, return_string=True,
            )
            out += "\x1b[0m"
            if self.name:
                out += "name".ljust(14) + ": " + self.name
                if "legend" in self.info.keys() and self.info["legend"]:
                    out+= f", legend='{self.info['legend']}'"
                out += "\n"

            n = len(self.unpack())
            out += "n. of objects".ljust(14) + ": " + str(n) + " "
            names = [a.name for a in self.unpack() if a.name]
            if names:
                out += str(names).replace("'","")[:56]
            return out.rstrip() + "\x1b[0m"

        def __iadd__(self, obj):
            """
            Add an object to the group
            """
            if not vedo.utils.is_sequence(obj):
                obj = [obj]
            for a in obj:
                if a:
                    ### self.AddPart(a)  ### old 
                    try:
                        self.objects.append(a)    ### I have added
                        self.AddPart(a.actor)
                    except:
                        self.AddPart(a)
            return self

        def _unpack(self):
            """Unpack the group into its elements"""
            elements = []
            self.InitPathTraversal()
            parts = self.GetParts()
            parts.InitTraversal()
            for i in range(parts.GetNumberOfItems()):
                ele = parts.GetItemAsObject(i)
                elements.append(ele)

            # gr.InitPathTraversal()
            # for _ in range(gr.GetNumberOfPaths()):
            #     path  = gr.GetNextPath()
            #     print([path])
            #     path.InitTraversal()
            #     for i in range(path.GetNumberOfItems()):
            #         a = path.GetItemAsObject(i).GetViewProp()
            #         print([a])

            return elements

        def clear(self) -> "Group":
            """Remove all parts"""
            for a in self._unpack():
                self.RemovePart(a)
            self.objects = []              ## I have added
            return self

        def on(self) -> "Group":
            """Switch on visibility"""
            self.VisibilityOn()
            return self

        def off(self) -> "Group":
            """Switch off visibility"""
            self.VisibilityOff()
            return self

        def pickable(self, value=True) -> "Group":
            """The pickability property of the Group."""
            self.SetPickable(value)
            return self

        def use_bounds(self, value=True) -> "Group":
            """Set the use bounds property of the Group."""
            self.SetUseBounds(value)
            return self

        def print(self) -> "Group":
            """Print info about the object."""
            print(self)
            return self

        ## I have added
        def objects(self) -> List["vedo.Mesh"]:
            """Return the list of objects in the group."""
            return self.objects

Please let me know if this is a correct approach and need a PR for this Best Regards

marcomusy commented 1 month ago

Yes please do! You can use vedo.utils.is_sequence(objects) instead of elif isinstance(objects, list): ## I have added