• <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) 評(píng)論(2)  編輯 收藏 引用 所屬分類: 2.OpenCASCADE4.AVEVA Solution

            Open Cascade Data Exchange --- STL

            eryar@163.com

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

            關(guān)鍵字Key Words:STL, Open Cascade, OpenSceneGraph, Data Exchange

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

            一、STL的明碼(ASCII)格式

            ASCII格式的STL文件逐行給出三角面片的幾何信息,每行以1個(gè)或2個(gè)關(guān)鍵字開頭。STL文件中的三角面片的信息單元facet是一個(gè)帶法向方向的三角面片,STL三維模型就是由這一系列的三角面片構(gòu)成。整個(gè)STL文件的首行給出了文件路徑及文件名。在一個(gè)STL文件中,每個(gè)facet由7行數(shù)據(jù)組成:facet normal是三角面片指向?qū)嶓w外部的單位法矢量;outer loop說明隨后的3行數(shù)據(jù)分別是三角面片的3個(gè)頂點(diǎn)坐標(biāo),3頂點(diǎn)沿指向?qū)嶓w外部的法矢量方向逆時(shí)針排列。

            ASCII格式的STL文件結(jié)構(gòu)如下:

            wps_clip_image-30396

            說明如下:

            wps_clip_image-7699

            下面給出由Open Cascade中導(dǎo)出的一個(gè)長方體的STL文件:

            長方體的尺寸為長200,寬150,高100,原點(diǎn)在一個(gè)角點(diǎn)上。

            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明碼文件可知,上述數(shù)據(jù)將一個(gè)長方體的6個(gè)面用12個(gè)三角形來表示。在OpenSceneGraph中顯示效果如下圖所示,分別為此長方體的實(shí)體渲染模式和線框渲染模式:

            wps_clip_image-30014 wps_clip_image-7473

            Figure 1.2 Shaded and Wireframe box in OpenSceneGraph

            二、STL的二進(jìn)制(Binary)格式

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

            wps_clip_image-17429

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

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

            l 遍歷一個(gè)TopoDS_Shape所有的面Face;

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

            l 計(jì)算每個(gè)三角面片的法矢量;

            l 將結(jié)果寫入文件。

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

            n RWStl::WriteBinary

            n RWStl::WriteAscii

            n RWStl::ReadBinary

            n RWStl::ReadAscii

            程序的具體實(shí)現(xiàn)可以查看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


             

            分別對(duì)應(yīng)二進(jìn)制文件中相關(guān)信息,即文件頭84個(gè)字節(jié),每個(gè)三角面片50個(gè)字節(jié),STL文件最小為284字節(jié)。ASCII的STL中每個(gè)三角面有7行。

            在數(shù)據(jù)的讀寫過程中,對(duì)數(shù)據(jù)進(jìn)行了小端轉(zhuǎn)換。將double數(shù)據(jù)轉(zhuǎn)換成小端表示的代碼如下所示:

             

            //=======================================================================
            //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));
            }


            使用聯(lián)合體(union)來處理顯得很優(yōu)雅。關(guān)于大端、小端的相關(guān)信息請(qǐng)參考:

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

            四、在OpenSceneGraph中顯示STL

            結(jié)合OpenCascade中對(duì)STL文件讀寫的功能和OpenSceneGraph的顯示功能,將STL讀取所得數(shù)據(jù)進(jìn)行顯示。源程序如下所示:

             


            // 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提供的幾個(gè)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

            五、結(jié)論

            通過使用OpenCascade的類RWStl來讀取STL格式的文件,理解了STL文件格式;通過將讀取的三角面面片數(shù)據(jù)在OpenSceneGraph中顯示,對(duì)三維物體在計(jì)算機(jī)中的表示有了感性的認(rèn)識(shí)。

            六、參考資料

            1. OpenCascade中類RWStl.cxx

            2. OpenCascade中STL模型數(shù)據(jù)

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

             

            Feedback

            # re: Open Cascade Data Exchange --- STL  回復(fù)  更多評(píng)論   

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

            # re: Open Cascade Data Exchange --- STL  回復(fù)  更多評(píng)論   

            2018-09-05 20:09 by eryar
            @birds
            opencascade開源部分沒有這個(gè)功能,要么使用他收費(fèi)的模塊,,要么使用其他SDK。
            久久久久青草线蕉综合超碰| 7777精品伊人久久久大香线蕉| 久久99这里只有精品国产| 亚洲一区二区三区日本久久九| 久久久久国产精品嫩草影院| 久久一区二区三区99| 国产精品无码久久四虎| 亚洲一区中文字幕久久| 久久综合九色综合精品| a高清免费毛片久久| 99久久er这里只有精品18| 亚洲AV无码1区2区久久| 亚洲伊人久久精品影院| 午夜精品久久久久久毛片| 亚洲级αV无码毛片久久精品| 久久久久亚洲AV无码专区首JN| 区久久AAA片69亚洲| 久久国语露脸国产精品电影 | 久久精品中文闷骚内射| 亚洲国产精品久久久天堂 | 国产精品九九久久免费视频| 青青草国产精品久久| 国产精品无码久久久久| 欧洲国产伦久久久久久久 | 久久久亚洲裙底偷窥综合| 免费久久人人爽人人爽av| 亚洲精品无码专区久久久| 久久久一本精品99久久精品66| 国产精品一区二区久久不卡| 狠色狠色狠狠色综合久久| 一本色道久久88加勒比—综合| 97精品国产97久久久久久免费| 久久播电影网| 精品国产乱码久久久久软件| 久久超乳爆乳中文字幕| 青青草原综合久久| 香蕉久久永久视频| 亚洲精品白浆高清久久久久久| 久久免费高清视频| 久久天天躁狠狠躁夜夜2020 | 国产精品久久久久久久久久影院 |