예제 #1
0
        static string NeighbourName(neighbour_e n)
        {
            switch (n)
            {
            case neighbour_e.NORTH: return("North");

            case neighbour_e.SOUTH: return("South");

            case neighbour_e.EAST: return("East");

            case neighbour_e.WEST: return("West");

            default: return("");
            }
        }
예제 #2
0
 static string NeighbourName(neighbour_e n)
 {
     switch (n)
     {
         case neighbour_e.NORTH: return "North";
         case neighbour_e.SOUTH: return "South";
         case neighbour_e.EAST: return "East";
         case neighbour_e.WEST: return "West";
         default: return "";
     }
 }
예제 #3
0
        private static void MergeTiles(List<PoissonSample> source, List<PoissonSample> toMerge,
                                         neighbour_e side,
                                         out List<PoissonSample> result)
        {
            List<MergeCandidate> candidates = new List<MergeCandidate>();
            foreach (PoissonSample s in source) candidates.Add(new MergeCandidate(s, 0));
            foreach (PoissonSample s in toMerge) candidates.Add(new MergeCandidate(s, 1));

            const float scale = 1000.0f; // apply a temporary scaling to the Poisson points (in 0-1 range)
            // before Delaunay triangulation (we'll undo this later) to avoid
            // requiring very small epsilons for point snapping etc which
            // may lead to numeric issues.

            List<Vertex> vertices = new List<Vertex>();
            for (int i = 0; i < candidates.Count; i++)
            {
                vertices.Add(new Vertex(candidates[i].sample.x * scale, candidates[i].sample.y * scale));
            }

            List<int> outTriangles;
            Adjacency adjacency = new Adjacency();
            Delaunay2D.Delaunay2DTriangulate(vertices, false, out outTriangles, ref adjacency);

            for (int j = 0; j < adjacency.vertices.Count; j++)
            {
                adjacency.vertices[j].x /= scale;
                adjacency.vertices[j].y /= scale;
            }

            Image debugImage = null;
            if (OnDebugStep != null) debugImage = new Bitmap(800, 800);

            Voronoi v = Voronoi.FromDelaunay(adjacency);

            #if DEBUG
            if (debugImage != null)
            {
                v.ToImage(debugImage, adjacency);
                OnDebugStep(debugImage, "Voronoi diagram generated from Delaunay Triangulation");
            }
            #endif
            Graph g = new Graph(v, adjacency, candidates);
            if (debugImage != null)
            {
                g.ToImage(debugImage);
                OnDebugStep(debugImage, "Merging " + NeighbourName(side) + " tile: Convert voronoi diagram into a graph");
            }

            int v0, v1;
            for (int i = 0; i < 4; i++)
                if (i != (int)side) g.Clip((WangTile.neighbour_e)i, out v0, out v1);
            g.Clip(side, out v0, out v1);
            #if DEBUG
            if (debugImage != null)
            {
                g.ToImage(debugImage);
                OnDebugStep(debugImage, "Graph generated from Voronoi Diagram");
            }
            #endif
            List<int> path;
            g.ShortestPath(v0, v1, out path);
            List<Vertex> shape;
            g.GenerateShape(path, out shape);

            for (int i = 0; i < shape.Count - 1; i++) // skip last one as it is the same as the first element (they're references)
            {
                shape[i].x *= scale;
                shape[i].y *= scale;
            }

            if (debugImage != null)
            {
                Graphics grph = Graphics.FromImage(debugImage);
                Pen sp = new Pen(Color.Orange, 2);
                for (int i = 0; i < shape.Count - 1; i++)
                {
                    grph.DrawLine(sp,
                                  shape[i].x / scale * debugImage.Width,
                                  shape[i].y / scale * debugImage.Height,
                                  shape[i + 1].x / scale * debugImage.Width,
                                  shape[i + 1].y / scale * debugImage.Height);
                }
                OnDebugStep(debugImage, "Merging " + NeighbourName(side) + " tile: Orange line displays the lowest cost seam");
            }

            result = new List<PoissonSample>();

            for (int i = 0; i < candidates.Count; i++)
            {
                bool insideSeam = GeomUtils.PointInPolygon(new Vertex(candidates[i].sample.x * scale, candidates[i].sample.y * scale), shape);
                if ((insideSeam && candidates[i].sourceDist == 1) ||
                     (!insideSeam && candidates[i].sourceDist == 0))
                    result.Add(candidates[i].sample);
            }

            if (debugImage != null)
            {
                Graphics grph = Graphics.FromImage(debugImage);
                grph.Clear(Color.White);
                SolidBrush brushInside = new SolidBrush(Color.Red);
                SolidBrush brushOutside = new SolidBrush(Color.Gray);
                for (int i = 0; i < result.Count; i++)
                {
                    bool insideSeam = GeomUtils.PointInPolygon(new Vertex(result[i].x * scale, result[i].y * scale), shape);
                    float r = (float)debugImage.Width * 0.01f;
                    RectangleF rect = new RectangleF(result[i].x * debugImage.Width - r, result[i].y * debugImage.Height - r, 2.0f * r, 2.0f * r);
                    if (insideSeam)
                        grph.FillEllipse(brushInside, rect);
                    else
                        grph.FillEllipse(brushOutside, rect);
                }
                OnDebugStep(debugImage, "Merging " + NeighbourName(side) + " tile: gray dots = base tile, red dots = merged points");
            }
        }
예제 #4
0
        private static void MergeTiles(List <PoissonSample> source, List <PoissonSample> toMerge,
                                       neighbour_e side,
                                       out List <PoissonSample> result)
        {
            List <MergeCandidate> candidates = new List <MergeCandidate>();

            foreach (PoissonSample s in source)
            {
                candidates.Add(new MergeCandidate(s, 0));
            }
            foreach (PoissonSample s in toMerge)
            {
                candidates.Add(new MergeCandidate(s, 1));
            }

            const float scale = 1000.0f; // apply a temporary scaling to the Poisson points (in 0-1 range)
            // before Delaunay triangulation (we'll undo this later) to avoid
            // requiring very small epsilons for point snapping etc which
            // may lead to numeric issues.

            List <Vertex> vertices = new List <Vertex>();

            for (int i = 0; i < candidates.Count; i++)
            {
                vertices.Add(new Vertex(candidates[i].sample.x * scale, candidates[i].sample.y * scale));
            }

            List <int> outTriangles;
            Adjacency  adjacency = new Adjacency();

            Delaunay2D.Delaunay2DTriangulate(vertices, false, out outTriangles, ref adjacency);

            for (int j = 0; j < adjacency.vertices.Count; j++)
            {
                adjacency.vertices[j].x /= scale;
                adjacency.vertices[j].y /= scale;
            }

            Image debugImage = null;

            if (OnDebugStep != null)
            {
                debugImage = new Bitmap(800, 800);
            }


            Voronoi v = Voronoi.FromDelaunay(adjacency);

#if DEBUG
            if (debugImage != null)
            {
                v.ToImage(debugImage, adjacency);
                OnDebugStep(debugImage, "Voronoi diagram generated from Delaunay Triangulation");
            }
#endif
            Graph g = new Graph(v, adjacency, candidates);
            if (debugImage != null)
            {
                g.ToImage(debugImage);
                OnDebugStep(debugImage, "Merging " + NeighbourName(side) + " tile: Convert voronoi diagram into a graph");
            }

            int v0, v1;
            for (int i = 0; i < 4; i++)
            {
                if (i != (int)side)
                {
                    g.Clip((WangTile.neighbour_e)i, out v0, out v1);
                }
            }
            g.Clip(side, out v0, out v1);
#if DEBUG
            if (debugImage != null)
            {
                g.ToImage(debugImage);
                OnDebugStep(debugImage, "Graph generated from Voronoi Diagram");
            }
#endif
            List <int> path;
            g.ShortestPath(v0, v1, out path);
            List <Vertex> shape;
            g.GenerateShape(path, out shape);

            for (int i = 0; i < shape.Count - 1; i++) // skip last one as it is the same as the first element (they're references)
            {
                shape[i].x *= scale;
                shape[i].y *= scale;
            }

            if (debugImage != null)
            {
                Graphics grph = Graphics.FromImage(debugImage);
                Pen      sp   = new Pen(Color.Orange, 2);
                for (int i = 0; i < shape.Count - 1; i++)
                {
                    grph.DrawLine(sp,
                                  shape[i].x / scale * debugImage.Width,
                                  shape[i].y / scale * debugImage.Height,
                                  shape[i + 1].x / scale * debugImage.Width,
                                  shape[i + 1].y / scale * debugImage.Height);
                }
                OnDebugStep(debugImage, "Merging " + NeighbourName(side) + " tile: Orange line displays the lowest cost seam");
            }

            result = new List <PoissonSample>();

            for (int i = 0; i < candidates.Count; i++)
            {
                bool insideSeam = GeomUtils.PointInPolygon(new Vertex(candidates[i].sample.x * scale, candidates[i].sample.y * scale), shape);
                if ((insideSeam && candidates[i].sourceDist == 1) ||
                    (!insideSeam && candidates[i].sourceDist == 0))
                {
                    result.Add(candidates[i].sample);
                }
            }

            if (debugImage != null)
            {
                Graphics grph = Graphics.FromImage(debugImage);
                grph.Clear(Color.White);
                SolidBrush brushInside  = new SolidBrush(Color.Red);
                SolidBrush brushOutside = new SolidBrush(Color.Gray);
                for (int i = 0; i < result.Count; i++)
                {
                    bool       insideSeam = GeomUtils.PointInPolygon(new Vertex(result[i].x * scale, result[i].y * scale), shape);
                    float      r          = (float)debugImage.Width * 0.01f;
                    RectangleF rect       = new RectangleF(result[i].x * debugImage.Width - r, result[i].y * debugImage.Height - r, 2.0f * r, 2.0f * r);
                    if (insideSeam)
                    {
                        grph.FillEllipse(brushInside, rect);
                    }
                    else
                    {
                        grph.FillEllipse(brushOutside, rect);
                    }
                }
                OnDebugStep(debugImage, "Merging " + NeighbourName(side) + " tile: gray dots = base tile, red dots = merged points");
            }
        }