コード例 #1
0
    public static Mesh CreateVoronoiMesh(GK.VoronoiDiagram diagram)
    {
        Mesh mesh = new Mesh();

        Vector3[] vertices = new Vector3[diagram.Vertices.Count];
        Vector2[] uv       = new Vector2[diagram.Vertices.Count];
        int[]     indices  = new int[diagram.Edges.Count * 2];


        for (int i = 0; i < diagram.Vertices.Count; i++)
        {
            vertices[i] = diagram.Vertices[i];
            uv[i]       = diagram.Vertices[i];
        }

        int j = 0;

        for (int i = 0; i < diagram.Edges.Count; i++)
        {
            if (diagram.Edges[i].Type == GK.VoronoiDiagram.EdgeType.Segment)
            {
                indices[j]     = diagram.Edges[i].Vert0;
                indices[j + 1] = diagram.Edges[i].Vert1;

                j += 2;
            }
        }

        mesh.SetVertices(vertices);
        mesh.uv = uv;
        mesh.SetIndices(indices, MeshTopology.Lines, 0);

        return(mesh);
    }
コード例 #2
0
        /// <summary>
        /// Calculate a voronoi diagram and return it.
        /// </summary>
        public VoronoiDiagram CalculateDiagram(IList <Vector2> inputVertices)
        {
            VoronoiDiagram result = null;

            CalculateDiagram(inputVertices, ref result);
            return(result);
        }
コード例 #3
0
    // calcula o diagrama de voronoi                                                      link para a implementação utilizada: https://github.com/OskarSigvardsson/unity-delaunay
    // serve mais para ser usar a triangulação de delaunay do resultado do diagrama
    public void BuildVoronoi()
    {
        var points2d = Graham.GetPointVectorList();

        GK.VoronoiCalculator voronoiCalculator = new GK.VoronoiCalculator();
        Diagram = voronoiCalculator.CalculateDiagram(Graham.GetPointVectorList());

        //var extends = Map.GetComponent<MeshFilter>().mesh.bounds.size;
        //extends.Scale(Map.transform.localScale);

        VoronoiMesh = CreateVoronoiMesh(Diagram);


        BuildGraph();
    }
コード例 #4
0
    public static Mesh CreateTriangulationMesh(GK.VoronoiDiagram diagram, int[] indices)
    {
        Mesh mesh = new Mesh();

        Vector3[] vertices = new Vector3[diagram.Triangulation.Vertices.Count];
        Vector2[] uv       = new Vector2[diagram.Triangulation.Vertices.Count];



        for (int i = 0; i < diagram.Triangulation.Vertices.Count; i++)
        {
            vertices[i] = diagram.Triangulation.Vertices[i];
            uv[i]       = diagram.Triangulation.Vertices[i];
        }

        mesh.SetVertices(vertices);
        mesh.uv = uv;
        mesh.SetIndices(indices, MeshTopology.Lines, 0);

        return(mesh);
    }
コード例 #5
0
        /// <summary>
        /// Non-allocating version of CalculateDiagram.
        ///
        /// I guess it's not strictly true that it generates NO garbage, because
        /// it might if it has to resize internal buffers, but all buffers are
        /// reused from invocation to invocation.
        /// </summary>
        public void CalculateDiagram(IList <Vector2> inputVertices, ref VoronoiDiagram result)
        {
            // TODO: special case for 1 points
            // TODO: special case for 2 points
            // TODO: special case for 3 points
            // TODO: special case for collinear points
            if (inputVertices.Count < 3)
            {
                throw new NotImplementedException("Not implemented for < 3 vertices");
            }

            if (result == null)
            {
                result = new VoronoiDiagram();
            }

            var trig = result.Triangulation;

            result.Clear();

            Profiler.BeginSample("Delaunay triangulation");
            delCalc.CalculateTriangulation(inputVertices, ref trig);
            Profiler.EndSample();

            pts.Clear();

            var verts   = trig.Vertices;
            var tris    = trig.Triangles;
            var centers = result.Vertices;
            var edges   = result.Edges;


            if (tris.Count > pts.Capacity)
            {
                   {
                    pts.Capacity = tris.Count;
                }
            }
            if (tris.Count > edges.Capacity)
            {
                edges.Capacity = tris.Count;
            }


            for (int ti = 0; ti < tris.Count; ti += 3)
            {
                var p0 = verts[tris[ti]];
                var p1 = verts[tris[ti + 1]];
                var p2 = verts[tris[ti + 2]];

                // Triangle is in CCW order
                Debug.Assert(Geom.ToTheLeft(p2, p0, p1));

                centers.Add(Geom.CircumcircleCenter(p0, p1, p2));
            }


            for (int ti = 0; ti < tris.Count; ti += 3)
            {
                pts.Add(new PointTriangle(tris[ti], ti));
                pts.Add(new PointTriangle(tris[ti + 1], ti));
                pts.Add(new PointTriangle(tris[ti + 2], ti));
            }

            cmp.tris  = tris;
            cmp.verts = verts;

            Profiler.BeginSample("Sorting");
            pts.Sort(cmp);
            Profiler.EndSample();

            // The comparer lives on between runs of the algorithm, so clear the
            // reference to the arrays so that the reference is lost. It may be
            // the case that the calculator lives on much longer than the
            // results, and not clearing these would keep the results alive,
            // leaking memory.
            cmp.tris  = null;
            cmp.verts = null;

            for (int i = 0; i < pts.Count; i++)
            {
                result.FirstEdgeBySite.Add(edges.Count);

                var start = i;
                var end   = -1;

                for (int j = i + 1; j < pts.Count; j++)
                {
                    if (pts[i].Point != pts[j].Point)
                    {
                        end = j - 1;
                        break;
                    }
                }

                if (end == -1)
                {
                    end = pts.Count - 1;
                }

                i = end;

                var count = end - start;

                Debug.Assert(count >= 0);

                for (int ptiCurr = start; ptiCurr <= end; ptiCurr++)
                {
                    bool isEdge;

                    var ptiNext = ptiCurr + 1;

                    if (ptiNext > end)
                    {
                        ptiNext = start;
                    }

                    var ptCurr = pts[ptiCurr];
                    var ptNext = pts[ptiNext];

                    var tiCurr = ptCurr.Triangle;
                    var tiNext = ptNext.Triangle;

                    var p0 = verts[ptCurr.Point];

                    var v2nan = new Vector2(float.NaN, float.NaN);

                    if (count == 0)
                    {
                        isEdge = true;
                    }
                    else if (count == 1)
                    {
                        var cCurr = Geom.TriangleCentroid(verts[tris[tiCurr]], verts[tris[tiCurr + 1]], verts[tris[tiCurr + 2]]);
                        var cNext = Geom.TriangleCentroid(verts[tris[tiNext]], verts[tris[tiNext + 1]], verts[tris[tiNext + 2]]);

                        isEdge = Geom.ToTheLeft(cCurr, p0, cNext);
                    }
                    else
                    {
                        isEdge = !SharesEdge(tris, tiCurr, tiNext);
                    }

                    if (isEdge)
                    {
                        Vector2 v0, v1;

                        if (ptCurr.Point == tris[tiCurr])
                        {
                            v0 = verts[tris[tiCurr + 2]] - verts[tris[tiCurr + 0]];
                        }
                        else if (ptCurr.Point == tris[tiCurr + 1])
                        {
                            v0 = verts[tris[tiCurr + 0]] - verts[tris[tiCurr + 1]];
                        }
                        else
                        {
                            Debug.Assert(ptCurr.Point == tris[tiCurr + 2]);
                            v0 = verts[tris[tiCurr + 1]] - verts[tris[tiCurr + 2]];
                        }

                        if (ptNext.Point == tris[tiNext])
                        {
                            v1 = verts[tris[tiNext + 0]] - verts[tris[tiNext + 1]];
                        }
                        else if (ptNext.Point == tris[tiNext + 1])
                        {
                            v1 = verts[tris[tiNext + 1]] - verts[tris[tiNext + 2]];
                        }
                        else
                        {
                            Debug.Assert(ptNext.Point == tris[tiNext + 2]);
                            v1 = verts[tris[tiNext + 2]] - verts[tris[tiNext + 0]];
                        }

                        edges.Add(new VoronoiDiagram.Edge(
                                      VoronoiDiagram.EdgeType.RayCCW,
                                      ptCurr.Point,
                                      tiCurr / 3,
                                      -1,
                                      Geom.RotateRightAngle(v0)
                                      ));

                        edges.Add(new VoronoiDiagram.Edge(
                                      VoronoiDiagram.EdgeType.RayCW,
                                      ptCurr.Point,
                                      tiNext / 3,
                                      -1,
                                      Geom.RotateRightAngle(v1)
                                      ));
                    }
                    else
                    {
                        if (!Geom.AreCoincident(centers[tiCurr / 3], centers[tiNext / 3]))
                        {
                            edges.Add(new VoronoiDiagram.Edge(
                                          VoronoiDiagram.EdgeType.Segment,
                                          ptCurr.Point,
                                          tiCurr / 3,
                                          tiNext / 3,
                                          v2nan
                                          ));
                        }
                    }
                }
            }
        }
コード例 #6
0
        /// <summary>
        /// Clip site of voronoi diagram using polygon (must be convex),
        /// returning the clipped vertices in clipped list. Modifies neither
        /// polygon nor diagram, so can be run in parallel for several sites at
        /// once.
        /// </summary>
        public void ClipSite(VoronoiDiagram diag, IList <Vector2> polygon, int site, ref List <Vector2> clipped)
        {
            pointsIn.Clear();

            pointsIn.AddRange(polygon);

            int firstEdge, lastEdge;

            if (site == diag.Sites.Count - 1)
            {
                firstEdge = diag.FirstEdgeBySite[site];
                lastEdge  = diag.Edges.Count - 1;
            }
            else
            {
                firstEdge = diag.FirstEdgeBySite[site];
                lastEdge  = diag.FirstEdgeBySite[site + 1] - 1;
            }

            for (int ei = firstEdge; ei <= lastEdge; ei++)
            {
                pointsOut.Clear();

                var edge = diag.Edges[ei];

                Vector2 lp, ld;

                if (edge.Type == VoronoiDiagram.EdgeType.RayCCW || edge.Type == VoronoiDiagram.EdgeType.RayCW)
                {
                    lp = diag.Vertices[edge.Vert0];
                    ld = edge.Direction;

                    if (edge.Type == VoronoiDiagram.EdgeType.RayCW)
                    {
                        ld *= -1;
                    }
                }
                else if (edge.Type == VoronoiDiagram.EdgeType.Segment)
                {
                    var lp0 = diag.Vertices[edge.Vert0];
                    var lp1 = diag.Vertices[edge.Vert1];

                    lp = lp0;
                    ld = lp1 - lp0;
                }
                else if (edge.Type == VoronoiDiagram.EdgeType.Line)
                {
                    throw new NotSupportedException("Haven't implemented voronoi halfplanes yet");
                }
                else
                {
                    Debug.Assert(false);
                    return;
                }

                for (int pi0 = 0; pi0 < pointsIn.Count; pi0++)
                {
                    var pi1 = pi0 == pointsIn.Count - 1 ? 0 : pi0 + 1;

                    var p0 = pointsIn[pi0];
                    var p1 = pointsIn[pi1];

                    var p0Inside = Geom.ToTheLeft(p0, lp, lp + ld);
                    var p1Inside = Geom.ToTheLeft(p1, lp, lp + ld);

                    if (p0Inside && p1Inside)
                    {
                        pointsOut.Add(p1);
                    }
                    else if (!p0Inside && !p1Inside)
                    {
                        // Do nothing, both are outside
                    }
                    else
                    {
                        var intersection = Geom.LineLineIntersection(lp, ld.normalized, p0, (p1 - p0).normalized);

                        if (p0Inside)
                        {
                            pointsOut.Add(intersection);
                        }
                        else if (p1Inside)
                        {
                            pointsOut.Add(intersection);
                            pointsOut.Add(p1);
                        }
                        else
                        {
                            Debug.Assert(false);
                        }
                    }
                }

                var tmp = pointsIn;
                pointsIn  = pointsOut;
                pointsOut = tmp;
            }

            if (clipped == null)
            {
                clipped = new List <Vector2>();
            }
            else
            {
                clipped.Clear();
            }

            clipped.AddRange(pointsIn);

            /*
             * pointsIn.Clear();
             *
             * pointsIn.AddRange(polygon);
             *
             * int firstEdge, lastEdge;
             *
             * if (site == diag.Sites.Count - 1)
             * {
             *  firstEdge = diag.FirstEdgeBySite[site];
             *  lastEdge = diag.Edges.Count - 1;
             * }
             * else
             * {
             *  firstEdge = diag.FirstEdgeBySite[site];
             *  lastEdge = diag.FirstEdgeBySite[site + 1] - 1;
             * }
             *
             * for (int ei = firstEdge; ei <= lastEdge; ei++)
             * {
             *  pointsOut.Clear();
             *
             *  var edge = diag.Edges[ei];
             *
             *  Vector2 lp, ld;
             *
             *  if (edge.Type == VoronoiDiagram.EdgeType.RayCCW || edge.Type == VoronoiDiagram.EdgeType.RayCW)
             *  {
             *      lp = diag.Vertices[edge.Vert0];
             *      ld = edge.Direction;
             *
             *      if (edge.Type == VoronoiDiagram.EdgeType.RayCW)
             *      {
             *          ld *= -1;
             *      }
             *  }
             *  else if (edge.Type == VoronoiDiagram.EdgeType.Segment)
             *  {
             *      var lp0 = diag.Vertices[edge.Vert0];
             *      var lp1 = diag.Vertices[edge.Vert1];
             *
             *      lp = lp0;
             *      ld = lp1 - lp0;
             *  }
             *  else if (edge.Type == VoronoiDiagram.EdgeType.Line)
             *  {
             *      throw new NotSupportedException("Haven't implemented voronoi halfplanes yet");
             *  }
             *  else
             *  {
             *      Debug.Assert(false);
             *      return;
             *  }
             *
             *  for (int pi0 = 0; pi0 < pointsIn.Count; pi0++)
             *  {
             *      var pi1 = pi0 == pointsIn.Count - 1 ? 0 : pi0 + 1;
             *
             *      var p0 = pointsIn[pi0];
             *      var p1 = pointsIn[pi1];
             *
             *      var p0Inside = Geom.ToTheLeft(p0, lp, lp + ld);
             *      var p1Inside = Geom.ToTheLeft(p1, lp, lp + ld);
             *
             *      if (p0Inside && p1Inside)
             *      {
             *          pointsOut.Add(p1);
             *      }
             *      else if (!p0Inside && !p1Inside)
             *      {
             *          // Do nothing, both are outside
             *      }
             *      else
             *      {
             *          var intersection = Geom.LineLineIntersection(lp, ld.normalized, p0, (p1 - p0).normalized);
             *
             *          if (p0Inside)
             *          {
             *              pointsOut.Add(intersection);
             *          }
             *          else if (p1Inside)
             *          {
             *              pointsOut.Add(intersection);
             *              pointsOut.Add(p1);
             *          }
             *          else
             *          {
             *              Debug.Assert(false);
             *          }
             *      }
             *  }
             *
             *  if(pointsOut.Count == 0)
             *  {
             *      //pointsOut = new List<Vector2>(pointsIn);
             *  }
             *
             *  var tmp = pointsIn;
             *  pointsIn = pointsOut;
             *  pointsOut = tmp;
             * }
             *
             * if (clipped == null)
             * {
             *  clipped = new List<Vector2>();
             * }
             * else
             * {
             *  clipped.Clear();
             * }
             *
             * clipped.AddRange(pointsIn);
             *
             */
        }
コード例 #7
0
        public void FixSiteEdges(ref VoronoiDiagram diag, int site)
        {
            if (diag == null)
            {
                return;
            }


            List <test> poly = new List <test>();
            int         firstEdge, lastEdge;
            Vector2     polyCenter = Vector2.zero;

            if (site == diag.Sites.Count - 1)
            {
                firstEdge = diag.FirstEdgeBySite[site];
                lastEdge  = diag.Edges.Count - 1;
            }
            else
            {
                firstEdge = diag.FirstEdgeBySite[site];
                lastEdge  = diag.FirstEdgeBySite[site + 1] - 1;
            }
            for (int i = firstEdge; i < lastEdge; i++)
            {
                test _test = new test();
                _test.index = diag.Edges[i].Vert0;
                _test.diag  = diag;
                poly.Add(_test);
                polyCenter += diag.Vertices[poly[poly.Count - 1].index];
            }
            polyCenter /= poly.Count;
            //VALIDATE
            for (int i = 0; i < poly.Count; i++)
            {
                for (int j = 0; j < poly.Count; j++)
                {
                    if (poly[i].index == poly[j].index)
                    {
                        Debug.LogError("THEY MATCH THIS IS BAD");
                    }
                }
            }

            //List<Vector2> polyList = new List<Vector2>();
            //foreach (test t in poly)
            //{
            //    polyList.Add(new Vector2(diag.Vertices[t.index].x, diag.Vertices[t.index].y));
            //}
            //CityTest.LineRenderPoly(polyList);

            poly.Sort((a, b) =>

            {
                double a2 = ((Mathf.Rad2Deg * (Mathf.Atan2(a.diag.Vertices[a.index].x - polyCenter.x, a.diag.Vertices[a.index].y - polyCenter.y)) + 360.0f) % 360.0f);
                double a1 = ((Mathf.Rad2Deg * (Math.Atan2(a.diag.Vertices[b.index].x - polyCenter.x, a.diag.Vertices[b.index].y - polyCenter.y)) + 360.0f) % 360.0f);
                return((int)(a1 - a2));
            }
                      //((Mathf.Rad2Deg * (Mathf.Atan2(a.diag.Vertices[a.index].x - polyCenter.x, a.diag.Vertices[a.index].y - polyCenter.y)) + 360) % 360).CompareTo((Mathf.Rad2Deg * (Math.Atan2(a.diag.Vertices[b.index].x - polyCenter.x, a.diag.Vertices[b.index].y - polyCenter.y)) + 360) % 360)
                      );

            //polyList.Clear();
            //foreach (test t in poly)
            //{
            //    polyList.Add(new Vector2(diag.Vertices[t.index].x, diag.Vertices[t.index].y));
            //}
            //CityTest.LineRenderPoly(polyList);

            for (int i = 0; i < poly.Count; i++)
            {
                int nextIndex = poly[0].index;
                if (nextIndex + 1 < poly.Count)
                {
                    nextIndex = poly[i + 1].index;
                }
                diag.Edges[firstEdge + i] = new VoronoiDiagram.Edge(diag.Edges[i].Type, diag.Edges[i].Site, poly[i].index, nextIndex, diag.Vertices[nextIndex] - diag.Vertices[poly[i].index]);
            }

            //List<Vector2> poly222 = new List<Vector2>();
            //
            //for (int ei = firstEdge; ei <= lastEdge; ei++)
            //{
            //    poly222.Add(diag.Vertices[diag.Edges[ei].Vert0]);
            //}
            //
            //CityTest.LineRenderPoly(poly222);
        }
コード例 #8
0
    public void GenerateCity()
    {
        // use our seed for generation
        Random.State currentRNGState = Random.state;
        Random.InitState(citySeed);

        myCity                 = new City();
        myCity.thisCity        = new GameObject("NewCity");
        myCity.cityNoiseOffset = new Vector2(Random.Range(-10000, 10000), Random.Range(-10000, 10000));

        GK.VoronoiDiagram cityDiagram = new GK.VoronoiDiagram();
        //generate points
        List <Vector2> points = CreateCityPoint(myCity.cityNoiseOffset);// calulate voroni fracture sites

        //calculate city
        cityDiagram = new GK.VoronoiCalculator().CalculateDiagram(points);//calculate vorino diagram (ie roads seperating suburbs) using out sites

        //bounding
        List <Vector2> Polygon = new List <Vector2>();

        Polygon.Add(new Vector2(0, 0));
        Polygon.Add(new Vector2(citySize.x, 0));
        Polygon.Add(new Vector2(citySize.x, citySize.y));
        Polygon.Add(new Vector2(0, citySize.y));


        List <Vector2> clippedSite = new List <Vector2>();

        for (int siteIndex = 0; siteIndex < cityDiagram.Sites.Count; siteIndex++)
        {
            new GK.VoronoiClipper().ClipSite(cityDiagram, Polygon, siteIndex, ref clippedSite);// clip each of our suburbs

            if (clippedSite.Count > 0)
            {
                // assign and create a suburb object

                Suburb newSuburb = new Suburb();
                myCity.suburbs.Add(newSuburb);

                newSuburb.thisSuburb   = new GameObject("Suburb");
                newSuburb.sitePosition = cityDiagram.Sites[siteIndex];
                newSuburb.thisSuburb.transform.position = new Vector3(newSuburb.sitePosition.x, 0, newSuburb.sitePosition.y);
                newSuburb.thisSuburb.transform.SetParent(myCity.thisCity.transform);
                newSuburb.borders = new List <Vector2>(clippedSite);

                float xCoord     = myCity.cityNoiseOffset.x + newSuburb.sitePosition.x / citySize.x * noiseScale;
                float yCoord     = myCity.cityNoiseOffset.x + newSuburb.sitePosition.y / citySize.y * noiseScale;
                float noiseValue = curve.Evaluate(Mathf.PerlinNoise(xCoord, yCoord));
                for (int i = 0; i < curve.keys.Length; i++)//set which type of suburb will be generated bassed off our noise weight at the suburbs position
                {
                    if (noiseValue == curve.keys[i].value)
                    {
                        switch (i)
                        {
                        case 0:
                        {
                            newSuburb.suburbType = residentialSettings;
                            break;
                        }

                        case 1:
                        {
                            newSuburb.suburbType = urbanSettings;
                            break;
                        }

                        default:
                        {
                            newSuburb.suburbType = citySettings;
                            break;
                        }
                        }
                    }
                }

                newSuburb.seed = Random.Range(int.MinValue, int.MaxValue);
            }
        }
        Random.state = currentRNGState;
    }