marcomusy / vedo

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

plane normal #1159

Closed smoothumut closed 4 months ago

smoothumut commented 4 months ago

Hi Marco, Hope everything is great with you. I try to get normal of the newly created Plane, but when I try to get the normal of the plane, strangly it gives different normal even the code looks good

    here my dummy example

    import numpy as np
    from vedo import Plane

    # Create a dummy center point
    center_point = np.array([1.0, 2.0, 3.0])

    # Create a dummy normal
    normal_vector = np.array([0.0, 0.0, 1.0])

    plane = Plane(center_point, normal_vector, s=(30,30), res=(30,30), c="blue", alpha=0.1)

    print("Plane normal:", plane.normal)

In my actual code, it gives totally different plane normal even it draws it correctly here the Plane class with the latest vedo version I try to use

    class Plane(Mesh):
        """Create a plane in space."""

        def __init__(
                self,
                pos=(0, 0, 0),
                normal=(0, 0, 1),
                s=(1, 1),
                res=(1, 1),
                c="gray5", alpha=1.0,
            ) -> None:
            """
            Create a plane of size `s=(xsize, ysize)` oriented perpendicular
            to vector `normal` so that it passes through point `pos`.

            Arguments:
                pos : (list)
                    position of the plane center
                normal : (list)
                    normal vector to the plane
                s : (list)
                    size of the plane along x and y
                res : (list)
                    resolution of the plane along x and y
            """
            if isinstance(pos, vtki.vtkPolyData):
                super().__init__(pos, c, alpha)
                # self.transform = LinearTransform().translate(pos)

            else:
                ps = vtki.new("PlaneSource")
                ps.SetResolution(res[0], res[1])
                tri = vtki.new("TriangleFilter")
                tri.SetInputConnection(ps.GetOutputPort())
                tri.Update()

                super().__init__(tri.GetOutput(), c, alpha)

                pos = utils.make3d(pos)
                normal = np.asarray(normal, dtype=float)
                axis = normal / np.linalg.norm(normal)
                theta = np.arccos(axis[2])
                phi = np.arctan2(axis[1], axis[0])

                t = LinearTransform()
                t.scale([s[0], s[1], 1])
                t.rotate_y(np.rad2deg(theta))
                t.rotate_z(np.rad2deg(phi))
                t.translate(pos)
                self.apply_transform(t)

            # self.normal = normal  ## umut ekledi

            self.lighting("off")
            self.name = "Plane"
            self.variance = 0

        @property
        def normal(self) -> np.ndarray:
            pts = self.vertices
            AB = pts[1] - pts[0]
            AC = pts[2] - pts[0]
            normal = np.cross(AB, AC)
            normal = normal / np.linalg.norm(normal)
            return normal

Am I missing something?? thanks in advance Best Regards Umut

smoothumut commented 4 months ago

Hi Marco, problem is about if the pts[1] and pts[2] looks to the same direction, then it cannot find the normal so I changed the code, I know it is not the best, but it may help

      @property
      def normal(self) -> np.ndarray:
          pts = self.vertices

          p0, p1 = pts[0], pts[1]

          for pt in pts[2:]:

              AB = p1 - p0
              AC = pt - p0

              cosine_angle = np.dot(AB, AC) / (np.linalg.norm(AB) * np.linalg.norm(AC))
              angle_in_degrees = np.arccos(cosine_angle) * (180.0 / np.pi)

              if angle_in_degrees > 5 and angle_in_degrees < 175:
                  normal = np.cross(AB, AC)
                  normal = normal / np.linalg.norm(normal)
                  return normal
marcomusy commented 4 months ago

Thanks Umut! Just pushed a fix by modifying a bit your suggestion which was already pretty good.

smoothumut commented 4 months ago

Frankly, Thank you Marco for this great work! 🙇