// process single hatch lines - shorten to match inside polygone
        private static void ClipLineByPolygone(Point p1, Point p2, List <PathObject> paths, List <Point[]> hatch)//, hatches, b_hold_back_hatches, f_hold_back_steps):
        {
            Point  p3, p4;
            double intersect;

            List <intersectionInfo> d_and_a = new List <intersectionInfo>();

            double holdBack       = (double)Properties.Settings.Default.importGraphicHatchFillInset;
            bool   holdBackEnable = Properties.Settings.Default.importGraphicHatchFillInsetEnable;
            bool   b_unconditionally_excise_hatch;
            double prelim_length_to_be_removed = 0;
            double dist_intersection_to_relevant_end, dist_intersection_to_irrelevant_end;

            foreach (PathObject path in paths)
            {
                if (path is ItemPath)
                {
                    ItemPath ipath = (ItemPath)path;

                    p3 = ipath.path[0].MoveTo;
//                    if ((logFlags & (uint)LogEnable.PathModification) > 0) Logger.Trace("   ClipLineByPolygone p3.x:{0:0.00} p3.y:{1:0.00}    {2}", p3.X,p3.Y, ipath.Info.id);

                    for (int k = 1; k < ipath.path.Count; k++)
                    {
                        p4        = ipath.path[k].MoveTo;
                        intersect = CalculateIntersection(p1, p2, p3, p4);
                        if ((0.0 <= intersect) && (intersect <= 1.0))
                        {
                            if (holdBackEnable)                                                              // shorten the hatch lines
                            {
                                double angle_hatch_radians      = Math.Atan2(-(p2.Y - p1.Y), (p2.X - p1.X)); //# from p1 toward p2, cartesian coordinates
                                double angle_segment_radians    = Math.Atan2(-(p4.Y - p3.Y), (p4.X - p3.X)); //# from p3 toward p4, cartesian coordinates
                                double angle_difference_radians = angle_hatch_radians - angle_segment_radians;

                                if (angle_difference_radians > Math.PI)
                                {
                                    angle_difference_radians -= 2 * Math.PI;
                                }
                                else if (angle_difference_radians < -Math.PI)
                                {
                                    angle_difference_radians += 2 * Math.PI;
                                }
                                double f_sin_of_join_angle     = Math.Sin(angle_difference_radians);
                                double f_abs_sin_of_join_angle = Math.Abs(f_sin_of_join_angle);
                                if (f_abs_sin_of_join_angle != 0.0) //  # Worrying about case of intersecting a segment parallel to the hatch
                                {
                                    prelim_length_to_be_removed    = holdBack / f_abs_sin_of_join_angle;
                                    b_unconditionally_excise_hatch = false;
                                }
                                else
                                {
                                    b_unconditionally_excise_hatch = true;
                                }

                                if (!b_unconditionally_excise_hatch)
                                {                                                      //# The relevant end of the segment is the end from which the hatch approaches at an acute angle.
                                    Point intersection = new Point();
                                    intersection.X = p1.X + intersect * (p2.X - p1.X); //# compute intersection point of hatch with segment
                                    intersection.Y = p1.Y + intersect * (p2.Y - p1.Y); // # intersecting hatch line starts at p1, vectored toward p2,

                                    if (Math.Abs(angle_difference_radians) < Math.PI / 2)
                                    {    //# It's near the p3 the relevant end from which the hatch departs
                                        dist_intersection_to_relevant_end   = CalcHypotenuse(p3.X - intersection.X, p3.Y - intersection.Y);
                                        dist_intersection_to_irrelevant_end = CalcHypotenuse(p4.X - intersection.X, p4.Y - intersection.Y);
                                    }
                                    else
                                    {    //# It's near the p4 end from which the hatch departs
                                        dist_intersection_to_relevant_end   = CalcHypotenuse(p4.X - intersection.X, p4.Y - intersection.Y);
                                        dist_intersection_to_irrelevant_end = CalcHypotenuse(p3.X - intersection.X, p3.Y - intersection.Y);
                                    }

                                    double length_remove_starting_hatch = prelim_length_to_be_removed;
                                    double length_remove_ending_hatch   = prelim_length_to_be_removed;

                                    //# Now check each of the two ends
                                    if (prelim_length_to_be_removed > (dist_intersection_to_relevant_end + holdBack))
                                    {
                                        //# Yes, would be excessive holdback approaching from this direction
                                        length_remove_starting_hatch = dist_intersection_to_relevant_end + holdBack;
                                    }
                                    if (prelim_length_to_be_removed > (dist_intersection_to_irrelevant_end + holdBack))
                                    {
                                        //# Yes, would be excessive holdback approaching from other direction
                                        length_remove_ending_hatch = dist_intersection_to_irrelevant_end + holdBack;
                                    }

                                    d_and_a.Add(new intersectionInfo(intersect, length_remove_starting_hatch, length_remove_ending_hatch));
                                }
                                else
                                {
                                    d_and_a.Add(new intersectionInfo(intersect, 123456.0, 123456.0));  //  # Mark for complete hatch excision, hatch is parallel to segment
                                }
                            }
                            else
                            {
                                d_and_a.Add(new intersectionInfo(intersect, 0, 0));  //  # zero length to be removed from hatch
                            }
                        }
                        p3 = p4;
                    }
                }
            }
            //# Return now if there were no intersections
            if (d_and_a.Count == 0)
            {
                return;
            }


            // d_and_a.sort() - by s
            d_and_a.Sort((x, y) => x.s.CompareTo(y.s));


            // Remove duplicate intersections
            int n = d_and_a.Count;
            int i_last = 1;
            int i = 1;
            intersectionInfo last = d_and_a[0];

            while (i < n)
            {
                if ((Math.Abs(d_and_a[i].s - last.s)) > 0.0000000001)                   //F_MINGAP_SMALL_VALUE)	// 0.0000000001
                {
                    d_and_a[i_last] = last = d_and_a[i];
                    i_last         += 1;
                }
                i += 1;
            }

            d_and_a = d_and_a.GetRange(0, i_last);
            if (d_and_a.Count < 2)
            {
                return;
            }


            int    j = 0;
            double x1, y1, x2, y2;
            double distance = (double)Properties.Settings.Default.importGraphicHatchFillDistance;
            double f_min_allowed_hatch_length, f_initial_hatch_length, f_length_to_be_removed_from_pt1, f_length_to_be_removed_from_pt2;

            while (j < (d_and_a.Count - 1))
            {
                x1 = p1.X + d_and_a[j].s * (p2.X - p1.X);
                y1 = p1.Y + d_and_a[j].s * (p2.Y - p1.Y);
                x2 = p1.X + d_and_a[j + 1].s * (p2.X - p1.X);
                y2 = p1.Y + d_and_a[j + 1].s * (p2.Y - p1.Y);

                if (!holdBackEnable)
                {
                    hatch.Add(new Point[] { new Point(x1, y1), new Point(x2, y2) });
                }
                else
                {
                    f_min_allowed_hatch_length      = distance * 0.25;                  //MIN_HATCH_FRACTION; # Minimum hatch length, as a fraction of the hatch spacing.
                    f_initial_hatch_length          = CalcHypotenuse(x2 - x1, y2 - y1);
                    f_length_to_be_removed_from_pt1 = d_and_a[j].s2;
                    f_length_to_be_removed_from_pt2 = d_and_a[j + 1].s1;
                    if ((f_initial_hatch_length - (f_length_to_be_removed_from_pt1 + f_length_to_be_removed_from_pt2)) <= f_min_allowed_hatch_length)
                    {
                    }       //  # Just don't insert it into the hatch list
                    else
                    {
                        Point pt1 = RelativeControlPointPosition(f_length_to_be_removed_from_pt1, x2 - x1, y2 - y1, x1, y1);
                        Point pt2 = RelativeControlPointPosition(f_length_to_be_removed_from_pt2, x1 - x2, y1 - y2, x2, y2);
                        hatch.Add(new Point[] { pt1, pt2 });
                    }
                }
                j += 2;
            }
        }
        private void correctIntersection(IntersectionNode intersection)
        {
            int roadCount = intersection.pointList.Count;
            List<int> highwayIndexes = new List<int>();

            float waySize = 0;
            for(int i = 0 ; i < roadCount ; i++)
            {
                int index = getHighwayIndex(intersection.wayIds[i]);
                highwayIndexes.Add(index);
                waySize += highwayList[index].waySize;
            }

            //Shared waySize at the intersection
            waySize = waySize / (float)roadCount;

            List<Vector3> forwardVectors = new List<Vector3>();
            List<Vector3> leftVectors = new List<Vector3>();
            List<Vector3> rightVectors = new List<Vector3>();
            List<LineSegment> lineSegments = new List<LineSegment>();

            Vector3 up = Vector3.up;

            for(int i = 0 ; i < roadCount ; i++)
            {
                Vector3 v = intersection.pointList[i] - intersection.node.meterPosition;
                forwardVectors.Add(v);
                Vector3 right = Vector3.Cross(up, v).normalized;
                rightVectors.Add(right);
                leftVectors.Add(-right);

                LineSegment ls = new LineSegment();
                ls.Left1 = new Vector2(intersection.node.meterPosition.x, intersection.node.meterPosition.z) + new Vector2(-right.x, -right.z) * (waySize / 2.0f);
                ls.Left2 = new Vector2(intersection.pointList[i].x, intersection.pointList[i].z) + new Vector2(-right.x, -right.z) * (waySize/2.0f);

                ls.Right1 = new Vector2(intersection.node.meterPosition.x, intersection.node.meterPosition.z) + new Vector2(right.x, right.z) * (waySize / 2.0f);
                ls.Right2 = new Vector2(intersection.pointList[i].x, intersection.pointList[i].z) + new Vector2(right.x, right.z) * (waySize / 2.0f);
                lineSegments.Add(ls);
            }

            List<IntersectionAngle> angles = new List<IntersectionAngle>();

            for (int i = 0; i < roadCount - 1; i++)
            {
                for (int j = i+1; j < roadCount; j++)
                {
                    float dot = Vector3.Dot(forwardVectors[i].normalized, forwardVectors[j].normalized);
                    double angle = Math.Acos(dot) * 180.0 / Math.PI;
                    IntersectionAngle ia = new IntersectionAngle();
                    ia.way1No = i;
                    ia.way2No = j;
                    ia.angle = angle;
                    angles.Add(ia);
                }
            }

            List<IntersectionAngle> sortedAngles = angles.OrderBy(o => o.angle).ToList();

            intersectValidator[] truthtable = new intersectValidator[roadCount];
            for(int k = 0 ; k < truthtable.Length ; k++)
            {
                truthtable[k].left = false;
                truthtable[k].right = false;
            }
            List<intersectionInfo> intersectList = new List<intersectionInfo>();

            int iterationCount = 0;

            while (sortedAngles.Count != 0)
            {
                if (iterationCount == 10)
                {
                    throw new System.InvalidOperationException("Sorted Angles entered to a loop");
                    //Debug.Log("ERRROR IN THE WHILE LOOP !!!");
                    //break;
                }
                else
                    iterationCount++;

                //intersect these two
                int way1No = sortedAngles[0].way1No;
                int way2No = sortedAngles[0].way2No;

                intersectionside iside;

                //Normal intersect
                if ((truthtable[way1No].left == false && truthtable[way1No].right == false) || (truthtable[way2No].left == false && truthtable[way2No].right == false))
                {
                    iside = intersectWay(way1No, way2No, intersection, lineSegments[way1No], lineSegments[way2No],
                                                      forwardVectors[way1No], forwardVectors[way2No],sortedAngles[0].angle);
                }
                else //Forced intersect
                {
                    if (truthtable[way1No].left || truthtable[way2No].right)
                        iside = forcedIntersectWay(way1No, way2No, intersection, lineSegments[way1No], lineSegments[way2No],
                                                      forwardVectors[way1No], forwardVectors[way2No], false);
                    else if (truthtable[way1No].right || truthtable[way2No].left)
                        iside = forcedIntersectWay(way1No, way2No, intersection, lineSegments[way1No], lineSegments[way2No],
                                                      forwardVectors[way1No], forwardVectors[way2No], true);
                    else
                    {
                        Debug.Log("SOMETHING SHOULD BE REALLY WRONG ABOUT HIGHWAYS :(  !!!");
                        throw new System.InvalidOperationException("Forced Intersection somehow does not work!");
                        //iside = new intersectionside();
                    }
                }

                if (iside.success)
                {
                    intersectionInfo ii = new intersectionInfo();
                    ii.vertice = iside.vertex;
                    ii.wayNo1 = way1No;
                    ii.wayNo2 = way2No;
                    ii.isleftright = iside.leftright;
                    intersectList.Add(ii);

                    if (iside.leftright == true)
                    {
                        truthtable[way1No].left = true;
                        truthtable[way2No].right = true;
                    }
                    else
                    {
                        truthtable[way1No].right = true;
                        truthtable[way2No].left = true;
                    }

                    //Update AngleList

                    sortedAngles.RemoveAt(0);
                    if (truthtable[way1No].left && truthtable[way1No].right)
                        sortedAngles.RemoveAll(item => (item.way1No == way1No || item.way2No == way1No));
                    if (truthtable[way2No].left && truthtable[way2No].right)
                        sortedAngles.RemoveAll(item => (item.way1No == way2No || item.way2No == way2No));

                }
                else
                {
                    IntersectionAngle ang = sortedAngles[0];
                    ang.angle = 360.0 - ang.angle;
                    sortedAngles.RemoveAt(0);
                    sortedAngles.Add(ang);
                }

            }

            fillIntersectionHole(intersectList, isTrafficLight(intersection.node), intersection.node.id);
        }