# 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
import networkx as nx
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
        for i in range(0,len(coord)):

            d = neigh.kneighbors(coord[i,:3])
            for c in range(1,self.number_neighbors):
                p1 = d[1][0][0]
                p2 = d[1][0][c]
                n1 = normals[d[1][0][0],:]
                n2 = normals[d[1][0][c],:]
                dot = np.dot(n1,n2)
                G.add_edge(p1,p2,weight =1-np.abs(dot))


        T = nx.minimum_spanning_tree(G)

        x=[]
        for i in nx.dfs_edges(T,z_max_point):
            x+=i


        inds = np.where(np.diff(x))[0]
        out = np.split(x,inds[np.diff(inds)==1][1::2]+1)

        for j in range(0,len(out)):
            for i in range(0,len(out[j])-1):
                n1 = normals[out[j][i],:]
                n2 = normals[out[j][i+1],:]
                if np.dot(n2,n1)<0:
                    normals[out[j][i+1],:]=-normals[out[j][i+1],:]



# 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/OrientedNormalEstimation.py
import numpy as np
import networkx as nx
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

        for i in range(0,len(coord)):

            d = neigh.kneighbors(coord[i,:3])
            for c in range(1,self.number_neighbors):
                p1 = d[1][0][0]
                p2 = d[1][0][c]
                n1 = normals[d[1][0][0],:]
                n2 = normals[d[1][0][c],:]
                dot = np.dot(n1,n2)
                G.add_edge(p1,p2,weight =1-np.abs(dot))


        T = nx.minimum_spanning_tree(G)

        x=[]
        for i in nx.dfs_edges(T,z_max_point):
            x+=i


        inds = np.where(np.diff(x))[0]
        out = np.split(x,inds[np.diff(inds)==1][1::2]+1)

        for j in range(0,len(out)):
            for i in range(0,len(out[j])-1):
                n1 = normals[out[j][i],:]
                n2 = normals[out[j][i+1],:]
                if np.dot(n2,n1)<0:
                    normals[out[j][i+1],:]=-normals[out[j][i+1],:]



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