//entry point of all generation. We excecute passes until all children are generated public static City GenerateCity(float radius) { CityEdgeFactory factory = new CityEdgeFactory(); CityEdge[] edges = GetPolygonEdges(20, radius, radius / 2, 70f, factory, new System.Object[] { CityEdgeType.Wall, 5.55f }); City city = new City(edges); double startTime = Time.realtimeSinceStartup; int pass = 0; bool allGenerated = false; //after pass1, generate clipping for roads while (!allGenerated) { allGenerated = city.TryGenerateRecursive(pass); if (!allGenerated) { pass++; } //switch (pass) //{ // case (1): // List<CityEdge> allEdges = city.GetAllEdges(); // foreach (CityEdge edge in allEdges) // { // //edge.width = Random.value + 1.5f; // BoundaryBuilder builder = new BoundaryBuilder(edge, city, null); // builder.PlaceBoundary(); // } // break; // case (2): // break; //} if (pass > MAXPASSES) { Debug.LogError("Too many passes. Failing."); return(city); } } Debug.Log("Finished generating in " + (Time.realtimeSinceStartup - startTime) + " seconds using " + (pass + 1) + " passes."); Debug.Log("City is verified (" + city.VerifyRecursive() + ")"); return(city); }
public override List <SubdividableEdgeLoop <CityEdge> > GetChildren(SubdividableEdgeLoop <CityEdge> parent) { Polygon parentPoly = parent.GetPolygon(); Path polygonAsClip = parentPoly.ClipperPath(HelperFunctions.clipperScale); EdgeLoopEdge[] edges = parent.GetEdges(); EdgeLoopEdge longestEdge = edges[0]; float longestEdgeLength = 0; parent.EnumerateEdges((EdgeLoopEdge edge) => { float edgeLength = Vector2.Distance(edge.a.pt, edge.b.pt); if (edgeLength > longestEdgeLength) { longestEdgeLength = edgeLength; longestEdge = edge; } }); Vector2 edgeDirection = longestEdge.b.pt - longestEdge.a.pt; float angle = Mathf.Atan2(edgeDirection.y, edgeDirection.x) * Mathf.Rad2Deg; Rect bounds = parentPoly.bounds; float maxDimension = Mathf.Max(bounds.width, bounds.height); bounds.width = maxDimension; bounds.height = maxDimension; Rect expandedBounds = new Rect(bounds.center - bounds.size * 0.55f, bounds.size * 1.1f); ILinkedGraphEdgeFactory <CityEdge> factory = new CityEdgeFactory(); List <DividingEdge> edgePaths = new List <DividingEdge>(); Vector2 centroid = parentPoly.centroid; float relativeBoundAngle = 0f; Rect parentRotatedBounds = HelperFunctions.GetOrientedBounds(new List <Vector2>(parentPoly.points), ref relativeBoundAngle); float rotation = relativeBoundAngle * Mathf.Rad2Deg; if (parentRotatedBounds.width > parentRotatedBounds.height * 0.7f) { //edgePaths.Add(new DividingEdge((centroid - Vector2.right * 1000f).RotatedAround(centroid, rotation), (centroid + Vector2.right * 1000f).RotatedAround(centroid, rotation), factory, factoryParams)); edgePaths.Add(new DividingEdge((centroid - Vector2.up * 1000f).RotatedAround(centroid, rotation), (centroid + Vector2.up * 1000f).RotatedAround(centroid, rotation), factory, factoryParams)); } if (parentRotatedBounds.height > parentRotatedBounds.width * 0.7f) { //edgePaths.Add(new DividingEdge((centroid - Vector2.up * 1000f).RotatedAround(centroid, rotation), (centroid + Vector2.up * 1000f).RotatedAround(centroid, rotation), factory, factoryParams)); edgePaths.Add(new DividingEdge((centroid - Vector2.right * 1000f).RotatedAround(centroid, rotation), (centroid + Vector2.right * 1000f).RotatedAround(centroid, rotation), factory, factoryParams)); } return(CollectChildren(parent, edgePaths)); }
//Cities always subdivide with citySkeleton //this function could randomize what subdivscheme is returned easily public override ISubDivScheme <SubdividableEdgeLoop <CityEdge> > GetDivScheme() { CityEdgeFactory factory = new CityEdgeFactory(); System.Object[] factoryParams = CityEdge.GetRoadFactoryParams(depth); if (Random.value > 0.4 || GetPolygon().area < City.MINSUBDIVAREA * 2f) { return(new GetBlocks(factoryParams)); } else { return(new CircularCenter <CityEdge>(factory, factoryParams)); } }
public override List <SubdividableEdgeLoop <CityEdge> > GetChildren(SubdividableEdgeLoop <CityEdge> parent) { Vector2[] parentPoints = parent.GetPoints(); Polygon parentPoly = parent.GetPolygon(); //generate points of interest List <RoadDestination> pointsOfInterest = new List <RoadDestination>(); Vector2 centroid = parent.GetCenter(); //parent.EnumerateEdges((EdgeLoopEdge edge) => //{ // pointsOfInterest.Add(new RoadDestination(Vector2.Lerp(edge.a.pt, edge.b.pt, Random.Range(0.2f, 0.8f)), 1, false, true)); //}); Rect bounds = parent.GetBounds(); bounds.width = bounds.width * 2; bounds.height = bounds.height * 2; int potentialRoadPointsRt = Mathf.CeilToInt(Mathf.Sqrt(potentialRoadPoints)); float approxDiameter = Mathf.Sqrt(parentPoly.area); float minimumPerimeterDistance = approxDiameter / 4f; for (int x = 0; x < potentialRoadPointsRt; x++) { for (int y = 0; y < potentialRoadPointsRt; y++) { Vector2 point = new Vector2((x / (float)potentialRoadPointsRt) * bounds.width + bounds.xMin, (y / (float)potentialRoadPointsRt) * bounds.height + bounds.yMin); float distBtwnPts = (bounds.width + bounds.height) / (potentialRoadPoints * 2); point = point + new Vector2(Random.Range(-1f, 1f), Random.Range(-1, 1f)) * distBtwnPts * 3f; if (parentPoly.ContainsPoint(point)) // && parent.DistToPerimeter(point) > minimumPerimeterDistance) { pointsOfInterest.Add(new RoadDestination(point, 0, false, false)); } } } pointsOfInterest.Add(new RoadDestination(bounds.center + new Vector2(bounds.width * 100, bounds.height * 100), 0, false, false)); pointsOfInterest.Add(new RoadDestination(bounds.center + new Vector2(bounds.width * 100, -bounds.height * 100), 0, false, false)); pointsOfInterest.Add(new RoadDestination(bounds.center + new Vector2(-bounds.width * 100, -bounds.height * 100), 0, false, false)); pointsOfInterest.Add(new RoadDestination(bounds.center + new Vector2(-bounds.width * 100, bounds.height * 100), 0, false, false)); //triangulate points of interest to get potential road segments TriangleNet.Geometry.Polygon polygon = new TriangleNet.Geometry.Polygon(); Dictionary <TriangleNet.Geometry.Vertex, RoadDestination> vertexDestMap = new Dictionary <TriangleNet.Geometry.Vertex, RoadDestination>(); foreach (RoadDestination dest in pointsOfInterest) { TriangleNet.Geometry.Vertex vert = new TriangleNet.Geometry.Vertex(dest.point.x, dest.point.y); vertexDestMap.Add(vert, dest); polygon.Add(vert); } TriangleNet.Meshing.ConstraintOptions options = new TriangleNet.Meshing.ConstraintOptions() { ConformingDelaunay = true }; TriangleNet.Meshing.GenericMesher mesher = new TriangleNet.Meshing.GenericMesher(); TriangleNet.Meshing.IMesh mesh = mesher.Triangulate(polygon); TriangleNet.Voronoi.StandardVoronoi voronoi = new TriangleNet.Voronoi.StandardVoronoi((TriangleNet.Mesh)mesh); IEnumerable <TriangleNet.Geometry.IEdge> voronoiEdges = voronoi.Edges; List <TriangleNet.Topology.DCEL.Vertex> voronoiVerts = voronoi.Vertices; List <DividingEdge> dividingEdges = new List <DividingEdge>(); ILinkedGraphEdgeFactory <CityEdge> factory = new CityEdgeFactory(); foreach (TriangleNet.Geometry.IEdge edge in voronoiEdges) { Vector2 a = new Vector2((float)voronoiVerts[edge.P0].X, (float)voronoiVerts[edge.P0].Y); Vector2 b = new Vector2((float)voronoiVerts[edge.P1].X, (float)voronoiVerts[edge.P1].Y); dividingEdges.Add(new DividingEdge(a, b, factory, factoryParams)); } //get vertices as list //ICollection<TriangleNet.Geometry.Vertex> vertices = mesh.Vertices; //TriangleNet.Geometry.Vertex[] vertexList = new TriangleNet.Geometry.Vertex[vertices.Count]; //vertices.CopyTo(vertexList, 0); //IEnumerable<TriangleNet.Geometry.Edge> meshEdges = mesh.Edges; //build a list of dividing edges and pass it to the child collector //foreach (TriangleNet.Geometry.Edge edge in meshEdges) { // //if (vertConnections[edge.P0] > 4) // //{ // // vertConnections[edge.P0]--; // // continue; // //} // //if (vertConnections[edge.P1] > 4) // //{ // // vertConnections[edge.P1]--; // // continue; // //} // Vector2 a = new Vector2((float)vertexList[edge.P0].X, (float)vertexList[edge.P0].Y); // Vector2 b = new Vector2((float)vertexList[edge.P1].X, (float)vertexList[edge.P1].Y); // dividingEdges.Add(new DividingEdge(a, b, factory, CityEdgeType.LandPath)); //} return(CollectChildren(parent, dividingEdges)); }
public override List <SubdividableEdgeLoop <CityEdge> > GetChildren(SubdividableEdgeLoop <CityEdge> parent) { Polygon parentPoly = parent.GetPolygon(); Path polygonAsClip = parentPoly.ClipperPath(HelperFunctions.clipperScale); CityEdge[] edges = parent.GetEdges(); //------------------------------------------ OLD BAD STUFF //Paths edgePaths = new Paths(); //Paths expandedLine = new Paths(); //float width = 2f; //ClipperOffset clipperOffset = new ClipperOffset(); //clipperOffset.AddPath(polygonAsClip, JoinType.jtSquare, EndType.etClosedPolygon); //clipperOffset.Execute(ref expandedLine, HelperFunctions.clipperScale * (-width / 2)); //if (expandedLine.Count > 0) //{ // Path shrunkPoly = expandedLine[0]; // LinkedGraphVertex[] subPlotVerts = new LinkedGraphVertex[shrunkPoly.Count]; // for (int i = 0; i < shrunkPoly.Count; i++) // { // subPlotVerts[i] = new LinkedGraphVertex(HelperFunctions.GetPoint(shrunkPoly[i])); // } // CityEdge[] subPlotEdges = new CityEdge[shrunkPoly.Count]; // for (int i = 0; i < shrunkPoly.Count; i++) // { // subPlotEdges[i] = new CityEdge(subPlotVerts[i], subPlotVerts[(i + 1) % shrunkPoly.Count], CityEdgeType.PlotBoundary, 0f); // } // SubdividableEdgeLoop<CityEdge> plot = parent.GetNextChild(subPlotEdges); // Polygon plotPoly = parent.GetPolygon(); // return new List<SubdividableEdgeLoop<CityEdge>> { plot }; //} //return new List<SubdividableEdgeLoop<CityEdge>>(); //--------------------------------------------------------------------------- OLD BAD STUFF END bool shapeRemains = true; //int uniqueEdgeStartEdge = -1; //for (int i = 0; i < edges.Length; i ++) //{ // if (!edges[(i+1)%edges.Length].GetID().Equals(edges[i].GetID())) // { // uniqueEdgeStartEdge = (i + 1) % edges.Length; // break; // } //} //LinkedGraphVertex anchorVert = edges[uniqueEdgeStartEdge].GetOppositeVertex(edges[uniqueEdgeStartEdge].GetSharedVertex(edges[(uniqueEdgeStartEdge+1)%edges.Length])); //LinkedGraphVertex previusVert = null; for (int j = 0; j < edges.Length; j++) { CityEdge edge = edges[j]; //int nextIndex = (j + uniqueEdgeStartEdge + 1) % edges.Length; //LinkedGraphVertex thisVert = edge.GetOppositeVertex() Path edgeLine = new Path(); edgeLine.Add(HelperFunctions.GetIntPoint(edge.a.pt)); edgeLine.Add(HelperFunctions.GetIntPoint(edge.b.pt)); Paths expandedLine = new Paths(); float width = edge.GetWidth() * HelperFunctions.clipperScale; ClipperOffset clipperOffset = new ClipperOffset(); clipperOffset.AddPath(edgeLine, JoinType.jtMiter, EndType.etOpenSquare); clipperOffset.Execute(ref expandedLine, width / 2); //since we only expand a single line, we should only have one path left Paths differenceSolution = new Paths(); Clipper clipper = new Clipper(); clipper.AddPath(polygonAsClip, PolyType.ptSubject, true); clipper.AddPath(expandedLine[0], PolyType.ptClip, true); clipper.Execute(ClipType.ctDifference, differenceSolution); //Debug.Log("diff sol count: " + differenceSolution.Count); if (differenceSolution.Count == 0) { shapeRemains = false; break; } else { Path maxAreaPath = null; float maxArea = 0f; foreach (Path path in differenceSolution) { Vector2[] points = new Vector2[path.Count]; int i = 0; foreach (IntPoint p in path) { points[i] = HelperFunctions.GetPoint(p); i++; } Polygon testPoly = new Polygon(points); if (testPoly.area > maxArea) { maxArea = testPoly.area; maxAreaPath = path; } } polygonAsClip = maxAreaPath; if (maxAreaPath == null) { shapeRemains = false; break; } } } if (shapeRemains) { for (int i = polygonAsClip.Count - 1; i >= 0; i--) { for (int j = 0; j < i; j++) { if (polygonAsClip[i].X == polygonAsClip[j].X && polygonAsClip[i].Y == polygonAsClip[j].Y) { polygonAsClip.RemoveAt(i); Debug.Log("removed dup of interior plot"); } } } } Vector2[] parentPoints = parent.GetPoints(); ILinkedGraphEdgeFactory <CityEdge> factory = new CityEdgeFactory(); System.Object[] roadCapBoundarySettings = new System.Object[] { CityEdgeType.EdgeCap, 0f }; System.Object[] plotBoundarySettings = new System.Object[] { CityEdgeType.PlotBoundary, 0f }; if (shapeRemains && polygonAsClip.Count > 0) { List <DividingEdge> dividingEdges = new List <DividingEdge>(); Vector2[] subPlotVerts = new Vector2[polygonAsClip.Count]; for (int i = 0; i < polygonAsClip.Count; i++) { subPlotVerts[i] = HelperFunctions.GetPoint(polygonAsClip[i]); } List <CityEdge> knownEdges = new List <CityEdge>(parent.GetEdgesEnumerable()); for (int i = 0; i < parentPoints.Length; i++) { float closestVertDistance = float.MaxValue; int closestVertIndex = -1; for (int j = 0; j < subPlotVerts.Length; j++) { float thisDist = (parentPoints[i] - subPlotVerts[j]).sqrMagnitude; if (thisDist < closestVertDistance) { closestVertDistance = thisDist; closestVertIndex = j; } } dividingEdges.Add(new DividingEdge(parentPoints[i], subPlotVerts[closestVertIndex], factory, roadCapBoundarySettings)); } for (int i = 0; i < subPlotVerts.Length; i++) { dividingEdges.Add(new DividingEdge(subPlotVerts[i], subPlotVerts[(i + 1) % subPlotVerts.Length], factory, plotBoundarySettings)); } List <CityEdge[]> formedChildRegions = CollectChildLoops(parent, dividingEdges); List <SubdividableEdgeLoop <CityEdge> > children = new List <SubdividableEdgeLoop <CityEdge> >(); for (int i = 0; i < formedChildRegions.Count; i++) { CityEdge[] loop = formedChildRegions[i]; bool allPlotBoundaries = true; for (int j = 0; j < loop.Length; j++) { if (loop[j].GetRoadType() != CityEdgeType.PlotBoundary) { allPlotBoundaries = false; } } if (allPlotBoundaries) { children.Add(parent.GetNextChild(loop)); } else { children.Add(new Road(loop, city)); } } return(children); //return new List<SubdividableEdgeLoop<CityEdge>>(); } return(new List <SubdividableEdgeLoop <CityEdge> >()); }