/// <summary>
        /// Gets a functional values in defined y position.
        /// </summary>
        /// <param name="start">The start point of the segment.</param>
        /// <param name="y">The y position.</param>
        /// <param name="global">True, if y and returned x value is are global space, false, if y and x are related to the start point.</param>
        /// <param name="tolerance">Tolerance</param>
        /// <returns>A values related to the y position.</returns>
        public override double[] GetValueByY(ref Point start, double y, bool global, double tolerance = 0)
        {
            Refresh(ref start);
            if (!global)
            {
                y += start.Y;
            }

            if (Comparators.InIntervalBoth(start.Y, EndPoint.Y, y, tolerance))
            {
                // y = ax^2 + bx + c
                // ax^2 + bx + (c - y) = 0;
                var cc = c - y;

                var discr = (b * b) - 4 * a * cc;
                if (discr.IsGreater(0, 1e-5) && !a.IsZero())
                {
                    var x1 = (-b + Math.Sqrt(discr)) / (2 * a);
                    var x2 = (-b - Math.Sqrt(discr)) / (2 * a);

                    if (Comparators.InIntervalBoth(start.X, EndPoint.X, x1, tolerance) && Comparators.InIntervalBoth(start.X, EndPoint.X, x2, tolerance))
                    {
                        return(new double[]
                        {
                            global?x1 : x1 - start.X,
                            global ? x2 : x2 - start.X,
                        });
                    }
                    else if (Comparators.InIntervalBoth(start.X, EndPoint.X, x1, tolerance))
                    {
                        return(new double[]
                        {
                            global?x1 : x1 - start.X
                        });
                    }
                    else if (Comparators.InIntervalBoth(start.X, EndPoint.X, x2, tolerance))
                    {
                        return(new double[]
                        {
                            global?x2 : x2 - start.X
                        });
                    }
                }
            }

            return(new double[0]);
        }
        /// <summary>
        /// Gets a functional values in defined y position.
        /// </summary>
        /// <param name="start">The start point of the segment.</param>
        /// <param name="y">The y position.</param>
        /// <param name="global">True, if y and returned x value is are global space, false, if y and x are related to the start point.</param>
        /// <param name="tolerance">Tolerance</param>
        /// <returns>A values related to the y position.</returns>
        public override double[] GetValueByY(ref Point start, double y, bool global, double tolerance = 0)
        {
            if (!global)
            {
                y += start.Y;
            }

            var bounds = GetBounds(ref start);

            if (Comparators.InIntervalBoth(bounds.Top, bounds.Bottom, y, tolerance))
            {
                var radius = GetRadius(ref start);
                var centre = GetCentre(ref start);
                y -= centre.Y;
                var x  = Math.Sqrt(radius * radius - y * y);
                var c1 = Comparators.InIntervalBoth(bounds.Left, bounds.Right, centre.X + x, tolerance);
                var c2 = Comparators.InIntervalBoth(bounds.Left, bounds.Right, centre.X - x, tolerance);
                if (c1 && c2)
                {
                    return(new double[]
                    {
                        global?centre.X + x : centre.X + x - start.X,
                        global ? centre.X - x : centre.X - x - start.X,
                    });
                }
                else if (c1)
                {
                    return(new double[]
                    {
                        global?centre.X + x : centre.X + x - start.X
                    });
                }
                else if (c2)
                {
                    return(new double[]
                    {
                        global?centre.X - x : centre.X - x - start.X
                    });
                }
            }

            return(new double[0]);
        }
        /// <summary>
        /// Gets a functional values in defined x position of the CircularArcSegment.
        /// </summary>
        /// <param name="start">The start point of the circular arc segment.</param>
        /// <param name="x">The x position.</param>
        /// <param name="global">True, if x and returned y value is are global space, false, if x and y are related to the start point.</param>
        /// <param name="tolerance">Tolerance</param>
        /// <returns>A values related to the x position.</returns>
        public override double[] GetValueByX(ref Point start, double x, bool global, double tolerance = 0)
        {
            if (!global)
            {
                x += start.X;
            }

            var bounds = GetBounds(ref start);

            if (Comparators.InIntervalBoth(bounds.Left, bounds.Right, x, tolerance))
            {
                var radius = GetRadius(ref start);
                var centre = GetCentre(ref start);
                x -= centre.X;
                var y  = Math.Sqrt(radius * radius - x * x);
                var c1 = Comparators.InIntervalBoth(bounds.Top, bounds.Bottom, centre.Y + y, tolerance);
                var c2 = Comparators.InIntervalBoth(bounds.Top, bounds.Bottom, centre.Y - y, tolerance);
                if (c1 && c2)
                {
                    return(new double[]
                    {
                        global?centre.Y + y : centre.Y + y - start.Y,
                        global ? centre.Y - y : centre.Y - y - start.Y,
                    });
                }
                else if (c1)
                {
                    return(new double[]
                    {
                        global?centre.Y + y : centre.Y + y - start.Y,
                    });
                }
                else if (c2)
                {
                    return(new double[]
                    {
                        global?centre.Y - y : centre.Y - y - start.Y,
                    });
                }
            }

            return(new double[0]);
        }
        /// <summary>
        /// Gets a functional values in defined x position of the ParabolicArcSegment.
        /// </summary>
        /// <param name="start">The start point of the parabolic arc segment.</param>
        /// <param name="x">The x position.</param>
        /// <param name="global">True, if x and returned y value is are global space, false, if x and y are related to the start point.</param>
        /// <param name="tolerance">Tolerance</param>
        /// <returns>A values related to the x position.</returns>
        public override double[] GetValueByX(ref Point start, double x, bool global, double tolerance = 0)
        {
            Refresh(ref start);
            if (!global)
            {
                x += start.X;
            }

            if (Comparators.InIntervalBoth(start.X, EndPoint.X, x, tolerance))
            {
                // y = ax^2 + bx + c
                var y = a * x * x + b * x + c;
                if (!global)
                {
                    y -= start.Y;
                }

                return(new double[] { y });
            }

            return(new double[0]);
        }
        /// <summary>
        /// Calculates relative position on segment by given x position.
        /// </summary>
        /// <param name="start">The start point of the segment.</param>
        /// <param name="x">The x position.</param>
        /// <param name="global">True, if x and returned y value is are global space, false, if x and y are related to the start point.</param>
        /// <returns>The relative position.</returns>
        public override double[] GetRelativePosition(ref Point start, double x, bool global, double tolerance = 0)
        {
            if (!global)
            {
                x += start.X;
            }

            var radius = GetRadius(ref start);
            var centre = GetCentre(ref start);

            if (Comparators.InIntervalBoth(centre.X - radius, centre.X + radius, x, tolerance))
            {
                var xx    = x - centre.X;
                var y     = (radius * radius - xx * xx).IsZero() ? 0 : Math.Sqrt(radius * radius - xx * xx);
                var cc    = IsCounterClockwise(ref start);
                var angle = GetAngle(ref start);
                Func <Point, Point, double> getAngle = (s, p) =>
                {
                    var u1 = Point.Subtract(s, centre);
                    var u2 = Point.Subtract(p, centre);
                    var a  = Vector.AngleBetween(u1, u2) * cc;
                    if (a.IsZero())
                    {
                        return(0);
                    }

                    return(a < 0 ? 360 + a : a);
                };
                var px     = new Point(x, centre.Y + y);
                var angle1 = getAngle(start, px);
                px.Y = centre.Y - y;
                var angle2 = getAngle(start, px);
                return(new double[] { angle1 / angle, angle2 / angle });
            }

            return(new double[0]);
        }