Example #1
0
        private bool exportMesh(String filename, Mesh mesh)
        {
            bool bSaved = false;

            try
            {
                StreamWriter sout = new StreamWriter(filename, false);
                sout.WriteLine("P1X, P1Y, P1Z, P2X, P2Y, P2Z, P3X, P3Y, P3Z");
                for (int tlp = 0; tlp < mesh.NumTriangles; tlp++)
                {
                    MeshTriangle tri = mesh.get_Triangle(tlp);

                    XYZ p1 = mesh.Vertices[(int)tri.get_Index(0)];
                    XYZ p2 = mesh.Vertices[(int)tri.get_Index(1)];
                    XYZ p3 = mesh.Vertices[(int)tri.get_Index(2)];

                    String tstr = String.Format("{0:0.000}, {1:0.000}, {2:0.000}, {3:0.000}, {4:0.000}, {5:0.000}, {6:0.000}, {7:0.000}, {8:0.000}", new object[] { p1.X, p1.Y, p1.Z, p2.X, p2.Y, p2.Z, p3.X, p3.Y, p3.Z });
                    sout.WriteLine(tstr);
                }
                sout.Close();

                bSaved = true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Unable to write file", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            return(bSaved);
        }
Example #2
0
        /***************************************************/
        /****               Public Methods              ****/
        /***************************************************/

        public static oM.Geometry.Face FromRevit(this MeshTriangle triangle)
        {
            if (triangle == null)
            {
                return(null);
            }

            return(new oM.Geometry.Face {
                A = (int)triangle.get_Index(0), B = (int)triangle.get_Index(1), C = (int)triangle.get_Index(2)
            });
        }
Example #3
0
        static private bool ExportMeshes(List <Mesh> meshes, ref Va3cContainer.Va3cGeometry meshGroupGeometry)
        {
            foreach (Mesh mesh in meshes)
            {
                int currentPointNum = meshGroupGeometry.data.points;
                int currentTriNum   = meshGroupGeometry.data.triangles;

                IList <XYZ> points   = mesh.Vertices;
                int         pointNum = points.Count;
                int         triNum   = mesh.NumTriangles;
                meshGroupGeometry.data.points    += pointNum;
                meshGroupGeometry.data.triangles += triNum;
                foreach (XYZ point in points)
                {
                    meshGroupGeometry.data.vertices.Add((float)point.X);
                    meshGroupGeometry.data.vertices.Add((float)point.Y);
                    meshGroupGeometry.data.vertices.Add((float)point.Z);

                    //test
                    meshGroupGeometry.data.normals.Add(0.0f);
                    meshGroupGeometry.data.normals.Add(0.0f);
                    meshGroupGeometry.data.normals.Add(1.0f);
                    meshGroupGeometry.data.uvs.Add(0.0f);
                    meshGroupGeometry.data.uvs.Add(0.0f);
                }
                for (int i = 0; i < triNum; ++i)
                {
                    MeshTriangle meshTri = mesh.get_Triangle(i);
                    int          index0  = (int)meshTri.get_Index(0) + currentPointNum;
                    int          index1  = (int)meshTri.get_Index(1) + currentPointNum;
                    int          index2  = (int)meshTri.get_Index(2) + currentPointNum;
                    meshGroupGeometry.data.indices.Add(index0);
                    meshGroupGeometry.data.indices.Add(index1);
                    meshGroupGeometry.data.indices.Add(index2);
                }
            }

            if (meshGroupGeometry.data.points > 0 && meshGroupGeometry.data.triangles > 0)
            {
                return(true);
            }

            return(false);
        }
        /// <summary>
        /// Function called before and after triangle merging.
        /// Before merging it calculates the Euler characteristic of the original mesh.
        /// After merging it calculates the Euler characteristic of the merged mesh.
        /// </summary>
        private int CalculateEulerCharacteristic()
        {
            int noVertices = 0;
            int noHoles    = 0; // Stays zero if mesh is triangular
            int noFaces;
            HashSet <IndexSegment> edges = new HashSet <IndexSegment>(new SegmentComparer(true /*compareBothDirections*/));

            if (m_MergedFaceSet.Count != 0)
            {
                // Merging already occurred, calculate new Euler characteristic
                noFaces = m_MergedFaceSet.Count;
                foreach (int mergedFace in m_MergedFaceSet)
                {
                    m_FacesCollDict[mergedFace].OuterAndInnerBoundaries.ToList().ForEach(vp => edges.Add(vp.Value));
                    if (m_FacesCollDict[mergedFace].IndexedInnerBoundaries != null)
                    {
                        noHoles += m_FacesCollDict[mergedFace].IndexedInnerBoundaries.Count;
                    }
                }
                noVertices = m_MeshVertices.Count; // m_MeshVertices doesn't contain isolated vertices
            }
            else
            {
                if (IsMesh)
                {
                    noVertices = m_MeshGeom.Vertices.Count;
                    noFaces    = m_MeshGeom.NumTriangles;
                    for (int faceIdx = 0; faceIdx < noFaces; faceIdx++)
                    {
                        MeshTriangle tri = m_MeshGeom.get_Triangle(faceIdx);
                        edges.Add(new IndexSegment((int)tri.get_Index(0), (int)tri.get_Index(1)));
                        edges.Add(new IndexSegment((int)tri.get_Index(1), (int)tri.get_Index(2)));
                        edges.Add(new IndexSegment((int)tri.get_Index(2), (int)tri.get_Index(0)));
                    }
                }
                else
                {
                    noVertices = m_Geom.VertexCount;
                    noFaces    = m_Geom.TriangleCount;
                    for (int faceIdx = 0; faceIdx < noFaces; faceIdx++)
                    {
                        TriangleInShellComponent tri = m_Geom.GetTriangle(faceIdx);
                        edges.Add(new IndexSegment(tri.VertexIndex0, tri.VertexIndex1));
                        edges.Add(new IndexSegment(tri.VertexIndex1, tri.VertexIndex2));
                        edges.Add(new IndexSegment(tri.VertexIndex2, tri.VertexIndex0));
                    }
                }
            }

            // V - E + F - I
            return(noVertices - edges.Count + noFaces - noHoles);
        }
Example #5
0
        public static List <LMAStudio.StreamVR.Common.Models.Face> ConvertToDTO(Autodesk.Revit.DB.Element parent, Autodesk.Revit.DB.Solid geometry)
        {
            List <LMAStudio.StreamVR.Common.Models.Face> wallFaces = new List <LMAStudio.StreamVR.Common.Models.Face>();

            IEnumerable <Face> faces = geometry.Faces.Cast <Face>();

            Face topFace = faces.Where(
                (f, i) => i == 1
                ).FirstOrDefault() ?? faces.FirstOrDefault();

            wallFaces = faces.Select((f, index) =>
            {
                Mesh m = f.Triangulate();

                List <int> indices = new List <int>();

                for (int i = 0; i < m.NumTriangles; i++)
                {
                    MeshTriangle mt = m.get_Triangle(i);
                    for (int j = 0; j < 3; j++)
                    {
                        indices.Add((int)mt.get_Index(j));
                    }
                }

                return(new LMAStudio.StreamVR.Common.Models.Face
                {
                    ElementId = parent.Id.ToString(),
                    FaceIndex = index,
                    MaterialId = f.MaterialElementId?.ToString(),
                    Indices = indices,
                    Vertices = m.Vertices.Select(v => new LMAStudio.StreamVR.Common.Models.XYZ
                    {
                        X = v.X,
                        Y = v.Y,
                        Z = v.Z,
                    }).ToList()
                });
            }).ToList();

            return(wallFaces);
        }
Example #6
0
        /// <summary>
        /// Function called before and after triangle merging.
        /// Before merging it calculates the Euler characteristic of the original mesh.
        /// After merging it calculates the Euler characteristic of the merged mesh.
        /// </summary>
        private int CalculateEulerCharacteristic()
        {
            int noVertices = (IsMesh) ? _meshGeom.Vertices.Count : _geom.VertexCount;
            int noHoles    = 0; // Stays zero if mesh is triangular
            int noFaces;
            HashSet <IndexSegment> edges = new HashSet <IndexSegment>(new SegmentComparer(true /*compareBothDirections*/));

            if (_mergedFaceList.Count != 0)
            {
                // Merging already occurred, calculate new Euler characteristic
                noFaces = _mergedFaceList.Count;
                foreach (int mergedFace in _mergedFaceList)
                {
                    edges.UnionWith(facesColl[mergedFace].outerAndInnerBoundaries);
                    if (facesColl[mergedFace].indexedInnerBoundaries != null)
                    {
                        noHoles += facesColl[mergedFace].indexedInnerBoundaries.Count;
                    }
                }
            }
            else
            {
                if (IsMesh)
                {
                    noFaces = _meshGeom.NumTriangles;
                    for (int faceIdx = 0; faceIdx < noFaces; faceIdx++)
                    {
                        MeshTriangle tri = _meshGeom.get_Triangle(faceIdx);
                        edges.Add(new IndexSegment((int)tri.get_Index(0), (int)tri.get_Index(1)));
                        edges.Add(new IndexSegment((int)tri.get_Index(1), (int)tri.get_Index(2)));
                        edges.Add(new IndexSegment((int)tri.get_Index(2), (int)tri.get_Index(0)));
                    }
                }
                else
                {
                    noFaces = _geom.TriangleCount;
                    for (int faceIdx = 0; faceIdx < noFaces; faceIdx++)
                    {
                        TriangleInShellComponent tri = _geom.GetTriangle(faceIdx);
                        edges.Add(new IndexSegment(tri.VertexIndex0, tri.VertexIndex1));
                        edges.Add(new IndexSegment(tri.VertexIndex1, tri.VertexIndex2));
                        edges.Add(new IndexSegment(tri.VertexIndex2, tri.VertexIndex0));
                    }
                }
            }

            // V - E + F - I
            return(noVertices - edges.Count + noFaces - noHoles);
        }
Example #7
0
        public Result Execute(
            ExternalCommandData commandData,
            ref string message,
            ElementSet elements)
        {
            UIApplication           uiapp = commandData.Application;
            UIDocument              uidoc = uiapp.ActiveUIDocument;
            Document                doc   = uidoc.Document;
            Selection               sel   = uidoc.Selection;
            ICollection <ElementId> ids   = sel.GetElementIds();

            if (1 != ids.Count)
            {
                message = "Please select an element to export to TWGL.";
                return(Result.Failed);
            }

            Element e = null;

            foreach (ElementId id in ids)
            {
                e = doc.GetElement(id);
            }

            // Determine bounding box in order to translate
            // all coordinates to bounding box midpoint.

            BoundingBoxXYZ bb    = e.get_BoundingBox(null);
            XYZ            pmin  = bb.Min;
            XYZ            pmax  = bb.Max;
            XYZ            vsize = pmax - pmin;
            XYZ            pmid  = pmin + 0.5 * vsize;

            Options         opt = new Options();
            GeometryElement geo = e.get_Geometry(opt);

            List <int>    faceIndices  = new List <int>();
            List <int>    faceVertices = new List <int>();
            List <double> faceNormals  = new List <double>();

            int[] triangleIndices = new int[3];
            XYZ[] triangleCorners = new XYZ[3];

            foreach (GeometryObject obj in geo)
            {
                Solid solid = obj as Solid;

                if (solid != null && 0 < solid.Faces.Size)
                {
                    faceIndices.Clear();
                    faceVertices.Clear();
                    faceNormals.Clear();

                    foreach (Face face in solid.Faces)
                    {
                        Mesh mesh = face.Triangulate();

                        int nTriangles = mesh.NumTriangles;

                        IList <XYZ> vertices = mesh.Vertices;

                        int nVertices = vertices.Count;

                        List <int> vertexCoordsMm = new List <int>(3 * nVertices);

                        // A vertex may be reused several times with
                        // different normals for different faces, so
                        // we cannot precalculate normals per vertex.
                        //List<double> normals = new List<double>( 3 * nVertices );

                        foreach (XYZ v in vertices)
                        {
                            // Translate the entire element geometry
                            // to the bounding box midpoint and scale
                            // to metric millimetres.

                            XYZ p = v - pmid;

                            vertexCoordsMm.Add(Util.FootToMm(p.X));
                            vertexCoordsMm.Add(Util.FootToMm(p.Y));
                            vertexCoordsMm.Add(Util.FootToMm(p.Z));
                        }

                        for (int i = 0; i < nTriangles; ++i)
                        {
                            MeshTriangle triangle = mesh.get_Triangle(i);

                            for (int j = 0; j < 3; ++j)
                            {
                                int k = (int)triangle.get_Index(j);
                                triangleIndices[j] = k;
                                triangleCorners[j] = vertices[k];
                            }

                            // Calculate constant triangle facet normal.

                            XYZ v = triangleCorners[1]
                                    - triangleCorners[0];
                            XYZ w = triangleCorners[2]
                                    - triangleCorners[0];
                            XYZ triangleNormal = v
                                                 .CrossProduct(w)
                                                 .Normalize();

                            for (int j = 0; j < 3; ++j)
                            {
                                int nFaceVertices = faceVertices.Count;

                                Debug.Assert(nFaceVertices.Equals(faceNormals.Count),
                                             "expected equal number of face vertex and normal coordinates");

                                faceIndices.Add(nFaceVertices / 3);

                                int i3 = triangleIndices[j] * 3;

                                // Rotate the X, Y and Z directions,
                                // since the Z direction points upward
                                // in Revit as opposed to sideways or
                                // outwards or forwards in WebGL.

                                faceVertices.Add(vertexCoordsMm[i3 + 1]);
                                faceVertices.Add(vertexCoordsMm[i3 + 2]);
                                faceVertices.Add(vertexCoordsMm[i3]);

                                if (RetainCurvedSurfaceFacets)
                                {
                                    faceNormals.Add(triangleNormal.Y);
                                    faceNormals.Add(triangleNormal.Z);
                                    faceNormals.Add(triangleNormal.X);
                                }
                                else
                                {
                                    UV uv = face.Project(
                                        triangleCorners[j]).UVPoint;

                                    XYZ normal = face.ComputeNormal(uv);

                                    faceNormals.Add(normal.Y);
                                    faceNormals.Add(normal.Z);
                                    faceNormals.Add(normal.X);
                                }
                            }
                        }
                    }

                    // Scale the vertices to a [-1,1] cube
                    // centered around the origin. Translation
                    // to the origin was already performed above.

                    double scale = 2.0 / Util.FootToMm(
                        Util.MaxCoord(vsize));

                    string json_geometry_data
                        = GetJsonGeometryData(scale, faceIndices,
                                              faceVertices, faceNormals);

                    DisplayWgl(json_geometry_data);

                    // Ignore other solids in this element.
                    // Please use the custom exporter for
                    // more complex element geometry.

                    break;
                }
            }
            return(Result.Succeeded);
        }
        /// <summary>
        /// Combine coplanar triangles from the faceted body if they share the edge. From this process, polygonal faces (with or without holes) will be created
        /// </summary>
        public void SimplifyAndMergeFaces(bool ignoreMerge = false)
        {
            int eulerBefore = ignoreMerge ? 0 : CalculateEulerCharacteristic();

            int noTriangle = GetTriangleCount();
            IEqualityComparer <XYZ>       normalComparer     = new VectorCompare();
            Dictionary <XYZ, List <int> > faceSortedByNormal = new Dictionary <XYZ, List <int> >(normalComparer);

            for (int ef = 0; ef < noTriangle; ++ef)
            {
                IList <int> vertIndex = new List <int>();

                if (IsMesh)
                {
                    MeshTriangle f = m_MeshGeom.get_Triangle(ef);
                    vertIndex = new List <int>(3)
                    {
                        (int)f.get_Index(0), (int)f.get_Index(1), (int)f.get_Index(2)
                    };
                }
                else
                {
                    TriangleInShellComponent f = m_Geom.GetTriangle(ef);
                    vertIndex = new List <int>(3)
                    {
                        f.VertexIndex0, f.VertexIndex1, f.VertexIndex2
                    };
                }

                IndexFace intF = new IndexFace(vertIndex, ref m_MeshVertices);
                m_FacesCollDict.Add(faceIdxOffset++, intF);     // Keep faces in a dictionary and assigns ID
                List <int> fIDList;

                if (!faceSortedByNormal.TryGetValue(intF.Normal, out fIDList))
                {
                    fIDList = new List <int>(1)
                    {
                        ef
                    };
                    faceSortedByNormal.Add(intF.Normal, fIDList);
                }
                else if (!fIDList.Contains(ef))
                {
                    fIDList.Add(ef);
                }
            }

            foreach (KeyValuePair <XYZ, List <int> > fListDict in faceSortedByNormal)
            {
                List <int> mergedFaceList = null;
                if (fListDict.Value.Count > 1)
                {
                    if (!ignoreMerge)
                    {
                        TryMergeFaces(fListDict.Value, out mergedFaceList);
                    }
                    else
                    {
                        // keep original face list
                        mergedFaceList = fListDict.Value;
                    }
                    if (mergedFaceList != null && mergedFaceList.Count > 0)
                    {
                        // insert only new face indexes as the mergedlist from different vertices can be duplicated
                        foreach (int fIdx in mergedFaceList)
                        {
                            if (!m_MergedFaceSet.Contains(fIdx))
                            {
                                m_MergedFaceSet.Add(fIdx);
                            }
                        }
                    }
                }
                else if (!m_MergedFaceSet.Contains(fListDict.Value[0]))
                {
                    m_MergedFaceSet.Add(fListDict.Value[0]); // No pair face, add it into the mergedList
                }
            }

            // Remove unused vertices
            CleanVerticesAndUpdateIndexes();

            int eulerAfter = ignoreMerge ? 0 : CalculateEulerCharacteristic();

            if (eulerBefore != eulerAfter)
            {
                throw new InvalidOperationException(); // Coplanar merge broke the mesh in some way, so we need to fall back to exporting a triangular mesh
            }
        }
Example #9
0
        /// <summary>
        /// Combine coplanar triangles from the faceted body if they share the edge. From this process, polygonal faces (with or without holes) will be created
        /// </summary>
        public void SimplifyAndMergeFaces()
        {
            int noTriangle = (IsMesh)? _meshGeom.NumTriangles : _geom.TriangleCount;
            int noVertices = (IsMesh)? _meshGeom.Vertices.Count : _geom.VertexCount;
            IEqualityComparer <XYZ>       normalComparer     = new vectorCompare();
            Dictionary <XYZ, List <int> > faceSortedByNormal = new Dictionary <XYZ, List <int> >(normalComparer);

            for (int ef = 0; ef < noTriangle; ++ef)
            {
                IList <int> vertIndex = new List <int>();

                if (IsMesh)
                {
                    MeshTriangle f = _meshGeom.get_Triangle(ef);
                    vertIndex.Add((int)f.get_Index(0));
                    vertIndex.Add((int)f.get_Index(1));
                    vertIndex.Add((int)f.get_Index(2));
                }
                else
                {
                    TriangleInShellComponent f = _geom.GetTriangle(ef);
                    vertIndex.Add(f.VertexIndex0);
                    vertIndex.Add(f.VertexIndex1);
                    vertIndex.Add(f.VertexIndex2);
                }

                IndexFace intF = new IndexFace(vertIndex);
                facesColl.Add(ef, intF);     // Keep faces in a dictionary and assigns ID
                List <int> fIDList;

                if (!faceSortedByNormal.TryGetValue(intF.normal, out fIDList))
                {
                    fIDList = new List <int>();
                    fIDList.Add(ef);
                    faceSortedByNormal.Add(intF.normal, fIDList);
                }
                else
                {
                    if (!fIDList.Contains(ef))
                    {
                        fIDList.Add(ef);
                    }
                }
            }

            foreach (KeyValuePair <XYZ, List <int> > fListDict in faceSortedByNormal)
            {
                List <int> mergedFaceList = null;
                if (fListDict.Value.Count > 1)
                {
                    TryMergeFaces(fListDict.Value, out mergedFaceList);
                    if (mergedFaceList != null && mergedFaceList.Count > 0)
                    {
                        // insert only new face indexes as the mergedlist from different vertices can be duplicated
                        foreach (int fIdx in mergedFaceList)
                        {
                            if (!_mergedFaceList.Contains(fIdx))
                            {
                                _mergedFaceList.Add(fIdx);
                            }
                        }
                    }
                }
                else if (!_mergedFaceList.Contains(fListDict.Value[0]))
                {
                    _mergedFaceList.Add(fListDict.Value[0]); // No pair face, add it into the mergedList
                }
            }
        }
Example #10
0
        private byte[] GeometryToOBJ(Document doc, GeometryElement geometry)
        {
            int indexOffset     = 0;
            int nextIndexOffset = 0;
            int part            = 0;

            StringBuilder fullObjectSB = new StringBuilder();

            fullObjectSB.Append($"o StreamVRExportedObject\n");

            foreach (GeometryObject obj in geometry)
            {
                Solid solid = obj as Solid;
                if (solid == null)
                {
                    continue;
                }

                if (solid.GraphicsStyleId != null)
                {
                    GraphicsStyle gs            = doc.GetElement(solid.GraphicsStyleId) as GraphicsStyle;
                    bool          isLightSource = gs?.GraphicsStyleCategory?.Name == "Light Source";
                    if (isLightSource)
                    {
                        XYZ centroid = solid.GetBoundingBox()?.Transform?.Origin;
                        if (centroid != null)
                        {
                            fullObjectSB.Append($"ls {centroid.X} {centroid.Z} {centroid.Y}\n");
                        }
                        continue;
                    }
                }

                fullObjectSB.Append($"g GeometryPart{part}\n");

                bool addedMaterial       = false;
                IEnumerable <Face> faces = solid.Faces.Cast <Face>();
                foreach (Face f in faces)
                {
                    if (!addedMaterial && f.MaterialElementId != null)
                    {
                        fullObjectSB.Append($"svrm {f.MaterialElementId.ToString()}\n");
                        addedMaterial = true;
                    }

                    Mesh m = f.Triangulate();

                    foreach (XYZ v in m.Vertices)
                    {
                        fullObjectSB.Append($"v {v.X} {v.Z} {v.Y}\n");
                    }
                    for (int i = 0; i < m.NumTriangles; i++)
                    {
                        MeshTriangle mt = m.get_Triangle(i);
                        int          f1 = (int)mt.get_Index(0) + indexOffset;
                        int          f2 = (int)mt.get_Index(1) + indexOffset;
                        int          f3 = (int)mt.get_Index(2) + indexOffset;
                        fullObjectSB.Append($"f {f1 + 1} {f2 + 1} {f3 + 1}\n");

                        if (f1 > nextIndexOffset)
                        {
                            nextIndexOffset = f1;
                        }
                        if (f2 > nextIndexOffset)
                        {
                            nextIndexOffset = f2;
                        }
                        if (f3 > nextIndexOffset)
                        {
                            nextIndexOffset = f3;
                        }
                    }

                    indexOffset = nextIndexOffset + 1;
                }

                part++;
            }

            byte[] file_bytes = Encoding.ASCII.GetBytes(fullObjectSB.ToString());

            return(file_bytes);
        }
Example #11
0
        private bool GetFaceGeometry(Face face, out List <int> faceIndices, out List <int> faceVertices, out List <double> faceNormals, out XYZ centerPoint)
        {
            bool result = false;

            faceIndices  = new List <int>();
            faceVertices = new List <int>();
            faceNormals  = new List <double>();
            centerPoint  = new XYZ();
            try
            {
                BoundingBoxUV bb    = face.GetBoundingBox();
                UV            midUV = new UV((bb.Max.U - bb.Min.U) / 2, (bb.Max.V - bb.Min.V) / 2);
                centerPoint = face.Evaluate(midUV);

                Mesh        mesh           = m_face.Triangulate();
                int         nTriangles     = mesh.NumTriangles;
                IList <XYZ> vertices       = mesh.Vertices;
                int         nVertices      = vertices.Count;
                List <int>  vertexCoordsMm = new List <int>(3 * nVertices);

                foreach (XYZ v in vertices)
                {
                    vertexCoordsMm.Add(ConverterUtil.FootToMm(v.X));
                    vertexCoordsMm.Add(ConverterUtil.FootToMm(v.Y));
                    vertexCoordsMm.Add(ConverterUtil.FootToMm(v.Z));
                }

                int[] triangleIndices = new int[3];
                XYZ[] triangleCorners = new XYZ[3];

                for (int i = 0; i < nTriangles; ++i)
                {
                    faceIndices.Add(2); //triangle with material

                    MeshTriangle triangle = mesh.get_Triangle(i);

                    for (int j = 0; j < 3; ++j)
                    {
                        int k = (int)triangle.get_Index(j);
                        triangleIndices[j] = k;
                        triangleCorners[j] = vertices[k];
                    }

                    // Calculate constant triangle facet normal.

                    XYZ v = triangleCorners[1]
                            - triangleCorners[0];
                    XYZ w = triangleCorners[2]
                            - triangleCorners[0];
                    XYZ triangleNormal = v
                                         .CrossProduct(w)
                                         .Normalize();

                    for (int j = 0; j < 3; ++j)
                    {
                        int nFaceVertices = faceVertices.Count;

                        faceIndices.Add(nFaceVertices / 3);

                        int i3 = triangleIndices[j] * 3;

                        // Rotate the X, Y and Z directions,
                        // since the Z direction points upward
                        // in Revit as opposed to sideways or
                        // outwards or forwards in WebGL.

                        faceVertices.Add(vertexCoordsMm[i3 + 1]);
                        faceVertices.Add(vertexCoordsMm[i3 + 2]);
                        faceVertices.Add(vertexCoordsMm[i3]);

                        UV uv = m_face.Project(
                            triangleCorners[j]).UVPoint;

                        XYZ normal = m_face.ComputeNormal(uv);

                        faceNormals.Add(normal.Y);
                        faceNormals.Add(normal.Z);
                        faceNormals.Add(normal.X);
                    }

                    faceIndices.Add(0);
                }
                result = true;
            }
            catch (Exception ex)
            {
                string message = "Cannot get face geometry: " + ex.Message;
            }
            return(result);
        }
Example #12
0
        static private bool ExportFaces(List <Face> faces, ref Va3cContainer.Va3cGeometry faceGroupGeometry, out bool bHasUvs)
        {
            bHasUvs = true;

            foreach (Face face in faces)
            {
                Mesh    mesh    = face.Triangulate(ExportEventHandler.Settings.TriangulateDetailLevel);
                Surface surface = face.GetSurface();
                if (mesh == null || surface == null)
                {
                    continue;
                }

                int currentPointNum = faceGroupGeometry.data.points;
                int currentTriNum   = faceGroupGeometry.data.triangles;

                IList <XYZ> points   = mesh.Vertices;
                int         pointNum = points.Count;
                int         triNum   = mesh.NumTriangles;
                faceGroupGeometry.data.points    += pointNum;
                faceGroupGeometry.data.triangles += triNum;

                foreach (XYZ point in points)
                {
                    faceGroupGeometry.data.vertices.Add((float)point.X);
                    faceGroupGeometry.data.vertices.Add((float)point.Y);
                    faceGroupGeometry.data.vertices.Add((float)point.Z);

                    try
                    {
                        if (bHasUvs)
                        {
                            UV     uv;
                            double distance;
                            surface.Project(point, out uv, out distance);
                            faceGroupGeometry.data.uvs.Add((float)uv.U);
                            faceGroupGeometry.data.uvs.Add((float)uv.V);
                            XYZ normal = face.ComputeNormal(uv);
                            faceGroupGeometry.data.normals.Add((float)normal.X);
                            faceGroupGeometry.data.normals.Add((float)normal.Y);
                            faceGroupGeometry.data.normals.Add((float)normal.Z);
                        }
                        else
                        {
                            faceGroupGeometry.data.uvs.Add(0.0f);
                            faceGroupGeometry.data.uvs.Add(0.0f);
                            faceGroupGeometry.data.normals.Add(0.0f);
                            faceGroupGeometry.data.normals.Add(0.0f);
                            faceGroupGeometry.data.normals.Add(1.0f);
                        }
                    }
                    catch (System.Exception ex)
                    {
                        bHasUvs = false;
                        faceGroupGeometry.data.uvs.Add(0.0f);
                        faceGroupGeometry.data.uvs.Add(0.0f);
                        faceGroupGeometry.data.normals.Add(0.0f);
                        faceGroupGeometry.data.normals.Add(0.0f);
                        faceGroupGeometry.data.normals.Add(1.0f);
                    }
                }
                for (int i = 0; i < triNum; ++i)
                {
                    MeshTriangle meshTri = mesh.get_Triangle(i);
                    int          index0  = (int)meshTri.get_Index(0) + currentPointNum;
                    int          index1  = (int)meshTri.get_Index(1) + currentPointNum;
                    int          index2  = (int)meshTri.get_Index(2) + currentPointNum;
                    faceGroupGeometry.data.indices.Add(index0);
                    faceGroupGeometry.data.indices.Add(index1);
                    faceGroupGeometry.data.indices.Add(index2);
                }
            }

            if (faceGroupGeometry.data.points > 0 && faceGroupGeometry.data.triangles > 0)
            {
                return(true);
            }

            return(false);
        }
Example #13
0
        // Create and populate a pair of vertex and index buffers. Also update parameters associated with the format of the vertices.
        private void ProcessFaces(RenderingPassBufferStorage bufferStorage)
        {
            List <MeshInfo> meshes = bufferStorage.Meshes;

            if (meshes.Count == 0)
            {
                return;
            }
            List <int> numVerticesInMeshesBefore = new List <int>();

            bool useNormals = this.Inputs.EnableFaceNormal;

            // Vertex attributes are stored sequentially in vertex buffers. The attributes can include position, normal vector, and color.
            // All vertices within a vertex buffer must have the same format. Possible formats are enumerated by VertexFormatBits.
            // Vertex format also determines the type of rendering effect that can be used with the vertex buffer. In this sample,
            // the color is always encoded in the vertex attributes.

            bufferStorage.FormatBits = useNormals ? VertexFormatBits.PositionNormalColored : VertexFormatBits.PositionColored;

            // The format of the vertices determines the size of the vertex buffer.
            int vertexBufferSizeInFloats = (useNormals ? VertexPositionNormalColored.GetSizeInFloats() : VertexPositionColored.GetSizeInFloats()) *
                                           bufferStorage.VertexBufferCount;

            numVerticesInMeshesBefore.Add(0);

            bufferStorage.VertexBuffer = new VertexBuffer(vertexBufferSizeInFloats);
            bufferStorage.VertexBuffer.Map(vertexBufferSizeInFloats);

            int numMeshes = meshes.Count;

            if (useNormals)
            {
                // A VertexStream is used to write data into a VertexBuffer.
                VertexStreamPositionNormalColored vertexStream = bufferStorage.VertexBuffer.GetVertexStreamPositionNormalColored();
                for (int i = 0; i < numMeshes; i++)
                {
                    var  meshInfo = meshes[i];
                    Mesh mesh     = meshInfo.Mesh;
                    foreach (XYZ vertex in mesh.Vertices)
                    {
                        vertexStream.AddVertex(new VertexPositionNormalColored(vertex + meshInfo.Offset, meshInfo.Normal, meshInfo.ColorWithTransparency));
                    }

                    numVerticesInMeshesBefore.Add(numVerticesInMeshesBefore.Last() + mesh.Vertices.Count);
                }
            }
            else
            {
                // A VertexStream is used to write data into a VertexBuffer.
                VertexStreamPositionColored vertexStream = bufferStorage.VertexBuffer.GetVertexStreamPositionColored();
                for (int i = 0; i < numMeshes; i++)
                {
                    var  meshInfo = meshes[i];
                    Mesh mesh     = meshInfo.Mesh;
                    // make the color of all faces white in HLR
                    ColorWithTransparency color = meshInfo.ColorWithTransparency;
                    foreach (XYZ vertex in mesh.Vertices)
                    {
                        vertexStream.AddVertex(new VertexPositionColored(vertex + meshInfo.Offset, color));
                    }

                    numVerticesInMeshesBefore.Add(numVerticesInMeshesBefore.Last() + mesh.Vertices.Count);
                }
            }

            bufferStorage.VertexBuffer.Unmap();

            // Primitives are specified using a pair of vertex and index buffers. An index buffer contains a sequence of indices into
            // the associated vertex buffer, each index referencing a particular vertex.

            int meshNumber = 0;

            bufferStorage.IndexBufferCount = bufferStorage.PrimitiveCount * IndexTriangle.GetSizeInShortInts();
            int indexBufferSizeInShortInts = 1 * bufferStorage.IndexBufferCount;

            bufferStorage.IndexBuffer = new IndexBuffer(indexBufferSizeInShortInts);
            bufferStorage.IndexBuffer.Map(indexBufferSizeInShortInts);
            {
                // An IndexStream is used to write data into an IndexBuffer.
                IndexStreamTriangle indexStream = bufferStorage.IndexBuffer.GetIndexStreamTriangle();
                foreach (MeshInfo meshInfo in meshes)
                {
                    Mesh mesh       = meshInfo.Mesh;
                    int  startIndex = numVerticesInMeshesBefore[meshNumber];
                    for (int i = 0; i < mesh.NumTriangles; i++)
                    {
                        MeshTriangle mt = mesh.get_Triangle(i);
                        // Add three indices that define a triangle.
                        indexStream.AddTriangle(new IndexTriangle((int)(startIndex + mt.get_Index(0)),
                                                                  (int)(startIndex + mt.get_Index(1)),
                                                                  (int)(startIndex + mt.get_Index(2))));
                    }
                    meshNumber++;
                }
            }
            bufferStorage.IndexBuffer.Unmap();

            // VertexFormat is a specification of the data that is associated with a vertex (e.g., position).
            bufferStorage.VertexFormat = new VertexFormat(bufferStorage.FormatBits);
            // Effect instance is a specification of the appearance of geometry. For example, it may be used to specify color, if there is no color information provided with the vertices.
            bufferStorage.EffectInstance = new EffectInstance(bufferStorage.FormatBits);
        }
Example #14
0
        int getGeometry(Element e)
        {
            bool RetainCurvedSurfaceFacets = true;

            Options         opt = new Options();
            GeometryElement geo = e.get_Geometry(opt);

            if (geo == null)
            {
                return(0);
            }

            List <int>    faceIndices  = new List <int>();
            List <double> faceVertices = new List <double>();
            List <double> faceNormals  = new List <double>();

            int[] triangleIndices = new int[3];
            XYZ[] triangleCorners = new XYZ[3];

            foreach (GeometryObject obj in geo)
            {
                Solid solid = obj as Solid;

                if (solid != null && 0 < solid.Faces.Size)
                {
                    faceIndices.Clear();
                    faceVertices.Clear();
                    faceNormals.Clear();

                    foreach (Face face in solid.Faces)
                    {
                        Mesh mesh = face.Triangulate();

                        int nTriangles = mesh.NumTriangles;

                        IList <XYZ> vertices = mesh.Vertices;

                        int nVertices = vertices.Count;

                        List <double> vertexCoordsMm = new List <double>(3 * nVertices);

                        // A vertex may be reused several times with
                        // different normals for different faces, so
                        // we cannot precalculate normals per vertex.
                        //List<double> normals = new List<double>( 3 * nVertices );

                        foreach (XYZ v in vertices)
                        {
                            // Translate the entire element geometry
                            // to the bounding box midpoint and scale
                            // to metric millimetres.

                            XYZ p = v;

                            vertexCoordsMm.Add(p.X * _footToMm);
                            vertexCoordsMm.Add(p.Y * _footToMm);
                            vertexCoordsMm.Add(p.Z * _footToMm);
                        }

                        for (int i = 0; i < nTriangles; ++i)
                        {
                            MeshTriangle triangle = mesh.get_Triangle(i);

                            for (int j = 0; j < 3; ++j)
                            {
                                int k = (int)triangle.get_Index(j);
                                triangleIndices[j] = k;
                                triangleCorners[j] = vertices[k];
                            }

                            // Calculate constant triangle facet normal.

                            XYZ v = triangleCorners[1]
                                    - triangleCorners[0];
                            XYZ w = triangleCorners[2]
                                    - triangleCorners[0];
                            XYZ triangleNormal = v
                                                 .CrossProduct(w)
                                                 .Normalize();

                            for (int j = 0; j < 3; ++j)
                            {
                                int nFaceVertices = faceVertices.Count;

                                //Debug.Assert(nFaceVertices.Equals(faceNormals.Count),
                                //  "expected equal number of face vertex and normal coordinates");

                                faceIndices.Add(nFaceVertices / 3);

                                int i3 = triangleIndices[j] * 3;

                                // Rotate the X, Y and Z directions,
                                // since the Z direction points upward
                                // in Revit as opposed to sideways or
                                // outwards or forwards in WebGL.

                                faceVertices.Add(vertexCoordsMm[i3 + 1]);
                                faceVertices.Add(vertexCoordsMm[i3 + 2]);
                                faceVertices.Add(vertexCoordsMm[i3]);

                                if (RetainCurvedSurfaceFacets)
                                {
                                    faceNormals.Add(triangleNormal.Y);
                                    faceNormals.Add(triangleNormal.Z);
                                    faceNormals.Add(triangleNormal.X);
                                }
                                else
                                {
                                    UV uv = face.Project(
                                        triangleCorners[j]).UVPoint;

                                    XYZ normal = face.ComputeNormal(uv);

                                    faceNormals.Add(normal.Y);
                                    faceNormals.Add(normal.Z);
                                    faceNormals.Add(normal.X);
                                }
                            }
                        }
                    }

                    // Scale the vertices to a [-1,1] cube
                    // centered around the origin. Translation
                    // to the origin was already performed above.

                    //double scale = 2.0 / FootToMm(MaxCoord(vsize));

                    //Debug.Print("position: [{0}],",
                    //  string.Join(", ",
                    //    faceVertices.ConvertAll<string>(
                    //      i => (i * scale).ToString("0.##"))));

                    //Debug.Print("normal: [{0}],",
                    //  string.Join(", ",
                    //    faceNormals.ConvertAll<string>(
                    //      f => f.ToString("0.##"))));

                    //Debug.Print("indices: [{0}],",
                    //  string.Join(", ",
                    //    faceIndices.ConvertAll<string>(
                    //      i => i.ToString())));
                }
            }

            return(faceIndices.Count);
        }
        public static string GetFacesAndEdges(Element e, bool startFromZero)
        {
            String xx = "";
            bool   RetainCurvedSurfaceFacets = true;

            // Get element geometry
            Options         opt      = new Options();
            GeometryElement geomElem = e.get_Geometry(opt);

            int[]         triangleIndices = new int[3];
            XYZ[]         triangleCorners = new XYZ[3];
            List <string> faceVertices    = new List <string>();
            List <string> faceNormals     = new List <string>();
            List <string> faceElements    = new List <string>();

            //// First we need to get transformation
            //LocationCurve lc = e.Location as LocationCurve;

            //// Get curve starting- and endpoint
            //XYZ startingPoint = lc.Curve.GetEndPoint(0);
            //XYZ endPoint = lc.Curve.GetEndPoint(1);

            foreach (GeometryObject geomObj in geomElem)
            {
                Solid geomSolid = geomObj as Solid;
                if (null != geomSolid)
                {
                    faceVertices.Clear();
                    faceNormals.Clear();
                    faceElements.Clear();

                    foreach (Face face in geomSolid.Faces)
                    {
                        // Triangulate face to get mesh
                        Mesh mesh = face.Triangulate();

                        int nTriangles = mesh.NumTriangles;

                        IList <XYZ> vertices = mesh.Vertices;

                        int nVertices = vertices.Count;

                        List <int> vertexCoordsMm = new List <int>(3 * nVertices);

                        // A vertex may be reused several times with
                        // different normals for different faces, so
                        // we cannot precalculate normals per vertex.
                        // List<double> normals = new List<double>( 3 * nVertices );

                        // Extract vertices
                        foreach (XYZ v in vertices)
                        {
                            vertexCoordsMm.Add(ConvertLengthToMM(v.X));
                            vertexCoordsMm.Add(ConvertLengthToMM(v.Y));
                            vertexCoordsMm.Add(ConvertLengthToMM(v.Z));
                        }

                        // Loop over triangles
                        for (int i = 0; i < nTriangles; ++i)
                        {
                            MeshTriangle triangle = mesh.get_Triangle(i);

                            for (int j = 0; j < 3; ++j)
                            {
                                int k = (int)triangle.get_Index(j);
                                triangleIndices[j] = k;
                                triangleCorners[j] = vertices[k];
                            }

                            // Calculate constant triangle facet normal.
                            XYZ v = triangleCorners[1]
                                    - triangleCorners[0];
                            XYZ w = triangleCorners[2]
                                    - triangleCorners[0];
                            XYZ triangleNormal = v
                                                 .CrossProduct(w)
                                                 .Normalize();

                            // List to store vertice indexes in the form: [v1//vn1 v2//vn2 v3//vn3]
                            List <string> vertIndexes = new List <string>();

                            for (int j = 0; j < 3; ++j)
                            {
                                int nFaceVertices = faceVertices.Count;

                                //if(nFaceVertices != faceNormals.Count)
                                //{
                                //    xx += "expected equal number of face vertex and normal coordinates\n";
                                //}

                                int i3 = triangleIndices[j] * 3;

                                // Rotate the X, Y and Z directions,
                                // since the Z direction points upward
                                // in Revit as opposed to sideways or
                                // outwards or forwards in WebGL.

                                string vStr = $"v {vertexCoordsMm[i3]} {vertexCoordsMm[i3 + 1]} {vertexCoordsMm[i3 + 2]}";

                                // get vertice index
                                int vidx = faceVertices.IndexOf(vStr);

                                // add if not exist
                                if (vidx == -1)
                                {
                                    faceVertices.Add(vStr);
                                    vidx = faceVertices.Count - 1;
                                }


                                string vnStr = "";
                                if (RetainCurvedSurfaceFacets)
                                {
                                    vnStr = $"vn {Math.Round(triangleNormal.X, 2)} {Math.Round(triangleNormal.Y, 2)} {Math.Round(triangleNormal.Z, 2)}";
                                }
                                else
                                {
                                    UV uv = face.Project(
                                        triangleCorners[j]).UVPoint;

                                    XYZ normal = face.ComputeNormal(uv);

                                    vnStr = $"vn {Math.Round(normal.X, 2)} {Math.Round(normal.Y, 2)} {Math.Round(normal.Z, 2)}";
                                }

                                // get face normal index
                                int vnidx = faceNormals.IndexOf(vnStr);

                                // add if not in list
                                if (vnidx == -1)
                                {
                                    faceNormals.Add(vnStr);
                                    vnidx = faceNormals.Count - 1;
                                }

                                // add indexes to list
                                vertIndexes.Add($"{vidx+1+objStartIndex}/{vnidx+1 + objStartNormal}");
                            }

                            // Store face elements
                            string fStr = $"f {vertIndexes[0]} {vertIndexes[1]} {vertIndexes[2]}";
                            faceElements.Add(fStr);
                        }
                    }

                    // Write to string
                    xx += String.Join("\n\t", faceVertices) + "\n\t";
                    xx += String.Join("\n\t", faceNormals) + "\n\t";
                    xx += String.Join("\n\t", faceElements) + "\n\t";
                    if (!startFromZero)
                    {
                        objStartIndex  += faceVertices.Count;
                        objStartNormal += faceNormals.Count;
                    }
                }

                Mesh     geomMesh  = geomObj as Mesh;
                Curve    geomCurve = geomObj as Curve;
                Point    geomPoint = geomObj as Point;
                PolyLine geomPoly  = geomObj as PolyLine;

                GeometryInstance geomInst = geomObj as GeometryInstance;
                if (null != geomInst)
                {
                    GeometryElement geomElement = geomInst.GetInstanceGeometry();
                    foreach (GeometryObject geomObj1 in geomElement)
                    {
                        Solid geomSolid1 = geomObj1 as Solid;
                        if (null != geomSolid1)
                        {
                            Console.Out.WriteLine("got element: " + geomSolid1.Faces);
                        }
                    }
                }
            }

            return(xx);
        }
Example #16
0
        private void ExportSolid2(Solid solid)
        {
            foreach (Face face in solid.Faces)
            {
                if (!(face.Equals(null)))
                {
                    Mesh mesh = face.Triangulate(userSetting.LevelOfDetail / 15.0);
                    if (!(mesh.Equals(null)) && !mesh.Visibility.Equals(Visibility.Invisible))
                    {
                        ModelGeometry exportedGeometry = new ModelGeometry();

                        // 设置坐标系
                        exportedGeometry.Transform = transformationStack.Peek();
                        exportedGeometry.Points    = new List <XYZ>(mesh.Vertices);
                        exportedGeometry.Indices   = new List <int>(mesh.NumTriangles * 3);

                        //指示此转换是否为保形的布尔值。指示此转换是否产生反射的布尔值。反射变换会更改坐标系的惯用性。
                        if (exportedGeometry.Transform.IsConformal && exportedGeometry.Transform.HasReflection)
                        {
                            for (int i = 0; i < mesh.NumTriangles; i++)
                            {
                                MeshTriangle meshTriangle = mesh.get_Triangle(i);
                                exportedGeometry.Indices.Add((int)meshTriangle.get_Index(0));
                                exportedGeometry.Indices.Add((int)meshTriangle.get_Index(2));
                                exportedGeometry.Indices.Add((int)meshTriangle.get_Index(1));
                            }
                        }
                        else
                        {
                            for (int j = 0; j < mesh.NumTriangles; j++)
                            {
                                MeshTriangle meshTriangle2 = mesh.get_Triangle(j);
                                exportedGeometry.Indices.Add((int)meshTriangle2.get_Index(0));
                                exportedGeometry.Indices.Add((int)meshTriangle2.get_Index(1));
                                exportedGeometry.Indices.Add((int)meshTriangle2.get_Index(2));
                            }
                        }
                        ModelGeometry TGeometry = exportedGeometry;

                        //计算模型法线
                        TGeometry.CalculateNormals(TGeometry.Transform.IsConformal && exportedGeometry.Transform.HasReflection);

                        exportedGeometry.CalculateUVs(true, false);

                        //判断是不是反正双面实体
                        if (face.IsTwoSided)
                        {
                            exportedGeometry.MakeDoubleSided();
                        }

                        //将当前元素面的材质ID放入元组中(文档,元素材质ID)
                        ElementId materialElementId       = face.MaterialElementId;
                        Tuple <Document, ElementId> tuple = new Tuple <Document, ElementId>(documentStack.Peek(), materialElementId);

                        //加入元组索引
                        ChangeCurrentMaterial(tuple);

                        //用元组索引将模型加入到模型数据池
                        documentAndMaterialIdToGeometries[tuple].Add(exportedGeometry);
                    }
                }
            }
        }