1 // Copyright (C) 2007-2024 CEA, EDF, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #include "DriverSTL_R_SMDS_Mesh.h"
25 #include <Basics_Utils.hxx>
26 #include <Basics_OCCTVersion.hxx>
29 #include <NCollection_DataMap.hxx>
30 #include <Standard_NoMoreObject.hxx>
32 #include "SMDS_Mesh.hxx"
33 #include "SMDS_MeshElement.hxx"
34 #include "SMDS_MeshNode.hxx"
35 #include "SMESH_File.hxx"
41 //=======================================================================
44 //=======================================================================
45 #if OCC_VERSION_LARGE < 0x07080000
46 inline static Standard_Integer HashCode
47 (const gp_Pnt& point, Standard_Integer Upper)
49 size_t operator()(const gp_Pnt& point) const
55 Standard_Integer I[6];
58 point.Coord( U.R[0], U.R[1], U.R[2] );
60 #if OCC_VERSION_LARGE < 0x07080000
61 return ::HashCode(U.I[0]/23+U.I[1]/19+U.I[2]/17+U.I[3]/13+U.I[4]/11+U.I[5]/7,Upper);
63 return static_cast<size_t>(U.I[0]/23+U.I[1]/19+U.I[2]/17+U.I[3]/13+U.I[4]/11+U.I[5]/7);
66 //=======================================================================
69 //=======================================================================
70 #if OCC_VERSION_LARGE < 0x07080000
71 inline static Standard_Boolean IsEqual
72 (const gp_Pnt& point1, const gp_Pnt& point2)
74 bool operator()(const gp_Pnt& point1, const gp_Pnt& point2) const
77 static Standard_Real tab1[3], tab2[3];
78 point1.Coord(tab1[0],tab1[1],tab1[2]);
79 point2.Coord(tab2[0],tab2[1],tab2[2]);
80 return (memcmp(tab1,tab2,sizeof(tab1)) == 0);
83 typedef NCollection_DataMap<gp_Pnt,SMDS_MeshNode*,Hasher> TDataMapOfPntNodePtr;
85 const int HEADER_SIZE = 84; // 80 chars + int
86 const int SIZEOF_STL_FACET = 50;
87 const int ASCII_LINES_PER_FACET = 7;
88 const int SIZE_OF_FLOAT = 4;
89 // const int STL_MIN_FILE_SIZE = 284;
92 //=======================================================================
93 //function : DriverSTL_R_SMDS_Mesh
95 //=======================================================================
97 DriverSTL_R_SMDS_Mesh::DriverSTL_R_SMDS_Mesh()
99 myIsCreateFaces = true;
100 myIsAscii = Standard_True;
103 //=======================================================================
104 //function : SetIsCreateFaces
106 //=======================================================================
108 void DriverSTL_R_SMDS_Mesh::SetIsCreateFaces( const bool theIsCreate )
109 { myIsCreateFaces = theIsCreate; }
111 //=======================================================================
114 //=======================================================================
116 Driver_Mesh::Status DriverSTL_R_SMDS_Mesh::Perform()
118 Kernel_Utils::Localizer loc;
120 Status aResult = DRS_OK;
122 if ( myFile.empty() ) {
123 fprintf(stderr, ">> ERREOR : invalid file name \n");
127 SMESH_File file( myFile, /*open=*/false );
128 if ( !file.open() ) {
129 fprintf(stderr, ">> ERROR : cannot open file %s \n", myFile.c_str());
130 if ( file.error().empty() )
131 fprintf(stderr, ">> ERROR : %s \n", file.error().c_str());
135 // we skip the header which is in Ascii for both modes
136 const char* data = file;
139 // we check 128 characters to detect if we have a non-ascii char
140 myIsAscii = Standard_True;
141 for (int i = 0; i < 128; ++i, ++data) {
142 if ( !isascii( *data ) && data < file.end() ) {
143 myIsAscii = Standard_False;
149 fprintf(stderr, ">> ERREOR : cannot create mesh \n");
154 aResult = readAscii( file );
156 aResult = readBinary( file );
159 myMesh->CompactMesh();
166 static Standard_Real readFloat(SMESH_File& theFile)
173 const char* c = theFile;
176 u.i |= (c[1] & 0xFF) << 0x08;
177 u.i |= (c[2] & 0xFF) << 0x10;
178 u.i |= (c[3] & 0xFF) << 0x18;
179 theFile += SIZE_OF_FLOAT;
184 static SMDS_MeshNode* addNode(const gp_Pnt& P,
185 TDataMapOfPntNodePtr& uniqnodes,
188 SMDS_MeshNode* node = 0;
189 if ( uniqnodes.IsBound(P) ) {
190 node = uniqnodes.Find(P);
192 node = theMesh->AddNode(P.X(), P.Y(), P.Z() );
193 uniqnodes.Bind(P,node);
199 static SMDS_MeshNode* readNode(FILE* file,
200 TDataMapOfPntNodePtr& uniqnodes,
203 Standard_ShortReal coord[3];
205 fscanf(file,"%*s %f %f %f\n",&coord[0],&coord[1],&coord[2]);
207 gp_Pnt P(coord[0],coord[1],coord[2]);
208 return addNode( P, uniqnodes, theMesh );
211 static SMDS_MeshNode* readNode(SMESH_File& theFile,
212 TDataMapOfPntNodePtr& uniqnodes,
216 coord.SetX( readFloat(theFile));
217 coord.SetY( readFloat(theFile));
218 coord.SetZ( readFloat(theFile));
220 return addNode( coord, uniqnodes, theMesh );
223 //=======================================================================
224 //function : readAscii
226 //=======================================================================
228 Driver_Mesh::Status DriverSTL_R_SMDS_Mesh::readAscii(SMESH_File& theFile) const
230 Status aResult = DRS_OK;
233 if ( strncmp( "solid ", theFile, strlen("solid ")) == 0 ) // not empty
235 const char * header = theFile;
236 std::string& name = const_cast<std::string&>( myName );
237 for ( header += strlen("solid "); !iscntrl( *header ); ++header )
238 name.push_back( *header );
240 std::string::iterator i = name.begin();
241 while ( i != name.end() && isspace( *i )) ++i;
242 name.erase( name.begin(), i );
244 size_t n = name.size();
245 while ( n > 0 && isspace( name[ n - 1 ] )) --n;
250 long filesize = theFile.size();
254 #if defined(WIN32) && defined(UNICODE)
255 std::wstring aFile = Kernel_Utils::utf8_decode_s(myFile);
256 FILE* file = _wfopen( aFile.c_str(), L"r");
258 FILE* file = fopen(myFile.c_str(), "r");
261 // count the number of lines
262 Standard_Integer nbLines = 0;
263 for (long ipos = 0; ipos < filesize; ++ipos)
265 if (getc(file) == '\n')
269 // go back to the beginning of the file
272 Standard_Integer nbTri = (nbLines / ASCII_LINES_PER_FACET);
274 TDataMapOfPntNodePtr uniqnodes;
276 while (getc(file) != '\n');
279 for (Standard_Integer iTri = 0; iTri < nbTri; ++iTri)
281 // skipping the facet normal
282 Standard_ShortReal normal[3];
283 fscanf(file,"%*s %*s %f %f %f\n",&normal[0],&normal[1],&normal[2]);
285 // skip the keywords "outer loop"
286 fscanf(file,"%*s %*s");
289 SMDS_MeshNode* node1 = readNode( file, uniqnodes, myMesh );
290 SMDS_MeshNode* node2 = readNode( file, uniqnodes, myMesh );
291 SMDS_MeshNode* node3 = readNode( file, uniqnodes, myMesh );
294 myMesh->AddFace(node1,node2,node3);
296 // skip the keywords "endloop"
299 // skip the keywords "endfacet"
307 //=======================================================================
308 //function : readBinary
310 //=======================================================================
312 Driver_Mesh::Status DriverSTL_R_SMDS_Mesh::readBinary(SMESH_File& file) const
314 Status aResult = DRS_OK;
316 // the size of the file (minus the header size)
317 // must be a multiple of SIZEOF_STL_FACET
319 long filesize = file.size();
321 if ( (filesize - HEADER_SIZE) % SIZEOF_STL_FACET != 0
322 // Commented to allow reading small files (ex: 1 face)
323 /*|| (filesize < STL_MIN_FILE_SIZE)*/) {
324 Standard_NoMoreObject::Raise("DriverSTL_R_SMDS_MESH::readBinary (wrong file size)");
327 // don't trust the number of triangles which is coded in the file
328 // sometimes it is wrong, and with this technique we don't need to swap endians for integer
329 Standard_Integer nbTri = ((filesize - HEADER_SIZE) / SIZEOF_STL_FACET);
332 if ( strncmp( "name: ", file, strlen("name: ")) == 0 ) // name present
334 const char * header = file;
335 std::string& name = const_cast<std::string&>( myName );
336 header += strlen("name: ");
337 name.assign( header, HEADER_SIZE - strlen("name: ") - 4);
339 size_t n = name.size();
340 while ( n > 0 && isspace( name[ n - 1 ] )) --n;
347 TDataMapOfPntNodePtr uniqnodes;
349 for (Standard_Integer iTri = 0; iTri < nbTri; ++iTri) {
352 file += 3 * SIZE_OF_FLOAT;
355 SMDS_MeshNode* node1 = readNode( file, uniqnodes, myMesh );
356 SMDS_MeshNode* node2 = readNode( file, uniqnodes, myMesh );
357 SMDS_MeshNode* node3 = readNode( file, uniqnodes, myMesh );
360 myMesh->AddFace(node1,node2,node3);