Exemple #1
0
        private void HandleNewInput()
        {
            // Reset mesh
            mesh    = null;
            voronoi = null;

            // Reset state
            settings.RefineMode      = false;
            settings.ExceptionThrown = false;

            // Reset buttons
            btnMesh.Enabled   = true;
            btnMesh.Text      = "Triangulate";
            btnSmooth.Enabled = false;

            // Update Statistic view
            statisticView.HandleNewInput(input);

            // Clear voronoi
            menuViewVoronoi.Checked = false;

            // Disable menu items
            menuFileSave.Enabled    = false;
            menuFileExport.Enabled  = false;
            menuViewVoronoi.Enabled = false;
            menuToolsCheck.Enabled  = false;
            menuToolsRcm.Enabled    = false;

            // Render input
            renderManager.Set(input);

            // Update window caption
            this.Text = "Triangle.NET - Mesh Explorer - " + settings.CurrentFile;
        }
        /**
         *      Iterate over every edge in the voronoi graph building edge objects and connecting centers and corners.
         *      This method is very important to complete the graph to be used for all later stages!
         */
        internal static List <Edge> createEdges(VoronoiBase voronoi, List <Center> centers, List <Corner> corners)
        {
            List <Edge>     edges     = new List <Edge>();
            List <HalfEdge> halfEdges = voronoi.HalfEdges;

            foreach (HalfEdge e0 in halfEdges)
            {
                HalfEdge e1 = e0.Twin;
                if (e1.ID < e0.ID)
                {
                    continue;
                }

                TriangleNet.Topology.DCEL.Vertex v0 = e0.Origin;
                TriangleNet.Topology.DCEL.Vertex v1 = e1.Origin;

                Corner corner0 = corners[v0.ID];
                Corner corner1 = corners[v1.ID];

                Face   face0    = e0.Face;
                Face   face1    = e1.Face;
                Center center0  = face0.ID < 0 ? null : centers[face0.ID];
                Center center1  = face1.ID < 0 ? null : centers[face1.ID];
                bool   isBorder = center0 == null || center1 == null;
                edges.Add(makeEdge(isBorder, corner0, corner1, center0, center1));
            }
            return(edges);
        }
        public static VoronoiBase generateVoronoi(int seed, float worldSize, int pointCount)
        {
            System.Random  pointRandom  = new System.Random(seed);
            List <Vector2> cornerPoints = new List <Vector2>(4);

            cornerPoints.Add(new Vector2(0, 0));
            cornerPoints.Add(new Vector2(worldSize, 0));
            cornerPoints.Add(new Vector2(0, worldSize));
            cornerPoints.Add(new Vector2(worldSize, worldSize));

            List <Vector2> points = new List <Vector2>(pointCount);

            points.AddRange(cornerPoints);
            for (int i = 0; i < pointCount; i++)
            {
                float x = (float)pointRandom.NextDouble() * worldSize;
                float y = (float)pointRandom.NextDouble() * worldSize;
                points.Add(new Vector2(x, y));
            }
            points = performLloydRelaxation(points, cornerPoints);
            points = performLloydRelaxation(points, cornerPoints);
            VoronoiBase voronoi = Triangulator.generateVoronoi(points);

            voronoi.ResolveBoundaryEdges();
            return(voronoi);
        }
        private static Graph generateGraph(int seed, float size, int pointCount)
        {
            VoronoiBase voronoi = WorldGeneratorUtils.generateVoronoi(seed, size, pointCount);

            List <Corner> corners = WorldGeneratorUtils.createCorners(voronoi.Vertices);

            List <Center> centers = WorldGeneratorUtils.createCenters(voronoi.Faces, corners);

            List <Edge> edges = WorldGeneratorUtils.createEdges(voronoi, centers, corners);

            WorldGeneratorUtils.recenterCorners(corners);

            return(new Graph(seed, size, centers, corners, edges));
        }
Exemple #5
0
        private void HandleMeshChange()
        {
            // Update Statistic view
            statisticView.HandleMeshChange(mesh);

            // TODO: Should the Voronoi diagram automatically update?
            voronoi = null;
            menuViewVoronoi.Checked = false;

            // Enable menu items
            menuFileSave.Enabled    = true;
            menuFileExport.Enabled  = true;
            menuViewVoronoi.Enabled = true;
            menuToolsCheck.Enabled  = true;
            menuToolsRcm.Enabled    = true;
        }
Exemple #6
0
 public static void triangulateVoronoi(VoronoiBase voronoi, out List <int> outIndices, out List <Vector3> outVertices)
 {
     outIndices  = new List <int>();
     outVertices = new List <Vector3>();
     foreach (Face face in voronoi.Faces)
     {
         int        offset = outVertices.Count;
         HalfEdge[] edges  = face.EnumerateEdges().ToArray();
         edges.Reverse();
         for (int i = 1; i < edges.Count() - 1; i++)
         {
             outIndices.Add(offset);
             outIndices.Add(offset + i);
             outIndices.Add(offset + i + 1);
         }
         outVertices.AddRange((from edge in edges select new Vector3((float)edge.Origin.X, 0f, (float)edge.Origin.Y)).ToList());
     }
 }
Exemple #7
0
    /// <summary>
    /// Returns polygon with points at centroid
    /// Source: https://penetcedric.wordpress.com/2017/06/13/polygon-maps/
    /// </summary>
    /// <param name="voronoi">VoronoiBase such as StandardVoronoi or Bounded Voronoi</param>
    public static Polygon LloydRelaxation(this VoronoiBase voronoi, Rectangle rectangle)
    {
        //create the new polygon
        Polygon centroid = new Polygon(voronoi.Faces.Count);

        //loop through the regions
        for (int i = 0; i < voronoi.Faces.Count; ++i)
        {
            Vector2 average = new Vector2(0, 0);

            //create the hash set of vertices -- this is neat as it will only contain 1 instance of each
            HashSet <Vector2> verts = new HashSet <Vector2>();

            var edge  = voronoi.Faces[i].Edge;
            var first = edge.Origin.ID;

            voronoi.Faces[i].LoopEdges(rectangle, true, (v1, v2) =>
            {
                if (!verts.Contains(v1))
                {
                    verts.Add(v1);
                }
                if (!verts.Contains(v2))
                {
                    verts.Add(v2);
                }
            });

            if (verts.Count == 0)
            {
                continue;
            }

            //compute the centroid
            var vertsEnum = verts.GetEnumerator();
            while (vertsEnum.MoveNext())
            {
                average += vertsEnum.Current;
            }
            average /= verts.Count;
            centroid.Add(average.ToVertex());
        }
        return(centroid);
    }
Exemple #8
0
        private void HandleMeshImport()
        {
            voronoi = null;

            // Render mesh
            renderManager.Set(mesh, true);
            renderManager.Update(GetRegions(mesh));
            this.Text = "Triangle.NET - Mesh Explorer - " + settings.CurrentFile;

            // Update Statistic view
            statisticView.HandleMeshImport(input, mesh);

            // Set refine mode
            btnMesh.Enabled = true;
            btnMesh.Text    = "Refine";

            settings.RefineMode = true;

            HandleMeshChange();
        }
    public static Polygon Lloyd_Relaxation(this VoronoiBase voronoi, Rectangle rectangle)
    {
        Polygon centroid = new Polygon(voronoi.Faces.Count);

        //loop
        for (int i = 0; i < voronoi.Faces.Count; ++i)
        {
            Vector2           average = new Vector2(0, 0);
            HashSet <Vector2> verts   = new HashSet <Vector2>();

            var edge  = voronoi.Faces[i].Edge;
            var first = edge.Origin.ID;

            voronoi.Faces[i].BorderLooping(rectangle, true, (v1, v2) =>
            {
                if (!verts.Contains(v1))
                {
                    verts.Add(v1);
                }
                if (!verts.Contains(v2))
                {
                    verts.Add(v2);
                }
            });

            if (verts.Count == 0)
            {
                continue;
            }

            // centroid
            var vertsEnum = verts.GetEnumerator();
            while (vertsEnum.MoveNext())
            {
                average += vertsEnum.Current;
            }
            average /= verts.Count;
            centroid.Add(average.ToVertex());
        }
        return(centroid);
    }
    void CreateMap(VoronoiBase sv, float maxz, float yOffset)
    {
        Dictionary <int, TriangleNet.Geometry.Vertex> id2vert  = new Dictionary <int, TriangleNet.Geometry.Vertex>();
        List <TriangleNet.Geometry.Vertex>            vertices = new List <TriangleNet.Geometry.Vertex>();
        List <ISegment> segments = new List <ISegment>();

        foreach (TriangleNet.Topology.DCEL.Vertex v in sv.Vertices)
        {
            TriangleNet.Geometry.Vertex new_v = new TriangleNet.Geometry.Vertex(v.x, v.y);
            id2vert[v.id] = new_v;
            vertices.Add(new_v);
        }

        foreach (Edge e in sv.Edges)
        {
            TriangleNet.Geometry.Vertex v1 = id2vert[e.P0];
            TriangleNet.Geometry.Vertex v2 = id2vert[e.P1];
            segments.Add(new Segment(v1, v2));
        }
        CreateMap(vertices, segments, maxz, yOffset);
    }
        /**
         *      Reposition the current center points to be at the average position of their corners.
         *      Doing this makes the point distribution more even, setting it up to create a better mesh.
         *      Can be performed recursively, each iteration yielding smaller and smaller improvements.
         */
        private static List <Vector2> performLloydRelaxation(List <Vector2> currentPoints, List <Vector2> cornerPoints)
        {
            VoronoiBase voronoi = Triangulator.generateVoronoi(currentPoints);
            List <TriangleNet.Topology.DCEL.Face> faces = voronoi.Faces;
            List <Vector2> points = new List <Vector2>(currentPoints.Count + cornerPoints.Count);

            points.AddRange(cornerPoints);
            foreach (Face face in faces)
            {
                float x = 0, y = 0;
                IEnumerable <HalfEdge> halfEdges = face.EnumerateEdges();
                float count = 0;
                foreach (var halfEdge in halfEdges)
                {
                    count++;
                    x += (float)halfEdge.Origin.X;
                    y += (float)halfEdge.Origin.Y;
                }
                points.Add(new Vector2(x / count, y / count));
            }
            return(points);
        }
Exemple #12
0
        private bool CreateVoronoi()
        {
            if (mesh == null)
            {
                return(false);
            }

            if (mesh.IsPolygon)
            {
                try
                {
                    this.voronoi = new BoundedVoronoi(mesh);
                }
                catch (Exception ex)
                {
                    if (!meshControlView.ParamConformDelChecked)
                    {
                        DarkMessageBox.Show("Exception - Bounded Voronoi", Settings.VoronoiString, MessageBoxButtons.OK);
                    }
                    else
                    {
                        DarkMessageBox.Show("Exception - Bounded Voronoi", ex.Message, MessageBoxButtons.OK);
                    }

                    return(false);
                }
            }
            else
            {
                this.voronoi = new StandardVoronoi(mesh);
            }

            // HACK: List<Vertex> -> ICollection<Point> ? Nope, no way.
            //           Vertex[] -> ICollection<Point> ? Well, ok.
            renderManager.Set(voronoi.Vertices.ToArray(), voronoi.Edges, false);

            return(true);
        }
    public Map Generate(Vector2 dimensions,
                        int generations,
                        PolygonList.FaceType faceType,
                        EnvironmentConstructionScript.FunctionType functionType,
                        float height,
                        AnimationCurve heightMap,
                        int regionCount,
                        int relaxationCount,
                        float radius)
    {
        data             = new Map();
        data.generations = generations;
        this.height      = height;
        this.heigtMap    = heightMap;
        islandShape      = new EnvironmentConstructionScript(generations, dimensions.x, dimensions.y, functionType);
        rectangle        = new Rectangle(0, 0, dimensions.x, dimensions.y);
        if (faceType == PolygonList.FaceType.Hexagon || faceType == PolygonList.FaceType.Square)
        {
            relaxationCount = 0;        // relaxation is used to create accurate polygon size
        }
        // no specific value for rectangle - able to resize in the editor

        Polygon     polygon = PolygonList.Create(dimensions, generations, faceType, regionCount, radius);
        VoronoiBase voronoi = GenerateVoronoi(ref polygon, relaxationCount);

        Build(polygon, voronoi);
        ImproveBorders();
        // Determine the elevations and water at Voronoi corners.
        Elevation.AssignCorner(ref data, islandShape, faceType == PolygonList.FaceType.Hexagon || faceType == PolygonList.FaceType.Square);


        // Determine polygon and corner type: ocean, coast, land.

        CheckingScript.AssignSeaSealandAndLand(ref data);

        // Rescale elevations so that the highest is 1.0, and they're
        // distributed well. Lower elevations will be more common
        // than higher elevations.

        List <Characteristics.Corner> corners = LandCorners(data.corners);

        Elevation.Readjust(ref corners);

        //  elevations assigned to water corners
        foreach (var q in data.corners)
        {
            if (q.sea || q.sealine)
            {
                q.built = 0.0f;
            }
        }

        // Polygon elevations are the average of their corners
        Elevation.AllocatePolygon(ref data);

        // Determine humidity at corners, starting at rivers
        // and lakes, but not oceans. Then redistribute
        // humidity to cover the entire range evenly from 0.0
        // to 1.0. Then assign polygon humidity as the average
        // of the corner humidity.
        Humidity.AccountEdge(ref data);
        Humidity.Redistribute(ref corners);
        Humidity.AssignPolygon(ref data);

        CheckingScript.AssignHabitat(ref data);

        return(data);
    }
    private void Build(Polygon polygon, VoronoiBase voronoi)
    {
        Dictionary <Point, Characteristics.Center> centerLoopup = new Dictionary <Point, Characteristics.Center>();

        foreach (var point in polygon.Points)
        {
            Characteristics.Center center = new Characteristics.Center
            {
                id         = data.centers.Count,
                pos        = point.ToVector(),
                neighbours = new List <Characteristics.Center>(),
                borders    = new List <Characteristics.Border>(),
                corners    = new List <Characteristics.Corner>()
            };
            data.centers.Add(center);
            centerLoopup[point] = center;
        }

        foreach (var face in voronoi.Faces)
        {
            face.BorderLooping(halfEdge =>
            {
                Point voronoiEdge1  = halfEdge.Origin;
                Point voronoiEdge2  = halfEdge.Twin.Origin;
                Point delaunayEdge1 = polygon.Points[halfEdge.Face.ID];
                Point delaunayEdge2 = polygon.Points[halfEdge.Twin.Face.ID];

                Characteristics.Border border = new Characteristics.Border
                {
                    id       = data.borders.Count,
                    midPoint = new Vector2((float)(voronoiEdge1.X + voronoiEdge2.X) / 2, (float)(voronoiEdge1.Y + voronoiEdge2.Y) / 2),
                    v0       = MakeCorner(voronoiEdge1),
                    v1       = MakeCorner(voronoiEdge2),
                    d0       = centerLoopup[delaunayEdge1],
                    d1       = centerLoopup[delaunayEdge2]
                };

                if (border.d0 != null)
                {
                    border.d0.borders.Add(border);
                }
                if (border.d1 != null)
                {
                    border.d1.borders.Add(border);
                }
                if (border.v0 != null)
                {
                    border.v0.protrudes.Add(border);
                }
                if (border.v1 != null)
                {
                    border.v1.protrudes.Add(border);
                }

                data.borders.Add(border);

                if (border.d0 != null && border.d1 != null)
                {
                    AddToCenterList(border.d0.neighbours, border.d1);
                    AddToCenterList(border.d1.neighbours, border.d0);
                }

                if (border.v0 != null && border.v1 != null)
                {
                    AddToCornerList(border.v0.adjacent, border.v1);
                    AddToCornerList(border.v1.adjacent, border.v0);
                }

                if (border.d0 != null)
                {
                    AddToCornerList(border.d0.corners, border.v0);
                    AddToCornerList(border.d0.corners, border.v1);
                }
                if (border.d1 != null)
                {
                    AddToCornerList(border.d1.corners, border.v0);
                    AddToCornerList(border.d1.corners, border.v1);
                }

                if (border.v0 != null)
                {
                    AddToCenterList(border.v0.touches, border.d0);
                    AddToCenterList(border.v0.touches, border.d1);
                }
                if (border.v1 != null)
                {
                    AddToCenterList(border.v1.touches, border.d0);
                    AddToCenterList(border.v1.touches, border.d1);
                }
            });
        }
    }
Exemple #15
0
    public Map Generate(Vector2 dimensions,
                        int seed,
                        PointSelector.FaceType faceType,
                        IslandShape.FunctionType functionType,
                        float height,
                        AnimationCurve heightMap,
                        int regionCount,
                        int relaxationCount,
                        float radius)
    {
        data          = new Map();
        data.seed     = seed;
        this.height   = height;
        this.heigtMap = heightMap;
        islandShape   = new IslandShape(seed, dimensions.x, dimensions.y, functionType);
        rectangle     = new Rectangle(0, 0, dimensions.x, dimensions.y);
        if (faceType == PointSelector.FaceType.Hexagon || faceType == PointSelector.FaceType.Square)
        {
            relaxationCount = 0;
        }

        Polygon     polygon = PointSelector.Generate(dimensions, seed, faceType, regionCount, radius);
        VoronoiBase voronoi = GenerateVoronoi(ref polygon, relaxationCount);

        Build(polygon, voronoi);
        ImproveCorners();
        // Determine the elevations and water at Voronoi corners.
        Elevation.AssignCorner(ref data, islandShape, faceType == PointSelector.FaceType.Hexagon || faceType == PointSelector.FaceType.Square);


        // Determine polygon and corner type: ocean, coast, land.
        Biomes.AssignOceanCoastAndLand(ref data);

        // Rescale elevations so that the highest is 1.0, and they're
        // distributed well. We want lower elevations to be more common
        // than higher elevations, in proportions approximately matching
        // concentric rings. That is, the lowest elevation is the
        // largest ring around the island, and therefore should more
        // land area than the highest elevation, which is the very
        // center of a perfectly circular island.

        List <Graph.Corner> corners = LandCorners(data.corners);

        Elevation.Redistribute(ref corners);

        // Assign elevations to non-land corners
        foreach (var q in data.corners)
        {
            if (q.ocean || q.coast)
            {
                q.elevation = 0.0f;
            }
        }

        // Polygon elevations are the average of their corners
        Elevation.AssignPolygon(ref data);

        // Determine moisture at corners, starting at rivers
        // and lakes, but not oceans. Then redistribute
        // moisture to cover the entire range evenly from 0.0
        // to 1.0. Then assign polygon moisture as the average
        // of the corner moisture.
        Moisture.AssignCorner(ref data);
        Moisture.Redistribute(ref corners);
        Moisture.AssignPolygon(ref data);

        Biomes.AssignBiomes(ref data);

        return(data);
    }
Exemple #16
0
    private void Build(Polygon polygon, VoronoiBase voronoi)
    {
        Dictionary <Point, Graph.Center> centerLoopup = new Dictionary <Point, Graph.Center>();

        foreach (var point in polygon.Points)
        {
            Graph.Center center = new Graph.Center
            {
                id         = data.centers.Count,
                pos        = point.ToVector(),
                neighbours = new List <Graph.Center>(),
                borders    = new List <Graph.Edge>(),
                corners    = new List <Graph.Corner>()
            };
            data.centers.Add(center);
            centerLoopup[point] = center;
        }

        foreach (var face in voronoi.Faces)
        {
            face.LoopEdges(halfEdge =>
            {
                Point voronoiEdge1  = halfEdge.Origin;
                Point voronoiEdge2  = halfEdge.Twin.Origin;
                Point delaunayEdge1 = polygon.Points[halfEdge.Face.ID];
                Point delaunayEdge2 = polygon.Points[halfEdge.Twin.Face.ID];

                Graph.Edge edge = new Graph.Edge
                {
                    id       = data.edges.Count,
                    midPoint = new Vector2((float)(voronoiEdge1.X + voronoiEdge2.X) / 2, (float)(voronoiEdge1.Y + voronoiEdge2.Y) / 2),
                    v0       = MakeCorner(voronoiEdge1),
                    v1       = MakeCorner(voronoiEdge2),
                    d0       = centerLoopup[delaunayEdge1],
                    d1       = centerLoopup[delaunayEdge2]
                };

                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);
                }

                data.edges.Add(edge);

                // Centers point to centers.
                if (edge.d0 != null && edge.d1 != null)
                {
                    AddToCenterList(edge.d0.neighbours, edge.d1);
                    AddToCenterList(edge.d1.neighbours, 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);
                }
            });
        }
    }