import numpy as np
from sklearn.linear_model import RANSACRegressor
from .dimension import Dimension

class DistanceDimension(Dimension):
    """Assign each point the distance to the estimated ground"""

    def __init__(self):
        super(DistanceDimension, self).__init__()

    def assign_default(self, point_cloud):
        default = np.full(point_cloud.len(), -1)
        super(DistanceDimension, self)._set_values(point_cloud, default)

    def assign(self, *point_clouds, **kwargs):
        for point_cloud in point_clouds:
            xy = point_cloud.get_xy()

            # Calculate RANSCAC model
            model = RANSACRegressor().fit(xy, point_cloud.get_z())

            # Calculate angle between estimated plane and XY plane
            angle = self.__calculate_angle(model)
            if angle >= 45:
                # If the angle is higher than 45 degrees, then don't calculate the difference, since it will probably be way off
                diff = np.full(point_cloud.len(), 0)
            else:
                predicted = model.predict(xy)
                diff = point_cloud.get_z() - predicted
                # Ignore the diff when the diff is below the ground
                diff[diff < 0] = 0
            super(DistanceDimension, self)._set_values(point_cloud, diff)

    def get_name(self):
        return 'distance_to_ground'

    def get_las_type(self):
        return 10

    def __calculate_angle(self, model):
        "Calculate the angle between the estimated plane and the XY plane"
        a = model.estimator_.coef_[0]
        b = model.estimator_.coef_[1]
        angle = np.arccos(1 / np.sqrt(a ** 2 + b ** 2 + 1))
        return np.degrees(angle)
