static internal Point RawIntersection(IntersectionInfo xx, Point origin) {
            // If this fires, then you didn't pass the LineSegment as the first argument to GetAllIntersections.
            Debug.Assert(xx.Segment0 is LineSegment, "LineSegment was not first arg to GetAllIntersections");

            // The intersection snaps the end of the intersection to the PolylinePoint at the start/end
            // of the interesecting segment on the obstacle if the intersection is Curve.CloseIntersections
            // to that segment endpoint, which can return a point that is just more than Curve.DistanceEpsilon
            // off the line.  Therefore, re-create the intersection using the LineSegment and intersection
            // parameters (this assumes the LineSegment.End is not Curve.CloseIntersections to the intersection).
            Point point = xx.Segment0[xx.Par0];

#if DEBUG
            // This may legitimately be rounding-error'd in the same way as xx.IntersectionPoint (and the
            // caller addresses this later).  The purpose of the assert is to verify that the LineSegment
            // interception is not outside the bbox in the perpendicular direction.
            var lineSeg = (LineSegment)xx.Segment0;
            if (StaticGraphUtility.IsVertical(PointComparer.GetDirections(lineSeg.Start, lineSeg.End))) {
                Debug.Assert(PointComparer.Equal(point.X, origin.X), "segment0 obstacle intersection is off the vertical line");
            }
            else {
                Debug.Assert(PointComparer.Equal(point.Y, origin.Y), "segment0 obstacle intersection is off the horizontal line");
            }
#endif // DEBUG
            return ApproximateComparer.Round(point);
        }
        // Most of the original contents of this file have been subsumed into ObstacleTree and TransientGraphUtility.
        internal static Point MungeClosestIntersectionInfo(Point rayOrigin, IntersectionInfo closestIntersection, bool isHorizontal) {
            Rectangle bbox = closestIntersection.Segment1.BoundingBox;
#if SHARPKIT //https://code.google.com/p/sharpkit/issues/detail?id=369
            Point closest = RawIntersection(closestIntersection, rayOrigin).Clone();
#else
            Point closest = RawIntersection(closestIntersection, rayOrigin);
#endif
            if (isHorizontal) {
                closest.X = MungeIntersect(rayOrigin.X, closest.X, bbox.Left, bbox.Right);
            }
            else {                                          // vertical
                closest.Y = MungeIntersect(rayOrigin.Y, closest.Y, bbox.Bottom, bbox.Top);
            }
            return closest;
        }
 internal static IntersectionInfo LiftIntersectionToCurves(ICurve c0, ICurve c1, IntersectionInfo xx) {
     return LiftIntersectionToCurves(c0, c1, xx.Par0, xx.Par1, xx.IntersectionPoint, xx.Segment0, xx.Segment1);
 }
        static void AddIntersection(ParallelogramLeaf n0, ParallelogramLeaf n1, List<IntersectionInfo> intersections,
            double aSol, double bSol,
            Point x) {
            //adjust the intersection if it is close to the ends of the segs
            if (ApproximateComparer.CloseIntersections(x, n0.Seg[n0.Low])) {
                x = n0.Seg[n0.Low];
                aSol = n0.Low;
            }
            else if (ApproximateComparer.CloseIntersections(x, n0.Seg[n0.High])) {
                x = n0.Seg[n0.High];
                aSol = n0.High;
            }

            if (ApproximateComparer.CloseIntersections(x, n1.Seg[n1.Low])) {
                x = n1.Seg[n1.Low];
                bSol = n1.Low;
            }
            else if (ApproximateComparer.CloseIntersections(x, n1.Seg[n1.High])) {
                x = n1.Seg[n1.High];
                bSol = n1.High;
            }

            bool oldIntersection = OldIntersection(intersections, ref x);
            if (!oldIntersection) {
                var xx = new IntersectionInfo(aSol, bSol, x, n0.Seg, n1.Seg);
                intersections.Add(xx);
            }

            return;
        }
        static IntersectionInfo DropIntersectionToSegs(IntersectionInfo xx) {
            ICurve seg0;
            double par0;

            if (xx.Segment0 is Curve)
                (xx.Segment0 as Curve).GetSegmentAndParameter(xx.Par0, out par0, out seg0);
            else {
                par0 = xx.Par0;
                seg0 = xx.Segment0;
            }

            ICurve seg1;
            double par1;

            if (xx.Segment1 is Curve)
                (xx.Segment1 as Curve).GetSegmentAndParameter(xx.Par1, out par1, out seg1);
            else {
                par1 = xx.Par1;
                seg1 = xx.Segment1;
            }

            return new IntersectionInfo(par0, par1, xx.IntersectionPoint, seg0, seg1);
        }
 static bool AlreadyInside(List<IntersectionInfo> ret, IntersectionInfo intersectionInfo) {
     for(int i=0;i<ret.Count;i++) {
         var ii = ret[i];
         if (ApproximateComparer.CloseIntersections(ii.IntersectionPoint, intersectionInfo.IntersectionPoint))
             return true;
     }
     return false;
 }
        public static bool RealCut(IntersectionInfo xx, Curve polyline, bool onlyFromInsideCuts) {
            ValidateArg.IsNotNull(xx, "xx");
            ValidateArg.IsNotNull(polyline, "polyline");
            ICurve sseg = xx.Segment0;
            ICurve pseg = xx.Segment1;
            double spar = xx.Par0;
            double ppar = xx.Par1;
            Point x = xx.IntersectionPoint;


            //normalised tangent to spline
            Point ts = sseg.Derivative(spar).Normalize();
            Point pn = pseg.Derivative(ppar).Normalize().Rotate(Math.PI/2);

            if (ApproximateComparer.Close(x, pseg.End)) {
                //so pseg enters the spline 
                ICurve exitSeg = null;
                for (int i = 0; i < polyline.Segments.Count - 1; i++)
                    if (polyline.Segments[i] == pseg) {
                        exitSeg = polyline.Segments[i + 1];
                        break;
                    }

                if (exitSeg == null)
                    return false; //hit the end of the polyline

                Point tsn = ts.Rotate((Math.PI/2));

                bool touch = (tsn*pseg.Derivative(pseg.ParEnd))*(tsn*exitSeg.Derivative(exitSeg.ParStart)) <
                             ApproximateComparer.Tolerance;

                return !touch;
            }

            if (ApproximateComparer.Close(x, pseg.Start)) {
                //so pseg exits the spline 
                ICurve enterSeg = null;
                for (int i = polyline.segs.Count - 1; i > 0; i--)
                    if (polyline.Segments[i] == pseg) {
                        enterSeg = polyline.Segments[i - 1];
                        break;
                    }
                if (enterSeg == null)
                    return false;
                Point tsn = ts.Rotate((Math.PI/2));
                bool touch = (tsn*pseg.Derivative(pseg.ParStart))*
                             (tsn*enterSeg.Derivative(enterSeg.ParEnd)) < ApproximateComparer.Tolerance;

                return !touch;
            }

            double d = ts*pn;
            if (onlyFromInsideCuts)
                return d > ApproximateComparer.DistanceEpsilon;
            return Math.Abs(d) > ApproximateComparer.DistanceEpsilon;
        }
        /// <summary>
        /// Returns true if curves do not touch in the intersection point
        /// </summary>
        /// <param name="xx"></param>
        /// <param name="polygon"></param>
        /// <param name="onlyFromInsideCuts">if set to true and first curve is closed will return true 
        /// only when the second curve cuts the first one from the inside</param>
        /// <returns></returns>
        public static bool RealCutWithClosedCurve(IntersectionInfo xx, Curve polygon, bool onlyFromInsideCuts) {
            ValidateArg.IsNotNull(xx, "xx");
            ValidateArg.IsNotNull(polygon, "polygon");
            ICurve sseg = xx.Segment0;
            ICurve pseg = xx.Segment1;
            double spar = xx.Par0;
            double ppar = xx.Par1;
            Point x = xx.IntersectionPoint;

            //normalised tangent to spline
            Point ts = sseg.Derivative(spar).Normalize();
            Point pn = pseg.Derivative(ppar).Normalize().Rotate(Math.PI/2);

            if (ApproximateComparer.Close(x, pseg.End)) {
                //so pseg enters the spline 
                ICurve exitSeg = null;
                for (int i = 0; i < polygon.Segments.Count; i++)
                    if (polygon.Segments[i] == pseg) {
                        exitSeg = polygon.Segments[(i + 1)%polygon.Segments.Count];
                        break;
                    }

                if (exitSeg == null)
                    throw new InvalidOperationException(); //"exitSeg==null");

                Point tsn = ts.Rotate((Math.PI/2));

                bool touch = (tsn*pseg.Derivative(pseg.ParEnd))*(tsn*exitSeg.Derivative(exitSeg.ParStart)) <
                             ApproximateComparer.Tolerance;

                return !touch;
            }

            if (ApproximateComparer.Close(x, pseg.Start)) {
                //so pseg exits the spline 
                ICurve enterSeg = null;
                for (int i = 0; i < polygon.Segments.Count; i++)
                    if (polygon.Segments[i] == pseg) {
                        enterSeg = polygon.Segments[i > 0 ? (i - 1) : polygon.Segments.Count - 1];
                        break;
                    }

                Point tsn = ts.Rotate((Math.PI/2));
                bool touch = (tsn*pseg.Derivative(pseg.ParStart))*
                             (tsn*enterSeg.Derivative(enterSeg.ParEnd)) < ApproximateComparer.Tolerance;

                return !touch;
            }

            double d = ts*pn;
            if (onlyFromInsideCuts)
                return d > ApproximateComparer.DistanceEpsilon;
            return Math.Abs(d) > ApproximateComparer.DistanceEpsilon;
        }
        static ICurve GetTrimmedCurveForHookingUpAnywhere(ICurve curve, PolylinePoint lastPointInside, IntersectionInfo x0, IntersectionInfo x1) {
            var clockwise =
                Point.GetTriangleOrientation(x1.IntersectionPoint, x0.IntersectionPoint, lastPointInside.Point) ==
                TriangleOrientation.Clockwise;

            double rightX = x0.Par0;
            double leftX = x1.Par0;
            ICurve tr0, tr1;
            Curve ret;
            if (clockwise) {
                if (rightX < leftX)
                    return curve.Trim(rightX, leftX);

                tr0 = curve.Trim(rightX, curve.ParEnd);
                tr1 = curve.Trim(curve.ParStart, leftX);
                ret = new Curve();
                return ret.AddSegs(tr0, tr1);
            }

            if (leftX < rightX)
                return curve.Trim(leftX, rightX);
            tr0 = curve.Trim(leftX, curve.ParEnd);
            tr1 = curve.Trim(curve.ParStart, rightX);
            ret = new Curve();
            return ret.AddSegs(tr0, tr1);
        }
        void ExtendPolyline(Point tangentAtIntersection, IntersectionInfo x, Point polylineTangent, HookUpAnywhereFromInsidePort port) {

            var normal=tangentAtIntersection.Rotate(Math.PI/2);
            if(normal*polylineTangent<0)
                normal=-normal;

            var pointBeforeLast = x.IntersectionPoint + normal * port.HookSize;
            Point pointAfterX;
            if (!Point.LineLineIntersection(pointBeforeLast, pointBeforeLast+tangentAtIntersection, _polyline.End, _polyline.End+polylineTangent, out pointAfterX))
                return;

            _polyline.AddPoint(pointAfterX);
            _polyline.AddPoint(pointBeforeLast);
            _polyline.AddPoint(x.IntersectionPoint);
        }