Example #1
0
    private void subdivide(Vector2 A, Vector2 B, Vector2 C, Vector2 D, List <Vector2> points, float minLength)
    {
        if (Vector2.Distance(A, C) < minLength || Vector2.Distance(B, D) < minLength)
        {
            return;
        }

        // Subdivide the quadrilateral
        float p = Random.Range(0.2f, 0.8f); // vertical (along A-D and B-C)
        float q = Random.Range(0.2f, 0.8f); // horizontal (along A-B and D-C)

        // Midpoints
        Vector2 E = Vector2Extensions.Interpolate(A, D, p);
        Vector2 F = Vector2Extensions.Interpolate(B, C, p);
        Vector2 G = Vector2Extensions.Interpolate(A, B, q);
        Vector2 I = Vector2Extensions.Interpolate(D, C, q);

        // Central point
        Vector2 H = Vector2Extensions.Interpolate(E, F, q);

        // Divide the quad into subquads, but meet at H
        float s = 1 - Random.Range(-0.4f, 0.4f);
        float t = 1 - Random.Range(-0.4f, 0.4f);

        subdivide(A, Vector2Extensions.Interpolate(G, B, s), H, Vector2Extensions.Interpolate(E, D, t), points,
                  minLength);
        points.Add(H);
        subdivide(H, Vector2Extensions.Interpolate(F, C, s), C, Vector2Extensions.Interpolate(I, D, t), points,
                  minLength);
    }
Example #2
0
    // Build noisy line paths for each of the Voronoi edges. There are
    // two noisy line paths for each edge, each covering half the
    // distance: path0 is from v0 to the midpoint and path1 is from v1
    // to the midpoint. When drawing the polygons, one or the other
    // must be drawn in reverse order.
    public void BuildNoisyEdges(Map map)
    {
        foreach (Center p in map.Graph.centers)
        {
            foreach (Edge edge in p.borders)
            {
                if (edge.d0 != null && edge.d1 != null && edge.v0 != null && edge.v1 != null &&
                    !path0.ContainsKey(edge.index))
                {
                    float   f = NOISY_LINE_TRADEOFF;
                    Vector2 t = Vector2Extensions.Interpolate(edge.v0.point, edge.d0.point, f);
                    Vector2 q = Vector2Extensions.Interpolate(edge.v0.point, edge.d1.point, f);
                    Vector2 r = Vector2Extensions.Interpolate(edge.v1.point, edge.d0.point, f);
                    Vector2 s = Vector2Extensions.Interpolate(edge.v1.point, edge.d1.point, f);

                    float minLength = 10 * SizeScale;
                    if (edge.d0.biome != edge.d1.biome)
                    {
                        minLength = 3 * SizeScale;
                    }
                    if (edge.d0.ocean && edge.d1.ocean)
                    {
                        minLength = 100 * SizeScale;
                    }
                    if (edge.d0.coast || edge.d1.coast)
                    {
                        minLength = 1 * SizeScale;
                    }
                    if (edge.river > 0)
                    {
                        minLength = 1 * SizeScale;
                    }

                    path0[edge.index] = buildNoisyLineSegments(edge.v0.point, t, edge.midpoint, q, minLength);
                    path1[edge.index] = buildNoisyLineSegments(edge.v1.point, s, edge.midpoint, r, minLength);
                }
            }
        }
    }
Example #3
0
        private void BuildGraph(IEnumerable <Vector2> points, Delaunay.Voronoi voronoi)
        {
            // Build graph data structure in 'edges', 'centers', 'corners',
            // based on information in the Voronoi results: point.neighbors
            // will be a list of neighboring points of the same type (corner
            // or center); point.edges will be a list of edges that include
            // that point. Each edge connects to four points: the Voronoi edge
            // edge.{v0,v1} and its dual Delaunay triangle edge edge.{d0,d1}.
            // For boundary polygons, the Delaunay edge will have one null
            // point, and the Voronoi edge may be null.
            var libedges = voronoi.Edges();

            var centerLookup = new Dictionary <Vector2?, Center>();

            // Build Center objects for each of the points, and a lookup map
            // to find those Center objects again as we build the graph
            foreach (var point in points)
            {
                var p = new Center {
                    index = centers.Count, point = point
                };
                centers.Add(p);
                centerLookup[point] = p;
            }

            // Workaround for Voronoi lib bug: we need to call region()
            // before Edges or neighboringSites are available
            foreach (var p in centers)
            {
                voronoi.Region(p.point);
            }

            foreach (var libedge in libedges)
            {
                var dedge = libedge.DelaunayLine();
                var vedge = libedge.VoronoiEdge();

                // Fill the graph data. Make an Edge object corresponding to
                // the edge from the voronoi library.
                var edge = new Edge
                {
                    index = edges.Count,
                    river = 0,

                    // Edges point to corners. Edges point to centers.
                    v0 = MakeCorner(vedge.p0),
                    v1 = MakeCorner(vedge.p1),
                    d0 = centerLookup[dedge.p0],
                    d1 = centerLookup[dedge.p1]
                };
                if (vedge.p0.HasValue && vedge.p1.HasValue)
                {
                    edge.midpoint = Vector2Extensions.Interpolate(vedge.p0.Value, vedge.p1.Value, 0.5f);
                }

                edges.Add(edge);

                // Centers point to edges. Corners point to edges.
                if (edge.d0 != null)
                {
                    edge.d0.borders.Add(edge);
                }
                if (edge.d1 != null)
                {
                    edge.d1.borders.Add(edge);
                }
                if (edge.v0 != null)
                {
                    edge.v0.protrudes.Add(edge);
                }
                if (edge.v1 != null)
                {
                    edge.v1.protrudes.Add(edge);
                }

                // Centers point to centers.
                if (edge.d0 != null && edge.d1 != null)
                {
                    AddToCenterList(edge.d0.neighbors, edge.d1);
                    AddToCenterList(edge.d1.neighbors, edge.d0);
                }

                // Corners point to corners
                if (edge.v0 != null && edge.v1 != null)
                {
                    AddToCornerList(edge.v0.adjacent, edge.v1);
                    AddToCornerList(edge.v1.adjacent, edge.v0);
                }

                // Centers point to corners
                if (edge.d0 != null)
                {
                    AddToCornerList(edge.d0.corners, edge.v0);
                    AddToCornerList(edge.d0.corners, edge.v1);
                }
                if (edge.d1 != null)
                {
                    AddToCornerList(edge.d1.corners, edge.v0);
                    AddToCornerList(edge.d1.corners, edge.v1);
                }

                // Corners point to centers
                if (edge.v0 != null)
                {
                    AddToCenterList(edge.v0.touches, edge.d0);
                    AddToCenterList(edge.v0.touches, edge.d1);
                }
                if (edge.v1 != null)
                {
                    AddToCenterList(edge.v1.touches, edge.d0);
                    AddToCenterList(edge.v1.touches, edge.d1);
                }
            }

            // TODO: use edges to determine these
            var topLeft = centers.OrderBy(p => p.point.x + p.point.y).First();

            AddCorner(topLeft, 0, 0);

            var bottomRight = centers.OrderByDescending(p => p.point.x + p.point.y).First();

            AddCorner(bottomRight, Width, Height);

            var topRight = centers.OrderByDescending(p => Width - p.point.x + p.point.y).First();

            AddCorner(topRight, 0, Height);

            var bottomLeft = centers.OrderByDescending(p => p.point.x + Height - p.point.y).First();

            AddCorner(bottomLeft, Width, 0);

            // required for polygon fill
            foreach (var center in centers)
            {
                center.corners.Sort(ClockwiseComparison(center));
            }
        }