/// <summary> /// Add a polygon ring to the geometry and make it a hole. /// </summary> /// <remarks> /// WARNING: This works for convex polygons, but not for non-convex regions in general. /// </remarks> /// <param name="points">List of points which make up the hole.</param> /// <param name="mark">Common boundary mark for all segments of the hole.</param> public static void AddRingAsHole(this InputGeometry geometry, IEnumerable<TriangleNet.Geometry.Point> points, int mark = 0) { // Save the current number of points. int N = geometry.Count; int m = 0; foreach (var pt in points) { geometry.AddPoint(pt.X, pt.Y, pt.Boundary, pt.Attributes); m++; } for (int i = 0; i < m; i++) { geometry.AddSegment(N + i, N + ((i + 1) % m), mark); } //a lényeg az hogy kell egy a lyukon lévő pont,hogy jelezze hogy az egy lyuk poligon... a legegyszerübb trükk a következő, az egybefüggő (akár konkáv) poligont háromszögesítem, ezzel nincs gond, ezután kiválasztok egy testzőleges háromszöget, és veszem annak a középpontját..ez már tuti hogy a nagy poligon belső pontja TriangleNetMesh mesh = new TriangleNetMesh(); var inputGeometry = new InputGeometry(); inputGeometry.AddRing(points); mesh.Triangulate(inputGeometry); var firstTriangle = new List<Triangle>(mesh.Triangles)[0]; double x = 0.0; double y = 0.0; for (int iii = 0; iii < 3; iii++) { var vertex = firstTriangle.GetVertex(iii); x += vertex.X; y += vertex.Y; } geometry.AddHole(x / 3, y / 3); }
public static TriangleNet.Mesh Generate(IEnumerable <Vector2> circuit) { var mesh = new TriangleNet.Mesh(Behavior); var geometry = GetGeometryFor(circuit); mesh.Triangulate(geometry); return(mesh); }
private void TriangulateMesh() { //TODO: Default to a heigher MinimumAngle (30); create a timeout loop that lowers (30 -> 15 -> 5 -> 0) it Polygon polygon = new Polygon(); foreach (Vector3 el in vertices) { polygon.Add(new Vertex(el.x, el.z, el.y, -1)); } TriangleNet.Mesh mesh = (TriangleNet.Mesh)polygon.Triangulate(new QualityOptions() { SteinerPoints = -1, MinimumAngle = degrees }); //Update Steiner points heights to the average of all its neighbours RecalculateSteinerPoints(mesh); //Use having ordered triangles to do preliminary smoothing List <Triangle> trianglesNet = mesh.Triangles.ToList(); trianglesNet.Sort((o2, o1) => ( o1.GetVertex(0).y + o1.GetVertex(1).y + o1.GetVertex(2).y).CompareTo(o2.GetVertex(0).y + o2.GetVertex(1).y + o2.GetVertex(2).y) ); //Vertex list needs re-creation from TriangleNet data vertices = new List <Vector3>(); triangles = new List <int>(); foreach (Triangle el in trianglesNet) { Vertex v0 = el.GetVertex(2), v1 = el.GetVertex(1), v2 = el.GetVertex(0); float averageHeight = (v0.up + v1.up + v2.up) / 3; if (averageHeight > v0.up) { v0.up = averageHeight; } if (averageHeight > v1.up) { v1.up = averageHeight; } if (averageHeight > v2.up) { v2.up = averageHeight; } triangles.Add(GetIndexByVertex2DCoords((float)v0.x, (float)v0.y, v0.up)); triangles.Add(GetIndexByVertex2DCoords((float)v1.x, (float)v1.y, v1.up)); triangles.Add(GetIndexByVertex2DCoords((float)v2.x, (float)v2.y, v2.up)); } }
public void GenerateWater() { float[,] noiseMap = Noise.GenerateNoiseMap(_size, data, false, 0); TriangleNet.Mesh mesh = MeshGenerator.GenerateTriangulatedMesh(_size, _distributionData); _meshData = MeshGenerator.GenerateMeshData(mesh, data.meshHeightCurve, noiseMap, data.meshHeightMultiplier); Color[] colors = _mapDisplay.GenerateColors(mesh, noiseMap); _meshData.AddColors(colors); UnityEngine.Mesh m = _meshData.CreateMesh(); _mapDisplay.DisplayMesh(m); }
private void RecalculateSteinerPoints(TriangleNet.Mesh mesh) { //Steiner points are added througout Delanunay to meet quality expectations //Add a height to these that is equal to the average of all its neighbouring triangles bool reverse = false; //Traverse backwards to account for Steiners affecting neighbouring Steiners for (int n = 0; n < 2; n++) { foreach (Triangle triangle in (reverse ? mesh.triangles : mesh.triangles.Reverse())) { Vertex[] vertices = triangle.vertices; float averageHeight = 0; List <int> steinersI = new List <int>(); int averageHeightWeight = 3; for (int i = 2; i >= 0; i--) { //If the point isn't Steiner then use its height for average if (vertices[i].steinerPointWeight == -1) { averageHeight += vertices[i].up; } //Else if the point is Steiner and hasn't been updated then update it else if (vertices[i].steinerPointWeight == 0) { steinersI.Add(i); averageHeightWeight--; } //Else the point is Steiner that has been updated then update it and use its height for average else { steinersI.Add(i); averageHeight += vertices[i].up; } } if (averageHeightWeight != 0) { averageHeight /= averageHeightWeight; foreach (int el in steinersI) { vertices[el].up = (vertices[el].up * vertices[el].steinerPointWeight + averageHeight * averageHeightWeight) / (vertices[el].steinerPointWeight + averageHeightWeight); vertices[el].steinerPointWeight += averageHeightWeight; } } } reverse = true; } }
public void OnCreate(TriangleNet.Mesh triMesh) { CreateShader( ); ResetBuffers(triMesh); CreateMesh(triMesh); hasCreated = true; StartCoroutine(WaitForStuffing( )); }
Mesh generateFaceMesh(ShapePoints shape) { var mesh = new Mesh(); var verts = new List <Vector3>(); var tris = new List <int>(); var uvs = new List <Vector2>(); var uv2 = new List <Vector2>(); var geometry = new InputGeometry(); for (int i = 0; i < shape.edge.Length; ++i) { var pt = shape.edge[i]; geometry.AddPoint(pt.x, pt.y); verts.Add(pt.p.AsVector3(-pt.groundness * _groundPull)); uvs.Add(pt.p); uv2.Add(new Vector2(pt.groundness * pt.groundness, 0)); geometry.AddSegment(i, (i + 1) % shape.edge.Length); } for (int i = 0; i < shape.interior.Length; ++i) { var pt = shape.interior[i]; geometry.AddPoint(pt.x, pt.y); verts.Add(pt.p.AsVector3(-pt.groundness * _groundPull + UnityEngine.Random.value * 0.4f)); uvs.Add(pt.p); uv2.Add(new Vector2(pt.groundness * pt.groundness, 0)); } var behave = new TriangleNet.Behavior(); behave.Algorithm = TriangleNet.TriangulationAlgorithm.Incremental; var meshRepresentation = new TriangleNet.Mesh(behave); meshRepresentation.Triangulate(geometry); foreach (var tri in meshRepresentation.Triangles) { tris.Add(tri.GetVertex(2).ID); tris.Add(tri.GetVertex(1).ID); tris.Add(tri.GetVertex(0).ID); } mesh.vertices = verts.ToArray(); mesh.triangles = tris.ToArray(); mesh.uv = uvs.ToArray(); mesh.uv2 = uv2.ToArray(); mesh.RecalculateNormals(); mesh.RecalculateBounds(); return(mesh); }
private Vector3 [] RecalculateVerticesByCurve(TriangleNet.Mesh mesh, AnimationCurve curve, float factor = Mathf.PI) // 3.1415926f ) { int size = mesh.vertices.Count; //求各点距边最近距离; float[] nearests = new float[size]; float furthest = float.MinValue; for (int i = 0; i < size; i++) { var point = mesh.vertices[i]; nearests [i] = 0; if (point.label == 0) { nearests [i] = float.MaxValue; foreach (var edge in mesh.Edges.Where(e => e.Label != 0)) { var v0 = mesh.vertices[edge.P0]; var v1 = mesh.vertices[edge.P1]; Vector2 position;// = Vector3.zero; float distance = CGAlgorithm.PointToSegementDistance(point.Vector2(), v0.Vector2(), v1.Vector2(), out position); //Debug.Log ( "Distance : " + distance ); if (distance < nearests [i]) { nearests [i] = distance; } if (distance > furthest) { furthest = distance; } } } } // 用 y = sqrt{1- (1-x )^2} 函数计算各点的Z值; Vector3[] result = new Vector3[size]; var average = nearests.Average(); for (int j = 0; j < size; j++) { var point = mesh.vertices[j]; Vector3 pos = point.Vector2(); var t = 1f - nearests[j] / furthest; pos.z = -Mathf.Sqrt(1f - t * t) * average * factor; //var t = nearests[j] / furthest; //pos.z = - curve.Evaluate(t) * average * factor; result [j] = pos; } return(result); }
public void BuildMeshFromFeaturePoints() { List <Vector3> rawPoints = GetPointCloudPositions().ToList(); List <Vector3> psuedoHightmapPoints = rawPoints.Select(item => GetPointAsPsuedoHeightmap(item)).ToList(); if (psuedoHightmapPoints.Count >= 3) { //psuedoHightmapPoints.AddRange(GetCornerPoints(psuedoHightmapPoints, rawPoints)); TriangleNet.Mesh mesh = GetTriangulatedMesh(psuedoHightmapPoints); UpdateOutputMesh(mesh); } }
//create 2D Delauny Triangulation out of the planeCoords[] void StartDelaunayTriangulation() { TriangleNet.Geometry.Polygon polygon = new TriangleNet.Geometry.Polygon(); for (int i = 0; i < planeCoords.Length; i++) { polygon.Add(new TriangleNet.Geometry.Vertex(planeCoords[i].x, planeCoords[i].z)); } TriangleNet.Meshing.ConstraintOptions options = new TriangleNet.Meshing.ConstraintOptions() { ConformingDelaunay = false }; generatedMesh = (TriangleNet.Mesh)polygon.Triangulate(options); }
private void Triangulate(List <Vector2> points) { // Vertex is TriangleNet.Geometry.Vertex Polygon polygon = new Polygon(); maxX = -1000; maxY = -1000; minY = 1000; minX = 1000; float x, y; foreach (Vector2 point in points) { x = point.x; y = point.y; polygon.Add(new Vertex(x, y)); if (x > maxX) { maxX = x; } if (y > maxY) { maxY = y; } if (x < minX) { minX = x; } if (y < minY) { minY = y; } } if (polygon.Count > 2) { // ConformingDelaunay is false by default; this leads to ugly long polygons at the edges // because the algorithm will try to keep the mesh convex // TriangleNet.Meshing.ConstraintOptions options = // new TriangleNet.Meshing.ConstraintOptions() { ConformingDelaunay = true }; triangulatorMesh = (TriangleNet.Mesh)polygon.Triangulate(); } else { Debug.Log(string.Format("Mesh needs minimum 3 points but did only receive: {0} point(s)", polygon.Count)); } Debug.Log(points.Count); }
private IEnumerable <Triangle> GetMeshTriangles(TriangleNet.Mesh mesh) { List <Vector3> vertices = new List <Vector3>(); foreach (var vertex in mesh.Vertices) { vertices.Add(TransformTo3D(new IntPoint((long)vertex.X, (long)vertex.Y))); } foreach (var triangle in mesh.Triangles) { yield return(new Triangle(vertices[triangle.P0], vertices[triangle.P1], vertices[triangle.P2])); } }
public void SaveBitmap(TriangleNet.Mesh mesh) { var mapDirectory = new DirectoryInfo(Loader.GetCurrentVersionDirectory() + @"\maps\"); if (!mapDirectory.Exists) { mapDirectory.Create(); } var filename = mapDirectory.FullName + MapID + ".png"; var test = PointMap.ToBitmap(mesh); test.Save(filename); }
public static VoronoiBase generateVoronoi(List <Vector2> points) { var poly = new Polygon(points.Count()); foreach (Vector2 point in points) { poly.Add(new TriangleNet.Geometry.Vertex(point.x, point.y)); } TriangleNet.Mesh mesh = (TriangleNet.Mesh)poly.Triangulate(new ConstraintOptions() { ConformingDelaunay = true }); return(new BoundedVoronoi(mesh)); }
public void Generate(IEnumerable<Vector3> locations, Transform groundPlaneTransform) { float waterHeight = 0; Polygon polygon = new Polygon(); elevations = new List<float>(); //Debug.Log($"Mesh Generated with {locations.ToList().Count} points."); // Create separate polygons for the triangulation foreach (var location in locations) { waterHeight = location.y; polygon.Add(new Vertex(location.x, location.z)); if (waterHeight != -9999) { elevations.Add((float)waterHeight + groundPlaneTransform.position.y); } else { elevations.Add(groundPlaneTransform.position.y); } } TriangleNet.Meshing.ConstraintOptions options = new TriangleNet.Meshing.ConstraintOptions() { ConformingDelaunay = false }; mesh = (TriangleNet.Mesh)polygon.Triangulate(options); //var globalLocalPositions = locations.ToArray(); //for (int i = 0; i < globalLocalPositions.Length; i++) //{ // //var currentPosition = globalLocalPositions[i]; // //var waterHeight = currentPosition.y; // var waterHeight = currentPosition.y; // if(waterHeight != -9999) // { // elevations.Add((float)waterHeight + groundPlaneTransform.position.y); // } // else // { // elevations.Add(groundPlaneTransform.position.y); // } //} ClearMesh(); MakeMesh(); // Boolean that is set once the mesh is created isMeshGenerated = true; }
private Mesh TriangulateMesh() { if (verts.Count > 2) { var tnMesh = new TriangleNet.Mesh(); var input = new TriangleNet.Geometry.InputGeometry(); var localVertices = verts.Select(v => spriteRenderer.transform.InverseTransformPoint(v.position)).ToArray(); for (int i = 0; i < verts.Count; i++) { verts[i].index = i; input.AddPoint(verts[i].position.x, verts[i].position.y); } foreach (var seg in segments) { if (!seg.IsDeleted()) { input.AddSegment(seg.first.index, seg.second.index); } } foreach (var hole in holes) { input.AddHole(hole.x, hole.y); } tnMesh.Triangulate(input); try { Mesh mesh = new Mesh(); mesh.vertices = localVertices; mesh.triangles = tnMesh.Triangles.ToUnityMeshTriangleIndices(); mesh.uv = genUV(mesh.vertices); mesh.RecalculateBounds(); mesh.RecalculateNormals(); return(mesh); } catch { Debug.LogError("Mesh topology was wrong. Make sure you dont have intersecting edges."); throw; } } else { return(null); } }
public void FillMeshEdges(TriangleNet.Mesh mesh) { foreach (var seg in mesh.Segments) { var v1 = new Point(seg.GetVertex(0)); var v2 = new Point(seg.GetVertex(1)); var line = new Line(v1, v2); foreach (var point in line.Points) { points[point.X, point.Y] = PointType.Interior; } } }
void DelaunayTriangulation() { polygon = new Polygon(); foreach (var vertex in bestRooms) { polygon.Add(new TriangleNet.Geometry.Vertex(vertex.Position.x, vertex.Position.z)); } TriangleNet.Meshing.ConstraintOptions options = new TriangleNet.Meshing.ConstraintOptions() { ConformingDelaunay = false }; mesh = (TriangleNet.Mesh)polygon.Triangulate(options); }
/* * @brief Initializer. * @param mesh The mesh which we are going to find triangles within. * @param xsize The maximum x value in the mesh. TODO: Use the mesh to figure this out. * @param ysize The maximum y value in the mesh. TODO: Use the mesh to figure this out. * @param binsize How large each grid tile is. This param is pretty important; larger means * the find operation gets slower, but smaller means the find operation might not find * the right triangle at all. */ public TriangleBin(TriangleNet.Mesh mesh, int xsize, int ysize, float binsize) { this.binsize = binsize; this.grid = new List <Vertex> [(int)Math.Ceiling(xsize / binsize), (int)Math.Ceiling(ysize / binsize)]; foreach (Vertex vertex in mesh.Vertices) { vertToTriangle.Add(new List <Triangle>()); addVertex(vertex); } foreach (Triangle triangle in mesh.Triangles) { addTriangle(triangle); } }
private TriangleNet.Mesh createMesh() { TriangleNet.Geometry.Polygon polygon = createPolygon(); TriangleNet.Meshing.ConstraintOptions options = new TriangleNet.Meshing.ConstraintOptions() { ConformingDelaunay = true }; TriangleNet.Meshing.GenericMesher mesher = new TriangleNet.Meshing.GenericMesher(); TriangleNet.Mesh mesh = (TriangleNet.Mesh)mesher.Triangulate(polygon, options); TriangleNet.Smoothing.SimpleSmoother smoother = new TriangleNet.Smoothing.SimpleSmoother(); smoother.Smooth(mesh, smoothingIterations); return(mesh); }
public MapMesh generateMapMesh() { List <List <Vector2> > riverPoints = this.generateRiverPoints(); TriangleNet.Mesh mapTriangulation = this.triangulateMap(map, riverPoints); MapMesh terrain = this.generateTerrain(map, riverPoints, mapTriangulation); List <Color32> terrainColors = getTerrainColours(terrain.landMesh.vertices); Debug.Log(terrainColors.Count); Debug.Log(terrain.landMesh.vertices.Length); Debug.Log(terrain.innerWaterMesh.vertices.Length); Debug.Log(terrain.oceanMesh.vertices.Length); terrain.landMesh.colors32 = terrainColors.ToArray(); return(terrain); }
private void CreateTriangleGraph(TriangleNet.Mesh mesh) { triGraph = new Graph <GraphNode, string>(); pointMapping = new Dictionary <PointStruct, uint>(); nodeMapping = new Dictionary <GraphNode, uint>(); foreach (var tri in mesh.Triangles) { GraphNode node = new GraphNode(tri); if (!pointMapping.ContainsKey(node.center)) { var id = triGraph.AddNode(node); pointMapping.Add(node.center, id); nodeMapping.Add(node, id); } var cID = pointMapping[node.center]; for (var i = 0; i < 3; i++) { var neighbor = (TriangleNet.Topology.Triangle)tri.GetNeighbor(i); if (neighbor != null) { var neighborNode = new GraphNode(neighbor); if (!pointMapping.ContainsKey(neighborNode.center)) { var id = triGraph.AddNode(neighborNode); pointMapping.Add(neighborNode.center, id); nodeMapping.Add(neighborNode, id); } var nID = pointMapping[neighborNode.center]; var dist = node.center.Distance(neighborNode.center); var portal = node.GetPortal(neighborNode); triGraph.Connect(cID, nID, (int)Math.Ceiling(dist), ""); } } } }
public void Triangulate() { indices.Clear(); if (texVertices.Count >= 3) { InputGeometry inputGeometry = new InputGeometry(texVertices.Count); for (int i = 0; i < texVertices.Count; ++i) { Vector2 vertex = texVertices[i].vertex; inputGeometry.AddPoint(vertex.x, vertex.y); } for (int i = 0; i < edges.Count; ++i) { Edge edge = edges[i]; inputGeometry.AddSegment(texVertices.IndexOf(edge.vertex1), texVertices.IndexOf(edge.vertex2)); } for (int i = 0; i < holes.Count; ++i) { Vector2 hole = holes[i].vertex; inputGeometry.AddHole(hole.x, hole.y); } TriangleNet.Mesh trangleMesh = new TriangleNet.Mesh(); trangleMesh.Triangulate(inputGeometry); foreach (TriangleNet.Data.Triangle triangle in trangleMesh.Triangles) { if (triangle.P0 >= 0 && triangle.P0 < texVertices.Count && triangle.P0 >= 0 && triangle.P1 < texVertices.Count && triangle.P0 >= 0 && triangle.P2 < texVertices.Count) { indices.Add(triangle.P0); indices.Add(triangle.P2); indices.Add(triangle.P1); } } } isDirty = true; }
/// <summary> /// https://straypixels.net/delaunay-triangulation-terrain/ /// </summary> /// <param name="largeRoomCubeObjects"></param> private void DelaunayTriangulation() { Polygon polygon = new Polygon(); for (int i = 0; i < m_largeRooms.Count; ++i) { polygon.Add(new Vertex(m_largeRooms[i].transform.position.x, m_largeRooms[i].transform.position.z)); // Save the delaunay id to the actual room id m_delaunayToRoomId.Add(i, System.Array.IndexOf(m_roomObjects, m_largeRooms[i])); } TriangleNet.Mesh mesh = (TriangleNet.Mesh)polygon.Triangulate(); StartCoroutine(DrawTriangulationLines(mesh));; MinimumSpanningTreePrim(mesh); }
// Use this for initialization void Start() { TriangleNet.Configuration conf = new TriangleNet.Configuration(); List <Vertex> vertices = OsgiViz.Helperfunctions.createPointsOnPlane(1f, 1f, 50, 50, 1f, new System.Random()); SweepLine sl = new SweepLine(); //TriangleNet.Mesh tMesh = (TriangleNet.Mesh)TriangleNet.Meshing.GenericMesher.StructuredMesh(1f, 1f, 10, 10); TriangleNet.Mesh tMesh = (TriangleNet.Mesh)sl.Triangulate(vertices, conf); TriangleNet.Voronoi.BoundedVoronoi voronoi = new TriangleNet.Voronoi.BoundedVoronoi(tMesh); foreach (TriangleNet.Topology.DCEL.Face vf in voronoi.Faces) { voronoiFaceToGO(vf); } }
public static List <List <Vertex> > VonoroiFaces(this TriangleNet.Mesh triMesh) { var voronoi = new StandardVoronoi(triMesh); List <List <Vertex> > result = new List <List <Vertex> >(); foreach (var face in voronoi.Faces) { result.Add(face.GetAllVertices( ).Select(p => new Vertex(p.x, p.y, p.id)).ToList( )); } var rect = triMesh.Bounds; result.Add(new List <Vertex> (rect.Path( ))); return(result); }
public virtual void GenerateMap() { print("GENERATING TRANGULATION."); UnityEngine.Random.InitState(0); // What does this do? float[] seed = new float[octaves]; for (int i = 0; i < octaves; i++) { seed[i] = UnityEngine.Random.Range(0.0f, 100.0f); } Polygon polygon = new Polygon(); for (int i = 0; i < randomPoints; i++) { polygon.Add(new Vertex(UnityEngine.Random.Range(0.0f, xsize), UnityEngine.Random.Range(0.0f, ysize))); } // Generate Delauney triangulation from points. TriangleNet.Meshing.ConstraintOptions options = new TriangleNet.Meshing.ConstraintOptions() { ConformingDelaunay = true }; TriangleNet.Mesh mesh = (TriangleNet.Mesh)polygon.Triangulate(options); // Generate Voronoi Tesselation from Delauney triangulation. //mesh2 = (TriangleNet.Topology.DCEL.DcelMesh)(new StandardVoronoi(mesh, new TriangleNet.Geometry.Rectangle(0f, 0f, (float)xsize, (float)ysize))); mesh2 = (TriangleNet.Topology.DCEL.DcelMesh)(new BoundedVoronoi(mesh)); // Post-processing and object-generation. ObtainVerticesEdgesAndFaces(); //RemoveShortEdges(); GenerateMesh(); MergeSmallFaces(); PopulateFacesManagers(); // Drawing calls. (Explicit or implicit.) DrawEdges(); DrawEdgeLabels(); DrawFaceLabels(); //GenerateVertexSpheres(); GenerateFaceCenterSpheres(); }
private IEnumerator DrawMinimumSpanningTree(TriangleNet.Mesh mesh, int[] parent) { while (true) { // Visualise the tree for (int v = 1; v < parent.Length; ++v) { Vertex v0 = mesh.vertices[parent[v]]; Vertex v1 = mesh.vertices[v]; Vector3 p0 = new Vector3((float)v0.x, 2f, (float)v0.y); Vector3 p1 = new Vector3((float)v1.x, 2f, (float)v1.y); Debug.DrawLine(p0, p1, Color.green); } yield return(null); } }
private IEnumerator DrawTriangulationLines(TriangleNet.Mesh mesh) { while (true) { // Visualise the triangulation foreach (Edge edge in mesh.Edges) { Vertex v0 = mesh.vertices[edge.P0]; Vertex v1 = mesh.vertices[edge.P1]; Vector3 p0 = new Vector3((float)v0.x, 2f, (float)v0.y); Vector3 p1 = new Vector3((float)v1.x, 2f, (float)v1.y); Debug.DrawLine(p0, p1, Color.green); } yield return(null); } }
public static void Triangulate(List <Vector2> vertices, List <IndexedEdge> edges, List <Hole> holes, ref List <int> indices) { indices.Clear(); if (vertices.Count >= 3) { InputGeometry inputGeometry = new InputGeometry(vertices.Count); for (int i = 0; i < vertices.Count; ++i) { Vector2 position = vertices[i]; inputGeometry.AddPoint(position.x, position.y); } for (int i = 0; i < edges.Count; ++i) { IndexedEdge edge = edges[i]; inputGeometry.AddSegment(edge.index1, edge.index2); } for (int i = 0; i < holes.Count; ++i) { Vector2 hole = holes[i].vertex; inputGeometry.AddHole(hole.x, hole.y); } TriangleNet.Mesh triangleMesh = new TriangleNet.Mesh(); triangleMesh.Triangulate(inputGeometry); foreach (TriangleNet.Data.Triangle triangle in triangleMesh.Triangles) { if (triangle.P0 >= 0 && triangle.P0 < vertices.Count && triangle.P0 >= 0 && triangle.P1 < vertices.Count && triangle.P0 >= 0 && triangle.P2 < vertices.Count) { indices.Add(triangle.P0); indices.Add(triangle.P2); indices.Add(triangle.P1); } } } }
public void Update(TriangleNet.Mesh mesh) { Vertices.Clear(); Indices.Clear(); Uvs.Clear(); VertexWeightsDictionary.Clear(); _vertexIndicesDictionary.Clear(); if (mesh == null) { return; } mesh.Renumber(); foreach (var vertex in mesh.Vertices) { var vector = new Vector3((float)vertex.X, (float)vertex.Y, 0); _vertexIndicesDictionary.Add(vector, _vertexIndicesDictionary.Count); VertexWeightsDictionary.Add(vector, 1); Vertices.Add(vector); Uvs.Add(new Vector2((float)(vertex.X / 640), (float)(vertex.Y / 480))); } foreach (var meshTriangle in mesh.Triangles) { var va = meshTriangle.GetVertex(0); var vb = meshTriangle.GetVertex(1); var vc = meshTriangle.GetVertex(2); var vca = new Vector3((float)va.X, (float)va.Y, 0); var vcb = new Vector3((float)vb.X, (float)vb.Y, 0); var vcc = new Vector3((float)vc.X, (float)vc.Y, 0); var vai = _vertexIndicesDictionary[vca]; var vbi = _vertexIndicesDictionary[vcb]; var vci = _vertexIndicesDictionary[vcc]; Indices.Add(vai); Indices.Add(vbi); Indices.Add(vci); } }
public static void Triangulate(List<Vector2> vertices, List<IndexedEdge> edges, List<Hole> holes,ref List<int> indices) { indices.Clear(); if(vertices.Count >= 3) { InputGeometry inputGeometry = new InputGeometry(vertices.Count); for(int i = 0; i < vertices.Count; ++i) { Vector2 position = vertices[i]; inputGeometry.AddPoint(position.x,position.y); } for(int i = 0; i < edges.Count; ++i) { IndexedEdge edge = edges[i]; inputGeometry.AddSegment(edge.index1,edge.index2); } for(int i = 0; i < holes.Count; ++i) { Vector2 hole = holes[i].vertex; inputGeometry.AddHole(hole.x,hole.y); } TriangleNet.Mesh trangleMesh = new TriangleNet.Mesh(); trangleMesh.Triangulate(inputGeometry); foreach (TriangleNet.Data.Triangle triangle in trangleMesh.Triangles) { if(triangle.P0 >= 0 && triangle.P0 < vertices.Count && triangle.P0 >= 0 && triangle.P1 < vertices.Count && triangle.P0 >= 0 && triangle.P2 < vertices.Count) { indices.Add(triangle.P0); indices.Add(triangle.P2); indices.Add(triangle.P1); } } } }
public static void Tessellate(List<Vector2> vertices, List<IndexedEdge> indexedEdges, List<Hole> holes, List<int> indices, float tessellationAmount) { if(tessellationAmount <= 0f) { return; } indices.Clear(); if(vertices.Count >= 3) { InputGeometry inputGeometry = new InputGeometry(vertices.Count); for(int i = 0; i < vertices.Count; ++i) { Vector2 vertex = vertices[i]; inputGeometry.AddPoint(vertex.x,vertex.y); } for(int i = 0; i < indexedEdges.Count; ++i) { IndexedEdge edge = indexedEdges[i]; inputGeometry.AddSegment(edge.index1,edge.index2); } for(int i = 0; i < holes.Count; ++i) { Vector2 hole = holes[i].vertex; inputGeometry.AddHole(hole.x,hole.y); } TriangleNet.Mesh triangleMesh = new TriangleNet.Mesh(); TriangleNet.Tools.Statistic statistic = new TriangleNet.Tools.Statistic(); triangleMesh.Triangulate(inputGeometry); triangleMesh.Behavior.MinAngle = 20.0; triangleMesh.Behavior.SteinerPoints = -1; triangleMesh.Refine(true); statistic.Update(triangleMesh,1); triangleMesh.Refine(statistic.LargestArea / tessellationAmount); triangleMesh.Renumber(); vertices.Clear(); indexedEdges.Clear(); foreach(TriangleNet.Data.Vertex vertex in triangleMesh.Vertices) { vertices.Add(new Vector2((float)vertex.X,(float)vertex.Y)); } foreach(TriangleNet.Data.Segment segment in triangleMesh.Segments) { indexedEdges.Add(new IndexedEdge(segment.P0,segment.P1)); } foreach (TriangleNet.Data.Triangle triangle in triangleMesh.Triangles) { if(triangle.P0 >= 0 && triangle.P0 < vertices.Count && triangle.P0 >= 0 && triangle.P1 < vertices.Count && triangle.P0 >= 0 && triangle.P2 < vertices.Count) { indices.Add(triangle.P0); indices.Add(triangle.P2); indices.Add(triangle.P1); } } } }
/// <summary> /// Get a list of triangles which will fill the area described by the slice /// </summary> public IEnumerable<Triangle> Triangles() { TriangleNet.Behavior behavior = new TriangleNet.Behavior(); behavior.ConformingDelaunay = true; foreach (var poly in IndividualPolygons()) { PolyNode node = polyTree.GetFirst(); InputGeometry geometry = new InputGeometry(); while (node != null) { var offset = geometry.Points.Count(); var index = 0; foreach (IntPoint point in node.Contour) { geometry.AddPoint(point.X, point.Y); if (index > 0) { geometry.AddSegment(index - 1 + offset, index + offset); } index++; } geometry.AddSegment(index - 1 + offset, offset); if (node.IsHole) { // To describe a hole, AddHole must be called with a location inside the hole. IntPoint last = new IntPoint(0, 0); bool lastKnown = false; double longest = 0; IntPoint longestAlong = new IntPoint(0, 0); IntPoint from = new IntPoint(0, 0); foreach (IntPoint point in node.Contour) { if (lastKnown) { IntPoint along = new IntPoint(point.X - last.X, point.Y - last.Y); double length = Math.Sqrt(along.X * along.X + along.Y * along.Y); if (length > longest) { longest = length; longestAlong = along; from = last; } } last = point; lastKnown = true; } if (longest > 0) { double perpendicularX = ((double)longestAlong.Y * (double)scale * 0.001d) / longest; double perpendicularY = -((double)longestAlong.X * (double)scale * 0.001d) / longest; geometry.AddHole(perpendicularX + from.X + longestAlong.X / 2.0d, perpendicularY + from.Y + longestAlong.Y / 2.0d); } else { } } node = node.GetNext(); } if (geometry.Points.Count() > 0) { var mesh = new TriangleNet.Mesh(behavior); mesh.Triangulate(geometry); mesh.Renumber(); foreach (Triangle t in this.GetMeshTriangles(mesh)) { yield return t; } } } }