public override int ComputeIntersect(Coordinate p1, Coordinate p2, Coordinate q1, Coordinate q2)
        {
            IsProper = false;

            // first try a fast test to see if the envelopes of the lines intersect
            if (!Envelope.Intersects(p1, p2, q1, q2))
            {
                return(NoIntersection);
            }

            // for each endpoint, compute which side of the other segment it lies
            // if both endpoints lie on the same side of the other segment,
            // the segments do not intersect
            var Pq1 = Orientation.Index(p1, p2, q1);
            var Pq2 = Orientation.Index(p1, p2, q2);

            if ((Pq1 > 0 && Pq2 > 0) ||
                (Pq1 < 0 && Pq2 < 0))
            {
                return(NoIntersection);
            }

            var Qp1 = Orientation.Index(q1, q2, p1);
            var Qp2 = Orientation.Index(q1, q2, p2);

            if ((Qp1 > 0 && Qp2 > 0) ||
                (Qp1 < 0 && Qp2 < 0))
            {
                return(NoIntersection);
            }

            bool collinear = Pq1 == 0 && Pq2 == 0 && Qp1 == 0 && Qp2 == 0;

            if (collinear)
            {
                return(ComputeCollinearIntersection(p1, p2, q1, q2));
            }

            /*
             * At this point we know that there is a single intersection point
             * (since the lines are not collinear).
             */

            /*
             *  Check if the intersection is an endpoint. If it is, copy the endpoint as
             *  the intersection point. Copying the point rather than computing it
             *  ensures the point has the exact value, which is important for
             *  robustness. It is sufficient to simply check for an endpoint which is on
             *  the other line, since at this point we know that the inputLines must
             *  intersect.
             */
            if (Pq1 == 0 || Pq2 == 0 || Qp1 == 0 || Qp2 == 0)
            {
                IsProper = false;

                /*
                 * Check for two equal endpoints.
                 * This is done explicitly rather than by the orientation tests
                 * below in order to improve robustness.
                 *
                 * [An example where the orientation tests fail to be consistent is
                 * the following (where the true intersection is at the shared endpoint
                 * POINT (19.850257749638203 46.29709338043669)
                 *
                 * LINESTRING ( 19.850257749638203 46.29709338043669, 20.31970698357233 46.76654261437082 )
                 * and
                 * LINESTRING ( -48.51001596420236 -22.063180333403878, 19.850257749638203 46.29709338043669 )
                 *
                 * which used to produce the INCORRECT result: (20.31970698357233, 46.76654261437082, NaN)
                 *
                 */
                if (p1.Equals2D(q1) || p1.Equals2D(q2))
                {
                    IntersectionPoint[0] = p1;
                }
                else if (p2.Equals2D(q1) || p2.Equals2D(q2))
                {
                    IntersectionPoint[0] = p2;
                }
                else if (Pq1 == 0)
                {
                    IntersectionPoint[0] = q1.Copy();
                }
                else if (Pq2 == 0)
                {
                    IntersectionPoint[0] = q2.Copy();
                }
                else if (Qp1 == 0)
                {
                    IntersectionPoint[0] = p1.Copy();
                }
                else if (Qp2 == 0)
                {
                    IntersectionPoint[0] = p2.Copy();
                }
            }
            else
            {
                IsProper             = true;
                IntersectionPoint[0] = Intersection(p1, p2, q1, q2);
            }
            return(PointIntersection);
        }