public void AddVertex(Vec3 v, ref ContourVertex contourVertex) { if (_vertices.Contains(v)) { contourVertex = _vertices[v]; } else { _vertices.Add(v, ref contourVertex); _minX = Math.Min(_minX, v.X); _minY = Math.Min(_minY, v.Y); _minZ = Math.Min(_minZ, v.Z); _maxX = Math.Max(_maxX, v.X); _maxY = Math.Max(_maxY, v.Y); _maxZ = Math.Max(_maxZ, v.Z); } }
public static void ComputeNewellsNormal(ContourVertex[] vertices, ref Vec3 normal) { float x = 0, y = 0, z = 0; ContourVertex current; var previous = new ContourVertex(); int count = 0; int total = vertices.Length; for (var i = 0; i <= total; i++) { if (i < total) { current = vertices[i]; } else { current = vertices[0]; } if (count > 0) { float xn = previous.Position.X; float yn = previous.Position.Y; float zn = previous.Position.Z; float xn1 = current.Position.X; float yn1 = current.Position.Y; float zn1 = current.Position.Z; x += (yn - yn1) * (zn + zn1); y += (xn + xn1) * (zn - zn1); z += (xn - xn1) * (yn + yn1); } previous = current; count++; } normal.X = x; normal.Y = y; normal.Z = z; Vec3.Normalize(ref normal); }
public void AddVertex(Vec3 v, ref ContourVertex contourVertex) { if (_vertices.Contains(v)) contourVertex = _vertices[v]; else { _vertices.Add(v, ref contourVertex); _minX = Math.Min(_minX, v.X); _minY = Math.Min(_minY, v.Y); _minZ = Math.Min(_minZ, v.Z); _maxX = Math.Max(_maxX, v.X); _maxY = Math.Max(_maxY, v.Y); _maxZ = Math.Max(_maxZ, v.Z); } }
private XbimTriangulatedMesh TriangulateFaces(IList <IIfcFace> ifcFaces, int entityLabel, float precision) { var faceId = 0; var faceCount = ifcFaces.Count; var triangulatedMesh = new XbimTriangulatedMesh(faceCount, precision); foreach (var ifcFace in ifcFaces) { //improves performance and reduces memory load var tess = new Tess(); var contours = new List <ContourVertex[]>(/*Count?*/); foreach (var bound in ifcFace.Bounds) //build all the loops { var polyLoop = bound.Bound as IIfcPolyLoop; if (polyLoop == null) { continue; //skip empty faces } var polygon = polyLoop.Polygon; if (polygon.Count < 3) { continue; //skip non-polygonal faces } var is3D = (polygon[0].Dim == 3); var contour = new ContourVertex[polygon.Count]; if (bound.Orientation) { for (var j = 0; j < polygon.Count; j++) { var v = new Vec3(polygon[j].X, polygon[j].Y, is3D ? polygon[j].Z : 0); triangulatedMesh.AddVertex(v, ref contour[j]); } } else { var i = 0; for (var j = polygon.Count - 1; j >= 0; j--) { var v = new Vec3(polygon[j].X, polygon[j].Y, is3D ? polygon[j].Z : 0); triangulatedMesh.AddVertex(v, ref contour[i]); i++; } } contours.Add(contour); } if (contours.Any()) { if (contours.Count == 1 && contours[0].Length == 3) //its a triangle just grab it { triangulatedMesh.AddTriangle(contours[0][0].Data, contours[0][1].Data, contours[0][2].Data, faceId); faceId++; } //else //if (contours.Count == 1 && contours[0].Length == 4) //its a quad just grab it //{ // foreach (var v in contours[0]) // { // Console.WriteLine("{0:F4} ,{1:F4}, {2:F4}", v.Position.X, v.Position.Y, v.Position.Z); // } // Console.WriteLine(""); // triangulatedMesh.AddTriangle(contours[0][0].Data, contours[0][1].Data, contours[0][3].Data, faceId); // triangulatedMesh.AddTriangle(contours[0][3].Data, contours[0][1].Data, contours[0][2].Data, faceId); // faceId++; //} else //it is multi-sided and may have holes { tess.AddContours(contours); tess.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3); var faceIndices = new List <int>(tess.ElementCount * 3); var elements = tess.Elements; var contourVerts = tess.Vertices; for (var j = 0; j < tess.ElementCount * 3; j++) { var idx = contourVerts[elements[j]].Data; if (idx < 0) //WE HAVE INSERTED A POINT { //add it to the mesh triangulatedMesh.AddVertex(contourVerts[elements[j]].Position, ref contourVerts[elements[j]]); } faceIndices.Add(contourVerts[elements[j]].Data); } if (faceIndices.Count > 0) { for (var j = 0; j < tess.ElementCount; j++) { var p1 = faceIndices[j * 3]; var p2 = faceIndices[j * 3 + 1]; var p3 = faceIndices[j * 3 + 2]; triangulatedMesh.AddTriangle(p1, p2, p3, faceId); } faceId++; } } } } triangulatedMesh.UnifyFaceOrientation(entityLabel); return(triangulatedMesh); }
private XbimTriangulatedMesh TriangulateFaces(IEnumerable<IfcFace> ifcFaces, int entityLabel, float precision) { var faceId = 0; var enumerable = ifcFaces as IList<IfcFace> ?? ifcFaces.ToList(); var faceCount = enumerable.Count; var triangulatedMesh = new XbimTriangulatedMesh(faceCount, precision); foreach (var ifcFace in enumerable) { var fc = (IfcFace)_model.InstancesLocal[ifcFace.EntityLabel]; //improves performance and reduces memory load var tess = new Tess(); var contours = new List<ContourVertex[]>(fc.Bounds.Count); foreach (var bound in fc.Bounds) //build all the loops { var polyLoop = bound.Bound as IfcPolyLoop; if (polyLoop == null || polyLoop.Polygon.Count < 3) continue; //skip non-polygonal faces var is3D = (polyLoop.Polygon[0].Dim == 3); var contour = new ContourVertex[polyLoop.Polygon.Count]; var i = 0; foreach (var p in bound.Orientation ? polyLoop.Polygon : polyLoop.Polygon.Reverse()) //add all the points into unique collection { var v = new Vec3(p.X, p.Y, is3D ? p.Z : 0); triangulatedMesh.AddVertex(v, ref contour[i]); i++; } contours.Add(contour); } if (contours.Any()) { if (contours.Count == 1 && contours[0].Length == 3) //its a triangle just grab it { triangulatedMesh.AddTriangle(contours[0][0].Data, contours[0][1].Data, contours[0][2].Data, faceId); faceId++; } //else //if (contours.Count == 1 && contours[0].Length == 4) //its a quad just grab it //{ // foreach (var v in contours[0]) // { // Console.WriteLine("{0:F4} ,{1:F4}, {2:F4}", v.Position.X, v.Position.Y, v.Position.Z); // } // Console.WriteLine(""); // triangulatedMesh.AddTriangle(contours[0][0].Data, contours[0][1].Data, contours[0][3].Data, faceId); // triangulatedMesh.AddTriangle(contours[0][3].Data, contours[0][1].Data, contours[0][2].Data, faceId); // faceId++; //} else //it is multi-sided and may have holes { tess.AddContours(contours); tess.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3); var faceIndices = new List<int>(tess.ElementCount * 3); var elements = tess.Elements; var contourVerts = tess.Vertices; for (var j = 0; j < tess.ElementCount * 3; j++) { var idx = contourVerts[elements[j]].Data; if (idx < 0) //WE HAVE INSERTED A POINT { //add it to the mesh triangulatedMesh.AddVertex(contourVerts[elements[j]].Position, ref contourVerts[elements[j]]); } faceIndices.Add(contourVerts[elements[j]].Data); } if (faceIndices.Count > 0) { for (var j = 0; j < tess.ElementCount; j++) { var p1 = faceIndices[j * 3]; var p2 = faceIndices[j * 3 + 1]; var p3 = faceIndices[j * 3 + 2]; triangulatedMesh.AddTriangle(p1, p2, p3, faceId); } faceId++; } } } } triangulatedMesh.UnifyFaceOrientation(entityLabel); return triangulatedMesh; }
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); }
public static void ComputeNewellsNormal(ContourVertex[] vertices, ref Vec3 normal) { float x = 0, y = 0, z = 0; ContourVertex current; var previous = new ContourVertex(); int count = 0; int total = vertices.Length; for (var i = 0; i <= total; i++) { if (i < total) current = vertices[i]; else current = vertices[0]; if (count > 0) { float xn = previous.Position.X; float yn = previous.Position.Y; float zn = previous.Position.Z; float xn1 = current.Position.X; float yn1 = current.Position.Y; float zn1 = current.Position.Z; x += (yn - yn1) * (zn + zn1); y += (xn + xn1) * (zn - zn1); z += (xn - xn1) * (yn + yn1); } previous = current; count++; } normal.X = x; normal.Y = y; normal.Z = z; Vec3.Normalize(ref normal); }