# Path: pyfor/rasterizer.py
# class Grid:
# class ImportedGrid(Grid):
# class Raster:
#     def __init__(self, cloud, cell_size):
#     def _update(self):
#     def raster(self, func, dim, **kwargs):
#     def empty_cells(self):
#     def interpolate(self, func, dim, interp_method="nearest"):
#     def metrics(self, func_dict, as_raster=False):
#     def standard_metrics(self, heightbreak=0):
#     def __init__(self, path, cloud):
#     def _update(self):
#     def __init__(self, array, grid):
#     def from_rasterio(cls):
#     def force_extent(self, bbox):
#     def plot(self, cmap="viridis", block=False, return_plot=False):
#     def pit_filter(self, kernel_size):
#     def write(self, path):
#         X, Y = np.mgrid[1 : self.n + 1, 1 : self.m + 1]
# 
# Path: pyfor/clip.py
# def square_clip(points, bounds):
# def ray_trace(x, y, poly):
#     def ray(x, y):
# def poly_clip(points, poly):


import laspy
import plyfile
import os
import numpy as np
import pandas as pd
import matplotlib.cm as cm
import pathlib
import warnings
        import pyqtgraph as pg
        import pyqtgraph.opengl as gl
from pyfor import rasterizer
from pyfor import clip
        from os.path import getsize
        from pyqtgraph.Qt import QtCore, QtGui
        from pyfor.ground_filter import Zhang2003
        from pyfor.metrics import standard_metrics_cloud
        from scipy.spatial import ConvexHull
        from shapely.geometry import Polygon
        else:
            filter.normalize(self)

    def subtract(self, path):
        """
        Normalize using a pre-computed raster file, i.e. "subtract" the heights from the input raster **in place**. \
        This assumes the raster and the point cloud are in the same coordinate system.
        :param path: The path to the raster file, must be in a format supported by `rasterio`.
        :return:
        """

        imported_grid = rasterizer.ImportedGrid(path, self)
        df = (
            pd.DataFrame(np.flipud(imported_grid.in_raster.read(1)))
            .stack()
            .rename_axis(["bins_y", "bins_x"])
            .reset_index(name="val")
        )
        df = self.data.points.reset_index().merge(df, how="left").set_index("index")
        self.data.points["z"] = df["z"] - df["val"]

    def clip(self, polygon):
        """
        Clips the point cloud to the provided shapely polygon using a ray casting algorithm. This method calls \
        :func:`.clip.poly_clip` directly. This returns a new :class:`.Cloud`.

        :param polygon: A :class:`shapely.geometry.Polygon` in the same CRS as the Cloud.
        :return: A new :class:.`Cloud` object clipped to the provided polygon.
        """


# Path: pyfor/rasterizer.py
# class Grid:
# class ImportedGrid(Grid):
# class Raster:
#     def __init__(self, cloud, cell_size):
#     def _update(self):
#     def raster(self, func, dim, **kwargs):
#     def empty_cells(self):
#     def interpolate(self, func, dim, interp_method="nearest"):
#     def metrics(self, func_dict, as_raster=False):
#     def standard_metrics(self, heightbreak=0):
#     def __init__(self, path, cloud):
#     def _update(self):
#     def __init__(self, array, grid):
#     def from_rasterio(cls):
#     def force_extent(self, bbox):
#     def plot(self, cmap="viridis", block=False, return_plot=False):
#     def pit_filter(self, kernel_size):
#     def write(self, path):
#         X, Y = np.mgrid[1 : self.n + 1, 1 : self.m + 1]
# 
# Path: pyfor/clip.py
# def square_clip(points, bounds):
# def ray_trace(x, y, poly):
#     def ray(x, y):
# def poly_clip(points, poly):


# Path: pyfor/cloud.py
import laspy
import plyfile
import os
import numpy as np
import pandas as pd
import matplotlib.cm as cm
import pathlib
import warnings
        import pyqtgraph as pg
        import pyqtgraph.opengl as gl
from pyfor import rasterizer
from pyfor import clip
        from os.path import getsize
        from pyqtgraph.Qt import QtCore, QtGui
        from pyfor.ground_filter import Zhang2003
        from pyfor.metrics import standard_metrics_cloud
        from scipy.spatial import ConvexHull
        from shapely.geometry import Polygon

        else:
            filter.normalize(self)

    def subtract(self, path):
        """
        Normalize using a pre-computed raster file, i.e. "subtract" the heights from the input raster **in place**. \
        This assumes the raster and the point cloud are in the same coordinate system.
        :param path: The path to the raster file, must be in a format supported by `rasterio`.
        :return:
        """

        imported_grid = rasterizer.ImportedGrid(path, self)
        df = (
            pd.DataFrame(np.flipud(imported_grid.in_raster.read(1)))
            .stack()
            .rename_axis(["bins_y", "bins_x"])
            .reset_index(name="val")
        )
        df = self.data.points.reset_index().merge(df, how="left").set_index("index")
        self.data.points["z"] = df["z"] - df["val"]

    def clip(self, polygon):
        """
        Clips the point cloud to the provided shapely polygon using a ray casting algorithm. This method calls \
        :func:`.clip.poly_clip` directly. This returns a new :class:`.Cloud`.

        :param polygon: A :class:`shapely.geometry.Polygon` in the same CRS as the Cloud.
        :return: A new :class:.`Cloud` object clipped to the provided polygon.
        """


        keep = clip.poly_clip(self.data.points, polygon)