//
// Created by Martin Gargalovič on 11. 8. 2021.
//

#ifndef ARC_SUPPORT_ELLIPSESET_H
#define ARC_SUPPORT_ELLIPSESET_H

#include <eigen3/Eigen/Eigenvalues>
#include "utility.h"

/**
 * approximates line length and compares it to the support inlier count
 * @param supportInliersCount count of support inliers
 * @param rectangles all bounding rectangles
 * @param group ellipse combination group
 * @param inliersRatio a threshold for comparison : threshold * approx < support inlier count
 * @return threshold * approx < support inlier count
 */
bool
lineAppr(int supportInliersCount, const std::vector<rectangle> &rectangles,
         const std::vector<int> &group, double inliersRatio);

/**
 * stores the points of all the arcs in the combination
 * @param lines all arcs
 * @param group combination grou[
 * @return points of the combination group
 */
std::vector<std::vector<cv::Point2i>>
getArc(const std::vector<std::vector<cv::Point2i>> &lines,
       std::vector<int> &group);

/**
 * calculates the scatter matrix for a arc group
 * @param group group of arcs segments
 * @param matrices scatter matrices for individual arcs
 * @return
 */
Eigen::Matrix<double, 6, 6>
scatterMatrixGroup(const std::vector<int> &group,
                   const std::vector<Eigen::Matrix<double, 6, 6>> &matrices);


/**
 * calculates scatter matrix for given points
 * @param supportGroup is an array of points contained in an arc-segments
 * @return scatter matrix S
 */
Eigen::Matrix<double, 6, 6> scatterMatrix(const std::vector<cv::Point2i> &supportGroup);

/**
 * calculating equation of an ellipse.
 * @param S is the scatter matrix
 * @return coeficients of a general ellipse equation
 */
Eigen::Matrix<double, 6, 1> fitEllipse(const Eigen::Matrix<double, 6, 6> &S);


/**
 * calculates the size of semi axis from the general ellipse equation
 * @param ellipseEQ general ellipse equation
 * @param major decides whether to calculate major axis
 * @return size of major/minor axis
 */
double semiAxis(Eigen::Matrix<double, 6, 1> &ellipseEQ, bool major);

/**
 * calculates the center point of the ellipse from general ellipse equation
 * @param ellipseEQ general ellipse equation
 * @return ellipse center point
 */
cv::Point2i centre(Eigen::Matrix<double, 6, 1> &ellipseEQ);

/**
 * calculates ellipse rotation from general ellipse equation
 * @param ellipseEQ general ellipse equation
 * @return ellipse rotation
 */
double angle(Eigen::Matrix<double, 6, 1> &ellipseEQ);

/**
 * transforms a gereneral ellipse equation to parametric equation
 * @param eq general ellipse equation
 * @param params ellipse parameters (output)
 * @return  true if the general ellipse equation can be transformed to parametric
 */
bool getParam(Eigen::Matrix<double, 6, 1> &eq, ellipseParameters &params);

/**
 * implementation of orthogonal conics published by Paul L.Rosin : https://doi.org/10.1006/gmip.1998.0471
 * @param params parameters of ellipse
 * @param point point to which orthogonal conics is calculated
 * @param threshold max distance between the point and hyperbola
 * @return True distance of the point and the orthogonal conic is lower than treshold, False otherwise
 */
bool rosinDistance(ellipseParameters &params, const cv::Point2i& point, double threshold);

/**
 * calculates inliers for a given ellipse
 * @param coefficients coefficients of a general ellipse equation
 * @param arc arc on the ellipse to count inliers on
 * @param angles image containing orientation of each pixel
 * @param distanceTolerance max distance of point on ellipse and hyperbola to form a support inlier
 * @param polarity polarity of calculated ellipse
 * @param inliersRatio ratio for ellipse validation
 * @param rectangles contains the rectangle bouding boxes for arc segments
 * @param group contains the indexes of the grouped arc segments
 * @return True if support inliers/inliers is larger than inliersRatio, False otherwise
 */

bool calcInliers(Eigen::Matrix<double, 6, 1> &coefficients, std::vector<std::vector<cv::Point2i>> &arc,
                 cv::Mat &angles,int &support_inliers_count ,double distanceTolerance,
                 int polarity, double inliersRatio, const std::vector<rectangle> & rectangles, const std::vector<int> & group);


/**
 * validation of the ellipse
 * @param arc arc of an ellipse
 * @param S is a scatter matrix for ellipse equation calculation
 * @param angles image containing orientation of each pixel
 * @param distanceTolerance max distance of point on ellipse and hyperbola to form a support inlier
 * @param parameters parameters of the ellipse will be returned here
 * @param polarity polarity of calculated ellipse
 * @param inliersRatio ratio for ellipse validation
 * @param group contains the indexes of the arc segments group
 * @param rectangles contains the bounding boxes for each arc segment
 * @param setParams sets the parameters after validating if the argument is set to True
 * @return True for a valid ellipse , False otherwise
 */

bool
validateEllipse(std::vector<std::vector<cv::Point2i>> &arc,
                Eigen::Matrix<double, 6, 6> &S, cv::Mat &angles,
                int &support_inliers_count,
                double distanceTolerance,
                ellipseParameters &parameters, int polarity,
                double inliersRatio, const std::vector<int> &group,
                const std::vector<rectangle> &rectangles, bool setParams);
/**
 * validation of ellipse
 * @param lines points of all lines in the
 * @param groups indexes of lines forming a group
 * @param matrices contains scatter matrices of each arc segment group
 * @param group1 first group for validation
 * @param group2 second group for validation
 * @param angles image containing orientation of each pixel
 * @param distanceTolerance max distance of point on ellipse and hyperbola to form a support inlier
 * @param parameters parameters of the ellipse will be returned here
 * @param polarity polarity of calculated ellipse
 * @param inliersRatio ratio for ellipse validation
 * @return True for a valid ellipse , False otherwise
 */

/**
 *
 * @param lines points of all lines in the
 * @param groups indexes of lines forming a group
 * @param group1 first group for validation
 * @param group2 second group for validation
 * @param angles image containing orientation of each pixel
 * @param support_inliers_group1_count stores the number of support inliers for group1
 * @param support_inliers_group2_countstores the number of support inliers for group2
 * @param distanceTolerance max distance of point on ellipse and hyperbola to form a support inlier
 * @param parameters parameters of the ellipse will be returned here
 * @param polarity polarity of calculated ellipse
 * @param inliersRatio ratio for ellipse validation
 * @param matrices contain scatter matrices for every arc segment group
 * @param rectangles contain bounding boxes for every arc segment
 * @return True for a valid ellipse , False otherwise
 */

bool
validateEllipse(std::vector<std::vector<cv::Point2i>> &lines,
                std::vector<std::vector<int>> &groups,
                size_t group1, size_t group2, cv::Mat &angles,
                int &support_inliers_group1_count,
                int &support_inliers_group2_count,
                double distanceTolerance,
                ellipseParameters &parameters, int polarity,
                double inliersRatio,
                std::vector<Eigen::Matrix<double, 6, 6>> &matrices,
                const std::vector<rectangle> &rectangles);
/**
 * normalization of vector
 * @param vector vector to be normalized
 * @return normalized vector
 */
cv::Point2i normalize(cv::Point2i &vector);

/**
 * rotates a point around point [0,0] by a given angle
 * @param point point to be rotated
 * @param angle angle of rotation
 * overrides the values in point
 */
void rotate(cv::Point2i &point, double angle);

/**
 *
 * @param lines points of all lines in the image
 * @param groups indexes of lines forming a group
 * @param group1 first group to calculate the constraint
 * @param group2 second group to calculate the constraint
 * @param rectangles rectangle approximations of every line
 * @param threshold max distance 2 points can be from each other to fulfil the constraint, default set to -6
 * @return True if the constraint was fulfilled, False otherwise
 */
bool regionConstraint(std::vector<std::vector<cv::Point2i>> &lines, std::vector<std::vector<int>> &groups, int group1,
                      int group2, const std::vector<rectangle> &rectangles, double threshold = -6);

/**
 * gets polarity of ellipse.
 * @param groups groups of all arc-segments
 * @param rectangles rectangle approximations to lines in image
 * @param group specific group of which polarity we are calculating
 * @return polarity of specific arc-segment
 */
int getPolarity(std::vector<std::vector<int>> &groups, std::vector<rectangle> &rectangles, size_t group);

/**
 * calculates the equations of ellipses
 * @param lines array of lines, lines is an array of points
 * @param rectangles array of rectangle approximations of lines
 * @param angles image containing orientation of pixels
 * @param groups contains indexes of lines that form a group
 * @param distanceTolerance max distance between two points that can form an ellipse
 * @param scale scale of the image, if it isn't 1.0 then the ellipse parameters are scaled depending on this value
 * @param specificPolarity can contain value of -1 for negative polarity, 1 for positive polarity and 0 for both
 * @param coverages array of coverages for individual groups
 * @param inliersRatio is ratio for ellipse validation, support-inliers/inliers
 * @param Tr  is a goodness measure threshold
 * @param approx indicates which approximation for line length is going to be used
 * @return equations of ellipses found in the image
 */
std::vector<ellipseParameters>
ellipseSet(std::vector<std::vector<cv::Point2i>> &lines,
           std::vector<rectangle> &rectangles, cv::Mat &angles,
           std::vector<std::vector<int>> &groups, double distanceTolerance,
           double scale, int specificPolarity, std::vector<double> &coverages,
           double inliersRatio, double Tr, double Tcover);


#endif //ARC_SUPPORT_ELLIPSESET_H
