Exemplo n.º 1
0
        public void BalanceNormals()
        {
            const double minAngle = Math.PI / 5;

            //set up the base normals
            foreach (var faceGroup in Faces)
            {
                foreach (var triangle in faceGroup.Value)
                {
                    ComputeTriangleNormal(triangle);
                }
            }


            var edgesAtVertex = _faces.Values.SelectMany(el => el).SelectMany(e => e).Where(e => e != null).GroupBy(k => k.StartVertexIndex);

            foreach (var edges in edgesAtVertex)
            {
                //create a set of faces to divide the point into a set of connected faces
                var faceSet = new List <List <XbimTriangleEdge> >();//the first face set at this point

                //find an unconnected edge if one exists
                var unconnectedEdges = edges.Where(e => e.AdjacentEdge == null);
                var freeEdges        = unconnectedEdges as IList <XbimTriangleEdge> ?? unconnectedEdges.ToList();

                if (!freeEdges.Any())
                //they are all connected to each other so find the first sharp edge or the any one if none sharp, this stops a face being split
                {
                    XbimTriangleEdge nextConnectedEdge = edges.First();
                    freeEdges = new List <XbimTriangleEdge>(1)
                    {
                        edges.First()
                    };                                                           //take the first if we don't find a sharp edge
                    //now look for any connected edges
                    var visited = new HashSet <long>();
                    do
                    {
                        visited.Add(nextConnectedEdge.EdgeId);
                        nextConnectedEdge = nextConnectedEdge.NextEdge.NextEdge.AdjacentEdge;
                        if (nextConnectedEdge != null)
                        {
                            if (visited.Contains(nextConnectedEdge.EdgeId)) //we have been here before
                            {
                                break;                                      //we are looping or at the start
                            }
                            //if the edge is sharp and the triangle is not colinear, start here
                            var nextAngle = nextConnectedEdge.Angle;
                            if (nextAngle > minAngle && nextConnectedEdge.Normal.IsValid)
                            {
                                freeEdges = new List <XbimTriangleEdge>(1)
                                {
                                    nextConnectedEdge
                                };
                                break;
                            }
                        }
                    } while (nextConnectedEdge != null);
                }

                foreach (var edge in freeEdges)
                {
                    var face = new List <XbimTriangleEdge> {
                        edge
                    };
                    faceSet.Add(face);
                    XbimTriangleEdge nextConnectedEdge = edge;
                    //now look for any connected edges
                    var visited = new HashSet <long>();
                    do
                    {
                        visited.Add(nextConnectedEdge.EdgeId);
                        var nextConnectedEdgeCandidate = nextConnectedEdge.NextEdge.NextEdge.AdjacentEdge;
                        while (nextConnectedEdgeCandidate != null && !visited.Contains(nextConnectedEdgeCandidate.EdgeId) && !nextConnectedEdgeCandidate.Normal.IsValid) //skip colinear triangles
                        {
                            //set the colinear triangle to have the same normals as the current edge
                            nextConnectedEdgeCandidate.Normal                   = nextConnectedEdge.Normal;
                            nextConnectedEdgeCandidate.NextEdge.Normal          = nextConnectedEdge.Normal;
                            nextConnectedEdgeCandidate.NextEdge.NextEdge.Normal = nextConnectedEdge.Normal;
                            visited.Add(nextConnectedEdgeCandidate.EdgeId);
                            nextConnectedEdgeCandidate = nextConnectedEdgeCandidate.NextEdge.NextEdge.AdjacentEdge;
                        }

                        nextConnectedEdge = nextConnectedEdgeCandidate;
                        if (nextConnectedEdge != null)
                        {
                            if (visited.Contains(nextConnectedEdge.EdgeId))
                            {
                                break; //we are looping or at the start
                            }
                            //if the edge is sharp start a new face
                            var angle = nextConnectedEdge.Angle;
                            if (angle > minAngle && nextConnectedEdge.Normal.IsValid)
                            {
                                face = new List <XbimTriangleEdge>();
                                faceSet.Add(face);
                            }
                            face.Add(nextConnectedEdge);
                        }
                    } while (nextConnectedEdge != null);
                    //move on to next face
                }

                //we have our smoothing groups
                foreach (var vertexEdges in faceSet.Where(f => f.Count > 1))
                {
                    var vertexNormal = Vec3.Zero;
                    foreach (var edge in vertexEdges)
                    {
                        if (edge.Normal.IsValid)
                        {
                            Vec3.AddTo(ref vertexNormal, ref edge.Normal);
                        }
                    }

                    Vec3.Normalize(ref vertexNormal);
                    foreach (var edge in vertexEdges)
                    {
                        edge.Normal = vertexNormal;
                    }
                }
            }

            //now regroup faces
            _faces = _faces.Values.SelectMany(v => v).GroupBy(t => ComputeTrianglePackedNormalInt(t)).ToDictionary(k => k.Key, v => v.ToList());
        }
Exemplo n.º 2
0
        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);
        }
Exemplo n.º 3
0
 public static void Cross(ref Vec3 u, ref Vec3 v, out Vec3 cross)
 {
     cross.X = u.Y * v.Z - u.Z * v.Y;
     cross.Y = u.Z * v.X - u.X * v.Z;
     cross.Z = u.X * v.Y - u.Y * v.X;
 }
Exemplo n.º 4
0
 public static void Dot(ref Vec3 u, ref Vec3 v, out double dot)
 {
     dot = u.X * v.X + u.Y * v.Y + u.Z * v.Z;
 }
Exemplo n.º 5
0
 public static void Neg(ref Vec3 v)
 {
     v.X = -v.X;
     v.Y = -v.Y;
     v.Z = -v.Z;
 }
Exemplo n.º 6
0
 public static void AddTo(ref Vec3 lhs, ref Vec3 rhs)
 {
     lhs.X += rhs.X;
     lhs.Y += rhs.Y;
     lhs.Z += rhs.Z;
 }
Exemplo n.º 7
0
 public static void Sub(ref Vec3 lhs, ref Vec3 rhs, out Vec3 result)
 {
     result.X = lhs.X - rhs.X;
     result.Y = lhs.Y - rhs.Y;
     result.Z = lhs.Z - rhs.Z;
 }