public Point FindStraightLineIntersection(StraightLine p, StraightLine q)
        {
            Point intersectionPoint = new Point();

            if (p.k == q.k || (double.IsInfinity(q.k) && double.IsInfinity(p.k)))
            {
                throw new Exception("Method: FindStraightLineIntersection . Message: Straight lines are paralell");
            }

            if (double.IsInfinity(p.k))
            {
                intersectionPoint.x = ConvertToZero(p.x);
                intersectionPoint.y = ConvertToZero(q.k * p.x + q.n);
                return(intersectionPoint);
            }

            if (double.IsInfinity(q.k))
            {
                intersectionPoint.x = ConvertToZero(q.x);
                intersectionPoint.y = ConvertToZero(p.k * q.x + p.n);
                return(intersectionPoint);
            }

            intersectionPoint.x = ConvertToZero((q.n - p.n) / (p.k - q.k));
            intersectionPoint.y = ConvertToZero(q.k * intersectionPoint.x + q.n);


            return(intersectionPoint);
        }
        // Domain - sets of point that belong to R
        // distanceD - distance between points on domain
        public List <float> GenerateStraightLine(StraightLine p, double[] domain, List <float> color, double distanceD = 0.001)
        {
            List <float> straightLine = new List <float>();
            double       a            = domain[0];
            double       b            = domain[1];
            double       y;

            while (a <= b)
            {
                if (double.IsInfinity(p.k))
                {
                    y = p.k * a + p.n;
                    straightLine.Add((float)p.x);
                    straightLine.Add((float)a);
                    straightLine.Add(0);
                    straightLine.AddRange(color);
                    a = a + distanceD;
                }
                else
                {
                    y = p.k * a + p.n;
                    straightLine.Add((float)a);
                    straightLine.Add((float)y);
                    straightLine.Add(0);
                    straightLine.AddRange(color);
                    a = a + distanceD;
                }
            }

            return(straightLine);
        }
        public List <float> GenerateHiperbolicSegment(Point pointA, Point pointB, List <float> color)
        {
            // Center of inversion circle
            Point o = new Point();
            // Radius of inversion circle
            double radius;

            if (IsColinear(pointA, pointB, new Point(0, 0)) == true)
            {
                // This is when you want to generate hiperbolic straight line through center
                List <Point> intersection = FindIntersectionBetweenStraightLineAndCircle(new Circle(new Point(0, 0), 1), new StraightLine(pointA, pointB));

                // If points belongs to line paralel with y axis
                // (pointA.x - pointB.x) < 0.00001
                if (pointB.x == pointA.x)
                {
                    double[] domain = { Math.Min(pointA.y, pointB.y), Math.Max(pointA.y, pointB.y) };
                    return(GenerateStraightLine(new StraightLine(pointA, pointB), domain, color, 0.001));
                }
                else
                {
                    double[] domain = { Math.Min(pointA.x, pointB.x), Math.Max(pointA.x, pointB.x) };
                    return(GenerateStraightLine(new StraightLine(pointA, pointB), domain, color, 0.001));
                }
            }
            else
            {
                Point pointA_inversе = CircleInversion(pointA);
                Point midPointM      = FindMidPoint(pointA, pointB);
                Point midPointN      = FindMidPoint(pointA_inversе, pointA);

                StraightLine s = new StraightLine(pointA, pointB);
                StraightLine d = new StraightLine(midPointM, -1 / s.k);

                StraightLine p = new StraightLine(pointA, pointA_inversе);
                StraightLine q = new StraightLine(midPointN, -1 / p.k);

                o      = FindStraightLineIntersection(d, q);
                radius = FindDistance(pointA, o);

                List <Point> points = FindIntersectionBetweenTwoCircles(new Circle(new Point(0, 0), 1), new Circle(o, radius));

                double minAngle = Math.Min(FindAngle(pointA, o, radius), FindAngle(pointB, o, radius));
                double maxAngle = Math.Max(FindAngle(pointA, o, radius), FindAngle(pointB, o, radius));


                // angle between 2 points must be 180 deegres or less because arch lenght must be less then half of circumstance of inversion circle
                if (maxAngle * minAngle < 0 && maxAngle - minAngle >= 180)
                {
                    var auxiliarAngle = maxAngle;
                    maxAngle = 360 + minAngle;
                    minAngle = auxiliarAngle;

                    return(GenerateCircle(o, radius, color, minAngle, maxAngle));
                }

                return(GenerateCircle(o, radius, color, minAngle, maxAngle));
            }
        }
        // Inversion circle is Poencare circle (Fundamental circle defined as x^2 + y^2 = 1)
        public Point CircleInversion(Point point)
        {
            StraightLine p = new StraightLine(new Point(0, 0), point);

            StraightLine v = new StraightLine(point, -1 / p.k);

            List <Point> intersections = FindIntersectionBetweenStraightLineAndCircle(new Circle(new Point(0, 0), 1), v);

            StraightLine q = new StraightLine(intersections[0], new Point(0, 0));
            StraightLine s = new StraightLine(intersections[0], -1 / q.k);

            return(FindStraightLineIntersection(p, s));
        }
        public List <Point> FindIntersectionBetweenStraightLineAndCircle(Circle k, StraightLine p, double sensitivity = 0.01)
        {
            // Regarding tesalation it should not happen that D <= 0

            List <Point> intersectionPoints = new List <Point>();

            // Case when p is parallel with y axis
            if (double.IsInfinity(p.k))
            {
                double x1 = ConvertToZero(p.x);
                double y1 = ConvertToZero(Math.Sqrt((1 - Math.Pow(p.x, 2))));
                double x2 = ConvertToZero(p.x);
                double y2 = ConvertToZero(-Math.Sqrt((1 - Math.Pow(p.x, 2))));

                intersectionPoints.Add(new Point(x1, y1));
                intersectionPoints.Add(new Point(x2, y2));

                return(intersectionPoints);
            }

            Point kCenter = k.center;
            // ax^2 + bx + c = 0
            double a = 1 + Math.Pow(p.k, 2);
            double b = 2 * (p.k * (p.n - kCenter.y) - kCenter.x);
            double c = Math.Pow(kCenter.x, 2) + Math.Pow(kCenter.y, 2) + Math.Pow(p.n, 2) - Math.Pow(k.radius, 2) - (2 * p.n * kCenter.y);
            double D = Math.Sqrt(Math.Pow(b, 2) - 4 * a * c);

            if (D == 0)
            {
                double x = ConvertToZero(-b / (2 * a));
                double y = ConvertToZero(p.k * x + p.n);

                intersectionPoints.Add(new Point(x, y));
            }
            else if (D > 0)
            {
                double x1 = ConvertToZero((-b + D) / (2 * a));
                double y1 = ConvertToZero(p.k * x1 + p.n);
                double x2 = ConvertToZero((-b - D) / (2 * a));
                double y2 = ConvertToZero(p.k * x2 + p.n);

                intersectionPoints.Add(new Point(x1, y1));
                intersectionPoints.Add(new Point(x2, y2));
            }

            // For D < 0  there are 2 solutions that belongs to C (set of complex numbers)

            return(intersectionPoints);
        }