public static void Triangulate(PointSet ps) { Triangulate(_defaultAlgorithm, ps); }
public void Generate() { generationMessage = "Generating points..."; //Generate some points... List<Point> generationPoints = new List<Point>(); for(int i = 0; i < numberOfPoints; i++) { Point randomPoint = new Point(Random.Range(-levelRadius, levelRadius), Random.Range(-levelRadius, levelRadius)); randomPoint = new Point( (randomPoint.x * delaunayPointSnap) / delaunayPointSnap, (randomPoint.y * delaunayPointSnap) / delaunayPointSnap); if(!generationPoints.Contains(randomPoint)) { generationPoints.Add(randomPoint); } } //Clean up duplicates generationMessage = "Triangulating..."; //Generate a delaunay triangulation of the points Poly2Tri.PointSet ps = new Poly2Tri.PointSet(generationPoints.Select(d=>(Poly2Tri.TriangulationPoint)d).ToList()); Poly2Tri.P2T.Triangulate (ps); List<Poly2Tri.DelaunayTriangle> delaunayTriangles = ps.Triangles.ToList(); generationMessage = "Performing Brownian Walk through triangulation..."; //Brownian Walk through the triangles. Poly2TriDelaunayTriangulationWalker walker = new Poly2TriDelaunayTriangulationWalker (delaunayTriangles); List<Poly2Tri.DelaunayTriangle> levelTriangleSet = new List<Poly2Tri.DelaunayTriangle>(); for (int i = 0; i < numberOfStepsForBrownianWalk; i++) { Poly2Tri.DelaunayTriangle nextTriangle = walker.Next(); if(!levelTriangleSet.Contains(nextTriangle)) { levelTriangleSet.Add(nextTriangle); } } generationMessage = "Performing Tendril Walks..."; for (int i = 0; i < numberOfTendrilWalksToComplete; i++) { generationMessage = "Performing Tendril Walk: " + i; walker.SetCurrentTriangleIndex(delaunayTriangles.IndexOf(levelTriangleSet[Mathf.FloorToInt(Random.value * levelTriangleSet.Count)])); for (int j = 0; j < numberOfStepsForBrownianWalk; j++) { Poly2Tri.DelaunayTriangle nextTriangle = walker.Next(); if(!levelTriangleSet.Contains(nextTriangle)) { levelTriangleSet.Add(nextTriangle); } } } generationMessage = "Getting level boolean..."; //List<Poly2Tri.DelaunayTriangle> booleanFromLevelSet = delaunayTriangles.Where (x => !levelTriangleSet.Contains (x)).ToList (); /* Debugging delaunay triangulation foreach (Poly2Tri.DelaunayTriangle tri in booleanFromLevelSet) { Gizmos.DrawLine(new Vector2(tri.Points[0].Xf, tri.Points[0].Yf), new Vector2(tri.Points[1].Xf, tri.Points[1].Yf)); Gizmos.DrawLine(new Vector2(tri.Points[1].Xf, tri.Points[1].Yf), new Vector2(tri.Points[2].Xf, tri.Points[2].Yf)); Gizmos.DrawLine(new Vector2(tri.Points[2].Xf, tri.Points[2].Yf), new Vector2(tri.Points[0].Xf, tri.Points[0].Yf)); } */ //Generate colliders... ClipperLib.Clipper clipper = new ClipperLib.Clipper (); foreach(Poly2Tri.DelaunayTriangle tri in levelTriangleSet) { Polygon trianglePoints = new Polygon(); for(int i = 0; i < 3; i++) { trianglePoints.points.Add(tri.Points[i]); } clipper.AddPath(trianglePoints, ClipperLib.PolyType.ptSubject, true); } List<List<ClipperLib.IntPoint>> solution = new List<List<ClipperLib.IntPoint>> (); clipper.Execute (ClipperLib.ClipType.ctUnion, solution, ClipperLib.PolyFillType.pftPositive, ClipperLib.PolyFillType.pftPositive); generationMessage = "Generating mesh from boolean..."; DestructibleLevel level = GetComponent<DestructibleLevel> (); if (level == null) { level = gameObject.AddComponent<DestructibleLevel>(); } foreach (List<ClipperLib.IntPoint> polygon in solution) { level.booleanPolygons.Add(new Tinkerbox.Geometry.Polygon(polygon)); } level.UpdateMesh(); generationMessage = "Calling Callback.."; OnFinishedGeneration(); GameObject[] players = GameObject.FindGameObjectsWithTag ("Player"); Poly2Tri.DelaunayTriangle spawnTriangle = levelTriangleSet [Mathf.FloorToInt (Random.value * levelTriangleSet.Count)]; generationMessage = "Spawning Players..."; Vector2 spawnPoint = new Vector2 (spawnTriangle.Centroid ().Xf, spawnTriangle.Centroid ().Yf); foreach (GameObject player in players) { player.transform.position = spawnPoint + Random.insideUnitCircle; } generationMessage = "Spawning Decorations..."; for (int i = 0; i < decorationsToSpawn; i++) { GameObject decoration = (GameObject) Instantiate(decorations[Mathf.FloorToInt(Random.value * decorations.Length)]); Poly2Tri.DelaunayTriangle decorSpawnTriangle = levelTriangleSet [Mathf.FloorToInt (Random.value * levelTriangleSet.Count)]; Point decorSpawnPoint = decorSpawnTriangle.Centroid(); decoration.transform.position = decorSpawnPoint + Random.insideUnitCircle; } //yield return 0; }
//////// public static PointSet LoadDatPointSet(string filename, bool xflip, bool yflip, bool displayFlipX, bool displayFlipY, float rotateAngleInDegrees) { var points = new List<TriangulationPoint>(); List<List<TriangulationPoint>> constrainedPoints = new List<List<TriangulationPoint>>(); List<string> constrainedPointSetNames = new List<string>(); List<TriangulationPoint> bounds = new List<TriangulationPoint>(); List<TriangulationPoint> currentList = points; double precision = TriangulationPoint.kVertexCodeDefaultPrecision; int lineNum = 0; bool skipLine = false; foreach (var line_ in File.ReadAllLines(filename)) { ++lineNum; string line = line_.Trim(); if (string.IsNullOrEmpty(line) || line.StartsWith("//") || line.StartsWith("#") || line.StartsWith(";")) { continue; } if (!skipLine && line.StartsWith("/*")) { skipLine = true; continue; } else if (skipLine) { if( line.StartsWith("*/")) { skipLine = false; } continue; } if (line.StartsWith("Precision", StringComparison.InvariantCultureIgnoreCase)) { if (line.Length > 9) { string precisionStr = line.Substring(9).Trim(); if (!double.TryParse(precisionStr, NumberStyles.Float, CultureInfo.InvariantCulture, out precision)) { Console.WriteLine("Invalid Precision '" + precisionStr + "' in file " + filename + ", line " + lineNum.ToString() + ". Setting to " + TriangulationPoint.kVertexCodeDefaultPrecision.ToString()); precision = TriangulationPoint.kVertexCodeDefaultPrecision; } } } else if (line.StartsWith("Set", StringComparison.InvariantCultureIgnoreCase)) { if (line.StartsWith("SetBegin")) { string[] setParts = line.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries); if (setParts.Length < 2) { continue; } //if (setParts[1].Equals("Constrained", StringComparison.InvariantCultureIgnoreCase)) if (setParts[1].Equals("Constrained", StringComparison.InvariantCultureIgnoreCase) || setParts[1].Equals("Unconstrained", StringComparison.InvariantCultureIgnoreCase)) { currentList = new List<TriangulationPoint>(); constrainedPoints.Add(currentList); if( setParts.Length>2) { constrainedPointSetNames.Add(setParts[2]); } else { constrainedPointSetNames.Add(""); } } else if (bounds.Count == 0 && setParts[1].Equals("Bounds", StringComparison.InvariantCultureIgnoreCase)) { currentList = bounds; } else { currentList = points; } } else { currentList = points; } } else { var xy = line.Split(new[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries); double x, y; if (xy != null && xy.Length >= 2 && double.TryParse(xy[0], NumberStyles.Float, CultureInfo.InvariantCulture, out x) && double.TryParse(xy[1], NumberStyles.Float, CultureInfo.InvariantCulture, out y)) { currentList.Add(new PolygonPoint((xflip ? -1.0 : 1.0) * x, (yflip ? -1.0 : 1.0) * y)); } else { Console.WriteLine("Invalid Input '" + line + "' in file " + filename + ", line " + lineNum.ToString()); } } } PointSet ps = null; if (constrainedPoints.Count > 0) { ConstrainedPointSet cps = null; if (bounds.Count < 3) { points.AddRange(bounds); cps = new ConstrainedPointSet(points); } else { cps = new ConstrainedPointSet(bounds); cps.AddRange(points); } int numConstrainedPointSets = constrainedPoints.Count; for( int i = 0; i < numConstrainedPointSets; ++i) { List<TriangulationPoint> hole = constrainedPoints[i]; if (hole.Count < 3) { cps.AddRange(hole); } else { cps.AddHole(hole, constrainedPointSetNames[i]); } } ps = cps; } else { if (bounds.Count < 3) { points.AddRange(bounds); ps = new PointSet(points); } else { ps = new PointSet(bounds); ps.AddRange(points); } } ps.FileName = filename; ps.DisplayFlipX = displayFlipX; ps.DisplayFlipY = displayFlipY; ps.DisplayRotate = rotateAngleInDegrees; ps.Precision = precision; return ps; }
public Bitmap ReconstructImage(SampledImage sampledImage) { int width = sampledImage.Width; int height = sampledImage.Height; Bitmap image = new Bitmap(width, height); Progress.ReportProgress(0); Stopwatch stopwatch = Stopwatch.StartNew(); // use cached triangulation if possible PointSet triMesh = (TriangulationCachingEnabled && sampledImage.Equals(previousSampledImage)) ? previousTriMesh : voronoiHelper.MakeDelaunayTriangulation(sampledImage); stopwatch.Stop(); Progress.TimeReport["delaunay"] = stopwatch.ElapsedMilliseconds; previousTriMesh = triMesh; previousSampledImage = sampledImage; Progress.ReportProgress(25); stopwatch.Reset(); stopwatch.Start(); using (Graphics graphics = Graphics.FromImage(image)) { // fill with black background //graphics.FillRectangle(Brushes.White, 0, 0, width, height); graphics.SmoothingMode = AntiAliasingEnabled ? System.Drawing.Drawing2D.SmoothingMode.AntiAlias : System.Drawing.Drawing2D.SmoothingMode.None; if (VoronoiCellsEnabled) { DrawVoronoiCells(triMesh, graphics, sampledImage); } Progress.ReportProgress(50); if (DelaunayTrianglesEnabled) { DrawDelaunayTriangles(triMesh, graphics); } Progress.ReportProgress(75); DrawAdditionalFeatures(width, height, triMesh, graphics, image); Progress.ReportProgress(100); } Progress.TimeReport["visualizer"] = stopwatch.ElapsedMilliseconds; return image; }
private void DrawVoronoiCells(PointSet triMesh, Graphics graphics, SampledImage sampledImage) { int samplePercent = 4 * triMesh.Triangles.Count / 100; int trianglesDone = 0; int percentDone = 0; // Voronoi cell which have already been drawn onto the image HashSet<Vector2> drawnVoronoiCells = new HashSet<Vector2>(); foreach (DelaunayTriangle triangle in triMesh.Triangles) { // draw Voronoi cells, one around each Delaunay triangle vertex foreach (TriangulationPoint triVertex in triangle.Points) { // each cell corresponds to a triangulation vertex Vector2 point = triVertex.ToVector2(); if (drawnVoronoiCells.Contains(point)) { // this Voronoi cell was already drawn continue; } drawnVoronoiCells.Add(point); IList<DelaunayTriangle> surroundingTriangles = VoronoiHelper.GetSurroundingTriangles(triangle, triVertex); if (surroundingTriangles.Count < 3) { // there are not enough vertices to make a polygon continue; } // TODO: the computation of the circumference could // be cached since the voronoi vertices are usually // share among multiple triangles IEnumerable<Vector2> voronoiCellVertices = surroundingTriangles.Select( (DelaunayTriangle tri) => VoronoiHelper.GetCircumcenter(tri)); PointF[] voronoiCellPolygon = voronoiCellVertices.Select( (Vector2 vertex) => vertex.ToPointF()).ToArray(); //Color sampleColor = GetRandomColor(); ImageSample imageSample; Color sampleColor = Color.Pink; // DEBUG if (sampledImage.SampleMap.TryGetValue((int)triVertex.Y * sampledImage.Width + (int)triVertex.X, out imageSample)) { sampleColor = imageSample.color; } graphics.FillPolygon(new SolidBrush(sampleColor), voronoiCellPolygon); if (VoronoiCellBordersEnabled) { graphics.DrawPolygon(Pens.Gray, voronoiCellPolygon); } } trianglesDone++; if ((samplePercent > 500) && (trianglesDone % samplePercent == 0)) { percentDone++; Progress.ReportProgress(25 + percentDone); } } }
private void DrawDelaunayTriangles(PointSet triMesh, Graphics graphics) { int samplePercent = 4 * triMesh.Triangles.Count / 100; int trianglesDone = 0; int percentDone = 0; foreach (DelaunayTriangle triangle in triMesh.Triangles) { // draw Delaunay triangulation PointF[] points = triangle.ToPointFArray(); graphics.DrawPolygon(Pens.Black, points); trianglesDone++; if ((samplePercent > 500) && (trianglesDone % samplePercent == 0)) { percentDone++; Progress.ReportProgress(50 + percentDone); } } }
private void DrawAdditionalFeatures(int width, int height, PointSet triMesh, Graphics graphics, Bitmap image) { int samplePercent = 4 * triMesh.Triangles.Count / 100; int trianglesDone = 0; int percentDone = 0; if (VoronoiVerticesEnabled || DelaunayCircumcirclesEnabled) { foreach (DelaunayTriangle triangle in triMesh.Triangles) { Vector2 voronoiVertex = VoronoiHelper.GetCircumcenter(triangle); if (VoronoiVerticesEnabled) { DrawVoronoiVertex(width, height, voronoiVertex, graphics, image); } if (DelaunayCircumcirclesEnabled) { DrawDelaunayCircumcircles(triangle, voronoiVertex, graphics); } trianglesDone++; if ((samplePercent > 500) && (trianglesDone % samplePercent == 0)) { percentDone++; Progress.ReportProgress(75 + percentDone); } } } }
public PointSet MakeDelaunayTriangulation(List<TriangulationPoint> points) { PointSet polygon = new PointSet(points); try { Stopwatch stopwatch = Stopwatch.StartNew(); P2T.Triangulate(polygon); stopwatch.Stop(); progress.TimeReport["delaunay"] = stopwatch.ElapsedMilliseconds; } catch (NotImplementedException ex) { Console.WriteLine("Delaunay triangulation - exception: {0}", ex.Message); } //catch (NullReferenceException ex) //{ // Console.WriteLine("Delaunay triangulation - exception: {0}", ex.Message); //} return polygon; }
//////// public static PointSet LoadDatPointSet(string filename, bool xflip, bool yflip, bool displayFlipX, bool displayFlipY, float rotateAngleInDegrees) { var points = new List <TriangulationPoint>(); List <List <TriangulationPoint> > constrainedPoints = new List <List <TriangulationPoint> >(); List <string> constrainedPointSetNames = new List <string>(); List <TriangulationPoint> bounds = new List <TriangulationPoint>(); List <TriangulationPoint> currentList = points; double precision = TriangulationPoint.kVertexCodeDefaultPrecision; int lineNum = 0; bool skipLine = false; foreach (var line_ in File.ReadAllLines(filename)) { ++lineNum; string line = line_.Trim(); if (string.IsNullOrEmpty(line) || line.StartsWith("//") || line.StartsWith("#") || line.StartsWith(";")) { continue; } if (!skipLine && line.StartsWith("/*")) { skipLine = true; continue; } else if (skipLine) { if (line.StartsWith("*/")) { skipLine = false; } continue; } if (line.StartsWith("Precision", StringComparison.InvariantCultureIgnoreCase)) { if (line.Length > 9) { string precisionStr = line.Substring(9).Trim(); if (!double.TryParse(precisionStr, NumberStyles.Float, CultureInfo.InvariantCulture, out precision)) { Console.WriteLine("Invalid Precision '" + precisionStr + "' in file " + filename + ", line " + lineNum.ToString() + ". Setting to " + TriangulationPoint.kVertexCodeDefaultPrecision.ToString()); precision = TriangulationPoint.kVertexCodeDefaultPrecision; } } } else if (line.StartsWith("Set", StringComparison.InvariantCultureIgnoreCase)) { if (line.StartsWith("SetBegin")) { string[] setParts = line.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries); if (setParts.Length < 2) { continue; } //if (setParts[1].Equals("Constrained", StringComparison.InvariantCultureIgnoreCase)) if (setParts[1].Equals("Constrained", StringComparison.InvariantCultureIgnoreCase) || setParts[1].Equals("Unconstrained", StringComparison.InvariantCultureIgnoreCase)) { currentList = new List <TriangulationPoint>(); constrainedPoints.Add(currentList); if (setParts.Length > 2) { constrainedPointSetNames.Add(setParts[2]); } else { constrainedPointSetNames.Add(""); } } else if (bounds.Count == 0 && setParts[1].Equals("Bounds", StringComparison.InvariantCultureIgnoreCase)) { currentList = bounds; } else { currentList = points; } } else { currentList = points; } } else { var xy = line.Split(new[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries); double x, y; if (xy != null && xy.Length >= 2 && double.TryParse(xy[0], NumberStyles.Float, CultureInfo.InvariantCulture, out x) && double.TryParse(xy[1], NumberStyles.Float, CultureInfo.InvariantCulture, out y)) { currentList.Add(new PolygonPoint((xflip ? -1.0 : 1.0) * x, (yflip ? -1.0 : 1.0) * y)); } else { Console.WriteLine("Invalid Input '" + line + "' in file " + filename + ", line " + lineNum.ToString()); } } } PointSet ps = null; if (constrainedPoints.Count > 0) { ConstrainedPointSet cps = null; if (bounds.Count < 3) { points.AddRange(bounds); cps = new ConstrainedPointSet(points); } else { cps = new ConstrainedPointSet(bounds); cps.AddRange(points); } int numConstrainedPointSets = constrainedPoints.Count; for (int i = 0; i < numConstrainedPointSets; ++i) { List <TriangulationPoint> hole = constrainedPoints[i]; if (hole.Count < 3) { cps.AddRange(hole); } else { cps.AddHole(hole, constrainedPointSetNames[i]); } } ps = cps; } else { if (bounds.Count < 3) { points.AddRange(bounds); ps = new PointSet(points); } else { ps = new PointSet(bounds); ps.AddRange(points); } } ps.FileName = filename; ps.DisplayFlipX = displayFlipX; ps.DisplayFlipY = displayFlipY; ps.DisplayRotate = rotateAngleInDegrees; ps.Precision = precision; return(ps); }