/** * Creates a TriangleNet IMesh from a list of shapes. The first shape is considered the base * and the rest as hole in that base. */ public static IMesh makeMesh(this List <Shape> shapes) { var polygon = new TriangleNet.Geometry.Polygon(); // Add shapes for (int i = 0; i < shapes.Count; i++) { var points = shapes[i].points; if (points.Count < 3) { return(null); } var isHole = i > 0; polygon.Add(new Contour(points.ToListVertex()), isHole); } var quality = new QualityOptions() { MinimumAngle = 25 }; // return polygon.Triangulate(); return(polygon.Triangulate(quality)); }
public static Mesh MeshFromVoronoi(Voronoi voronoi) { var options = new TriangleNet.Meshing.ConstraintOptions { ConformingDelaunay = true }; var vertices = new List <Vector3>(); var verticesIndex = 0; var triangles = new List <int>(); var colors = new List <Color>(); var regions = voronoi.Regions(); for (var i = 0; i < regions.Count; i++) { var region = regions[i]; var polygon = new TriangleNetGeo.Polygon(); foreach (var corner in region) { polygon.Add(new TriangleNetGeo.Vertex(corner.x, corner.y)); } var cellMesh = (TriangleNet.Mesh)polygon.Triangulate(options); vertices.AddRange( cellMesh.Vertices.Select(v => new Vector3((float)v.x, 0, (float)v.y)) ); triangles.AddRange( cellMesh.Triangles.SelectMany( t => t.vertices.Select(v => v.id + verticesIndex) .Reverse() // Reverse triangles so they're facing the right way ) ); // Update index so the next batch of triangles point to the correct vertices verticesIndex = vertices.Count; // Assign same color to all vertices in region var regionColor = new Color(Random.Range(0, 1f), Random.Range(0, 1f), Random.Range(0, 1f)); colors.AddRange(cellMesh.Vertices.Select(v => regionColor)); } // Just make world-space UVs for now var uvs = vertices.Select(v => new Vector2(v.x, v.y)); var mesh = new Mesh { vertices = vertices.ToArray(), colors = colors.ToArray(), uv = uvs.ToArray(), triangles = triangles.ToArray() }; mesh.RecalculateNormals(); return(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); }
List <PopulationCentreConnection> getNearestNeighbourConnections(List <PopulationCentre> pops, RoadType roadType, List <PopulationCentreConnection> connections = null) { var geometry = new TriangleNet.Geometry.Polygon(); //Dictionary<Vertex, PopulationCentre> popDictionary = new Dictionary<Vertex, PopulationCentre>(); var connectionList = new List <PopulationCentreConnection>(); foreach (var pop in pops) { var vertex = new Vertex(pop.Position.x, pop.Position.y); //popDictionary.Add(vertex, pop); geometry.Add(vertex); } var mesh = geometry.Triangulate(); int org, dest; ITriangle neighbor; int nid; foreach (var tri in mesh.Triangles) { for (int i = 0; i < 3; i++) { // The neighbor opposite of vertex i. GetNeighbor(tri, i, out neighbor, out nid); // Consider each edge only once. if ((tri.ID < nid) || (nid < 0)) { // Get the edge endpoints. org = tri.GetVertexID((i + 1) % 3); dest = tri.GetVertexID((i + 2) % 3); var pop1 = pops[org]; var pop2 = pops[dest]; var connection = new PopulationCentreConnection(pop1, pop2); connection.roadType = roadType; if (connections == null || !connections.Any(x => x.Equal(connection))) { connectionList.Add(connection); } } } } return(connectionList); }
public void GenerateMeshData(ConstraintOptions options) { var polygon = new TriangleNet.Geometry.Polygon(); vertices = surroundingCorners .Where(corner => isFaceBorderCorner | corner != borderCorner) .Select(corner => corner.vertex - vertex) .OrderBy(difference => difference.GetAngle()) .ToArray(); normals = new Vertex[vertices.Length]; for (int q = 0; q < vertices.Length; q++) { Vertex v0 = vertices[q]; Vertex v1 = vertices[(q + 1) % vertices.Length]; normals[q] = (v1 - v0).Perpendicular().Normalize(); } foreach (Vertex vertex in vertices) { polygon.Add(vertex); } Mesh mesh = (Mesh)polygon.Triangulate(options); triangles = new int[mesh.triangles.Count * 3]; int index = 0; // if conforming delauny is off Id should eqaul index // if not I will have to develop a work around foreach (var triangle in mesh.triangles) { var vertices = triangle.vertices; triangles[index * 3] = vertices[2].id; triangles[index * 3 + 1] = vertices[1].id; triangles[index * 3 + 2] = vertices[0].id; index++; } }
public static UnityEngine.Mesh Mesh(this EPPZ.Geometry.Model.Polygon this_, Color color, TriangulatorType triangulator, string name = "") { // Create geometry. TriangleNet.Geometry.Polygon polygon = this_.TriangleNetPolygon(); // Triangulate. ConstraintOptions options = new ConstraintOptions(); // ConformingDelaunay // Convex // SegmentSplitting QualityOptions quality = new QualityOptions(); // MinimumAngle // MaximumArea // UserTest // VariableArea // SteinerPoints IMesh triangulatedMesh = polygon.Triangulate(options, quality, TriangulatorForType(triangulator)); // Counts. int vertexCount = triangulatedMesh.Vertices.Count; int triangleCount = triangulatedMesh.Triangles.Count; // Mesh store. Vector3[] _vertices = new Vector3[vertexCount]; Vector2[] _uv = new Vector2[vertexCount]; Vector3[] _normals = new Vector3[vertexCount]; Color[] _colors = new Color[vertexCount]; List <int> _triangles = new List <int>(); // Size may vary // Vertices. int index = 0; foreach (TriangleNet.Geometry.Vertex eachVertex in triangulatedMesh.Vertices) { _vertices[index] = new Vector3( (float)eachVertex.X, (float)eachVertex.Y, 0.0f // As of 2D ); _uv[index] = _vertices[index]; _normals[index] = Vector3.forward; _colors[index] = color; index++; } // Triangles. foreach (TriangleNet.Topology.Triangle eachTriangle in triangulatedMesh.Triangles) { // Get vertices. Point P2 = eachTriangle.GetVertex(2); Point P1 = eachTriangle.GetVertex(1); Point P0 = eachTriangle.GetVertex(0); // Get centroid. Vector2 centroid = new Vector2( (float)(P2.X + P1.X + P0.X) / 3.0f, (float)(P2.Y + P1.Y + P0.Y) / 3.0f ); // Add only if centroid contained. if (this_.ContainsPoint(centroid) || skipCentroidTest) { _triangles.Add(P2.ID); _triangles.Add(P1.ID); _triangles.Add(P0.ID); } } // Create / setup mesh. Mesh mesh = new Mesh(); mesh.vertices = _vertices; mesh.uv = _uv; mesh.normals = _normals; mesh.colors = _colors; mesh.subMeshCount = 1; mesh.SetTriangles(_triangles.ToArray(), 0); mesh.name = name; return(mesh); }
protected override void ProcessContext(Canvas canvas, List <Point> points) { if (points.Count < 3) { return; } var options = new ConstraintOptions(); options.ConformingDelaunay = true; var quality = new QualityOptions(); quality.MinimumAngle = MinAngel; quality.MaximumArea = MaxSquare; var polygon = new TriangleNet.Geometry.Polygon(); points.ForEach(p => polygon.Add(new Vertex(p.X, p.Y))); for (int i = 0; i < points.Count - 1; i++) { polygon.Add(new Segment(new Vertex(points[i].X, points[i].Y), new Vertex(points[i + 1].X, points[i + 1].Y))); } Point last = points.LastOrDefault(); Point first = points.FirstOrDefault(); polygon.Add(new Segment(new Vertex(last.X, last.Y), new Vertex(first.X, first.Y))); var mesh = polygon.Triangulate(options, quality); this.mesh = mesh; if (mesh != null) { mesh.Refine(quality, true); } this.mesh.Renumber(); foreach (ITriangle triangle in mesh.Triangles) { Point p1 = new Point { X = (triangle.GetVertex(0).X + 1) * 100, Y = (triangle.GetVertex(0).Y + 1) * 100, ID = triangle.GetVertex(0).ID }; Point p2 = new Point { X = (triangle.GetVertex(1).X + 1) * 100, Y = (triangle.GetVertex(1).Y + 1) * 100, ID = triangle.GetVertex(1).ID }; Point p3 = new Point { X = (triangle.GetVertex(2).X + 1) * 100, Y = (triangle.GetVertex(2).Y + 1) * 100, ID = triangle.GetVertex(2).ID }; Triangle myTriangle = new Triangle { Points = new List <Point> { p1, p2, p3 }, SegmentId = triangle.ID }; myTriangle.Stroke = Brushes.Black; myTriangle.MouseEnter += (sender, e) => { MouseEnterAction(sender, e); }; myTriangle.MouseLeave += (sender, e) => { MouseLeaveAction(sender, e); }; myTriangle.MouseDown += (sender, e) => { MouseUp(sender, e); }; if (canvas != null) { canvas.Children.Add(myTriangle); } } }
private void Triangulate_Click(object sender, RoutedEventArgs e) { var qualityOptions = new TriangleNet.Meshing.QualityOptions(); qualityOptions.MaximumArea = double.Parse(hTextBox.Text); qualityOptions.MinimumAngle = double.Parse(LTextBox.Text); var objct = new TriangleNet.Geometry.Polygon(); foreach (var item in mycoordinates) { objct.Add(item); } for (int i = 0; i < mycoordinates.Count - 1; i++) { objct.Add(new Segment(mycoordinates[i], mycoordinates[i + 1])); } objct.Add(new Segment(mycoordinates.LastOrDefault(), mycoordinates.FirstOrDefault())); //var test = new TriangleNet.Meshing.Algorithm.SweepLine(); var constraintOption = new TriangleNet.Meshing.ConstraintOptions(); meshResult = objct.Triangulate(constraintOption, qualityOptions, new TriangleNet.Meshing.Algorithm.Incremental()); //Triangulation //meshResult = objct.Triangulate(qualityOptions); meshResult.Renumber(); //triangleResult = new List<TriangleNet.Topology.Triangle>(meshResult.Triangles); //Triangles trianglesResult = GetTrianglesFromMeshTriangles(meshResult.Triangles); resultsTriangles.ItemsSource = trianglesResult; //Vertices verticesResult = new List <Vertex>(meshResult.Vertices); myvertixesResult = meshResult.Vertices.Select(v => new MyVertex { Id = v.ID, X = v.X, Y = v.Y }).ToList(); results.ItemsSource = myvertixesResult; //Заповнення граничних сегментів for (int i = 0; i < boundaries.Count; i++) { boundaries[i].SetSegments(meshResult.Segments, boundaries.Count); } //Перетворення орієнтації всіх сегментів проти годинникової стрілки for (int i = 0; i < boundaries.Count; i++) { if (i != boundaries.Count - 1) { boundaries[i].SetSegmentsOrientationToCounterclockwise(i, i + 1); } else { boundaries[i].SetSegmentsOrientationToCounterclockwise(i, 0); } } // FillGridWithBoundaries(resultsBoundaries, boundaries); DrawData(meshResult); //Етап 2: Створення матриць Me, Ke, Qe, Re, Pe //Підготовка //Зчитування параметрів double a11 = double.Parse(a11TextBox.Text); double a22 = double.Parse(a22TextBox.Text); double d = double.Parse(dTextBox.Text); double f = double.Parse(fTextBox.Text); //Створення масиву точок var CT = GetPointsArray(myvertixesResult); //Створення масиву трикутників var NT = GetTrianglesArray(trianglesResult); //Створення масиву граничних сегментів var NTGR = GetBoundarySegments(boundaries); //Створення масиву значень ф-кції f у точках var fe = GetFe(CT, f); //Етап 3 (ініціалізація A,B) //Кількість вузлів int nodeNumber = CT.Length; var A = new double[nodeNumber][]; for (int i = 0; i < nodeNumber; i++) { A[i] = new double[nodeNumber]; } var b = new double[nodeNumber]; //Створення Me, Ke, Qe (та їх розсилання) double[] function_value = new double[3]; for (int k = 0; k < trianglesResult.Count; k++) { //трикутник містить координати вузлів скінченного елемента var triangle = NT[k]; //Підготовка double[] i = CT[triangle[0]], j = CT[triangle[1]], m = CT[triangle[2]]; double Se = GetArea(i, j, m); double ai = GetA(j, m), bi = GetB(j, m), ci = GetC(j, m), aj = GetA(m, i), bj = GetB(m, i), cj = GetC(m, i), am = GetA(i, j), bm = GetB(i, j), cm = GetC(i, j); double[] a = new double[] { ai, aj, am }, B = new double[] { bi, bj, bm }, c = new double[] { ci, cj, cm }; function_value[0] = fe[triangle[0]]; function_value[1] = fe[triangle[1]]; function_value[2] = fe[triangle[2]]; //Ke var ke = new KE(k, Se, a11, a22, B, c); ke.print(); //Me var me = new ME(k, Se, d); me.print(); //Qe var qe = new QE(k, Se, fe); qe.print(); //Етап 3 for (int q = 0; q < 3; q++) { //triangle[q] це номер вузла елемента for (int w = 0; w < 3; w++) { A[triangle[q]][triangle[w]] += ke.Ke[q][w] + me.Me[q][w]; } b[triangle[q]] += qe.Qe[q][0]; } } //Створення Re, Pe (та їх розсилання) for (int k = 0; k < boundaries.Count; k++) { for (int l = 0; l < NTGR[k].Length; l++) { //сегмент містить координати вузлів граничного сегмента var segment = NTGR[k][l]; //Підготовка double[] i = CT[NTGR[k][l][0]], j = CT[NTGR[k][l][1]]; double Length = GetLength(i, j); //Re var re = new RE(k + l, boundaries[k].G, boundaries[k].B, Length, k + "|" + l + "|" + NTGR[k][l][0] + "-" + NTGR[k][l][1]); re.print(); //Pe var pe = new PE(k + l, boundaries[k].G, boundaries[k].B, boundaries[k].Uc, Length, k + "|" + l + "|" + NTGR[k][l][0] + "-" + NTGR[k][l][1]); pe.print(); //Етап 3 for (int q = 0; q < 2; q++) { //segment[q] це номер вузла сегмента for (int w = 0; w < 2; w++) { A[segment[q]][segment[w]] += re.Re[q][w]; } b[segment[q]] += pe.Pe[q][0]; } } } //Запис у файл A,b print(A, b); //Етап 3-2 var u = GausseMethod(nodeNumber, A, b); printNonFormatted(CT, u, "results.txt"); }
private static Mesh GetTriangleDotNetMesh(List <Vector2[]> poly_vertices) { var num_vxs = 0; foreach (var ring_vxs in poly_vertices) { num_vxs += ring_vxs.Length + 1; } var poly = new TriangleNet.Geometry.Polygon(num_vxs); // set vertices var ri = 0; foreach (var ring_vxs in poly_vertices) { var vxs_input = new List <TriangleNet.Geometry.Vertex>(ring_vxs.Length + 1); foreach (var vx in ring_vxs) { vxs_input.Add(new TriangleNet.Geometry.Vertex(vx.x, vx.y)); } // add to poly bool is_hole = ri != 0; var contour = new TriangleNet.Geometry.Contour(vxs_input); poly.Add(contour, is_hole); ++ri; } // triangulate var opts = new TriangleNet.Meshing.ConstraintOptions() { ConformingDelaunay = true }; var tn_mesh = (TriangleNet.Mesh)poly.Triangulate(opts); // write var tri_vxs = new Vector3[tn_mesh.Triangles.Count * 3]; var tri_ids = new int[tn_mesh.Triangles.Count * 3]; int i = 0; foreach (var tri in tn_mesh.Triangles) { tri_vxs[i + 0] = new Vector3((float)tri.GetVertex(0).x, (float)tri.GetVertex(0).y, 0); tri_vxs[i + 1] = new Vector3((float)tri.GetVertex(2).x, (float)tri.GetVertex(2).y, 0); tri_vxs[i + 2] = new Vector3((float)tri.GetVertex(1).x, (float)tri.GetVertex(1).y, 0); tri_ids[i + 0] = i + 0; tri_ids[i + 1] = i + 1; tri_ids[i + 2] = i + 2; i += 3; } // create mesh var m = new Mesh(); // assign to mesh m.vertices = tri_vxs; m.triangles = tri_ids; // recompute geometry // QUESTION why do we need bounds? m.RecalculateNormals(); m.RecalculateBounds(); return(m); }