青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

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 閱讀(12935) 評(píng)論(2)  編輯 收藏 引用 所屬分類: 2.OpenCASCADE 、4.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。
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲七七久久综合桃花剧情介绍| 欧美日韩精品一区二区三区四区 | 亚洲视频1区| 亚洲欧美另类国产| 欧美一区观看| 免费高清在线视频一区·| 亚洲黄色成人久久久| 亚洲人成欧美中文字幕| 亚洲精品国产精品乱码不99| 亚洲色图自拍| 美女日韩在线中文字幕| 国产精品v欧美精品v日韩精品| 国产综合视频在线观看| 在线中文字幕一区| 欧美国产亚洲视频| 欧美在线观看一二区| 国产精品福利在线观看网址| 亚洲三级视频| 欧美大片免费久久精品三p| 欧美一区二区三区精品| 国产精品久久久久久久久免费樱桃| 91久久精品国产91性色| 正在播放欧美一区| 亚洲国产老妈| 欧美福利在线观看| 国产精品手机在线| 亚洲欧美成人网| 久久天天躁夜夜躁狠狠躁2022| 国产日产欧美一区| 午夜精品久久久久久久99黑人| aa国产精品| 欧美日韩成人精品| 久久久久久久97| 欧美在线影院在线视频| 亚洲最新在线| 亚洲美女毛片| 欧美亚韩一区| 亚洲高清在线观看| 欧美激情欧美狂野欧美精品| 最新成人av网站| 欧美一区二区三区四区在线| 一区二区三区视频观看| 美国成人直播| 麻豆成人在线观看| 久久深夜福利免费观看| 欧美专区在线观看一区| 欧美在线视频在线播放完整版免费观看 | 欧美91精品| 91久久夜色精品国产九色| 性色av一区二区三区| 国产在线精品自拍| 亚洲一区二区精品在线| 国产日韩av一区二区| 亚洲一区二区三区精品在线观看| 日韩小视频在线观看专区| 一本色道久久综合亚洲精品高清 | 久久久久亚洲综合| 亚洲精品日韩激情在线电影| 久久久久久夜| 你懂的视频欧美| 欧美日本精品| 欧美一区二区性| 国产精品一区在线观看你懂的| 免费在线亚洲| 亚洲第一精品夜夜躁人人爽| 亚洲人成网站999久久久综合| 亚洲精品韩国| 欧美理论在线| 亚洲精品国产精品国自产在线| 日韩视频不卡| 欧美专区在线播放| 久久久噜噜噜久久狠狠50岁| 欧美日韩国产经典色站一区二区三区| 亚洲第一精品夜夜躁人人爽 | 在线精品亚洲| 狂野欧美激情性xxxx| 亚洲中无吗在线| 久久综合狠狠综合久久综合88| 蜜臀久久久99精品久久久久久| 亚洲片国产一区一级在线观看| 欧美黄色日本| 麻豆精品在线视频| 亚洲欧洲日产国产网站| 欧美日韩小视频| 欧美成人午夜剧场免费观看| 亚洲国产岛国毛片在线| 亚洲综合大片69999| 一本色道久久99精品综合| 欧美性大战xxxxx久久久| 亚洲欧美中文另类| 亚洲一级片在线观看| 美女视频网站黄色亚洲| 99视频精品全国免费| 久久国产手机看片| 国产精品欧美在线| 久久综合久久久久88| 一本色道久久综合亚洲精品婷婷| 久久久xxx| 亚洲视频在线视频| 精久久久久久| 欧美伊人久久| 亚洲日本中文字幕| 久久久国产精品一区二区中文| 99精品视频免费观看| 国产在线不卡视频| 欧美日韩亚洲国产精品| 久久国产精品免费一区| 久久久久在线观看| 亚洲婷婷综合久久一本伊一区| 尤物九九久久国产精品的分类| 久久精品国产一区二区三区免费看 | 欧美91视频| 午夜欧美视频| 9i看片成人免费高清| 精品999网站| 国产精品一区在线播放| 欧美视频观看一区| 在线视频亚洲一区| 亚洲国内精品| 欧美jizz19hd性欧美| 久久国产色av| 久久国产福利| 午夜精品福利一区二区三区av | 久久精品1区| 性久久久久久久久久久久| 国产日韩欧美一区在线| 久久精品国产v日韩v亚洲| 亚洲在线免费视频| 日韩一级大片| 亚洲精品欧美在线| 欧美在线免费观看亚洲| 亚洲欧美色一区| 亚洲视频碰碰| 亚洲一区二区三区视频播放| 99在线|亚洲一区二区| 亚洲美女精品成人在线视频| 亚洲精品久久久蜜桃| 亚洲精品国产精品乱码不99 | 亚洲精品九九| 99精品国产99久久久久久福利| 亚洲九九爱视频| 亚洲免费高清视频| 一区二区免费在线视频| 夜夜嗨av色一区二区不卡| 一本色道88久久加勒比精品| 一区二区高清在线| 亚洲在线一区| 久久狠狠久久综合桃花| 久久中文字幕一区| 一本大道久久精品懂色aⅴ| 亚洲精品欧美日韩专区| 一区二区三区四区精品| 亚洲一区二区日本| 久久超碰97中文字幕| 久久中文字幕一区| 91久久久久久久久久久久久| 久久久久久久精| 免费黄网站欧美| 最新亚洲电影| 亚洲一区影院| 久久综合狠狠综合久久综合88| 欧美国产成人精品| 欧美丝袜一区二区| 国产一区二区精品丝袜| 欧美丝袜第一区| 国产视频精品xxxx| 亚洲精品色图| 久久gogo国模啪啪人体图| 欧美黄色一级视频| 一本大道久久a久久精品综合| 午夜一区在线| 免费亚洲电影| 国产欧美成人| 亚洲精品专区| 久久久亚洲人| 久久精品国产清高在天天线| 亚洲视频一区| 国产一区深夜福利| 欧美日韩在线不卡| 免费永久网站黄欧美| 国产精品99免费看| 国内外成人免费激情在线视频| 亚洲免费成人| 久久中文字幕一区二区三区| 日韩一级片网址| 久久亚洲国产精品一区二区| 国产精品久久久久一区| 亚洲精品免费在线播放| 久久精品亚洲热| aa级大片欧美三级| 久久深夜福利免费观看| 国产日韩精品入口| 亚洲网站视频福利| 欧美大片国产精品| 欧美一区二区三区播放老司机| 欧美亚男人的天堂| av成人老司机| 亚洲国产天堂久久综合网| 久久久91精品国产| 国产欧美日韩亚洲精品|