public static VertexFindResults Reject() { VertexFindResults vfr = new VertexFindResults(); vfr.ToUse = null; vfr.EndRoad = true; return(vfr); }
public static VertexFindResults Accept(Vertex toUse, bool endRoad) { VertexFindResults vfr = new VertexFindResults(); vfr.ToUse = toUse; vfr.EndRoad = endRoad; return(vfr); }
/// <summary> /// Creates a new road from the given starting point along the given axis. /// Takes care of adding the vertices and segments to their respective BVH. /// </summary> private Road Trace(Vertex start, bool useMajorAxis, int dir) { float stepInterval = RoadStepInterval * (float)dir; //Step along the road in increments to build up the segments defining it. Vector2 currentPos = start.Pos; Vector2 currentVel = (float)dir * (useMajorAxis ? GetBasis(start).Major : GetBasis(start).Minor); Road r = new Road(); r.Points.Add(start); start.ConnectTo(r); bool keepGoing = true; Vertex newVert = start; while (keepGoing) { //Get the next vertex along the road. Vector2 nextPos = GetNext(newVert, stepInterval, currentVel, useMajorAxis); VertexFindResults vfr = FindOrMakeVertex(r, nextPos); newVert = vfr.ToUse; if (newVert != null) { newVert.ConnectTo(r); r.Points.Add(newVert); Segments.Add(new Segment(r.Points[r.Points.Count - 2], newVert, r)); nextPos = newVert.Pos; } currentVel = nextPos - currentPos; currentPos = nextPos; keepGoing = !vfr.EndRoad; } //If the road is a dud, exit. if (r.Points.Count < 2) { foreach (Vertex v in r.Points) { v.DisconnectFrom(r); } return(null); } //Finalize the road's data and return it. r.UpdateBoundingBox(); return(r); }
/// <summary> /// Given a road and a new position to add to the road, /// gets or creates a vertex to add to the road. /// The vertex will always already be added to the vertex BVH. /// If the returned vertex is null, it shouldn't be added to the road. /// If "EndRoad" is true, the road should not continue on. /// </summary> private VertexFindResults FindOrMakeVertex(Road r, Vector2 nextPos) { Vertex lastPoint = r.Points[r.Points.Count - 1]; //Reject if the segment length is too short or its position is outside the city limits. if (lastPoint.Pos.DistSqr(nextPos) <= (SegmentMinLength * SegmentMinLength) || !IsInBounds(nextPos)) { return(VertexFindResults.Reject()); } //If the next position is near another vertex, use that vertex and end the road there. foreach (Vertex v in Vertices.GetAllNearbyPos(nextPos)) { //Don't let the road loop back onto itself. if (v.RoadsConnectedTo.Contains(r)) { continue; } //Don't create a segment that already exists. if (v.VertsConnectedTo.Contains(lastPoint)) { return(VertexFindResults.Reject()); } v.ConnectTo(lastPoint); return(VertexFindResults.Accept(v, true)); } Rect segBnds = new Rect().BoundByPoints(nextPos, lastPoint.Pos); //If the segment intersects another segment, turn it into an intersection and continue. List <Segment> segs = Segments.GetAllNearbyBnds(segBnds).ToList(); float t1 = float.NaN, t2 = float.NaN; Segment?hitSeg = null; //Get any intersected segments. //If we intersect with a previous part of this road, reject. for (int i = 0; i < segs.Count; ++i) { float temp1 = float.NaN, temp2 = float.NaN; bool intersects = GeneratorUtils.SegmentsIntersect(lastPoint.Pos, nextPos, segs[i].P1.Pos, segs[i].P2.Pos, ref temp1, ref temp2); if (segs[i].Owner == r || segs[i].P1.RoadsConnectedTo.Contains(r) || segs[i].P2.RoadsConnectedTo.Contains(r)) { if (intersects) { return(VertexFindResults.Reject()); } } else if (intersects) { t1 = temp1; t2 = temp2; hitSeg = segs[i]; } } if (hitSeg.HasValue) { //Split up the road that the segment is a part of // by adding a new vertex at the intersection. Vertex vtx = new Vertex(hitSeg.Value.P1.Pos + ((hitSeg.Value.P2.Pos - hitSeg.Value.P1.Pos) * t2)); vtx.ConnectTo(lastPoint); Vertices.Add(vtx); SplitSegment(vtx, hitSeg.Value); return(VertexFindResults.Accept(vtx, false)); } //This segment isn't special in any way. Vertex vert = new Vertex(nextPos); vert.ConnectTo(lastPoint); Vertices.Add(vert); return(VertexFindResults.Accept(vert, false)); }