From 9a9f18bbed8938323548335d9225e480a0ea8ca6 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Mon, 6 Nov 2017 22:30:07 +0100 Subject: [PATCH 1/5] closes https://github.com/assimp/assimp/issues/104: deal with more solids in one STL file. --- code/STLLoader.cpp | 86 ++++++++++++++++++++++++++++------------------ code/STLLoader.h | 60 ++++++++++++++++++-------------- 2 files changed, 86 insertions(+), 60 deletions(-) diff --git a/code/STLLoader.cpp b/code/STLLoader.cpp index f4d6ddda7..6b71ba920 100644 --- a/code/STLLoader.cpp +++ b/code/STLLoader.cpp @@ -200,17 +200,17 @@ void STLImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS if (IsBinarySTL(mBuffer, fileSize)) { bMatClr = LoadBinaryFile(); } else if (IsAsciiSTL(mBuffer, fileSize)) { - LoadASCIIFile(); + LoadASCIIFile( pScene->mRootNode ); } else { throw DeadlyImportError( "Failed to determine STL storage representation for " + pFile + "."); } // add all created meshes to the single node - pScene->mRootNode->mNumMeshes = pScene->mNumMeshes; + /*pScene->mRootNode->mNumMeshes = pScene->mNumMeshes; pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes]; for (unsigned int i = 0; i < pScene->mNumMeshes; i++) pScene->mRootNode->mMeshes[i] = i; - + */ // create a single default material, using a white diffuse color for consistency with // other geometric types (e.g., PLY). aiMaterial* pcMat = new aiMaterial(); @@ -231,11 +231,12 @@ void STLImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS pScene->mMaterials = new aiMaterial*[1]; pScene->mMaterials[0] = pcMat; } + // ------------------------------------------------------------------------------------------------ // Read an ASCII STL file -void STLImporter::LoadASCIIFile() -{ +void STLImporter::LoadASCIIFile( aiNode *root ) { std::vector meshes; + std::vector nodes; const char* sz = mBuffer; const char* bufferEnd = mBuffer + fileSize; std::vector positionBuffer; @@ -247,12 +248,15 @@ void STLImporter::LoadASCIIFile() positionBuffer.reserve(sizeEstimate); normalBuffer.reserve(sizeEstimate); - while (IsAsciiSTL(sz, static_cast(bufferEnd - sz))) - { + while (IsAsciiSTL(sz, static_cast(bufferEnd - sz))) { + std::vector meshIndices; aiMesh* pMesh = new aiMesh(); pMesh->mMaterialIndex = 0; + meshIndices.push_back( meshes.size() ); meshes.push_back(pMesh); - + aiNode *node = new aiNode; + node->mParent = root; + nodes.push_back( node ); SkipSpaces(&sz); ai_assert(!IsLineEnd(sz)); @@ -265,20 +269,21 @@ void STLImporter::LoadASCIIFile() size_t temp; // setup the name of the node - if ((temp = (size_t)(sz-szMe))) { + if ((temp = (size_t)(sz-szMe))) { if (temp >= MAXLEN) { throw DeadlyImportError( "STL: Node name too long" ); } - - pScene->mRootNode->mName.length = temp; - memcpy(pScene->mRootNode->mName.data,szMe,temp); - pScene->mRootNode->mName.data[temp] = '\0'; + std::string name( szMe, temp ); + node->mName.Set( name.c_str() ); + //pScene->mRootNode->mName.length = temp; + //memcpy(pScene->mRootNode->mName.data,szMe,temp); + //pScene->mRootNode->mName.data[temp] = '\0'; + } else { + pScene->mRootNode->mName.Set(""); } - else pScene->mRootNode->mName.Set(""); unsigned int faceVertexCounter = 3; - for ( ;; ) - { + for ( ;; ) { // go to the next token if(!SkipSpacesAndLineEnd(&sz)) { @@ -300,9 +305,7 @@ void STLImporter::LoadASCIIFile() SkipSpaces(&sz); if (strncmp(sz,"normal",6)) { DefaultLogger::get()->warn("STL: a facet normal vector was expected but not found"); - } - else - { + } else { if (sz[6] == '\0') { throw DeadlyImportError("STL: unexpected EOF while parsing facet"); } @@ -316,16 +319,11 @@ void STLImporter::LoadASCIIFile() normalBuffer.push_back(*vn); normalBuffer.push_back(*vn); } - } - // vertex 1.50000 1.50000 0.00000 - else if (!strncmp(sz,"vertex",6) && ::IsSpaceOrNewLine(*(sz+6))) - { + } else if (!strncmp(sz,"vertex",6) && ::IsSpaceOrNewLine(*(sz+6))) { // vertex 1.50000 1.50000 0.00000 if (faceVertexCounter >= 3) { DefaultLogger::get()->error("STL: a facet with more than 3 vertices has been found"); ++sz; - } - else - { + } else { if (sz[6] == '\0') { throw DeadlyImportError("STL: unexpected EOF while parsing facet"); } @@ -340,17 +338,14 @@ void STLImporter::LoadASCIIFile() sz = fast_atoreal_move(sz, (ai_real&)vn->z ); faceVertexCounter++; } - } - else if (!::strncmp(sz,"endsolid",8)) { + } else if (!::strncmp(sz,"endsolid",8)) { do { ++sz; } while (!::IsLineEnd(*sz)); SkipSpacesAndLineEnd(&sz); // finished! break; - } - // else skip the whole identifier - else { + } else { // else skip the whole identifier do { ++sz; } while (!::IsSpaceOrNewLine(*sz)); @@ -380,13 +375,22 @@ void STLImporter::LoadASCIIFile() // now copy faces addFacesToMesh(pMesh); + + // assign the meshes to the current node + pushMeshesToNode( meshIndices, node ); } + // now add the loaded meshes pScene->mNumMeshes = (unsigned int)meshes.size(); pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; - for (size_t i = 0; i < meshes.size(); i++) - { - pScene->mMeshes[i] = meshes[i]; + for (size_t i = 0; i < meshes.size(); i++) { + pScene->mMeshes[ i ] = meshes[i]; + } + + root->mNumChildren = nodes.size(); + root->mChildren = new aiNode*[ root->mNumChildren ]; + for ( size_t i=0; imChildren[ i ] = nodes[ i ]; } } @@ -513,4 +517,18 @@ bool STLImporter::LoadBinaryFile() return false; } +void STLImporter::pushMeshesToNode( std::vector &meshIndices, aiNode *node ) { + ai_assert( nullptr != node ); + if ( meshIndices.empty() ) { + return; + } + + node->mNumMeshes = static_cast( meshIndices.size() ); + node->mMeshes = new unsigned int[ meshIndices.size() ]; + for ( size_t i=0; imMeshes[ i ] = meshIndices[ i ]; + } + meshIndices.clear(); +} + #endif // !! ASSIMP_BUILD_NO_STL_IMPORTER diff --git a/code/STLLoader.h b/code/STLLoader.h index 87ed3288d..ff7b32a15 100644 --- a/code/STLLoader.h +++ b/code/STLLoader.h @@ -48,53 +48,61 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "BaseImporter.h" #include -namespace Assimp { +// Forward declarations +class aiNode; + +namespace Assimp { + // --------------------------------------------------------------------------- -/** Importer class for the sterolithography STL file format -*/ -class STLImporter : public BaseImporter -{ +/** + * @brief Importer class for the sterolithography STL file format. + */ +class STLImporter : public BaseImporter { public: + /** + * @brief STLImporter, the class default constructor. + */ STLImporter(); + + /** + * @brief The class destructor. + */ ~STLImporter(); - -public: - - // ------------------------------------------------------------------- - /** Returns whether the class can handle the format of the given file. - * See BaseImporter::CanRead() for details. + /** + * @brief Returns whether the class can handle the format of the given file. + * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler, - bool checkSig) const; + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const; protected: - // ------------------------------------------------------------------- - /** Return importer meta information. - * See #BaseImporter::GetInfo for the details + /** + * @brief Return importer meta information. + * See #BaseImporter::GetInfo for the details */ const aiImporterDesc* GetInfo () const; - // ------------------------------------------------------------------- - /** Imports the given file into the given scene structure. + /** + * @brief Imports the given file into the given scene structure. * See BaseImporter::InternReadFile() for details */ void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); - - // ------------------------------------------------------------------- - /** Loads a binary .stl file + /** + * @brief Loads a binary .stl file * @return true if the default vertex color must be used as material color - */ + */ bool LoadBinaryFile(); - // ------------------------------------------------------------------- - /** Loads a ASCII text .stl file - */ - void LoadASCIIFile(); + /** + * @brief Loads a ASCII text .stl file + */ + void LoadASCIIFile( aiNode *root ); + + void pushMeshesToNode( std::vector &meshIndices, aiNode *node ); protected: From 26171a7949178d6b98140c749ccc9806792b4fa6 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Mon, 6 Nov 2017 22:37:52 +0100 Subject: [PATCH 2/5] SLD: add test model and a unit test. --- test/CMakeLists.txt | 1 + test/models/STL/triangle_with_two_solids.stl | 18 ++++++ test/unit/utSTLImportExport.cpp | 68 ++++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 test/models/STL/triangle_with_two_solids.stl create mode 100644 test/unit/utSTLImportExport.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 62270b935..e50e8a742 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -131,6 +131,7 @@ SET( TEST_SRCS unit/utXImporterExporter.cpp unit/utD3MFImportExport.cpp unit/utQ3DImportExport.cpp + unit/utSTLImportExport.cpp unit/utProfiler.cpp ) SET( POST_PROCESSES diff --git a/test/models/STL/triangle_with_two_solids.stl b/test/models/STL/triangle_with_two_solids.stl new file mode 100644 index 000000000..9af3841ae --- /dev/null +++ b/test/models/STL/triangle_with_two_solids.stl @@ -0,0 +1,18 @@ +solid testTriangle_1 + facet normal 0.0 0.0 1.0 + outer loop + vertex 1.0 1.0 0.0 + vertex -1.0 1.0 0.0 + vertex 0.0 -1.0 0.0 + endloop + endfacet +endsolid +solid testTriangle_2 + facet normal 0.0 0.0 1.0 + outer loop + vertex 3.0 3.0 0.0 + vertex 2.0 3.0 0.0 + vertex 0.0 2.0 0.0 + endloop + endfacet +endsolid diff --git a/test/unit/utSTLImportExport.cpp b/test/unit/utSTLImportExport.cpp new file mode 100644 index 000000000..0ee3de955 --- /dev/null +++ b/test/unit/utSTLImportExport.cpp @@ -0,0 +1,68 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2017, assimp team + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ + +#include "UnitTestPCH.h" +#include "SceneDiffer.h" +#include "AbstractImportExportBase.h" + +#include + +using namespace Assimp; + +class utSTLImporterExporter : public AbstractImportExportBase { +public: + virtual bool importerTest() { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/STL/Spider_ascii.stl", 0 ); + return nullptr != scene; + } +}; + +TEST_F( utSTLImporterExporter, importXFromFileTest ) { + EXPECT_TRUE( importerTest() ); +} + +TEST_F( utSTLImporterExporter, test_with_two_solids ) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/STL/triangle_with_two_solids.stl", 0 ); + EXPECT_NE( nullptr, scene ); +} From 4ff2592747787eedca14e24ad1d088250eab86da Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Tue, 7 Nov 2017 00:31:09 +0100 Subject: [PATCH 3/5] Update STLLoader.h Fixed a typo. --- code/STLLoader.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/STLLoader.h b/code/STLLoader.h index ff7b32a15..c51604861 100644 --- a/code/STLLoader.h +++ b/code/STLLoader.h @@ -49,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include // Forward declarations -class aiNode; +struct aiNode; namespace Assimp { From b87e7643d2534a561301631bf87cdee3397bf366 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Tue, 7 Nov 2017 10:42:51 +0100 Subject: [PATCH 4/5] Update STLLoader.cpp Fix memory-alignment bug. --- code/STLLoader.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/STLLoader.cpp b/code/STLLoader.cpp index 6b71ba920..a492d47e8 100644 --- a/code/STLLoader.cpp +++ b/code/STLLoader.cpp @@ -80,7 +80,9 @@ static bool IsBinarySTL(const char* buffer, unsigned int fileSize) { return false; } - const uint32_t faceCount = *reinterpret_cast(buffer + 80); + char *facecount_pos = buffer + 80; + uint32_t faceCount( 0 ); + ::memcpy( &faceCount, facecount_pos, sizeof( uint32_t ) ); const uint32_t expectedBinaryFileSize = faceCount * 50 + 84; return expectedBinaryFileSize == fileSize; From da7ce89ff23425b217194c3d1bde06d4d2a5936b Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Tue, 7 Nov 2017 10:47:27 +0100 Subject: [PATCH 5/5] Update STLLoader.cpp add missing const. --- code/STLLoader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/STLLoader.cpp b/code/STLLoader.cpp index a492d47e8..600c4275d 100644 --- a/code/STLLoader.cpp +++ b/code/STLLoader.cpp @@ -80,7 +80,7 @@ static bool IsBinarySTL(const char* buffer, unsigned int fileSize) { return false; } - char *facecount_pos = buffer + 80; + const char *facecount_pos = buffer + 80; uint32_t faceCount( 0 ); ::memcpy( &faceCount, facecount_pos, sizeof( uint32_t ) ); const uint32_t expectedBinaryFileSize = faceCount * 50 + 84;