# Path: pcloudpy/core/filters/base.py
# class FilterBase(BaseObject):
#     """
#     Base Class for all Filter Objects
# 
#     Attributes
#     ----------
#     input_: vtkPolyData
#         Input Data  to be filtered
# 
#     output_: vtkPolyData
#         Output Data
# 
#     """
# 
#     def __init__(self):
# 
#         self.input_ = None
#         self.output_ = None
# 
#     def set_input(self, input_data):
# 
#         """
#         set input data
# 
#         Parameters
#         ----------
#         input-data : vtkPolyData
# 
#         Returns
#         -------
#         is_valid: bool
#             Returns True if the input_data is valid for processing
# 
#         """
#         if isinstance(input_data, vtkPolyData):
#             self.input_ = input_data
#             return True
#         else:
#             return False
# 
# 
#     def get_output(self):
# 
#         if self.output_:
#             return self.output_
# 
#     def update(self):
#         pass
# 
# Path: pcloudpy/core/io/converters.py
# def numpy_from_polydata(polydata):
#     """
#     Converts vtkPolyData to Numpy Array
# 
#     Parameters
#     ----------
# 
#     polydata: vtkPolyData
#         Input Polydata
# 
#     """
# 
#     nodes_vtk_array = polydata.GetPoints().GetData()
#     nodes_numpy_array = vtk_to_numpy(nodes_vtk_array)
# 
#     if polydata.GetPointData().GetScalars():
#         nodes_numpy_array_colors = vtk_to_numpy(polydata.GetPointData().GetScalars("colors"))
#         return np.c_[nodes_numpy_array, nodes_numpy_array_colors]
#     else:
#         return nodes_numpy_array
# 
# def copy_polydata_add_normals(polydata, normals):
# 
#     Points = vtkPoints()
#     ntype = get_numpy_array_type(Points.GetDataType())
#     normals_vtk = numpy_to_vtk(np.asarray(normals[:,0:3], order='C',dtype=ntype), deep=1)
#     normals_vtk.SetName("Normals")
# 
#     output = vtkPolyData()
#     output.ShallowCopy(polydata)
#     output.GetPointData().SetNormals(normals_vtk)
#     return output


import numpy as np
from scipy.linalg import eigh
from sklearn.neighbors import NearestNeighbors
from pcloudpy.core.filters.base import FilterBase
from ..io.converters import numpy_from_polydata, copy_polydata_add_normals
    input_: vtkPolyData
        Input Data  to be filtered

    output_: vtkPolyData
        Output Data

    """

    def __init__(self, number_neighbors = 10):
        self.number_neighbors = number_neighbors

    def update(self):

        array_with_color = numpy_from_polydata(self.input_)
        normals = np.empty_like(array_with_color[:,0:3])
        coord = array_with_color[:,0:3]

        neigh = NearestNeighbors(self.number_neighbors)
        neigh.fit(coord)

        for i in range(0,len(coord)):
            #Determine the neighbours of point
            d = neigh.kneighbors(coord[i])
            #Add coordinates of neighbours , dont include center point to array. Determine coordinate by the index of the neighbours.
            y = np.zeros((self.number_neighbors-1,3))
            y = coord[d[1][0][1:self.number_neighbors],0:3]
            #Get information content
            #Assign information content to each point i.e xyzb
            normals[i,0:3] = self.get_normals(y)


# Path: pcloudpy/core/filters/base.py
# class FilterBase(BaseObject):
#     """
#     Base Class for all Filter Objects
# 
#     Attributes
#     ----------
#     input_: vtkPolyData
#         Input Data  to be filtered
# 
#     output_: vtkPolyData
#         Output Data
# 
#     """
# 
#     def __init__(self):
# 
#         self.input_ = None
#         self.output_ = None
# 
#     def set_input(self, input_data):
# 
#         """
#         set input data
# 
#         Parameters
#         ----------
#         input-data : vtkPolyData
# 
#         Returns
#         -------
#         is_valid: bool
#             Returns True if the input_data is valid for processing
# 
#         """
#         if isinstance(input_data, vtkPolyData):
#             self.input_ = input_data
#             return True
#         else:
#             return False
# 
# 
#     def get_output(self):
# 
#         if self.output_:
#             return self.output_
# 
#     def update(self):
#         pass
# 
# Path: pcloudpy/core/io/converters.py
# def numpy_from_polydata(polydata):
#     """
#     Converts vtkPolyData to Numpy Array
# 
#     Parameters
#     ----------
# 
#     polydata: vtkPolyData
#         Input Polydata
# 
#     """
# 
#     nodes_vtk_array = polydata.GetPoints().GetData()
#     nodes_numpy_array = vtk_to_numpy(nodes_vtk_array)
# 
#     if polydata.GetPointData().GetScalars():
#         nodes_numpy_array_colors = vtk_to_numpy(polydata.GetPointData().GetScalars("colors"))
#         return np.c_[nodes_numpy_array, nodes_numpy_array_colors]
#     else:
#         return nodes_numpy_array
# 
# def copy_polydata_add_normals(polydata, normals):
# 
#     Points = vtkPoints()
#     ntype = get_numpy_array_type(Points.GetDataType())
#     normals_vtk = numpy_to_vtk(np.asarray(normals[:,0:3], order='C',dtype=ntype), deep=1)
#     normals_vtk.SetName("Normals")
# 
#     output = vtkPolyData()
#     output.ShallowCopy(polydata)
#     output.GetPointData().SetNormals(normals_vtk)
#     return output


# Path: pcloudpy/core/filters/NormalsEstimation.py
import numpy as np
from scipy.linalg import eigh
from sklearn.neighbors import NearestNeighbors
from pcloudpy.core.filters.base import FilterBase
from ..io.converters import numpy_from_polydata, copy_polydata_add_normals

    input_: vtkPolyData
        Input Data  to be filtered

    output_: vtkPolyData
        Output Data

    """

    def __init__(self, number_neighbors = 10):
        self.number_neighbors = number_neighbors

    def update(self):

        array_with_color = numpy_from_polydata(self.input_)
        normals = np.empty_like(array_with_color[:,0:3])
        coord = array_with_color[:,0:3]

        neigh = NearestNeighbors(self.number_neighbors)
        neigh.fit(coord)

        for i in range(0,len(coord)):
            #Determine the neighbours of point
            d = neigh.kneighbors(coord[i])
            #Add coordinates of neighbours , dont include center point to array. Determine coordinate by the index of the neighbours.
            y = np.zeros((self.number_neighbors-1,3))
            y = coord[d[1][0][1:self.number_neighbors],0:3]
            #Get information content
            #Assign information content to each point i.e xyzb
            normals[i,0:3] = self.get_normals(y)


        self.output_ = copy_polydata_add_normals(self.input_, normals)