• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            eryar

            PipeCAD - Plant Piping Design Software.
            RvmTranslator - Translate AVEVA RVM to OBJ, glTF, etc.
            posts - 603, comments - 590, trackbacks - 0, articles - 0

            Open Cascade Data Exchange --- STL

            Posted on 2013-05-01 18:29 eryar 閱讀(12795) 評論(2)  編輯 收藏 引用 所屬分類: 2.OpenCASCADE4.AVEVA Solution

            Open Cascade Data Exchange --- STL

            eryar@163.com

            摘要Abstract:介紹了三維數據交換格式STL的組成,以及Open Cascade中對STL的讀寫。并將Open Cascade讀進來的STL的三角面片在OpenSceneGraph中顯示。

            關鍵字Key Words:STL, Open Cascade, OpenSceneGraph, Data Exchange

            STL(the Stereo Lithograpy)是快速原型系統所應用的標準文件類型。它的目的是將幾何數據發送到可以讀取和解釋這些數據的機器,這種機器可將模型轉換成塑料的物理模型。STL是用三角網格來表示三維模型的。STL文件格式簡單,只能描述三維物體的幾何信息,不支持顏色、材質等信息,是三維打印機支持的最常見的文件格式。由于STL文件的網格表示方法只能表示封閉的形狀,所以要轉換的形狀必須是實體,或封閉的面和體。STL文件有兩種:一種是明碼(ASCII)格式,一種是二進制(Binary)格式。

            一、STL的明碼(ASCII)格式

            ASCII格式的STL文件逐行給出三角面片的幾何信息,每行以1個或2個關鍵字開頭。STL文件中的三角面片的信息單元facet是一個帶法向方向的三角面片,STL三維模型就是由這一系列的三角面片構成。整個STL文件的首行給出了文件路徑及文件名。在一個STL文件中,每個facet由7行數據組成:facet normal是三角面片指向實體外部的單位法矢量;outer loop說明隨后的3行數據分別是三角面片的3個頂點坐標,3頂點沿指向實體外部的法矢量方向逆時針排列。

            ASCII格式的STL文件結構如下:

            wps_clip_image-30396

            說明如下:

            wps_clip_image-7699

            下面給出由Open Cascade中導出的一個長方體的STL文件:

            長方體的尺寸為長200,寬150,高100,原點在一個角點上。

            wps_clip_image-14545

            Figure 1.1 Box in Open Cascade

             

            solid 

            facet normal 
            -1.000000e+000 -0.000000e+000 -0.000000e+000 

               outer loop 

                 vertex  
            0.000000e+000  1.500000e+002  1.000000e+002 

                 vertex  
            0.000000e+000  1.500000e+002  0.000000e+000 

                 vertex  
            0.000000e+000  0.000000e+000  1.000000e+002 

               endloop 

            endfacet 

            facet normal 
            -1.000000e+000  0.000000e+000  0.000000e+000 

               outer loop 

                 vertex  
            0.000000e+000  1.500000e+002  0.000000e+000 

                 vertex  
            0.000000e+000  0.000000e+000  0.000000e+000 

                 vertex  
            0.000000e+000  0.000000e+000  1.000000e+002 

               endloop 

            endfacet 

            facet normal  
            1.000000e+000 -0.000000e+000  0.000000e+000 

               outer loop 

                 vertex  
            2.000000e+002  0.000000e+000  1.000000e+002 

                 vertex  
            2.000000e+002  1.500000e+002  0.000000e+000 

                 vertex  
            2.000000e+002  1.500000e+002  1.000000e+002 

               endloop 

            endfacet 

            facet normal  
            1.000000e+000 -0.000000e+000  0.000000e+000 

               outer loop 

                 vertex  
            2.000000e+002  0.000000e+000  1.000000e+002 

                 vertex  
            2.000000e+002  0.000000e+000  0.000000e+000 

                 vertex  
            2.000000e+002  1.500000e+002  0.000000e+000 

               endloop 

            endfacet 

            facet normal  
            0.000000e+000 -1.000000e+000  0.000000e+000 

               outer loop 

                 vertex  
            0.000000e+000  0.000000e+000  0.000000e+000 

                 vertex  
            2.000000e+002  0.000000e+000  0.000000e+000 

                 vertex  
            2.000000e+002  0.000000e+000  1.000000e+002 

               endloop 

            endfacet 

            facet normal  
            0.000000e+000 -1.000000e+000  0.000000e+000 

               outer loop 

                 vertex  
            0.000000e+000  0.000000e+000  1.000000e+002 

                 vertex  
            0.000000e+000  0.000000e+000  0.000000e+000 

                 vertex  
            2.000000e+002  0.000000e+000  1.000000e+002 

               endloop 

            endfacet 

            facet normal  
            0.000000e+000  1.000000e+000  0.000000e+000 

               outer loop 

                 vertex  
            2.000000e+002  1.500000e+002  1.000000e+002 

                 vertex  
            2.000000e+002  1.500000e+002  0.000000e+000 

                 vertex  
            0.000000e+000  1.500000e+002  0.000000e+000 

               endloop 

            endfacet 

            facet normal  
            0.000000e+000  1.000000e+000 -0.000000e+000 

               outer loop 

                 vertex  
            2.000000e+002  1.500000e+002  1.000000e+002 

                 vertex  
            0.000000e+000  1.500000e+002  0.000000e+000 

                 vertex  
            0.000000e+000  1.500000e+002  1.000000e+002 

               endloop 

            endfacet 

            facet normal  
            0.000000e+000  0.000000e+000 -1.000000e+000 

               outer loop 

                 vertex  
            0.000000e+000  0.000000e+000  0.000000e+000 

                 vertex  
            0.000000e+000  1.500000e+002  0.000000e+000 

                 vertex  
            2.000000e+002  1.500000e+002  0.000000e+000 

               endloop 

            endfacet 

            facet normal  
            0.000000e+000  0.000000e+000 -1.000000e+000 

               outer loop 

                 vertex  
            2.000000e+002  0.000000e+000  0.000000e+000 

                 vertex  
            0.000000e+000  0.000000e+000  0.000000e+000 

                 vertex  
            2.000000e+002  1.500000e+002  0.000000e+000 

               endloop 

            endfacet 

            facet normal  
            0.000000e+000  0.000000e+000  1.000000e+000 

               outer loop 

                 vertex  
            2.000000e+002  1.500000e+002  1.000000e+002 

                 vertex  
            0.000000e+000  1.500000e+002  1.000000e+002 

                 vertex  
            0.000000e+000  0.000000e+000  1.000000e+002 

               endloop 

            endfacet 

            facet normal 
            -0.000000e+000  0.000000e+000  1.000000e+000 

               outer loop 

                 vertex  
            2.000000e+002  1.500000e+002  1.000000e+002 

                 vertex  
            0.000000e+000  0.000000e+000  1.000000e+002 

                 vertex  
            2.000000e+002  0.000000e+000  1.000000e+002 

               endloop 

            endfacet 

            endsolid 



            由上面的STL明碼文件可知,上述數據將一個長方體的6個面用12個三角形來表示。在OpenSceneGraph中顯示效果如下圖所示,分別為此長方體的實體渲染模式和線框渲染模式:

            wps_clip_image-30014 wps_clip_image-7473

            Figure 1.2 Shaded and Wireframe box in OpenSceneGraph

            二、STL的二進制(Binary)格式

            二進制的STL文件用固定的字節數來給出三角面片的幾何信息。文件起始80個字節是文件頭,用于存貯零件名;緊接著4個字節的整數來描述模型的三角面片個數;后面逐個給出每個三角面片的幾何信息。每個三角面片用固定的50個字節,依次是表示三角面片的法矢量的3個4字節浮點數;表示三角面片三個頂點的3x3個4字節浮點數;最后2個字節用來描述三角面片的屬性信息。

            wps_clip_image-17429

            三、OCC中STL文件的讀寫Read/Write STL in Open Cascade

            在Open Cascade中STL文件的讀寫分別使用類:StlAPI_Reader/StlAPI_Writer來實現。查看源程序可知,寫STL文件的步驟如下:

            l 遍歷一個TopoDS_Shape所有的面Face;

            l 使用工具BRep_Tool::Triangulation將每個面Face三角面片化;

            l 計算每個三角面片的法矢量;

            l 將結果寫入文件。

            類RWStl對STL的讀定也是有兩種格式,即ASCII格式和Binary格式:

            n RWStl::WriteBinary

            n RWStl::WriteAscii

            n RWStl::ReadBinary

            n RWStl::ReadAscii

            程序的具體實現可以查看Open Cascade源代碼,將讀寫部分主要代碼RWStl.cxx列出如下:

             

            // Created on: 1994-10-13
            // Created by: Marc LEGAY
            // Copyright (c) 1994-1999 Matra Datavision
            // Copyright (c) 1999-2012 OPEN CASCADE SAS
            //
            // The content of this file is subject to the Open CASCADE Technology Public
            // License Version 6.5 (the "License"). You may not use the content of this file
            // except in compliance with the License. Please obtain a copy of the License
            // at http://www.opencascade.org and read it completely before using this file.
            //
            // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
            // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
            //
            // The Original Code and all software distributed under the License is
            // distributed on an "AS IS" basis, without warranty of any kind, and the
            // Initial Developer hereby disclaims all such warranties, including without
            // limitation, any warranties of merchantability, fitness for a particular
            // purpose or non-infringement. Please see the License for the specific terms
            // and conditions governing the rights and limitations under the License.



            #include 
            <RWStl.ixx>
            #include 
            <OSD_Protection.hxx>
            #include 
            <OSD_File.hxx>
            #include 
            <Message_ProgressSentry.hxx>
            #include 
            <TCollection_AsciiString.hxx>
            #include 
            <Standard_NoMoreObject.hxx>
            #include 
            <Standard_TypeMismatch.hxx>
            #include 
            <Precision.hxx>
            #include 
            <StlMesh_MeshExplorer.hxx>
            #include 
            <OSD.hxx>
            #include 
            <OSD_Host.hxx>
            #include 
            <gp_XYZ.hxx>
            #include 
            <gp.hxx>
            #include 
            <stdio.h>
            #include 
            <gp_Vec.hxx>


            // constants
            static const int HEADER_SIZE           =  84;
            static const int SIZEOF_STL_FACET      =  50;
            static const int STL_MIN_FILE_SIZE     = 284;
            static const int ASCII_LINES_PER_FACET =   7;
            static const int IND_THRESHOLD         = 1000// increment the indicator every 1k triangles

            //=======================================================================
            //function : WriteInteger
            //purpose  : writing a Little Endian 32 bits integer
            //=======================================================================

            inline 
            static void WriteInteger(OSD_File& ofile,const Standard_Integer value)
            {
              union 
            {
                Standard_Integer i;
            // don't be afraid, this is just an unsigned int
                char c[4];
              }
             bidargum;

              bidargum.i 
            = value;

              Standard_Integer entier;

              entier  
            =  bidargum.c[0& 0xFF;
              entier 
            |= (bidargum.c[1& 0xFF<< 0x08;
              entier 
            |= (bidargum.c[2& 0xFF<< 0x10;
              entier 
            |= (bidargum.c[3& 0xFF<< 0x18;

              ofile.Write((
            char *)&entier,sizeof(bidargum.c));
            }


            //=======================================================================
            //function : WriteDouble2Float
            //purpose  : writing a Little Endian 32 bits float
            //=======================================================================

            inline 
            static void WriteDouble2Float(OSD_File& ofile,Standard_Real value)
            {
              union 
            {
                Standard_ShortReal f;
                
            char c[4];
              }
             bidargum;

              bidargum.f 
            = (Standard_ShortReal)value;

              Standard_Integer entier;

              entier  
            =  bidargum.c[0& 0xFF;
              entier 
            |= (bidargum.c[1& 0xFF<< 0x08;
              entier 
            |= (bidargum.c[2& 0xFF<< 0x10;
              entier 
            |= (bidargum.c[3& 0xFF<< 0x18;

              ofile.Write((
            char *)&entier,sizeof(bidargum.c));
            }



            //=======================================================================
            //function : readFloat2Double
            //purpose  : reading a Little Endian 32 bits float
            //=======================================================================

            inline 
            static Standard_Real ReadFloat2Double(OSD_File &aFile)
            {
              union 
            {
                Standard_Boolean i; 
            // don't be afraid, this is just an unsigned int
                Standard_ShortReal f;
              }
            bidargum;

              
            char c[4];
              Standard_Address adr;
              adr 
            = (Standard_Address)c;
              Standard_Integer lread;
              aFile.Read(adr,
            4,lread);
              bidargum.i  
            =  c[0& 0xFF;
              bidargum.i 
            |=  (c[1& 0xFF<< 0x08;
              bidargum.i 
            |=  (c[2& 0xFF<< 0x10;
              bidargum.i 
            |=  (c[3& 0xFF<< 0x18;

              
            return (Standard_Real)(bidargum.f);
            }




            //=======================================================================
            //function : WriteBinary
            //purpose  : write a binary STL file in Little Endian format
            //=======================================================================

            Standard_Boolean RWStl::WriteBinary (
            const Handle(StlMesh_Mesh)& theMesh,
                                                 
            const OSD_Path& thePath,
                                                 
            const Handle(Message_ProgressIndicator)& theProgInd)
            {
              OSD_File aFile (thePath);
              aFile.Build (OSD_WriteOnly, OSD_Protection());

              Standard_Real x1, y1, z1;
              Standard_Real x2, y2, z2;
              Standard_Real x3, y3, z3;

              
            // writing 80 bytes of the trash?
              char sval[80];
              aFile.Write ((Standard_Address)sval,
            80);
              WriteInteger (aFile, theMesh
            ->NbTriangles());

              
            int dum=0;
              StlMesh_MeshExplorer aMexp (theMesh);

              
            // create progress sentry for domains
              Standard_Integer aNbDomains = theMesh->NbDomains();
              Message_ProgressSentry aDPS (theProgInd, 
            "Mesh domains"0, aNbDomains, 1);
              
            for (Standard_Integer nbd = 1; nbd <= aNbDomains && aDPS.More(); nbd++, aDPS.Next())
              
            {
                
            // create progress sentry for triangles in domain
                Message_ProgressSentry aTPS (theProgInd, "Triangles"0,
                    theMesh
            ->NbTriangles (nbd), IND_THRESHOLD);
                Standard_Integer aTriangleInd 
            = 0;
                
            for (aMexp.InitTriangle (nbd); aMexp.MoreTriangle(); aMexp.NextTriangle())
                
            {
                  aMexp.TriangleVertices (x1,y1,z1,x2,y2,z2,x3,y3,z3);
                  
            //pgo      aMexp.TriangleOrientation (x,y,z);
                  gp_XYZ Vect12 ((x2-x1), (y2-y1), (z2-z1));
                  gp_XYZ Vect13 ((x3
            -x1), (y3-y1), (z3-z1));
                  gp_XYZ Vnorm 
            = Vect12 ^ Vect13;
                  Standard_Real Vmodul 
            = Vnorm.Modulus ();
                  
            if (Vmodul > gp::Resolution())
                  
            {
                    Vnorm.Divide(Vmodul);
                  }

                  
            else
                  
            {
                    
            // si Vnorm est quasi-nul, on le charge a 0 explicitement
                    Vnorm.SetCoord (0., 0., 0.);
                  }


                  WriteDouble2Float (aFile, Vnorm.X());
                  WriteDouble2Float (aFile, Vnorm.Y());
                  WriteDouble2Float (aFile, Vnorm.Z());

                  WriteDouble2Float (aFile, x1);
                  WriteDouble2Float (aFile, y1);
                  WriteDouble2Float (aFile, z1);

                  WriteDouble2Float (aFile, x2);
                  WriteDouble2Float (aFile, y2);
                  WriteDouble2Float (aFile, z2);

                  WriteDouble2Float (aFile, x3);
                  WriteDouble2Float (aFile, y3);
                  WriteDouble2Float (aFile, z3);

                  aFile.Write (
            &dum, 2);

                  
            // update progress only per 1k triangles
                  if (++aTriangleInd % IND_THRESHOLD == 0)
                  
            {
                    
            if (!aTPS.More())
                      
            break;
                    aTPS.Next();
                  }

                }

              }

              aFile.Close();
              Standard_Boolean isInterrupted 
            = !aDPS.More();
              
            return !isInterrupted;
            }

            //=======================================================================
            //function : WriteAscii
            //purpose  : write an ASCII STL file
            //=======================================================================

            Standard_Boolean RWStl::WriteAscii (
            const Handle(StlMesh_Mesh)& theMesh,
                                                
            const OSD_Path& thePath,
                                                
            const Handle(Message_ProgressIndicator)& theProgInd)
            {
              OSD_File theFile (thePath);
              theFile.Build(OSD_WriteOnly,OSD_Protection());
              TCollection_AsciiString buf (
            "solid\n");
              theFile.Write (buf,buf.Length());buf.Clear();

              Standard_Real x1, y1, z1;
              Standard_Real x2, y2, z2;
              Standard_Real x3, y3, z3;
              
            char sval[512];

              
            // create progress sentry for domains
              Standard_Integer aNbDomains = theMesh->NbDomains();
              Message_ProgressSentry aDPS (theProgInd, 
            "Mesh domains"0, aNbDomains, 1);
              StlMesh_MeshExplorer aMexp (theMesh);
              
            for (Standard_Integer nbd = 1; nbd <= aNbDomains && aDPS.More(); nbd++, aDPS.Next())
              
            {
                
            // create progress sentry for triangles in domain
                Message_ProgressSentry aTPS (theProgInd, "Triangles"0,
                    theMesh
            ->NbTriangles (nbd), IND_THRESHOLD);
                Standard_Integer aTriangleInd 
            = 0;
                
            for (aMexp.InitTriangle (nbd); aMexp.MoreTriangle(); aMexp.NextTriangle())
                
            {
                  aMexp.TriangleVertices (x1,y1,z1,x2,y2,z2,x3,y3,z3);

            //      Standard_Real x, y, z;
            //      aMexp.TriangleOrientation (x,y,z);

                  gp_XYZ Vect12 ((x2
            -x1), (y2-y1), (z2-z1));
                  gp_XYZ Vect23 ((x3
            -x2), (y3-y2), (z3-z2));
                  gp_XYZ Vnorm 
            = Vect12 ^ Vect23;
                  Standard_Real Vmodul 
            = Vnorm.Modulus ();
                  
            if (Vmodul > gp::Resolution())
                  
            {
                    Vnorm.Divide (Vmodul);
                  }

                  
            else
                  
            {
                    
            // si Vnorm est quasi-nul, on le charge a 0 explicitement
                    Vnorm.SetCoord (0., 0., 0.);
                  }

                  sprintf (sval,
                      
            " facet normal % 12e % 12e % 12e\n"
                      
            "   outer loop\n"
                      
            "     vertex % 12e % 12e % 12e\n"
                      
            "     vertex % 12e % 12e % 12e\n"
                      
            "     vertex % 12e % 12e % 12e\n"
                      
            "   endloop\n"
                      
            " endfacet\n",
                      Vnorm.X(), Vnorm.Y(), Vnorm.Z(),
                      x1, y1, z1,
                      x2, y2, z2,
                      x3, y3, z3);
                  buf 
            += sval;
                  theFile.Write (buf, buf.Length()); buf.Clear();

                  
            // update progress only per 1k triangles
                  if (++aTriangleInd % IND_THRESHOLD == 0)
                  
            {
                    
            if (!aTPS.More())
                        
            break;
                    aTPS.Next();
                  }

                }

              }


              buf 
            += "endsolid\n";
              theFile.Write (buf, buf.Length()); buf.Clear();
              theFile.Close();
              Standard_Boolean isInterrupted 
            = !aDPS.More();
              
            return !isInterrupted;
            }

            //=======================================================================
            //function : ReadFile
            //Design   :
            //Warning  :
            //=======================================================================

            Handle_StlMesh_Mesh RWStl::ReadFile (
            const OSD_Path& thePath,
                                                 
            const Handle(Message_ProgressIndicator)& theProgInd)
            {
              OSD_File file (thePath);
              file.Open(OSD_ReadOnly,OSD_Protection(OSD_RWD,OSD_RWD,OSD_RWD,OSD_RWD));
              Standard_Boolean IsAscii;
              unsigned 
            char str[128];
              Standard_Integer lread,i;
              Standard_Address ach;
              ach 
            = (Standard_Address)str;

              
            // we skip the header which is in Ascii for both modes
              file.Read(ach,HEADER_SIZE,lread);

              
            // we read 128 characters to detect if we have a non-ascii char
              file.Read(ach,sizeof(str),lread);

              IsAscii 
            = Standard_True;
              
            for (i = 0; i< lread && IsAscii; ++i) {
                
            if (str[i] > '~'{
                  IsAscii 
            = Standard_False;
                }

              }

            #ifdef DEB
              cout 
            << (IsAscii ? "ascii\n" : "binary\n");
            #endif
              file.Close();

              
            return IsAscii ? RWStl::ReadAscii  (thePath, theProgInd)
                             : RWStl::ReadBinary (thePath, theProgInd);
            }


            //=======================================================================
            //function : ReadBinary
            //Design   :
            //Warning  :
            //=======================================================================

            Handle_StlMesh_Mesh RWStl::ReadBinary (
            const OSD_Path& thePath,
                                                   
            const Handle(Message_ProgressIndicator)& /*theProgInd*/)
            {
              Standard_Integer NBFACET;
              Standard_Integer ifacet;
              Standard_Real fx,fy,fz,fx1,fy1,fz1,fx2,fy2,fz2,fx3,fy3,fz3;
              Standard_Integer i1,i2,i3,lread;
              
            char buftest[5];
              Standard_Address adr;
              adr 
            = (Standard_Address)buftest;

              
            // Open the file
              OSD_File theFile (thePath);
              theFile.Open(OSD_ReadOnly,OSD_Protection(OSD_RWD,OSD_RWD,OSD_RWD,OSD_RWD));

              
            // the size of the file (minus the header size)
              
            // must be a multiple of SIZEOF_STL_FACET

              
            // compute file size
              Standard_Integer filesize = theFile.Size();

              
            if ( (filesize - HEADER_SIZE) % SIZEOF_STL_FACET !=0
                
            || (filesize < STL_MIN_FILE_SIZE)) {
                Standard_NoMoreObject::Raise(
            "RWStl::ReadBinary (wrong file size)");
              }


              
            // don't trust the number of triangles which is coded in the file
              
            // sometimes it is wrong, and with this technique we don't need to swap endians for integer
              NBFACET = ((filesize - HEADER_SIZE) / SIZEOF_STL_FACET);

              
            // skip the header
              theFile.Seek(HEADER_SIZE,OSD_FromBeginning);

              
            // create the StlMesh_Mesh object
              Handle(StlMesh_Mesh) ReadMesh = new StlMesh_Mesh ();
              ReadMesh
            ->AddDomain ();

              
            for (ifacet=1; ifacet<=NBFACET; ++ifacet) {
                
            // read normal coordinates
                fx = ReadFloat2Double(theFile);
                fy 
            = ReadFloat2Double(theFile);
                fz 
            = ReadFloat2Double(theFile);

                
            // read vertex 1
                fx1 = ReadFloat2Double(theFile);
                fy1 
            = ReadFloat2Double(theFile);
                fz1 
            = ReadFloat2Double(theFile);

                
            // read vertex 2
                fx2 = ReadFloat2Double(theFile);
                fy2 
            = ReadFloat2Double(theFile);
                fz2 
            = ReadFloat2Double(theFile);

                
            // read vertex 3
                fx3 = ReadFloat2Double(theFile);
                fy3 
            = ReadFloat2Double(theFile);
                fz3 
            = ReadFloat2Double(theFile);

                i1 
            = ReadMesh->AddOnlyNewVertex (fx1,fy1,fz1);
                i2 
            = ReadMesh->AddOnlyNewVertex (fx2,fy2,fz2);
                i3 
            = ReadMesh->AddOnlyNewVertex (fx3,fy3,fz3);
                ReadMesh
            ->AddTriangle (i1,i2,i3,fx,fy,fz);

                
            // skip extra bytes
                theFile.Read(adr,2,lread);
              }


              theFile.Close ();
              
            return ReadMesh;

            }

            //=======================================================================
            //function : ReadAscii
            //Design   :
            //Warning  :
            //=======================================================================

            Handle_StlMesh_Mesh RWStl::ReadAscii (
            const OSD_Path& thePath,
                                                  
            const Handle(Message_ProgressIndicator)& theProgInd)
            {
              TCollection_AsciiString filename;
              
            long ipos;
              Standard_Integer nbLines 
            = 0;
              Standard_Integer nbTris 
            = 0;
              Standard_Integer iTri;
              Standard_ShortReal x[
            4],y[4],z[4];
              Standard_Integer i1,i2,i3;
              Handle(StlMesh_Mesh) ReadMesh;

              thePath.SystemName (filename);

              
            // Open the file
              FILE* file = fopen(filename.ToCString(),"r");

              fseek(file,
            0L,SEEK_END);

              
            long filesize = ftell(file);

              fclose(file);
              file 
            = fopen(filename.ToCString(),"r");



              
            // count the number of lines
              for (ipos = 0; ipos < filesize; ++ipos) {
                  
            if (getc(file) == '\n')
                    nbLines
            ++;
              }


              
            // compute number of triangles
              nbTris = (nbLines / ASCII_LINES_PER_FACET);

              
            // go back to the beginning of the file
            //  fclose(file);
            //  file = fopen(filename.ToCString(),"r");
              rewind(file);

              
            // skip header
              while (getc(file) != '\n');
            #ifdef DEB
              cout 
            << "start mesh\n";
            #endif
              ReadMesh 
            = new StlMesh_Mesh();
              ReadMesh
            ->AddDomain();

              
            // main reading
              Message_ProgressSentry aPS (theProgInd, "Triangles"0, (nbTris - 1* 1.0 / IND_THRESHOLD, 1);
              
            for (iTri = 0; iTri < nbTris && aPS.More();)
              
            {
                
            // reading the facet normal
                fscanf(file,"%*s %*s %f %f %f\n",&x[0],&y[0],&z[0]);

                
            // skip the keywords "outer loop"
                fscanf(file,"%*s %*s");

                
            // reading vertex
                fscanf(file,"%*s %f %f %f\n",&x[1],&y[1],&z[1]);
                fscanf(file,
            "%*s %f %f %f\n",&x[2],&y[2],&z[2]);
                fscanf(file,
            "%*s %f %f %f\n",&x[3],&y[3],&z[3]);

                
            // here the facet must be built and put in the mesh datastructure

                i1 
            = ReadMesh->AddOnlyNewVertex ((Standard_Real)x[1],(Standard_Real)y[1],(Standard_Real)z[1]);
                i2 
            = ReadMesh->AddOnlyNewVertex ((Standard_Real)x[2],(Standard_Real)y[2],(Standard_Real)z[2]);
                i3 
            = ReadMesh->AddOnlyNewVertex ((Standard_Real)x[3],(Standard_Real)y[3],(Standard_Real)z[3]);
                ReadMesh
            ->AddTriangle (i1,i2,i3,(Standard_Real)x[0],(Standard_Real)y[0],(Standard_Real)z[0]);

                
            // skip the keywords "endloop"
                fscanf(file,"%*s");

                
            // skip the keywords "endfacet"
                fscanf(file,"%*s");

                
            // update progress only per 1k triangles
                if (++iTri % IND_THRESHOLD == 0)
                  aPS.Next();
              }

            #ifdef DEB
              cout 
            << "end mesh\n";
            #endif
              fclose(file);
              
            return ReadMesh;

            }



            程序開始定義了一些常量:

             

            // constants
            static const int HEADER_SIZE           =  84;
            static const int SIZEOF_STL_FACET      =  50;
            static const int STL_MIN_FILE_SIZE     = 284;
            static const int ASCII_LINES_PER_FACET =   7;
            static const int IND_THRESHOLD         = 1000// increment the indicator every 1k triangles


             

            分別對應二進制文件中相關信息,即文件頭84個字節,每個三角面片50個字節,STL文件最小為284字節。ASCII的STL中每個三角面有7行。

            在數據的讀寫過程中,對數據進行了小端轉換。將double數據轉換成小端表示的代碼如下所示:

             

            //=======================================================================
            //function : WriteDouble2Float
            //purpose  : writing a Little Endian 32 bits float
            //=======================================================================

            inline 
            static void WriteDouble2Float(OSD_File& ofile,Standard_Real value)
            {
              union 
            {
                Standard_ShortReal f;
                
            char c[4];
              }
             bidargum;

              bidargum.f 
            = (Standard_ShortReal)value;

              Standard_Integer entier;

              entier  
            =  bidargum.c[0& 0xFF;
              entier 
            |= (bidargum.c[1& 0xFF<< 0x08;
              entier 
            |= (bidargum.c[2& 0xFF<< 0x10;
              entier 
            |= (bidargum.c[3& 0xFF<< 0x18;

              ofile.Write((
            char *)&entier,sizeof(bidargum.c));
            }


            使用聯合體(union)來處理顯得很優雅。關于大端、小端的相關信息請參考:

            http://www.shnenglu.com/tx7do/archive/2009/01/06/71276.html

            四、在OpenSceneGraph中顯示STL

            結合OpenCascade中對STL文件讀寫的功能和OpenSceneGraph的顯示功能,將STL讀取所得數據進行顯示。源程序如下所示:

             


            // Open Cascade
            #include <gp_Vec.hxx>
            #include 
            <OSD_Path.hxx>
            #include 
            <RWStl.hxx>
            #include 
            <StlMesh_Mesh.hxx>
            #include 
            <StlMesh_MeshExplorer.hxx>

            #pragma comment(lib, 
            "TKernel.lib")
            #pragma comment(lib, 
            "TKMath.lib")
            #pragma comment(lib, 
            "TKSTL.lib")

            // OpenSceneGraph
            #include <osgDB/ReadFile>
            #include 
            <osgViewer/Viewer>
            #include 
            <osgViewer/ViewerEventHandlers>
            #include 
            <osgGA/StateSetManipulator>

            #pragma comment(lib, 
            "osgd.lib")
            #pragma comment(lib, 
            "osgDbd.lib")
            #pragma comment(lib, 
            "osgGAd.lib")
            #pragma comment(lib, 
            "osgViewerd.lib")

            osg::Node
            * readSTLFile(const std::string& fileName)
            {
                osg::Group
            * root = new osg::Group();

                OSD_Path stlFile(fileName.c_str());
                Handle_StlMesh_Mesh stlMesh 
            = RWStl::ReadFile(stlFile);
                Standard_Integer nDomains 
            = stlMesh->NbDomains();
                StlMesh_MeshExplorer meshExplorer(stlMesh);

                Standard_Real x[
            3= {0};
                Standard_Real y[
            3= {0};
                Standard_Real z[
            3= {0};
                Standard_Real n[
            3= {0};

                gp_XYZ p1;
                gp_XYZ p2;
                gp_XYZ p3;
                gp_XYZ normal;
                gp_Vec vecNormal;

                
            for (int i = 1; i <= nDomains; i++)
                
            {
                    
            for (meshExplorer.InitTriangle(i); meshExplorer.MoreTriangle(); meshExplorer.NextTriangle())
                    
            {
                        meshExplorer.TriangleVertices(x[
            0], y[0], z[0], x[1], y[1], z[1], x[2], y[2], z[2]);
                        meshExplorer.TriangleOrientation(n[
            0], n[1], n[2]);

                        p1.SetCoord(x[
            0], y[0], z[0]);
                        p2.SetCoord(x[
            1], y[1], z[1]);
                        p3.SetCoord(x[
            2], y[2], z[2]);
                        normal.SetCoord(n[
            0], n[1], n[2]);

                        
            //gp_Vec vec12((x[1] - x[0]), (y[1] - y[0]), (z[1] - z[0]));
                        
            //gp_Vec vec23((x[2] - x[1]), (y[2] - y[1]), (z[2] - z[1]));
                        
            //vecNormal = vec12.Crossed(vec23).Normalized();

                        osg::ref_ptr
            <osg::Geode> geode = new osg::Geode();
                        osg::ref_ptr
            <osg::Geometry> triGeom = new osg::Geometry();
                        osg::ref_ptr
            <osg::Vec3Array> vertices = new osg::Vec3Array();
                        osg::ref_ptr
            <osg::Vec3Array> normals = new osg::Vec3Array();
                        
                        vertices
            ->push_back(osg::Vec3(x[0], y[0], z[0]));
                        vertices
            ->push_back(osg::Vec3(x[1], y[1], z[1]));
                        vertices
            ->push_back(osg::Vec3(x[2], y[2], z[2]));

                        normals
            ->push_back(osg::Vec3(n[0], n[1], n[2]));

                        triGeom
            ->setVertexArray(vertices.get());
                        triGeom
            ->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, vertices->size()));

                        triGeom
            ->setNormalArray(normals);
                        triGeom
            ->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE);

                        geode
            ->addDrawable(triGeom);

                        root
            ->addChild(geode);
                    }

                }


                
            return root;
            }


            int main(int argc, char* argv[])
            {
                osgViewer::Viewer myViewer;
                osg::ref_ptr
            <osg::Group> root = new osg::Group();

                
            //root->addChild(readSTLFile("D:\\OpenCASCADE6.5.0\\data\\stl\\propeller.stl"));
                root->addChild(readSTLFile("D:\\OpenCASCADE6.5.0\\data\\stl\\sh1.stl"));
                
            //root->addChild(readSTLFile("D:\\OpenCASCADE6.5.0\\data\\stl\\motor.stl"));
                
            //root->addChild(readSTLFile("D:\\box.stl"));
                
                myViewer.setSceneData(root);

                myViewer.addEventHandler(
            new osgGA::StateSetManipulator(myViewer.getCamera()->getOrCreateStateSet()));
                myViewer.addEventHandler(
            new osgViewer::StatsHandler);
                myViewer.addEventHandler(
            new osgViewer::WindowSizeHandler);

                
            return myViewer.run();
            }



            以下所示為OpenCascade提供的幾個STL文件在OpenSceneGraph中顯示的效果:

            wps_clip_image-4060

            Figure 4.1 Shaded Piston

            wps_clip_image-21794

            Figure 4.2 Wireframe Piston

            wps_clip_image-3504

            Figure 4.3 Shaded Propeller

            wps_clip_image-1112

            Figure 4.4 Wireframe Propeller

            五、結論

            通過使用OpenCascade的類RWStl來讀取STL格式的文件,理解了STL文件格式;通過將讀取的三角面面片數據在OpenSceneGraph中顯示,對三維物體在計算機中的表示有了感性的認識。

            六、參考資料

            1. OpenCascade中類RWStl.cxx

            2. OpenCascade中STL模型數據

            3. 字節序、大端、小端:http://www.shnenglu.com/tx7do/archive/2009/01/06/71276.html

             

            Feedback

            # re: Open Cascade Data Exchange --- STL  回復  更多評論   

            2018-09-05 20:00 by birds
            博主您好,我如何在opencascade里讀取.sat文件?

            # re: Open Cascade Data Exchange --- STL  回復  更多評論   

            2018-09-05 20:09 by eryar
            @birds
            opencascade開源部分沒有這個功能,要么使用他收費的模塊,,要么使用其他SDK。
            国产精品久久婷婷六月丁香| 久久精品无码一区二区无码| 波多野结衣AV无码久久一区| 久久久久夜夜夜精品国产| 色综合久久中文字幕综合网| 国产精品久久久久久影院| 亚洲精品白浆高清久久久久久| 婷婷久久综合九色综合绿巨人| 久久这里只有精品首页| 国内精品人妻无码久久久影院| 久久亚洲国产精品成人AV秋霞| 久久精品国产网红主播| 亚洲国产精品热久久| 免费观看成人久久网免费观看| 看全色黄大色大片免费久久久| 国产精品gz久久久| 久久精品中文字幕有码| 精品久久久久久国产免费了| 国内精品久久久久影院网站| 久久久久高潮综合影院| 亚洲AV无码一区东京热久久 | 99久久精品免费看国产一区二区三区| 久久久WWW成人免费精品| 久久久久久夜精品精品免费啦| 久久夜色精品国产亚洲av| 久久久国产精品亚洲一区| 亚洲国产成人精品91久久久| 好久久免费视频高清| 97精品伊人久久久大香线蕉| 欧美黑人激情性久久| 精品国产一区二区三区久久蜜臀 | 91精品国产高清久久久久久国产嫩草 | 伊人久久精品影院| 久久精品国产亚洲7777| 久久久久人妻精品一区| 色婷婷久久综合中文久久一本 | 久久婷婷色香五月综合激情| 久久人人爽人人爽人人片AV麻烦| 久久er国产精品免费观看2| 午夜人妻久久久久久久久| 久久笫一福利免费导航 |