diff --git a/code/Exporter.cpp b/code/Exporter.cpp index 0a8f054b7..53a623ecd 100644 --- a/code/Exporter.cpp +++ b/code/Exporter.cpp @@ -62,6 +62,7 @@ Here we implement only the C++ interface (Assimp::Exporter). #include "JoinVerticesProcess.h" #include "MakeVerboseFormat.h" #include "ConvertToLHProcess.h" +#include "PretransformVertices.h" #include #include "ScenePrivate.h" #include @@ -397,6 +398,11 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c } } + bool exportPointCloud(false); + if (nullptr != pProperties) { + exportPointCloud = pProperties->GetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS); + } + // dispatch other processes for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) { BaseProcess* const p = pimpl->mPostProcessingSteps[a]; @@ -405,7 +411,9 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c && !dynamic_cast(p) && !dynamic_cast(p) && !dynamic_cast(p)) { - + if (dynamic_cast(p) && exportPointCloud) { + continue; + } p->Execute(scenecopy.get()); } } @@ -441,7 +449,6 @@ const char* Exporter::GetErrorString() const { return pimpl->mError.c_str(); } - // ------------------------------------------------------------------------------------------------ void Exporter::FreeBlob() { delete pimpl->blob; @@ -495,7 +502,8 @@ aiReturn Exporter::RegisterExporter(const ExportFormatEntry& desc) { // ------------------------------------------------------------------------------------------------ void Exporter::UnregisterExporter(const char* id) { - for(std::vector::iterator it = pimpl->mExporters.begin(); it != pimpl->mExporters.end(); ++it) { + for(std::vector::iterator it = pimpl->mExporters.begin(); + it != pimpl->mExporters.end(); ++it) { if (!strcmp((*it).mDescription.id,id)) { pimpl->mExporters.erase(it); break; diff --git a/code/PretransformVertices.cpp b/code/PretransformVertices.cpp index 0623f00ef..9745abd60 100644 --- a/code/PretransformVertices.cpp +++ b/code/PretransformVertices.cpp @@ -60,14 +60,17 @@ using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer PretransformVertices::PretransformVertices() -: configKeepHierarchy (false), configNormalize(false), configTransform(false), configTransformation() -{ +: configKeepHierarchy (false) +, configNormalize(false) +, configTransform(false) +, configTransformation() +, mConfigPointCloud( false ) { + // empty } // ------------------------------------------------------------------------------------------------ // Destructor, private as well -PretransformVertices::~PretransformVertices() -{ +PretransformVertices::~PretransformVertices() { // nothing to do here } @@ -89,6 +92,8 @@ void PretransformVertices::SetupProperties(const Importer* pImp) configTransform = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION,0)); configTransformation = pImp->GetPropertyMatrix(AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION, aiMatrix4x4()); + + mConfigPointCloud = pImp->GetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS); } // ------------------------------------------------------------------------------------------------ @@ -502,9 +507,7 @@ void PretransformVertices::Execute( aiScene* pScene) pScene->mMeshes[i]->mBones = NULL; pScene->mMeshes[i]->mNumBones = 0; } - } - else { - + } else { apcOutMeshes.reserve(pScene->mNumMaterials<<1u); std::list aiVFormats; @@ -556,7 +559,8 @@ void PretransformVertices::Execute( aiScene* pScene) } // If no meshes are referenced in the node graph it is possible that we get no output meshes. - if (apcOutMeshes.empty()) { + if (apcOutMeshes.empty()) { + throw DeadlyImportError("No output meshes: all meshes are orphaned and are not referenced by any nodes"); } else diff --git a/code/PretransformVertices.h b/code/PretransformVertices.h index 8b400dc0c..a8196289d 100644 --- a/code/PretransformVertices.h +++ b/code/PretransformVertices.h @@ -61,15 +61,11 @@ namespace Assimp { * and removes the whole graph. The output is a list of meshes, one for * each material. */ -class ASSIMP_API PretransformVertices : public BaseProcess -{ +class ASSIMP_API PretransformVertices : public BaseProcess { public: - PretransformVertices (); ~PretransformVertices (); -public: - // ------------------------------------------------------------------- // Check whether step is active bool IsActive( unsigned int pFlags) const; @@ -82,7 +78,6 @@ public: // Setup import settings void SetupProperties(const Importer* pImp); - // ------------------------------------------------------------------- /** @brief Toggle the 'keep hierarchy' option * @param d hm ... difficult to guess what this means, hu!? @@ -100,7 +95,6 @@ public: } private: - // ------------------------------------------------------------------- // Count the number of nodes unsigned int CountNodes( aiNode* pcNode ); @@ -161,6 +155,7 @@ private: bool configNormalize; bool configTransform; aiMatrix4x4 configTransformation; + bool mConfigPointCloud; }; } // end of namespace Assimp diff --git a/code/RemoveRedundantMaterials.h b/code/RemoveRedundantMaterials.h index 37b69ffbe..314bbf345 100644 --- a/code/RemoveRedundantMaterials.h +++ b/code/RemoveRedundantMaterials.h @@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include class RemoveRedundantMatsTest; + namespace Assimp { // --------------------------------------------------------------------------- diff --git a/code/STLExporter.cpp b/code/STLExporter.cpp index 5f9bfbde2..dd4df9212 100644 --- a/code/STLExporter.cpp +++ b/code/STLExporter.cpp @@ -141,13 +141,15 @@ STLExporter::STLExporter(const char* _filename, const aiScene* pScene, bool expo mOutput << " facet normal " << nor.x << " " << nor.y << " " << nor.z << endl; for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { aiMesh *mesh = pScene->mMeshes[i]; - if (mesh->mNormals) { - for (unsigned int a = 0; a < mesh->mNumVertices; ++a) { - const aiVector3D& v = mesh->mVertices[a]; - mOutput << " vertex " << v.x << " " << v.y << " " << v.z << endl; - mOutput << " vertex " << v.x << " " << v.y << " " << v.z << endl; - mOutput << " vertex " << v.x << " " << v.y << " " << v.z << endl; - } + if (nullptr == mesh) { + continue; + } + + for (unsigned int a = 0; a < mesh->mNumVertices; ++a) { + const aiVector3D& v = mesh->mVertices[a]; + mOutput << " vertex " << v.x << " " << v.y << " " << v.z << endl; + mOutput << " vertex " << v.x << " " << v.y << " " << v.z << endl; + mOutput << " vertex " << v.x << " " << v.y << " " << v.z << endl; } } mOutput << "endsolid " << name << endl; @@ -163,7 +165,7 @@ STLExporter::STLExporter(const char* _filename, const aiScene* pScene, bool expo } // ------------------------------------------------------------------------------------------------ -void STLExporter :: WriteMesh(const aiMesh* m) +void STLExporter::WriteMesh(const aiMesh* m) { for (unsigned int i = 0; i < m->mNumFaces; ++i) { const aiFace& f = m->mFaces[i]; diff --git a/code/STLExporter.h b/code/STLExporter.h index a1d306944..51a440de7 100644 --- a/code/STLExporter.h +++ b/code/STLExporter.h @@ -52,8 +52,7 @@ struct aiScene; struct aiNode; struct aiMesh; -namespace Assimp -{ +namespace Assimp { // ------------------------------------------------------------------------------------------------ /** Helper class to export a given scene to a STL file. */ diff --git a/test/unit/utPLYImportExport.cpp b/test/unit/utPLYImportExport.cpp index c009bda39..5aabe0805 100644 --- a/test/unit/utPLYImportExport.cpp +++ b/test/unit/utPLYImportExport.cpp @@ -138,18 +138,19 @@ TEST_F( utPLYImportExport, vertexColorTest ) { EXPECT_EQ(2u, first_face.mIndices[2]); } -//Test issue #623, PLY importer should not automatically create faces +// Test issue #623, PLY importer should not automatically create faces TEST_F(utPLYImportExport, pointcloudTest) { - Assimp::Importer importer; - //Could not use aiProcess_ValidateDataStructure since it's missing faces. - const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/PLY/issue623.ply", 0); - EXPECT_NE(nullptr, scene); + Assimp::Importer importer; - EXPECT_EQ(1u, scene->mNumMeshes); - EXPECT_NE(nullptr, scene->mMeshes[0]); - EXPECT_EQ(24u, scene->mMeshes[0]->mNumVertices); - EXPECT_EQ(aiPrimitiveType::aiPrimitiveType_POINT, scene->mMeshes[0]->mPrimitiveTypes); - EXPECT_EQ(0u, scene->mMeshes[0]->mNumFaces); + //Could not use aiProcess_ValidateDataStructure since it's missing faces. + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/PLY/issue623.ply", 0); + EXPECT_NE(nullptr, scene); + + EXPECT_EQ(1u, scene->mNumMeshes); + EXPECT_NE(nullptr, scene->mMeshes[0]); + EXPECT_EQ(24u, scene->mMeshes[0]->mNumVertices); + EXPECT_EQ(aiPrimitiveType::aiPrimitiveType_POINT, scene->mMeshes[0]->mPrimitiveTypes); + EXPECT_EQ(0u, scene->mMeshes[0]->mNumFaces); } static const char *test_file = diff --git a/test/unit/utSTLImportExport.cpp b/test/unit/utSTLImportExport.cpp index 0cb9f73ee..aad6b0fa1 100644 --- a/test/unit/utSTLImportExport.cpp +++ b/test/unit/utSTLImportExport.cpp @@ -47,6 +47,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include +#include + +#include using namespace Assimp; @@ -68,3 +72,60 @@ TEST_F( utSTLImporterExporter, test_with_two_solids ) { const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/STL/triangle_with_two_solids.stl", aiProcess_ValidateDataStructure ); EXPECT_NE( nullptr, scene ); } + +#ifndef ASSIMP_BUILD_NO_EXPORT + +TEST_F(utSTLImporterExporter, test_export_pointclouds) { + struct XYZ { + float x, y, z; + }; + + std::vector points; + + for (size_t i = 0; i < 10; ++i) { + XYZ current; + current.x = static_cast(i); + current.y = static_cast(i); + current.z = static_cast(i); + points.push_back(current); + } + aiScene scene; + scene.mRootNode = new aiNode(); + + scene.mMeshes = new aiMesh*[1]; + scene.mMeshes[0] = nullptr; + scene.mNumMeshes = 1; + + scene.mMaterials = new aiMaterial*[1]; + scene.mMaterials[0] = nullptr; + scene.mNumMaterials = 1; + + scene.mMaterials[0] = new aiMaterial(); + + scene.mMeshes[0] = new aiMesh(); + scene.mMeshes[0]->mMaterialIndex = 0; + + scene.mRootNode->mMeshes = new unsigned int[1]; + scene.mRootNode->mMeshes[0] = 0; + scene.mRootNode->mNumMeshes = 1; + + auto pMesh = scene.mMeshes[0]; + + long numValidPoints = points.size(); + + pMesh->mVertices = new aiVector3D[numValidPoints]; + pMesh->mNumVertices = numValidPoints; + + int i = 0; + for (XYZ &p : points) { + pMesh->mVertices[i] = aiVector3D(p.x, p.y, p.z); + ++i; + } + + Assimp::Exporter mAiExporter; + ExportProperties *properties = new ExportProperties; + properties->SetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS, true); + mAiExporter.Export(&scene, "stl", "testExport.stl", 0, properties ); +} + +#endif