Пример #1
0
    //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);
    }
Пример #2
0
    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));
    }
Пример #3
0
    //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));
        }
    }
Пример #4
0
    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));
    }
Пример #5
0
    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> >());
    }