protected List <SubdividableEdgeLoop <EdgeType> > CollectChildren(SubdividableEdgeLoop <EdgeType> parent, List <DividingEdge> dividingEdges) { List <EdgeType[]> formedChildLoops = CollectChildLoops(parent, dividingEdges); List <SubdividableEdgeLoop <EdgeType> > children = new List <SubdividableEdgeLoop <EdgeType> >(); foreach (EdgeType[] childLoop in formedChildLoops) { children.Add(parent.GetNextChild(childLoop)); } return(children); }
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)); }
private void GetPlotsRecursive(SubdividableEdgeLoop <CityEdge> some, List <Plot> storage) { if (some is Plot) { storage.Add((Plot)some); } else { SubdividableEdgeLoop <CityEdge>[] children = some.GetChildren(); foreach (SubdividableEdgeLoop <CityEdge> child in children) { GetPlotsRecursive(child, storage); } } }
public override List <SubdividableEdgeLoop <EdgeType> > GetChildren(SubdividableEdgeLoop <EdgeType> parent) { Polygon parentPoly = new Polygon(parent.GetSimplifiedPoints(1f * Mathf.Deg2Rad)); //build a list of dividing edges and pass it to the child collector List <DividingEdge> dividingEdges = new List <DividingEdge>(); Vector2 center = parentPoly.centroid; float width = parentPoly.bounds.width; Vector2 a = center + Vector2.right * width; Vector2 b = center - Vector2.right * width; dividingEdges.Add(new DividingEdge(a, b, factory, factoryParams)); return(CollectChildren(parent, dividingEdges)); }
public override List <SubdividableEdgeLoop <EdgeType> > GetChildren(SubdividableEdgeLoop <EdgeType> parent) { Vector2[] simplifiedPoints = parent.GetSimplifiedPoints(1f * Mathf.Deg2Rad); Polygon parentPoly = new Polygon(simplifiedPoints); Vector2 centroid = parentPoly.centroid; float centroidDistance = parent.DistToPerimeter(centroid); float circleRadius = centroidDistance / 2f; int circleResolution = Random.Range(3, 8); int numRays = Mathf.CeilToInt(circleResolution / 3f); Vector2[] circlePoints = new Vector2[circleResolution]; for (int i = 0; i < circleResolution; i++) { float angle = (i / (float)circleResolution) * Mathf.PI * 2; circlePoints[i] = centroid + new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)) * circleRadius; } //build a list of dividing edges and pass it to the child collector List <DividingEdge> dividingEdges = new List <DividingEdge>(); for (int i = 0; i < circleResolution; i++) { dividingEdges.Add(new DividingEdge(circlePoints[i], circlePoints[(i + 1) % circleResolution], factory, factoryParams)); //if (i % numRays == 0) //{ Vector2 extended = (circlePoints[i] - centroid) * 100f + centroid; dividingEdges.Add(new DividingEdge(circlePoints[i], extended, factory, factoryParams)); //} } return(CollectChildren(parent, dividingEdges)); }
public override List <SubdividableEdgeLoop <EdgeType> > GetChildren(SubdividableEdgeLoop <EdgeType> parent) { Vector2[] simplifiedPoints = parent.GetSimplifiedPoints(1f * Mathf.Deg2Rad); Polygon parentPoly = new Polygon(simplifiedPoints); Vector2 centroid = parentPoly.centroid; List <Vector2> edgeCrossings = new List <Vector2>(); parentPoly.EnumerateEdges((Edge edge) => { Vector2 edgeCrossing = HelperFunctions.ScaleFrom(Vector2.Lerp(edge.a, edge.b, Random.Range(0.4f, 0.6f)), centroid, 1.5f); edgeCrossings.Add(edgeCrossing); //points.Add(HelperFunctions.ScaleFrom(edgeCrossing, centroid, 5)); }); //build a list of dividing edges and pass it to the child collector List <DividingEdge> dividingEdges = new List <DividingEdge>(); foreach (Vector2 crossing in edgeCrossings) { dividingEdges.Add(new DividingEdge(crossing, centroid, factory, factoryParams)); } return(CollectChildren(parent, dividingEdges)); }
protected List <EdgeType[]> CollectChildLoops(SubdividableEdgeLoop <EdgeType> parent, List <DividingEdge> dividingEdges) { List <EdgeType> knownEdges = new List <EdgeType>(parent.GetEdgesEnumerable()); Polygon parentPoly = parent.GetPolygon(); Path polygonAsClip = parentPoly.ClipperPath(HelperFunctions.clipperScale); Vector2[] parentPoints = parent.GetPoints(); //kinda ugly, these two variables are implicitly paired together Paths edgePaths = new Paths(); List <ILinkedGraphEdgeFactory <EdgeType> > edgePathFactories = new List <ILinkedGraphEdgeFactory <EdgeType> >(); List <System.Object[]> edgePathFactoriesParams = new List <System.Object[]>(); foreach (DividingEdge edge in dividingEdges) { Path edgePath = new Path(); edgePath.Add(HelperFunctions.GetIntPoint(edge.p1)); edgePath.Add(HelperFunctions.GetIntPoint(edge.p2)); PolyTree clippedResults = new PolyTree(); Clipper clipper = new Clipper(); clipper.AddPath(edgePath, PolyType.ptSubject, false); clipper.AddPath(polygonAsClip, PolyType.ptClip, true); clipper.Execute(ClipType.ctIntersection, clippedResults); Paths subPaths = Clipper.OpenPathsFromPolyTree(clippedResults); edgePaths.AddRange(subPaths); //if this edge was split into multiple paths when intersecting with parent poly, note that each subpath has the same factory foreach (Path path in subPaths) { edgePathFactories.Add(edge.factory); edgePathFactoriesParams.Add(edge.factoryParams); } } DebugLines debug = GameObject.FindObjectOfType <DebugLines>(); int totalAddedEdges = 0; for (int j = 0; j < edgePaths.Count; j++) { Path edgePath = edgePaths[j]; ILinkedGraphEdgeFactory <EdgeType> edgeFactory = edgePathFactories[j]; System.Object[] edgeParams = edgePathFactoriesParams[j]; //this is almost always just 2 elements in which case it runs once for (int i = 0; i < edgePath.Count - 1; i++) { //convert path back into regular coordinates. Watch out that there is high enough resolution //that when this conversion happens, the linkedGraph still thinks points/edges are adjacent and connects them Vector2 p1 = HelperFunctions.GetPoint(edgePath[i]); Vector2 p2 = HelperFunctions.GetPoint(edgePath[i + 1]); LinkedGraph <EdgeType> .ConnectNewEdge(p1, p2, edgeFactory, edgeParams, knownEdges); totalAddedEdges++; } } List <EdgeType[]> formedChildLoops = parent.GetInteriorEdgeLoops(); if (formedChildLoops.Count == 0) { Debug.Log("No Children " + parent.GetHashCode()); } return(formedChildLoops); }
public abstract List <SubdividableEdgeLoop <EdgeType> > GetChildren(SubdividableEdgeLoop <EdgeType> parent);
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> >()); }