diff --git a/VirtualRobot/Import/MeshImport/AssimpReader.cpp b/VirtualRobot/Import/MeshImport/AssimpReader.cpp
index 9f7ece6190ae4889b4f2414afe8905e452548f95..b7742c6edb81ae7fb8d9bc4228f0f1ae5b0d6654 100644
--- a/VirtualRobot/Import/MeshImport/AssimpReader.cpp
+++ b/VirtualRobot/Import/MeshImport/AssimpReader.cpp
@@ -9,8 +9,17 @@
 
 namespace
 {
-    bool readScene(const aiScene* scene, const VirtualRobot::TriMeshModelPtr& t, const std::string& filename, float scaling, float eps, bool mergeMultipleMeshes, bool ignoreMissingNormals)
+    bool readScene(
+        const aiScene* scene,
+        const VirtualRobot::TriMeshModelPtr& t,
+        const std::string& filename,
+        const VirtualRobot::AssimpReader::Parameters& param,
+        VirtualRobot::AssimpReader::ResultMetaData& meta
+    )
     {
+        meta.loadingSuccessful = false;
+        meta.regeneratedNormals = false;
+        meta.skippedFaces = 0;
         if (!t)
         {
             VR_ERROR << "Tri mesh is null\n";
@@ -31,7 +40,7 @@ namespace
             VR_ERROR << "mesh from '" << filename << "' has no mesh\n";
             return false;
         }
-        if (scene->mNumMeshes > 1 && !mergeMultipleMeshes)
+        if (scene->mNumMeshes > 1 && !param.mergeMultipleMeshes)
         {
             VR_ERROR << "mesh from '" << filename << "' has not exactly one mesh"
                      << " It has " << scene->mNumMeshes << " meshes\n";
@@ -63,12 +72,13 @@ namespace
             }
             if (!m.mNormals)
             {
-                if (!ignoreMissingNormals)
+                if (!param.ignoreMissingNormals)
                 {
                     error_log << " has no normals (and none were generated when loading it)\n";
                     return false;
                 }
                 error_log << " has no normals (and none were generated when loading it) (ignoring this)\n";
+                meta.regeneratedNormals = true;
             }
 
             for (unsigned i = 0; i < m.mNumVertices; ++i)
@@ -89,6 +99,12 @@ namespace
                     error_log << " has face (# " << i
                               << ") with the wrong number of vertices ("
                               << f.mNumIndices << ")\n";
+                    if (param.skipInvalidFaces)
+                    {
+                        ++meta.skippedFaces;
+                        continue;
+                    }
+
                     return false;
                 }
                 if (
@@ -113,18 +129,21 @@ namespace
 #undef error_log
         }
 
-        t->scale(scaling);
-        t->mergeVertices(eps);
+        t->scale(param.scaling);
+        t->mergeVertices(param.eps);
         t->addMissingNormals();
+        meta.loadingSuccessful = true;
         return true;
     }
 }
 
 namespace VirtualRobot
 {
-    AssimpReader::AssimpReader(float eps, float scaling) :
-        scaling{scaling}, eps{eps}
-    {}
+    AssimpReader::AssimpReader(float eps, float scaling)
+    {
+        parameters.scaling = scaling;
+        parameters.eps = eps;
+    }
 
     std::string AssimpReader::get_extensions()
     {
@@ -148,7 +167,7 @@ namespace VirtualRobot
         return extensions;
     }
 
-    bool AssimpReader::readFileAsTriMesh(const std::string& filename, const TriMeshModelPtr& t, bool mergeMultipleMeshes, bool ignoreMissingNormals)
+    bool AssimpReader::readFileAsTriMesh(const std::string& filename, const TriMeshModelPtr& t)
     {
         //code adapted from http://assimp.sourceforge.net/lib_html/usage.html
         Assimp::Importer importer;
@@ -162,9 +181,9 @@ namespace VirtualRobot
                                    aiProcess_GenSmoothNormals         |
                                    aiProcess_SortByPType
                                );
-        return readScene(scene, t, filename, scaling, eps, mergeMultipleMeshes, ignoreMissingNormals);
+        return readScene(scene, t, filename, parameters, resultMetaData);
     }
-    bool AssimpReader::readBufferAsTriMesh(const std::string_view& v, const TriMeshModelPtr& t, bool mergeMultipleMeshes, bool ignoreMissingNormals)
+    bool AssimpReader::readBufferAsTriMesh(const std::string_view& v, const TriMeshModelPtr& t)
     {
         //code adapted from http://assimp.sourceforge.net/lib_html/usage.html
         Assimp::Importer importer;
@@ -178,59 +197,44 @@ namespace VirtualRobot
                                    aiProcess_GenSmoothNormals         |
                                    aiProcess_SortByPType
                                );
-        return readScene(scene, t, "<MEMORY_BUFFER>", scaling, eps, mergeMultipleMeshes, ignoreMissingNormals);
+        return readScene(scene, t, "<MEMORY_BUFFER>", parameters, resultMetaData);
     }
 
-    TriMeshModelPtr AssimpReader::readFileAsTriMesh(const std::string& filename, bool mergeMultipleMeshes, bool ignoreMissingNormals)
+    TriMeshModelPtr AssimpReader::readFileAsTriMesh(const std::string& filename)
     {
         auto tri = boost::make_shared<TriMeshModel>();
-        if (!readFileAsTriMesh(filename, tri, mergeMultipleMeshes, ignoreMissingNormals))
+        if (!readFileAsTriMesh(filename, tri))
         {
             return nullptr;
         }
         return tri;
     }
 
-    TriMeshModelPtr AssimpReader::readBufferAsTriMesh(const std::string_view& v, bool mergeMultipleMeshes, bool ignoreMissingNormals)
+    TriMeshModelPtr AssimpReader::readBufferAsTriMesh(const std::string_view& v)
     {
         auto tri = boost::make_shared<TriMeshModel>();
-        if (!readBufferAsTriMesh(v, tri, mergeMultipleMeshes, ignoreMissingNormals))
+        if (!readBufferAsTriMesh(v, tri))
         {
             return nullptr;
         }
         return tri;
     }
 
-    ManipulationObjectPtr AssimpReader::readFileAsManipulationObject(const std::string& filename, const std::string& name, bool mergeMultipleMeshes, bool ignoreMissingNormals)
+    ManipulationObjectPtr AssimpReader::readFileAsManipulationObject(const std::string& filename, const std::string& name)
     {
-        if (auto tri = readFileAsTriMesh(filename, mergeMultipleMeshes, ignoreMissingNormals))
+        if (auto tri = readFileAsTriMesh(filename))
         {
             return boost::make_shared<ManipulationObject>(name, tri, filename);
         }
         return nullptr;
     }
-    ManipulationObjectPtr AssimpReader::readBufferAsManipulationObject(const std::string_view& v, const std::string& name, bool mergeMultipleMeshes, bool ignoreMissingNormals)
+    ManipulationObjectPtr AssimpReader::readBufferAsManipulationObject(const std::string_view& v, const std::string& name)
     {
-        if (auto tri = readBufferAsTriMesh(v, mergeMultipleMeshes, ignoreMissingNormals))
+        if (auto tri = readBufferAsTriMesh(v))
         {
             return boost::make_shared<ManipulationObject>(name, tri);
         }
         return nullptr;
     }
-
-    void AssimpReader::set_epsilon(float _eps)
-    {
-        eps = _eps;
-    }
-
-    float AssimpReader::epsilon() const
-    {
-        return eps;
-    }
-
-    void AssimpReader::setScaling(float s)
-    {
-        scaling = s;
-    }
 }
 
diff --git a/VirtualRobot/Import/MeshImport/AssimpReader.h b/VirtualRobot/Import/MeshImport/AssimpReader.h
index f6c48efd5f2f01a4383ea917b0803015d888945e..77f18d436b93567e4733e522921d71c6cf6f7566 100644
--- a/VirtualRobot/Import/MeshImport/AssimpReader.h
+++ b/VirtualRobot/Import/MeshImport/AssimpReader.h
@@ -22,26 +22,34 @@ namespace VirtualRobot
         static std::string get_extensions();
 
         // read data and store it to trimesh
-        bool readFileAsTriMesh(const std::string& _filename, const TriMeshModelPtr& t, bool mergeMultipleMeshes = false, bool ignoreMissingNormals = false);
-        bool readBufferAsTriMesh(const std::string_view& v, const TriMeshModelPtr& t, bool mergeMultipleMeshes = false, bool ignoreMissingNormals = false);
+        bool readFileAsTriMesh(const std::string& _filename, const TriMeshModelPtr& t);
+        bool readBufferAsTriMesh(const std::string_view& v, const TriMeshModelPtr& t);
 
-        TriMeshModelPtr readFileAsTriMesh(const std::string& filename, bool mergeMultipleMeshes = false, bool ignoreMissingNormals = false);
-        TriMeshModelPtr readBufferAsTriMesh(const std::string_view& v, bool mergeMultipleMeshes = false, bool ignoreMissingNormals = false);
+        TriMeshModelPtr readFileAsTriMesh(const std::string& filename);
+        TriMeshModelPtr readBufferAsTriMesh(const std::string_view& v);
 
-        ManipulationObjectPtr readFileAsManipulationObject(const std::string& filename, const std::string& name = "", bool mergeMultipleMeshes = false, bool ignoreMissingNormals = false);
-        ManipulationObjectPtr readBufferAsManipulationObject(const std::string_view& v, const std::string& name = "", bool mergeMultipleMeshes = false, bool ignoreMissingNormals = false);
-
-        /** Set the threshold to be used for considering two point to be equal.
-            Can be used to merge small gaps */
-        void set_epsilon(float _eps);
-
-        /// Returns the threshold to be used for considering two point to be equal.
-        float epsilon() const;
+        ManipulationObjectPtr readFileAsManipulationObject(const std::string& filename, const std::string& name = "");
+        ManipulationObjectPtr readBufferAsManipulationObject(const std::string_view& v, const std::string& name = "");
+        
+        struct Parameters
+        {
+            float scaling = 1;
+            /// Returns the threshold to be used for considering two point to be equal.
+            float eps = FLT_MIN;
+            bool mergeMultipleMeshes = false;
+            bool ignoreMissingNormals = false;
+            bool skipInvalidFaces = false;
+        };
+        Parameters parameters;
+
+        struct ResultMetaData
+        {
+            std::size_t skippedFaces = 0;
+            bool loadingSuccessful  = false;
+            bool regeneratedNormals  = false;
+        };
 
-        void setScaling(float s);
-    private:
-        float scaling;
-        float eps;
+        ResultMetaData resultMetaData;
     };
 
     typedef boost::shared_ptr<AssimpReader> AssimpReaderPtr;
diff --git a/VirtualRobot/Visualization/CoinVisualization/CoinVisualizationFactory.cpp b/VirtualRobot/Visualization/CoinVisualization/CoinVisualizationFactory.cpp
index 04da6baa1b1ca9ca1c790274d64070a7e14550a6..7f8c7ba80f52a5147a4b5de5a7729dea87e3785c 100644
--- a/VirtualRobot/Visualization/CoinVisualization/CoinVisualizationFactory.cpp
+++ b/VirtualRobot/Visualization/CoinVisualization/CoinVisualizationFactory.cpp
@@ -278,8 +278,9 @@ namespace VirtualRobot
         // try to read from file
         TriMeshModelPtr t(new TriMeshModel());
         AssimpReader r;
-        r.setScaling(1000.0f); // mm
-        bool readOK = r.readFileAsTriMesh(filename, t, true);
+        r.parameters.scaling = 1000.0f; // mm
+        r.parameters.mergeMultipleMeshes = true;
+        bool readOK = r.readFileAsTriMesh(filename, t);
 
         if (!readOK)
         {
@@ -393,19 +394,17 @@ namespace VirtualRobot
 
     VisualizationPtr CoinVisualizationFactory::getVisualization(const std::vector<VisualizationNodePtr>& visus)
     {
-        boost::shared_ptr<CoinVisualization> v(new CoinVisualization(visus));
-        return v;
+        return boost::make_shared<CoinVisualization>(visus);
     }
 
     VisualizationPtr CoinVisualizationFactory::getVisualization(VisualizationNodePtr visu)
     {
-        boost::shared_ptr<CoinVisualization> v(new CoinVisualization(visu));
-        return v;
+        return boost::make_shared<CoinVisualization>(visu);
     }
 
     SoSeparator* CoinVisualizationFactory::CreateBoundingBox(SoNode* ivModel, bool wireFrame)
     {
-        THROW_VR_EXCEPTION_IF(!ivModel, "NULL ivModel!");
+        THROW_VR_EXCEPTION_IF(!ivModel, "NULL ivModel!")
 
         float minX;
         float minY;
@@ -869,8 +868,8 @@ namespace VirtualRobot
 
             float theta = 0.0f;
             float phi = 0.0f;
-            float verticalAngularStride = (float)(M_PI * 2.0f) / (float)rings;
-            float horizontalAngularStride = ((float)M_PI * 2.0f) / (float)sides;
+            float verticalAngularStride = static_cast<float>((M_PI * 2.0f) / rings);
+            float horizontalAngularStride = static_cast<float>((M_PI * 2.0f) / sides);
 
             for (int verticalIt = 0; verticalIt < numVerticesPerColumn; verticalIt++)
             {