public void Smooth(IMesh mesh, int limit) { var smoothedMesh = (Mesh)mesh; var mesher = new GenericMesher(config); var predicates = config.Predicates(); // The smoother should respect the mesh segment splitting behavior. this.options.SegmentSplitting = smoothedMesh.behavior.NoBisect; // Take a few smoothing rounds (Lloyd's algorithm). for (int i = 0; i < limit; i++) { Step(smoothedMesh, factory, predicates); // Actually, we only want to rebuild, if the mesh is no longer // Delaunay. Flipping edges could be the right choice instead // of re-triangulating... smoothedMesh = (Mesh)mesher.Triangulate(Rebuild(smoothedMesh), options); factory.Reset(); } smoothedMesh.CopyTo((Mesh)mesh); }
private static IMesh GetScatteredDataMesh(Rectangle domain) { var r = new Rectangle(domain); double h = domain.Width / SIZE; // Generate a rectangle boundary point set (SIZE points on each side). var input = Generate.Rectangle(r, h); // Making sure we add some margin to the boundary. h = -h / 2; r.Resize(h, h); int n = Math.Max(1, SIZE * SIZE - input.Points.Count); // Add more input points (more sampling points, better interpolation). input.Points.AddRange(Generate.RandomPoints(n, r)); var mesher = new GenericMesher(new Dwyer()); // Generate mesh. var mesh = mesher.Triangulate(input.Points); mesh.Renumber(); return(mesh); }
public void TestAdjacencyMatrixDuplicate() { var p = GetVertices(true); var mesher = new GenericMesher(); var mesh = (Mesh)mesher.Triangulate(p); mesh.Renumber(); var matrix = new AdjacencyMatrix(mesh); var ai = matrix.RowIndices; // Highest vertex id after renumbering is 4, duplicates // are ignored. Assert.AreEqual(4, ai.Max()); // Get the single, duplicate vertex. var dup = mesh.Vertices .Where(v => v.Type == VertexType.UndeadVertex) .Single(); // Side effect: undead vertices will have negative indices // after computing the adjacency matrix. Assert.IsTrue(dup.id < 0); Assert.IsTrue(!ai.Contains(dup.id)); }
public void Execute() { Util.Tic(); var polygons = LoadPolygons(); //Console.WriteLine(" Polygons: {0} (took {1}ms to load)", polygons.Count, Util.Toc()); string loadingPolygons = $"Polygons: {polygons.Count} (took {Util.Toc()}ms to load)"; Util.Tic(); var sequentialInfo = RunSequential(polygons); //Console.WriteLine("Sequential: {0}ms", Util.Toc()); string sequential = $"Sequential: {Util.Toc()}ms"; Util.Tic(); var parallelInfo = RunParallel(polygons); //Console.WriteLine(" Parallel: {0}ms", Util.Toc()); string parallel = $"Parallel: {Util.Toc()}ms"; //var dummymesh = new Mesh(new Configuration()); var mesher = new GenericMesher(new Configuration()); DarkMessageBox.Show($"{Name} - {Description}", $"{loadingPolygons}\n{sequential} {sequentialInfo} \n{parallel} {parallelInfo}"); foreach (var poly in polygons) { InputGenerated(mesher.Triangulate(poly), EventArgs.Empty); DarkMessageBox.Show("Just showing all the read poly files", "Show next"); } }
public static string RunSequential(List <IPolygon> polygons) { var pool = new TrianglePool(); var predicates = new RobustPredicates(); var config = new Configuration(); config.Predicates = () => predicates; config.TrianglePool = () => pool.Restart(); var mesher = new GenericMesher(config); var result = new MeshResult(); foreach (var poly in polygons) { var mesh = mesher.Triangulate(poly); ProcessMesh(mesh, result); } pool.Clear(); //Console.WriteLine("Total number of triangles processed: {0}", result.NumberOfTriangles); var sequential = $"Total number of triangles processed: {result.NumberOfTriangles}"; if (result.Invalid > 0) { //Console.WriteLine(" Number of invalid triangulations: {0}", result.Invalid); sequential += $"Number of invalid triangulations: {result.Invalid}"; } return(sequential); }
internal void CalcDL(Structure str) { if (str == null || str.RedPlanning == null || str.RedPlanning.Count == 0) { return; } List <Vertex> vrtxs = new List <Vertex>(); Vertex vrtx; int i = 1; foreach (PlanningVertex item in str.RedPlanning) { vrtx = new Vertex(item.X, item.Y, item.Number, 2); vrtx.Attributes[0] = item.Red; vrtx.Attributes[1] = item.Black; vrtxs.Add(vrtx); i++; } Contour cnt = new Contour(vrtxs); TriangleNet.Geometry.Polygon polygon = new TriangleNet.Geometry.Polygon(); polygon.Add(cnt); GenericMesher mesher = new GenericMesher(); ConstraintOptions constraint = new ConstraintOptions(); constraint.Convex = true; Mesh meshPlanning = (Mesh)mesher.Triangulate(polygon, constraint); TriangleQuadTree meshTree = new TriangleQuadTree(meshPlanning); TriangleNet.Topology.Triangle trgl = (TriangleNet.Topology.Triangle)meshTree.Query(X, Y); if (trgl == null) { Dictionary <Vertex, double> valuePairs = new Dictionary <Vertex, double>(); Line2d ln; foreach (Vertex item in meshPlanning.Vertices) { ln = new Line2d(new Point2d(X, Y), new Point2d(item.X, item.Y)); valuePairs.Add(item, ln.Length); } IOrderedEnumerable <KeyValuePair <Vertex, double> > selected = from v in valuePairs // определяем каждый объект как orderby v.Value // упорядочиваем по возрастанию select v; // выбираем объект List <KeyValuePair <Vertex, double> > lst = selected.ToList(); foreach (TriangleNet.Topology.Triangle item in meshPlanning.Triangles) { if (item.Contains(lst[0].Key) && item.Contains(lst[1].Key)) { trgl = item; break; } } } vrtx = new Vertex(X, Y, Number, 2); Interpolation.InterpolateAttributes(vrtx, trgl, 1); DL = Math.Round(vrtx.Attributes[0], 3); }
public static void ExtrudeText(this MeshBuilder builder, string text, string font, FontStyle fontStyle, FontWeight fontWeight, double fontSize, Vector3D textDirection, Point3D p0, Point3D p1) { var outlineList = GetTextOutlines(text, font, fontStyle, fontWeight, fontSize); // Build the polygon to mesh (using Triangle.NET to triangulate) var polygon = new TriangleNet.Geometry.Polygon(); int marker = 0; foreach (var outlines in outlineList) { var outerOutline = outlines.OrderBy(x => x.AreaOfSegment()).Last(); for (int i = 0; i < outlines.Count; i++) { var outline = outlines[i]; var isHole = i != outlines.Count - 1 && IsPointInPolygon(outerOutline, outline[0]); polygon.AddContour(outline.Select(p => new Vertex(p.X, p.Y)), marker++, isHole); builder.AddExtrudedSegments(outline.ToSegments().Select(x => new SharpDX.Vector2((float)x.X, (float)x.Y)).ToList(), textDirection, p0, p1); } } var mesher = new GenericMesher(); var options = new ConstraintOptions(); var mesh = mesher.Triangulate(polygon, options); var u = textDirection; u.Normalize(); var z = p1 - p0; z.Normalize(); var v = Vector3D.Cross(z, u); // Convert the triangles foreach (var t in mesh.Triangles) { var v0 = t.GetVertex(2); var v1 = t.GetVertex(1); var v2 = t.GetVertex(0); // Add the top triangle. // Project the X/Y vertices onto a plane defined by textdirection, p0 and p1. builder.AddTriangle(v0.Project(p0, u, v, z, 1), v1.Project(p0, u, v, z, 1), v2.Project(p0, u, v, z, 1)); // Add the bottom triangle. builder.AddTriangle(v2.Project(p0, u, v, z, 0), v1.Project(p0, u, v, z, 0), v0.Project(p0, u, v, z, 0)); } if (builder.CreateNormals) { builder.Normals = null; builder.ComputeNormalsAndTangents(MeshFaces.Default, builder.HasTangents); } }
public void TestTriangulateDwyer() { var m = new GenericMesher(); var vertices = GetVertices(); var mesh = m.Triangulate(vertices); Assert.AreEqual(6, vertices.Count); Assert.AreEqual(6, mesh.Vertices.Count); Assert.AreEqual(1, mesh.Vertices .Where(v => v.Type == VertexType.UndeadVertex) .Count()); }
public void TestAdjacencyMatrix() { var p = GetVertices(false); var mesher = new GenericMesher(); var mesh = (Mesh)mesher.Triangulate(p); Assert.AreEqual(5, mesh.Vertices.Max(v => v.ID)); mesh.Renumber(); var matrix = new AdjacencyMatrix(mesh); // Highest vertex id after renumbering is 4, since there // is no duplicate vertex. Assert.AreEqual(4, matrix.RowIndices.Max()); }
void CreateMesh() { colors = new Color[points.Length]; normals = new Vector3[points.Length]; for (int i = 0; i < points.Length; i++) { float cscale = (points [i].y - 0.9f) / 0.2f; colors [i] = new Color(cscale, 0, 1 - cscale); normals [i] = new Vector3(0, 1, 0); } GenericMesher gm = new GenericMesher(); List <Vertex> vertices = new List <Vertex> (); for (int i = 0; i < points.Length; i++) { Vertex v = new Vertex(points [i].x, points [i].z); vertices.Add(v); } //Dwyer dw = new Dwyer (); //Configuration con = new Configuration (); //dw.Triangulate (vertices, con); IMesh imesh = gm.Triangulate(vertices); ICollection <Triangle> tri = imesh.Triangles; int ntri = tri.Count; triangles = new int[3 * ntri]; int ctri = 0; foreach (Triangle triangle in tri) { triangles[ctri] = triangle.GetVertexID(0); triangles[ctri + 1] = triangle.GetVertexID(1); triangles[ctri + 2] = triangle.GetVertexID(2); ctri += 3; } UnityEngine.Mesh mesh = GetComponent <MeshFilter> ().mesh; mesh.vertices = points; mesh.triangles = triangles; mesh.normals = normals; mesh.colors = colors; mesh.RecalculateNormals(); mesh.RecalculateBounds(); }
/// <summary> /// Smooth mesh with a maximum given number of rounds of Voronoi /// iteration. /// </summary> /// <param name="mesh">The mesh.</param> /// <param name="limit">The maximum number of iterations. If /// non-positive, no iteration is applied at all.</param> /// <param name="tol">The desired tolerance on the result. At each /// iteration, the maximum movement by any side is considered, both for /// the previous and the current solutions. If their relative difference /// is not greater than the tolerance, the current solution is /// considered good enough already.</param> /// <returns>The number of actual iterations performed. It is 0 if a /// non-positive limit is passed. Otherwise, it is always a value /// between 1 and the limit (inclusive). /// </returns> public int Smooth(IMesh mesh, int limit = 10, double tol = .01) { if (limit <= 0) { return(0); } var smoothedMesh = (Mesh)mesh; var mesher = new GenericMesher(config); var predicates = config.Predicates(); // The smoother should respect the mesh segment splitting behavior. this.options.SegmentSplitting = smoothedMesh.behavior.NoBisect; // The maximum distances moved from any site at the previous and // current iterations. double prevMax = Double.PositiveInfinity, currMax = Step(smoothedMesh, factory, predicates); // Take a few smoothing rounds (Lloyd's algorithm). The stop // criteria are the maximum number of iterations and the convergence // criterion. int i = 1; while (i < limit && Math.Abs(currMax - prevMax) > tol * currMax) { prevMax = currMax; currMax = Step(smoothedMesh, factory, predicates); // Actually, we only want to rebuild, if the mesh is no longer // Delaunay. Flipping edges could be the right choice instead // of re-triangulating... smoothedMesh = (Mesh)mesher.Triangulate(Rebuild(smoothedMesh), options); factory.Reset(); i++; } smoothedMesh.CopyTo((Mesh)mesh); return(i); }
//public void GenHighway() { public IEnumerator GenHighwayCoroutine() { WorldManager.GenHighwayState = true; Dictionary <Vector2, float> densityLookup = new Dictionary <Vector2, float>(); // cluster nearby points with DBScan List <Vector2> features = new List <Vector2>();// = new MyFeatureDataSource().GetFeatureData(); for (int i = 0; i < patchDensityCenters.Count; i++) { (Vector2, float)cd = ((Vector2, float))patchDensityCenters[i]; features.Add(cd.Item1); densityLookup[cd.Item1] = cd.Item2; } var result = RunOfflineDbscan(features); // Build highway graph var points = new List <Vertex>(); foreach (int i in result.Clusters.Keys) { points.Add(new Vertex(result.Clusters[i][0].Feature.x, result.Clusters[i][0].Feature.y)); } // Generate a default mesher var mesher = new GenericMesher(new Dwyer()); // Generate mesh (Delaunay Triangulation) mesh = mesher.Triangulate(points); // Init edge/vertex lists for mutation foreach (Vertex v in mesh.Vertices) { vertices.Add(v); } foreach (Edge e in mesh.Edges) { edges.Add(e); // build neighbor map Vertex v0 = (Vertex)vertices[e.P0]; Vertex v1 = (Vertex)vertices[e.P1]; if (!neighbors.ContainsKey(v0)) { neighbors[v0] = new List <Vertex>(); } neighbors[v0].Add(v1); } // Remove unecessary edges on cost basis foreach (Edge e in mesh.Edges) { Vertex v0 = (Vertex)vertices[e.P0]; Vertex v1 = (Vertex)vertices[e.P1]; (Vector2, Vector2)tup1 = (Util.VertexToVector2(v0), Util.VertexToVector2(v1)); (Vector2, Vector2)tup2 = (Util.VertexToVector2(v1), Util.VertexToVector2(v0)); if (!InPatchBounds(regionIdx, tup1.Item1, tup1.Item2)) { RemoveEdge(e); continue; } if (!WorldManager.edgeState.ContainsKey(tup1)) //needs removal check { if (ShouldRemoveEdge(e, densityLookup)) { // remove edge for first time WorldManager.edgeState[tup1] = false; WorldManager.edgeState[tup2] = false; RemoveEdge(e); } else { // keep edge, register with edgeState WorldManager.edgeState[tup1] = true; WorldManager.edgeState[tup2] = true; } } else // remove if removed before { if (!WorldManager.edgeState[tup1]) { RemoveEdge(e); } } } // Generate final highway segments for each edge // Uses A* search to pathfind int hwCount = 0; foreach (Edge e in edges) { hwCount++; (Vector2Int, Vector2Int)eVec = (Util.VertexToVector2Int((Vertex)vertices[e.P0]), Util.VertexToVector2Int((Vertex)vertices[e.P1])); Vertex v0 = (Vertex)vertices[e.P0]; Vertex v1 = (Vertex)vertices[e.P1]; // Skip pathfinding for edges that have been generated/built already if (WorldBuilder.builtHighways.ContainsKey((Util.VertexToVector2(v0), Util.VertexToVector2(v0))) && WorldBuilder.builtHighways[(Util.VertexToVector2(v0), Util.VertexToVector2(v0))]) { //Debug.Log("Aborting pathfind since already built!"); continue; } // A* pathfind from v0 to v1 ArrayList segments = pathfinding.FindPath(Util.VertexToVector2(v0), Util.VertexToVector2(v1)); // Removal of redundant paths int firstIdx = -1, secondIdx = -1; List <(Vector2, (Vector2Int, Vector2Int))> vertListFirst = null, vertListSecond = null; // traverse from beginning for (int i = 0; i < segments.Count - 1; i++) { Vector2 v = (Vector2)segments[i]; if (WorldBuilder.DoesChunkContainHighway(v)) { firstIdx = i; vertListFirst = WorldBuilder.GetHighwayVertList(v); break; } } // traverse from end if (firstIdx >= 0) { for (int i = segments.Count - 1; i > 0; i--) { Vector2 v = (Vector2)segments[i]; if (WorldBuilder.DoesChunkContainHighway(v)) { secondIdx = i; vertListSecond = WorldBuilder.GetHighwayVertList(v); break; } } } // segment join logic if (vertListFirst != null && vertListSecond != null && firstIdx >= 0 && secondIdx >= 0) { // Direct connection with existing path bool done = false; // *--|____/* foreach ((Vector2, (Vector2Int, Vector2Int))tup in vertListFirst) { if (eVec.Item2 == tup.Item2.Item2 || eVec.Item2 == tup.Item2.Item1) { segments.RemoveRange(firstIdx, segments.Count - firstIdx); segments.Insert(firstIdx, tup.Item1); done = true; break; } } if (!done) { // *\____|--* foreach ((Vector2, (Vector2Int, Vector2Int))tup in vertListSecond) { if (eVec.Item1 == tup.Item2.Item2 || eVec.Item1 == tup.Item2.Item1) { segments.RemoveRange(0, secondIdx); segments.Insert(0, tup.Item1); done = true; break; } } } if (!done) { // No direct connection cases (needs paths from start and end) (bool, (Vector2Int, Vector2Int))sameEdgeRes = DoListsContainSameEdge(vertListFirst, vertListSecond); if (sameEdgeRes.Item1) { Vector2 con1 = FindVecWithEdge(sameEdgeRes.Item2, vertListFirst), con2 = FindVecWithEdge(sameEdgeRes.Item2, vertListSecond); if (con1 == con2) // same vert // *--|-----* pass through path { segments.RemoveAt(firstIdx); segments.Insert(firstIdx, con1); } else // diff vert // *--|__|--* join at existing path //Debug.Log(firstIdx + " " + secondIdx); { segments.RemoveRange(firstIdx, secondIdx - firstIdx + 1); segments.Insert(firstIdx, con2); segments.Insert(firstIdx, WorldBuilder.SignalVector); segments.Insert(firstIdx, con1); } } else// not matched so edges different! { Vector2 con1 = vertListFirst[0].Item1, con2 = vertListSecond[0].Item1; //neighbor or not if (DoListsContainNeighbors(vertListFirst, vertListSecond)) { // *--\./---* segments.RemoveRange(firstIdx, secondIdx - firstIdx + 1); segments.Insert(firstIdx, con2); segments.Insert(firstIdx, WorldBuilder.SignalVector); segments.Insert(firstIdx, con1); } else { // *--|--|--* pass through paths segments.RemoveAt(secondIdx); segments.RemoveAt(firstIdx); segments.Insert(firstIdx, con1); segments.Insert(secondIdx, con2); } } } } foreach (Vector2 v in segments) { WorldBuilder.AddHighwayVertToChunkHash(v, eVec); } if (segments != null) { highways.Add(segments); } if (hwCount % Settings.hwPathfindingIncrement == 0) { yield return(null); } } WorldManager.GenHighwayState = false; }
void GenMap() { /* * <settings> */ int starsAm = 10000; // What percentage of space is taken up by stars. int starDensity = 20; // Minimal corridor length relative to maximal star size. float minCorridorLengthCoeff = 3.0f; // What percentage of space is taken up by corridors. int corridorDensity = 60; float maxz = 3.0f; /* * </settings> */ float max_star_size = Mathf.Max(pos_star_sizes); Debug.Log("Max star size: " + max_star_size); float min_corridor_length = max_star_size * minCorridorLengthCoeff; float min_corridor_length_squared = Mathf.Pow(min_corridor_length, 2); int starsx = Mathf.RoundToInt(Mathf.Sqrt(starsAm)); int starsy = starsx; float width = (starsx * max_star_size) + ((starsx - 1) * min_corridor_length); float height = (starsy * max_star_size) + ((starsy - 1) * min_corridor_length); background.transform.localScale = new Vector3(width * 0.11f, 1.0f, height * 0.11f); background.GetComponent <MeshRenderer>().material.SetTextureScale("_MainTex", new Vector2(width / 70.0f, height / 70.0f)); Debug.Log("Dimensions: " + width + ", " + height); float minx = width * -0.5f; float miny = height * -0.5f; float maxx = width * 0.5f; float maxy = height * 0.5f; float max_offset_x = (width / starsx) - ((min_corridor_length - max_star_size) * 0.5f); float max_offset_y = (height / starsy) - ((min_corridor_length - max_star_size) * 0.5f); Debug.Log("Offsets: " + max_offset_x + ", " + max_offset_y); Rectangle bounds = new Rectangle(minx, miny, width, height); TriangleNet.Mesh mesh = (TriangleNet.Mesh)GenericMesher.StructuredMesh(bounds, starsx - 1, starsy - 1); List <TriangleNet.Geometry.Vertex> stars = new List <TriangleNet.Geometry.Vertex>(); List <TriangleNet.Geometry.Vertex> shuffled_verts = new List <TriangleNet.Geometry.Vertex>(mesh.Vertices); shuffled_verts.Shuffle(); int stars_amount = 0; foreach (TriangleNet.Geometry.Vertex v in shuffled_verts) { if (stars_amount > 3 && Random.Range(0, 101) > starDensity) { continue; } stars.Add(v); stars_amount++; } GenericMesher gm = new GenericMesher(new SweepLine()); mesh = (TriangleNet.Mesh)gm.Triangulate(stars); StandardVoronoi sv = new StandardVoronoi(mesh); Polygon final = new Polygon(sv.Vertices.Count); Dictionary <int, TriangleNet.Geometry.Vertex> good_stars = new Dictionary <int, TriangleNet.Geometry.Vertex>(); Dictionary <int, int> bad2goodstar = new Dictionary <int, int>(); List <int> outBoundStars = new List <int>(); foreach (TriangleNet.Topology.DCEL.Vertex v in sv.Vertices) { if (v.x < minx || v.x > maxx || v.y < miny || v.y > maxy) { outBoundStars.Add(v.id); continue; } bool invalid = false; foreach (TriangleNet.Geometry.Vertex other in good_stars.Values) { Vector2 v1 = new Vector2((float)v.x, (float)v.y); Vector2 v2 = new Vector2((float)other.x, (float)other.y); if ((v2 - v1).sqrMagnitude < min_corridor_length_squared) { invalid = true; bad2goodstar[v.id] = other.id; } } if (invalid) { continue; } TriangleNet.Geometry.Vertex new_v = new TriangleNet.Geometry.Vertex(v.x, v.y); new_v.id = v.id; good_stars[v.id] = new_v; final.Add(new_v); } List <Segment> good_segments = new List <Segment>(); foreach (Edge e in sv.Edges) { if (outBoundStars.Contains(e.P0) || outBoundStars.Contains(e.P1)) { continue; } int P0_id; int P1_id; if (bad2goodstar.ContainsKey(e.P0)) { P0_id = bad2goodstar[e.P0]; } else { P0_id = e.P0; } if (bad2goodstar.ContainsKey(e.P1)) { P1_id = bad2goodstar[e.P1]; } else { P1_id = e.P1; } if (P0_id == P1_id) { continue; } good_segments.Add(new Segment(good_stars[P0_id], good_stars[P1_id])); } Dictionary <int, List <int> > connected_stars = new Dictionary <int, List <int> >(); foreach (Segment s in good_segments) { if (!connected_stars.ContainsKey(s.P0)) { connected_stars[s.P0] = new List <int>(); } connected_stars[s.P0].Add(s.P1); if (!connected_stars.ContainsKey(s.P1)) { connected_stars[s.P1] = new List <int>(); } connected_stars[s.P1].Add(s.P0); } Debug.Log("Currently edges: " + good_segments.Count); List <Segment> temp_segments = new List <Segment>(good_segments); temp_segments.Shuffle(); foreach (Segment s in temp_segments) { if (Random.Range(0, 101) > corridorDensity && RemovalConnectionsCheck(connected_stars, s.P0, s.P1)) { connected_stars[s.P0].Remove(s.P1); connected_stars[s.P1].Remove(s.P0); good_segments.Remove(s); } } foreach (Segment s in good_segments) { final.Add(s); } Debug.Log("Stars after everything: " + final.Points.Count); Debug.Log("Corridors after everything: " + good_segments.Count); CreateMap(final, maxz, 0.0f); }
/// <summary> /// Reads all .poly files from given directory and processes them in parallel. /// </summary> public static bool Run(string dir) { var files = Directory.EnumerateFiles(dir, "*.poly", SearchOption.AllDirectories); var queue = new ConcurrentQueue <string>(files); int concurrencyLevel = Environment.ProcessorCount / 2; var tasks = new Task <MeshResult> [concurrencyLevel]; for (int i = 0; i < concurrencyLevel; i++) { tasks[i] = Task.Run(() => { // Each task has it's own triangle pool and predicates instance. var pool = new TrianglePool(); var predicates = new RobustPredicates(); // The factory methods return the above instances. var config = new Configuration() { Predicates = () => predicates, TrianglePool = () => pool.Restart(), RandomSource = () => Random.Shared }; var mesher = new GenericMesher(config); var result = new MeshResult(); while (queue.Count > 0) { if (queue.TryDequeue(out var file)) { var poly = FileProcessor.Read(file); var mesh = mesher.Triangulate(poly); ProcessMesh(mesh, result); } } pool.Clear(); return(result); }); } Task.WaitAll(tasks); int numberOfTriangles = tasks.Sum(t => t.Result.NumberOfTriangles); int invalid = tasks.Sum(t => t.Result.Invalid); Console.WriteLine("Total number of triangles processed: {0}", numberOfTriangles); if (invalid > 0) { Console.WriteLine(" Number of invalid triangulations: {0}", invalid); } return(invalid == 0); }
private MeshData UpdateMeshData(MeshData oldData, IClipShape clipShape) { var clipPolygon = clipShape.ClipPolygon(); var oldVertices = oldData.vertices; var oldTriangles = oldData.triangles; var oldPaths = oldData.paths; var newVertices = new List <Vector2>(oldVertices.Length); var vertexIndex = new Dictionary <int, int>(oldVertices.Length); Vector2 v; for (int i = 0; i < oldVertices.Length; i++) { v = oldVertices[i]; if (clipPolygon.PointInPolygon(v)) { vertexIndex.Add(i, -1); } else { vertexIndex.Add(i, newVertices.Count); newVertices.Add(v); } } var newTriangles = new List <int>(oldTriangles.Length); var clippedTriangles = new List <int[]>(); List <int> oldTriangle = new List <int>(3); for (int i = 0; i < oldTriangles.Length / 3; i++) { oldTriangle.Clear(); oldTriangle.Add(oldTriangles[3 * i]); oldTriangle.Add(oldTriangles[3 * i + 1]); oldTriangle.Add(oldTriangles[3 * i + 2]); var newTriangle = oldTriangle.Select(oldIndex => vertexIndex[oldIndex]).ToArray(); if (newTriangle.Any(newIndex => newIndex > -1)) { if (newTriangle.All(newIndex => newIndex > -1) && !clipShape.ShouldClipTriangle(newTriangle.Select(newIndex => newVertices[newIndex]))) { newTriangles.AddRange(newTriangle); } else { clippedTriangles.Add(oldTriangle.ToArray()); } } } var newPolygons = clippedTriangles .Select(t => t.Select(oldIndex => (Vector2)oldVertices[oldIndex])) .SelectMany(t => PSClipperHelper.difference(t, clipPolygon.points)); var mesher = new GenericMesher(); foreach (var points in newPolygons) { var poly = new Polygon(); poly.Add(TerrainMesh.createContour(points)); var imesh = mesher.Triangulate(poly); TerrainMesh.getTriangles(imesh, ref newVertices, ref newTriangles); } var newPaths = oldPaths .SelectMany(p => PSClipperHelper.difference(p, clipPolygon.points)) .Select(p => p.ToArray()) .ToArray(); var particles = oldPaths .SelectMany(p => PSClipperHelper.intersection(p, clipPolygon.points)) .Select(p => GenerateParticles(new PSPolygon(p))) .ToArray(); return(new MeshData( newVertices.Select(c => new Vector3(c.x, c.y, 0)).ToArray(), newVertices.Select(c => (Color32)terrainMesh.terrainTintColor(c, doNotWrapUV)).ToArray(), newVertices.Select(c => terrainMesh.getUV(c, doNotWrapUV)).ToArray(), newVertices.Select(c => terrainMesh.getUV2(c, doNotWrapUV, floorEdges)).ToArray(), newTriangles.ToArray(), newPaths, particles)); }
public static string RunParallel(List <IPolygon> polygons) { var queue = new ConcurrentQueue <IPolygon>(polygons); int concurrencyLevel = Environment.ProcessorCount; var tasks = new Task <MeshResult> [concurrencyLevel]; for (int i = 0; i < concurrencyLevel; i++) { tasks[i] = Task.Run(() => { // Each task has it's own triangle pool and predicates instance. var pool = new TrianglePool(); var predicates = new RobustPredicates(); var config = new Configuration(); // The factory methods return the above instances. config.Predicates = () => predicates; config.TrianglePool = () => pool.Restart(); IPolygon poly; var mesher = new GenericMesher(config); var result = new MeshResult(); while (queue.Count > 0) { if (queue.TryDequeue(out poly)) { var mesh = mesher.Triangulate(poly); ProcessMesh(mesh, result); } } pool.Clear(); return(result); }); } Task.WaitAll(tasks); int numberOfTriangles = 0; int invalid = 0; for (int i = 0; i < concurrencyLevel; i++) { var result = tasks[i].Result; numberOfTriangles += result.NumberOfTriangles; invalid += result.Invalid; } string parallel = $"Total number of triangles processed: {numberOfTriangles}"; //Console.WriteLine("Total number of triangles processed: {0}", numberOfTriangles); if (invalid > 0) { //Console.WriteLine(" Number of invalid triangulations: {0}", invalid); parallel += $"\tNumber of invalid triangulations: {invalid}"; } return(parallel); }
/////////////////////////////////////////////////////////////////// // GENERATION FUNCTIONS /////////////////////////////////////////// /////////////////////////////////////////////////////////////////// /// public void GenBlock() { //List<Vector2f> points = new List<Vector2f>(); List <Vector2> startLotCenters = new List <Vector2>(); // find corners for (int i = 0; i < verts.Count - 1; i++) { Vector2 vc = (Vector2)verts[i]; Vector2 vp = (Vector2)(i == 0 ? verts[verts.Count - 1] : verts[i - 1]); Vector2 vn = (Vector2)verts[i + 1]; Vector2 diffP = vp - vc; Vector2 diffN = vn - vc; float angle = Mathf.Abs(Vector2.Angle(diffP, diffN)); if (angle < 165) { corners.Add(vc); cornersIdx.Add(i); //points.Add(new Vector2f(vc.x, vc.y)); } } Vector2 avgCorner = Vector2.zero; foreach (Vector2 c in corners) { avgCorner += c; } avgCorner /= corners.Count; foreach (Vector2 c in corners) { Vector2 dir = (avgCorner - c).normalized; startLotCenters.Add(c + dir * 3); } //corners = new List<Vector2>(tempCorners); // gen points if (true) { for (int i = 0; i < startLotCenters.Count - 1; i++) { Vector2 corner1 = startLotCenters[i]; Vector2 corner2 = startLotCenters[i + 1]; lotCenters.Add(corner1); Vector2 diff = corner2 - corner1; Vector2 dir = diff.normalized; float lineDist = diff.magnitude; int numLots = (int)(lineDist / 7); float lotWidth = lineDist / numLots; //traverse corner to corner Vector2 cur = corner1 + (lotWidth / 2) * dir; float distTraversed = lotWidth / 2; if (!( cur.x == Mathf.Infinity || cur.x == -Mathf.Infinity || cur.y == Mathf.Infinity || cur.y == -Mathf.Infinity || float.IsNaN(cur.x) || float.IsNaN(cur.y) )) { lotCenters.Add(cur); //points.Add(new Vector2f(cur.x, cur.y)); int lotsPlaced = 1; while (distTraversed < lineDist && lotsPlaced < numLots) { cur += (lotWidth / 2) * dir; if (!bounds.InBounds(cur)) { break; } //points.Add(new Vector2f(cur.x, cur.y)); lotCenters.Add(cur); lotsPlaced++; } } } } // Build lot graph if (lotCenters.Count >= 3) { List <Vector2> lotGuides = new List <Vector2>(lotCenters); for (int i = 0; i < verts.Count - 1; i++) { Vector2 v = (Vector2)verts[i]; Vector2 dir = (avgCorner - v).normalized; Vector2 newv = v + dir * 1; lotGuides.Add(newv); outerBoundary.Add(newv); } List <Vertex> points = new List <Vertex>(); foreach (Vector2 v in lotGuides) { points.Add(new Vertex(v.x, v.y)); } //Debug.Log("LotCenters: " + Util.List2String(lotCenters)); // Generate a default mesher var mesher = new GenericMesher(new Dwyer()); // Generate mesh (Delaunay Triangulation) IMesh mesh = mesher.Triangulate(points); // Init edge/vertex lists for mutation ArrayList vertices = new ArrayList(); foreach (Vertex v in mesh.Vertices) { vertices.Add(v); } foreach (Edge e in mesh.Edges) { Vertex vert1 = (Vertex)vertices[e.P0]; Vertex vert2 = (Vertex)vertices[e.P1]; Vector2 vec1 = Util.VertexToVector2(vert1); Vector2 vec2 = Util.VertexToVector2(vert2); edges.Add((vec1, vec2)); // build neighbor map if (!neighbors.ContainsKey(vec1)) { neighbors[vec1] = new List <Vector2>(); } if (!neighbors.ContainsKey(vec2)) { neighbors[vec2] = new List <Vector2>(); } neighbors[vec1].Add(vec2); neighbors[vec2].Add(vec1); } // find lot bounds foreach (Vector2 v in lotCenters) { Lot lot = new Lot(v); foreach (Vector2 vn in neighbors[v]) { Vector2 vNew; if (outerBoundary.Contains(vn)) { vNew = vn; // accept as outer bound // 0=N, 1=E, 2=S, 3=W /*if (vn.y > (float)lot.extrema[0]) { * lot.extrema[0] = vn.y; * } * if (vn.x > (float)lot.extrema[1]) { * lot.extrema[1] = vn.x; * } * if (vn.y < (float)lot.extrema[2]) { * lot.extrema[2] = vn.y; * } * if (vn.x < (float)lot.extrema[3]) { * lot.extrema[3] = vn.x; * }*/ } else { vNew = (v + vn) / 2; } if (vNew.y > v.y && vNew.y < (float)lot.extrema[0]) { lot.extrema[0] = vNew.y; } if (vNew.x > v.x && vNew.x < (float)lot.extrema[1]) { lot.extrema[1] = vNew.x; } if (vNew.y < v.y && vNew.y > (float)lot.extrema[2]) { lot.extrema[2] = vNew.y; } if (vNew.x < v.x && vNew.x > (float)lot.extrema[3]) { lot.extrema[3] = vNew.x; } } lot.Calc(); if (!lots.ContainsKey(v)) { lots.Add(v, lot); } } } /////////////////////////////////////////////////////////////// /*for (int i = 0; i < verts.Count; i++) { * if (i % 6 == 0) { * Vector2 v = (Vector2)verts[i]; * points.Add(new Vector2f(v.x, v.y)); * } * }*/ /* * //List<Vector2f> p = CreateRandomPoint(); * * * Rectf rect = new Rectf(//0, 0, 20, 20); * bounds.xMin - 500, bounds.zMin - 500, * bounds.xMax + 500, bounds.zMax + 500); * * Voronoi voronoi = new Voronoi(points, rect, 0); * * // Now retreive the edges from it, and the new sites position if you used lloyd relaxtion * sites = voronoi.SitesIndexedByLocation; * edges = voronoi.Edges; * * //GenVoronoi(points); * * Debug.Log("Voronoi sites: " + sites.Count + " edges:" + edges.Count); */ // place points along road side // building plots // extrude plots into buildings }