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, 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); }
public TRoadSegment(Vector3 position, RoadSegmentEndPoint top, RoadSegmentEndPoint right, RoadSegmentEndPoint bottom) { Position = position; Top = top; Right = right; Bottom = bottom; }
public XRoadSegment( RoadSegmentEndPoint left, RoadSegmentEndPoint top, RoadSegmentEndPoint right, RoadSegmentEndPoint bottom) { Left = left; Top = top; Right = right; Bottom = bottom; }
protected override Vector3 ToCorner(RoadSegmentEndPoint neighbor, bool atEnd) { var curve = Segment as CurvedRoadSegment; if (atEnd) { return(0.5f * (curve.TopRight - curve.BottomRight)); } else { return(0.5f * (curve.TopLeft - curve.BottomLeft)); } }
protected override Vector3 ToCorner(RoadSegmentEndPoint neighbor, bool atEnd) { var neighborNormal = GetNeighborNormal(neighbor, atEnd); var segment = (StraightRoadSegment)Segment; var oppositeNeighbor = atEnd ? segment.Start.To : segment.End.To; var toCornerDirection = neighbor.To switch { null when oppositeNeighbor is CrossingRoadSegment crossing => // special handling to reproduce (somewhat strange) behavior of the original engine OriginalNormal(crossing.Position), null => // if I have no neighbor, use my own normal DirectionNormalNoZ, StraightRoadSegment _ => // if my neighbor is also a straight road segment, meet in the middle Vector3.Normalize(DirectionNormalNoZ + neighborNormal), _ => neighborNormal, // otherwise use my unflexible neighbor's normal }; Vector3 OriginalNormal(Vector3 crossingPosition) { var originalDirection = atEnd ? segment.EndPosition - crossingPosition : crossingPosition - segment.StartPosition; var originalDirectionNoZ = Vector3.Normalize(originalDirection.WithZ(0)); return(Vector3.Cross(originalDirectionNoZ, Vector3.UnitZ)); } // This shouldn't happen but sometimes does in broken maps (Heartland Shield for example). var toCornerLengthSquared = toCornerDirection.LengthSquared(); if (float.IsNaN(toCornerLengthSquared) || toCornerLengthSquared < 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 curve or 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 StraightRoadSegment ? HalfHeight / cosine : HalfHeight; return(toCornerDirection * toCornerLength); }
/// <summary> /// Generate vector from the start/end position of an edge to the corner of the mesh's base geometry /// </summary> /// <param name="neighbor"></param> /// <param name="atEnd"></param> /// <returns></returns> private Vector3 ToCorner(RoadSegmentEndPoint neighbor, bool atEnd) { var neighborDirection = (atEnd ? -1 : 1) * neighbor?.IncomingDirection ?? Vector3.Zero; var neighborNormal = Vector3.Cross(Vector3.Normalize(neighborDirection.WithZ(0)), Vector3.UnitZ); 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, use its normal _ => (DirectionNormalNoZ + neighborNormal) / 2, // otherwise, meet in the middle }; // 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); }
/// <summary> /// Generate vector from the start/end position of an edge to the corner of the mesh's base geometry /// </summary> /// <param name="neighbor"></param> /// <param name="atEnd"></param> /// <returns></returns> protected abstract Vector3 ToCorner(RoadSegmentEndPoint neighbor, bool atEnd);
//helper method used by crossings and curves protected Vector3 GetNeighborNormal(RoadSegmentEndPoint neighbor, bool atEnd) { var neighborDirection = (atEnd ? -1 : 1) * neighbor?.IncomingDirection ?? Vector3.Zero; return(Vector3.Cross(Vector3.Normalize(neighborDirection.WithZ(0)), Vector3.UnitZ)); }
public IncomingRoadData( RoadTopologyEdge topologyEdge, RoadSegmentEndPoint targetEndPoint, in Vector3 outDirection,