// 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); }