private static void InsertEndCapSegments(IReadOnlyDictionary <RoadTopologyEdge, StraightRoadSegment> edgeSegments, RoadTemplateList roadTemplateList) { foreach (var edge in edgeSegments.Reverse()) { // the end cap flag is only relevant when the edge is not connected to another edge on this end bool hasEndCapAtStart = edge.Key.StartType.HasFlag(RoadType.EndCap) && edge.Value.Start.To == null; bool hasEndCapAtEnd = edge.Key.EndType.HasFlag(RoadType.EndCap) && edge.Value.End.To == null; // single edges without any connected edges can only have one end cap (at the end position), even when the flag is present at both nodes if (hasEndCapAtEnd) { EndCapRoadSegment.CreateEndCap( GetIncomingRoadData(edge.Key.End, edge.Key, edgeSegments[edge.Key]), edge.Value.EndPosition, edge.Key.Template, edgeSegments, roadTemplateList); } else if (hasEndCapAtStart) { EndCapRoadSegment.CreateEndCap( GetIncomingRoadData(edge.Key.Start, edge.Key, edgeSegments[edge.Key]), edge.Value.StartPosition, edge.Key.Template, edgeSegments, roadTemplateList); } } }
protected override Vector3 ToCorner(RoadSegmentEndPoint neighbor, bool atEnd) { var neighborNormal = GetNeighborNormal(neighbor, atEnd); var toCornerDirection = neighbor.To switch { null => DirectionNormalNoZ, // if I have no neighbor, use my own normal CrossingRoadSegment _ => neighborNormal, // if my neighbor is an unflexible crossing EndCapRoadSegment _ => neighborNormal, // or end cap, use its normal _ => Vector3.Normalize(DirectionNormalNoZ + neighborNormal) / 2, // otherwise, meet in the middle }; // This shouldn't happen but sometimes does in broken maps (Heartland Shield for example). if (toCornerDirection.LengthSquared() < 0.1f) { toCornerDirection = DirectionNormalNoZ; } // When two road segments meet in an angled curve, their meeting edge is tilted and thus longer than the width of the road // -> divide by cosine // For straight roads ending in a crossing: // -> the angles in the crossing texture may not well match the actual angles of the incoming roads // (especially for x-crossings, since there's only one texture for 4-road crossings which assumes 90° everywhere) // -> the meeting edge may become quite tilted and noticeably longer than road width, // while the road shown in the texture of the crossing always has the fixed road width // -> to avoid visible breaks between the road segment and the crossing texture, distort the edge so its tilted seam is 'roadwidth' long var cosine = Vector3.Dot(DirectionNormalNoZ, toCornerDirection); var toCornerLength = neighbor.To is CrossingRoadSegment ? HalfHeight : HalfHeight / cosine; return(toCornerDirection * toCornerLength); }