/// <summary> /// Creates a triangulation of the vertices given, and gives you the indices of it. /// </summary> /// <param name="aPoints">A list of points to triangulate.</param> /// <param name="aTreatAsPath">Should we discard any triangles at all? Use this if you want to get rid of triangles that are outside the path.</param> /// <param name="aInvert">if we're treating it as a path, should we instead sicard triangles inside the path?</param> /// <returns>A magical list of indices describing the triangulation!</returns> public static List <int> GetIndices(ref List <Vector2> aPoints, bool aTreatAsPath, bool aInvert) { Vector4 bounds = GetBounds(aPoints); LibTessDotNet.Tess tess = new LibTessDotNet.Tess(); LibTessDotNet.ContourVertex[] verts = new LibTessDotNet.ContourVertex[aPoints.Count]; for (int i = 0; i < aPoints.Count; i++) { verts[i] = new LibTessDotNet.ContourVertex(); verts[i].Position = new LibTessDotNet.Vec3(); verts[i].Position.X = aPoints[i].x; verts[i].Position.Y = aPoints[i].y; verts[i].Position.Z = 0; } tess.AddContour(verts, LibTessDotNet.ContourOrientation.Original); if (aInvert) { aPoints.Add(new Vector2(bounds.x - (bounds.z - bounds.x) * 1, bounds.w - (bounds.y - bounds.w) * 1)); // 4 aPoints.Add(new Vector2(bounds.z + (bounds.z - bounds.x) * 1, bounds.w - (bounds.y - bounds.w) * 1)); // 3 aPoints.Add(new Vector2(bounds.z + (bounds.z - bounds.x) * 1, bounds.y + (bounds.y - bounds.w) * 1)); // 2 aPoints.Add(new Vector2(bounds.x - (bounds.z - bounds.x) * 1, bounds.y + (bounds.y - bounds.w) * 1)); // 1 LibTessDotNet.ContourVertex[] outer = new LibTessDotNet.ContourVertex[4]; for (int i = 0; i < 4; i++) { outer[i] = new LibTessDotNet.ContourVertex(); outer[i].Position = new LibTessDotNet.Vec3(); outer[i].Position.X = aPoints[(aPoints.Count - 4) + i].x; outer[i].Position.Y = aPoints[(aPoints.Count - 4) + i].y; outer[i].Position.Z = 0; } tess.AddContour(outer, aInvert ? LibTessDotNet.ContourOrientation.CounterClockwise : LibTessDotNet.ContourOrientation.Clockwise); } tess.Tessellate(LibTessDotNet.WindingRule.EvenOdd, LibTessDotNet.ElementType.Polygons, 3); List <int> result = new List <int>(); for (int i = 0; i < tess.Elements.Length; i += 3) { for (int t = 0; t < 3; t++) { if (tess.Elements[i + t] == -1) { continue; } for (int v = 0; v < aPoints.Count; v++) { if (aPoints[v].x == tess.Vertices[tess.Elements[i + t]].Position.X && aPoints[v].y == tess.Vertices[tess.Elements[i + t]].Position.Y) { result.Add(v); break; } } } } return(result); }
/// <summary> /// Creates a triangulation of the vertices given, and gives you the indices of it. /// </summary> /// <param name="aPoints">A list of points to triangulate.</param> /// <param name="aTreatAsPath">Should we discard any triangles at all? Use this if you want to get rid of triangles that are outside the path.</param> /// <param name="aInvert">if we're treating it as a path, should we instead sicard triangles inside the path?</param> /// <returns>A magical list of indices describing the triangulation!</returns> public static List<int> GetIndices(ref List<Vector2> aPoints, bool aTreatAsPath, bool aInvert) { Vector4 bounds = GetBounds(aPoints); LibTessDotNet.Tess tess = new LibTessDotNet.Tess(); LibTessDotNet.ContourVertex[] verts = new LibTessDotNet.ContourVertex[aPoints.Count]; for (int i = 0; i < aPoints.Count; i++) { verts[i] = new LibTessDotNet.ContourVertex(); verts[i].Position = new LibTessDotNet.Vec3(); verts[i].Position.X = aPoints[i].x; verts[i].Position.Y = aPoints[i].y; verts[i].Position.Z = 0; } tess.AddContour(verts, LibTessDotNet.ContourOrientation.Original); if (aInvert) { aPoints.Add(new Vector2(bounds.x - (bounds.z - bounds.x) * 1, bounds.w - (bounds.y - bounds.w) * 1)); // 4 aPoints.Add(new Vector2(bounds.z + (bounds.z - bounds.x) * 1, bounds.w - (bounds.y - bounds.w) * 1)); // 3 aPoints.Add(new Vector2(bounds.z + (bounds.z - bounds.x) * 1, bounds.y + (bounds.y - bounds.w) * 1)); // 2 aPoints.Add(new Vector2(bounds.x - (bounds.z - bounds.x) * 1, bounds.y + (bounds.y - bounds.w) * 1)); // 1 LibTessDotNet.ContourVertex[] outer = new LibTessDotNet.ContourVertex[4]; for (int i = 0; i < 4; i++) { outer[i] = new LibTessDotNet.ContourVertex(); outer[i].Position = new LibTessDotNet.Vec3(); outer[i].Position.X = aPoints[(aPoints.Count - 4) + i].x; outer[i].Position.Y = aPoints[(aPoints.Count - 4) + i].y; outer[i].Position.Z = 0; } tess.AddContour(outer, aInvert ? LibTessDotNet.ContourOrientation.CounterClockwise : LibTessDotNet.ContourOrientation.Clockwise); } tess.Tessellate(LibTessDotNet.WindingRule.EvenOdd, LibTessDotNet.ElementType.Polygons, 3); List<int> result = new List<int>(); for (int i = 0; i < tess.Elements.Length; i += 3) { for (int t = 0; t < 3; t++) { if (tess.Elements[i + t] == -1) { continue; } for (int v = 0; v < aPoints.Count; v++) { if (aPoints[v].x == tess.Vertices[tess.Elements[i + t]].Position.X && aPoints[v].y == tess.Vertices[tess.Elements[i + t]].Position.Y) { result.Add(v); break; } } } } return result; }
public static Cad2D.Polygon Tesselate(List <Cad2D.Polygon> Polygons) { // Create an instance of the tessellator. Can be reused. var tess = new LibTessDotNet.Tess(); // Construct the contours from input polygons // A polygon can be composed of multiple contours which are all tessellated at the same time. foreach (Cad2D.Polygon poly in Polygons) { int numPoints = poly.Vertices.Count; var contour = new LibTessDotNet.ContourVertex[numPoints]; for (int i = 0; i < numPoints; i++) { // NOTE : Z is here for convenience if you want to keep a 3D vertex position throughout the tessellation process but only X and Y are important. contour[i].Position = new LibTessDotNet.Vec3 { X = poly.Vertices[i].X, Y = poly.Vertices[i].Y, Z = 0.0f }; // Data can contain any per-vertex data, here a constant color. contour[i].Data = Color.Azure; } // Add the contour with a specific orientation, use "Original" if you want to keep the input orientation. tess.AddContour(contour, LibTessDotNet.ContourOrientation.Clockwise); } // Tessellate! // The winding rule determines how the different contours are combined together. // See http://www.glprogramming.com/red/chapter11.html (section "Winding Numbers and Winding Rules") for more information. // If you want triangles as output, you need to use "Polygons" type as output and 3 vertices per polygon. tess.Tessellate(LibTessDotNet.WindingRule.EvenOdd, LibTessDotNet.ElementType.Polygons, 3, VertexCombine); // Same call but the last callback is optional. Data will be null because no interpolated data would have been generated. //tess.Tessellate(LibTessDotNet.WindingRule.EvenOdd, LibTessDotNet.ElementType.Polygons, 3); // Some vertices will have null Data in this case. Cad2D.Polygon result = new Cad2D.Polygon(); int numTriangles = tess.ElementCount; result.Triangles = new List <Cad2D.Triangle>(); for (int i = 0; i < numTriangles; i++) { var v0 = tess.Vertices[tess.Elements[i * 3]].Position; var v1 = tess.Vertices[tess.Elements[i * 3 + 1]].Position; var v2 = tess.Vertices[tess.Elements[i * 3 + 2]].Position; result.Triangles.Add(new Cad2D.Triangle(v0.X, v0.Y, v1.X, v1.Y, v2.X, v2.Y)); } return(result); }
private float SignedArea(ContourVertex[] vertices) { float num = 0f; for (int i = 0; i < vertices.Length; i++) { ContourVertex contourVertex = vertices[i]; ContourVertex contourVertex2 = vertices[(i + 1) % vertices.Length]; num += contourVertex.Position.X * contourVertex2.Position.Y; num -= contourVertex.Position.Y * contourVertex2.Position.X; } return(0.5f * num); }
static void Main(string[] args) { // Example input data in the form of a star that intersects itself. var inputData = new float[] { 0.0f, 3.0f, -1.0f, 0.0f, 1.6f, 1.9f, -1.6f, 1.9f, 1.0f, 0.0f }; // Create an instance of the tessellator. Can be reused. var tess = new LibTessDotNet.Tess(); // Construct the contour from inputData. // A polygon can be composed of multiple contours which are all tessellated at the same time. int numPoints = inputData.Length / 2; var contour = new LibTessDotNet.ContourVertex[numPoints]; for (int i = 0; i < numPoints; i++) { // NOTE : Z is here for convenience if you want to keep a 3D vertex position throughout the tessellation process but only X and Y are important. contour[i].Position = new LibTessDotNet.Vec3 { X = inputData[i * 2], Y = inputData[i * 2 + 1], Z = 0.0f }; // Data can contain any per-vertex data, here a constant color. contour[i].Data = Color.Azure; } // Add the contour with a specific orientation, use "Original" if you want to keep the input orientation. tess.AddContour(contour, LibTessDotNet.ContourOrientation.Clockwise); // Tessellate! // The winding rule determines how the different contours are combined together. // See http://www.glprogramming.com/red/chapter11.html (section "Winding Numbers and Winding Rules") for more information. // If you want triangles as output, you need to use "Polygons" type as output and 3 vertices per polygon. tess.Tessellate(LibTessDotNet.WindingRule.EvenOdd, LibTessDotNet.ElementType.Polygons, 3, VertexCombine); // Same call but the last callback is optional. Data will be null because no interpolated data would have been generated. //tess.Tessellate(LibTessDotNet.WindingRule.EvenOdd, LibTessDotNet.ElementType.Polygons, 3); // Some vertices will have null Data in this case. Console.WriteLine("Output triangles:"); int numTriangles = tess.ElementCount; for (int i = 0; i < numTriangles; i++) { var v0 = tess.Vertices[tess.Elements[i * 3]].Position; var v1 = tess.Vertices[tess.Elements[i * 3 + 1]].Position; var v2 = tess.Vertices[tess.Elements[i * 3 + 2]].Position; Console.WriteLine("#{0} ({1:F1},{2:F1}) ({3:F1},{4:F1}) ({5:F1},{6:F1})", i, v0.X, v0.Y, v1.X, v1.Y, v2.X, v2.Y); } Console.ReadLine(); }
private void RefreshAsset(string name) { var asset = _data.GetAsset(name); _sw.Reset(); foreach (var poly in asset.Polygons) { var v = new ContourVertex[poly.Count]; for (int i = 0; i < poly.Count; i++) { v[i].Position = new Vec3 { X = poly[i].X, Y = poly[i].Y }; v[i].Data = poly[i].Color; } _sw.Start(); _tess.AddContour(v, poly.Orientation); _sw.Stop(); } _sw.Start(); _tess.Tessellate(_windingRule, ElementType.Polygons, _polySize, VertexCombine); _sw.Stop(); var output = new PolygonSet(); for (int i = 0; i < _tess.ElementCount; i++) { var poly = new Polygon(); for (int j = 0; j < _polySize; j++) { int index = _tess.Elements[i * _polySize + j]; if (index == -1) continue; var v = new PolygonPoint { X = _tess.Vertices[index].Position.X, Y = _tess.Vertices[index].Position.Y, Color = (Color)_tess.Vertices[index].Data }; poly.Add(v); } output.Add(poly); } statusMain.Text = string.Format("{0:F3} ms - {1} polygons (of {2} vertices) {3}", _sw.Elapsed.TotalMilliseconds, _tess.ElementCount, _polySize, _polySize == 3 ? "... triangles" : ""); _canvas.Input = asset.Polygons; _canvas.Output = output; _canvas.Invalidate(); }
private float SignedArea(ContourVertex[] vertices) { float area = 0.0f; for (int i = 0; i < vertices.Length; i++) { var v0 = vertices[i]; var v1 = vertices[(i + 1) % vertices.Length]; area += v0.Position.X * v1.Position.Y; area -= v0.Position.Y * v1.Position.X; } return area * 0.5f; }
public void AddContour(ContourVertex[] vertices, ContourOrientation forceOrientation) { if (_mesh == null) { _mesh = new Mesh(); } bool reverse = false; if (forceOrientation != ContourOrientation.Original) { float area = SignedArea(vertices); reverse = (forceOrientation == ContourOrientation.Clockwise && area < 0.0f) || (forceOrientation == ContourOrientation.CounterClockwise && area > 0.0f); } MeshUtils.Edge e = null; for (int i = 0; i < vertices.Length; ++i) { if (e == null) { e = _mesh.MakeEdge(); _mesh.Splice(e, e._Sym); } else { // Create a new vertex and edge which immediately follow e // in the ordering around the left face. _mesh.SplitEdge(e); e = e._Lnext; } int index = reverse ? vertices.Length - 1 - i : i; // The new vertex is now e._Org. e._Org._coords = vertices[index].Position; e._Org._data = vertices[index].Data; // The winding of an edge says how the winding number changes as we // cross from the edge's right face to its left face. We add the // vertices in such an order that a CCW contour will add +1 to // the winding number of the region inside the contour. e._winding = 1; e._Sym._winding = -1; } }
public void AddContour(ContourVertex[] vertices) { AddContour(vertices, ContourOrientation.Original); }
void StartOld() { OsmBuilding building = Data.Instance.buildings [buildingId]; //float[] points = building.getPolygon (); Vector3[] points = building.getPolygonAsVector3 (); var tess = new LibTessDotNet.Tess(); //Debug.Log ("-" + buildingId); var contour = new LibTessDotNet.ContourVertex[points.Length]; for (int i = 0; i < points.Length; i++) { // NOTE : Z is here for convenience if you want to keep a 3D vertex position throughout the tessellation process but only X and Y are important. contour[i].Position = new LibTessDotNet.Vec3 { X = points[i].x, Y = points[i].y, Z = points[i].z }; // Data can contain any per-vertex data, here a constant color. contour[i].Data = Color.cyan; if (i != points.Length-1) { Debug.DrawLine(points [i], points [i + 1],Color.red,2000f); } } tess.AddContour(contour, LibTessDotNet.ContourOrientation.Original); tess.Tessellate(LibTessDotNet.WindingRule.EvenOdd, LibTessDotNet.ElementType.Polygons, 3, VertexCombine); //gameObject.AddComponent<MeshFilter>(); //gameObject.AddComponent<MeshRenderer>(); Mesh mesh = new Mesh (); mesh.Clear(); mesh.name = "Building"; mesh.vertices = points; mesh.RecalculateNormals(); mesh.RecalculateBounds(); Vector2[] uvs = new Vector2[points.Length]; Bounds bounds = mesh.bounds; for(int i = 0; i < points.Length; i++) { uvs[i] = new Vector2(points[i].x / bounds.size.x, points[i].z / bounds.size.x); } mesh.uv = uvs; mesh.triangles = tess.Elements; GameObject meshObject = new GameObject (); meshObject.AddComponent<MeshFilter> ().mesh = mesh; Renderer renderer = meshObject.AddComponent<MeshRenderer> (); meshObject.transform.parent = this.transform; //meshObject.transform.position = new Vector3(-mesh.bounds.center.x, -mesh.bounds.center.y, -mesh.bounds.center.z); //gameObject.transform.position = new Vector3(-mesh.bounds.center.x, -mesh.bounds.center.y, -mesh.bounds.center.z); //GetComponent<MeshRenderer> ().material = Resources.Load<Material> ("Source/Red"); }
public List <Triangle> TrianglateGlyph(Glyph g) { var re = new List <Triangle>(); var tess = new LibTessDotNet.Tess(); var c = 0; var last = 0; var vecs = new List <Vec3>(); for (var i = 0; i < g.Points.Count; i++) { var glyphPointA = g.Points[i]; vecs.Add(new Vec3() { X = glyphPointA["x"], Y = glyphPointA["y"], Z = 0 }); if (i == g.ContourEnds[c]) { c += 1; var contour = new LibTessDotNet.ContourVertex[vecs.Count]; for (var index = 0; index < vecs.Count; index++) { contour[index].Position = vecs[index]; contour[index].Data = Color.Black; } tess.AddContour(contour, LibTessDotNet.ContourOrientation.Clockwise); vecs.Clear(); } } tess.Tessellate(LibTessDotNet.WindingRule.EvenOdd, LibTessDotNet.ElementType.Polygons, 3); Console.WriteLine("Output triangles:"); int numTriangles = tess.ElementCount; for (int i = 0; i < numTriangles; i++) { var v0 = tess.Vertices[tess.Elements[i * 3]].Position; var v1 = tess.Vertices[tess.Elements[i * 3 + 1]].Position; var v2 = tess.Vertices[tess.Elements[i * 3 + 2]].Position; re.Add(new Triangle(new Point((int)v0.X, (int)v0.Y), new Point((int)v1.X, (int)v1.Y), new Point((int)v2.X, (int)v2.Y))); } return(re); }
private static void ToTess(PolygonSet pset, Tess tess) { foreach (var poly in pset) { var v = new ContourVertex[poly.Count]; for (int i = 0; i < poly.Count; i++) { v[i].Position = new Vec3 { X = poly[i].X, Y = poly[i].Y }; v[i].Data = poly[i].Color; } tess.AddContour(v, poly.Orientation); } }
private void adaptate() { if (!this.aad.isRectangular() && this.aad.getInfluenceArea () != null) { this.transform.localScale = new Vector3 (1, 1, 1); Mesh mesh = new Mesh (); List<Vector3> vertices = new List<Vector3> (); List<Vector2> vertices2 = new List<Vector2> (); Tess tess = new LibTessDotNet.Tess(); ContourVertex[] contour = new ContourVertex[aad.getPoints().Count]; int i = 0; float minx = float.MaxValue, miny = float.MaxValue, maxx = 0, maxy = 0; foreach (Vector2 v in this.aad.getPoints()) { if (v.x < minx) minx = v.x; if (v.x > maxx) maxx = v.x; if (v.y < miny) miny = v.y; if (v.y > maxy) maxy = v.y; } minx = (minx + (maxx - minx) / 2 ) / 10; miny = 60 - (miny + (maxy - miny) / 2 ) / 10; foreach (Vector2 v in this.aad.getPoints()) { contour[i].Position = new LibTessDotNet.Vec3 { X = v.x / 10f - minx, Y = 60 - v.y / 10f - miny, Z = this.transform.position.z }; i++; } tess.AddContour(contour, LibTessDotNet.ContourOrientation.CounterClockwise); tess.Tessellate(WindingRule.EvenOdd, LibTessDotNet.ElementType.Polygons,3); Debug.Log("Output triangles:"); List<int> triangles = new List<int> (); int numTriangles = tess.ElementCount; for (i = 0; i < numTriangles; i++){ vertices.Add(Vec3toVector3(tess.Vertices[tess.Elements[i * 3]].Position)); vertices.Add(Vec3toVector3(tess.Vertices[tess.Elements[i * 3 + 1]].Position)); vertices.Add(Vec3toVector3(tess.Vertices[tess.Elements[i * 3 + 2]].Position)); triangles.AddRange(new int[] { i * 3, i * 3+1, i * 3+2 }); } mesh.SetVertices (vertices); mesh.SetTriangles (triangles,0); this.GetComponent<MeshFilter> ().sharedMesh = mesh; this.GetComponent<MeshCollider> ().sharedMesh = mesh; } }