浏览代码

Merge pull request #1558 from assimp/issue_216

closes https://github.com/assimp/assimp/issues/216: check the area of…
Kim Kulling 7 年之前
父节点
当前提交
98a1b7671d

+ 0 - 1
code/FBXBinaryTokenizer.cpp

@@ -422,7 +422,6 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor,
     return true;
 }
 
-
 }
 
 // ------------------------------------------------------------------------------------------------

+ 76 - 36
code/FindDegenerates.cpp

@@ -56,98 +56,138 @@ using namespace Assimp;
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 FindDegeneratesProcess::FindDegeneratesProcess()
-: configRemoveDegenerates (false)
-{}
+: mConfigRemoveDegenerates( false )
+, mConfigCheckAreaOfTriangle( false ){
+    // empty
+}
 
 // ------------------------------------------------------------------------------------------------
 // Destructor, private as well
-FindDegeneratesProcess::~FindDegeneratesProcess()
-{
+FindDegeneratesProcess::~FindDegeneratesProcess() {
     // nothing to do here
 }
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
-bool FindDegeneratesProcess::IsActive( unsigned int pFlags) const
-{
+bool FindDegeneratesProcess::IsActive( unsigned int pFlags) const {
     return 0 != (pFlags & aiProcess_FindDegenerates);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Setup import configuration
-void FindDegeneratesProcess::SetupProperties(const Importer* pImp)
-{
+void FindDegeneratesProcess::SetupProperties(const Importer* pImp) {
     // Get the current value of AI_CONFIG_PP_FD_REMOVE
-    configRemoveDegenerates = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_REMOVE,0));
+    mConfigRemoveDegenerates = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_REMOVE,0));
+    mConfigCheckAreaOfTriangle = ( 0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_CHECKAREA) );
 }
 
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported data.
-void FindDegeneratesProcess::Execute( aiScene* pScene)
-{
+void FindDegeneratesProcess::Execute( aiScene* pScene) {
     DefaultLogger::get()->debug("FindDegeneratesProcess begin");
     for (unsigned int i = 0; i < pScene->mNumMeshes;++i){
-        ExecuteOnMesh( pScene->mMeshes[i]);
+        ExecuteOnMesh( pScene->mMeshes[ i ] );
     }
     DefaultLogger::get()->debug("FindDegeneratesProcess finished");
 }
 
+static ai_real heron( ai_real a, ai_real b, ai_real c ) {
+    ai_real s = (a + b + c) / 2;
+    ai_real area = pow((s * ( s - a ) * ( s - b ) * ( s - c ) ), 0.5 );
+    return area;
+}
+
+static ai_real distance3D( const aiVector3D &vA, aiVector3D &vB ) {
+    const ai_real lx = ( vB.x - vA.x );
+    const ai_real ly = ( vB.y - vA.y );
+    const ai_real lz = ( vB.z - vA.z );
+    ai_real a = lx*lx + ly*ly + lz*lz;
+    ai_real d = pow( a, 0.5 );
+
+    return d;
+}
+
+static ai_real calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh ) {
+    ai_real area = 0;
+
+    aiVector3D vA( mesh->mVertices[ face.mIndices[ 0 ] ] );
+    aiVector3D vB( mesh->mVertices[ face.mIndices[ 1 ] ] );
+    aiVector3D vC( mesh->mVertices[ face.mIndices[ 2 ] ] );
+
+    ai_real a( distance3D( vA, vB ) );
+    ai_real b( distance3D( vB, vC ) );
+    ai_real c( distance3D( vC, vA ) );
+    area = heron( a, b, c );
+
+    return area;
+}
+
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported mesh
-void FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh)
-{
+void FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
     mesh->mPrimitiveTypes = 0;
 
     std::vector<bool> remove_me;
-    if (configRemoveDegenerates)
-        remove_me.resize(mesh->mNumFaces,false);
+    if (mConfigRemoveDegenerates) {
+        remove_me.resize( mesh->mNumFaces, false );
+    }
 
     unsigned int deg = 0, limit;
-    for (unsigned int a = 0; a < mesh->mNumFaces; ++a)
-    {
+    for ( unsigned int a = 0; a < mesh->mNumFaces; ++a ) {
         aiFace& face = mesh->mFaces[a];
         bool first = true;
 
         // check whether the face contains degenerated entries
-        for (unsigned int i = 0; i < face.mNumIndices; ++i)
-        {
+        for (unsigned int i = 0; i < face.mNumIndices; ++i) {
             // Polygons with more than 4 points are allowed to have double points, that is
             // simulating polygons with holes just with concave polygons. However,
             // double points may not come directly after another.
             limit = face.mNumIndices;
-            if (face.mNumIndices > 4)
-                limit = std::min(limit,i+2);
+            if (face.mNumIndices > 4) {
+                limit = std::min( limit, i+2 );
+            }
 
-            for (unsigned int t = i+1; t < limit; ++t)
-            {
-                if (mesh->mVertices[face.mIndices[i]] == mesh->mVertices[face.mIndices[t]])
-                {
+            for (unsigned int t = i+1; t < limit; ++t) {
+                if (mesh->mVertices[face.mIndices[ i ] ] == mesh->mVertices[ face.mIndices[ t ] ]) {
                     // we have found a matching vertex position
                     // remove the corresponding index from the array
-                    --face.mNumIndices;--limit;
-                    for (unsigned int m = t; m < face.mNumIndices; ++m)
-                    {
-                        face.mIndices[m] = face.mIndices[m+1];
+                    --face.mNumIndices;
+                    --limit;
+                    for (unsigned int m = t; m < face.mNumIndices; ++m) {
+                        face.mIndices[ m ] = face.mIndices[ m+1 ];
                     }
                     --t;
 
                     // NOTE: we set the removed vertex index to an unique value
                     // to make sure the developer gets notified when his
                     // application attemps to access this data.
-                    face.mIndices[face.mNumIndices] = 0xdeadbeef;
+                    face.mIndices[ face.mNumIndices ] = 0xdeadbeef;
 
-                    if(first)
-                    {
+                    if(first) {
                         ++deg;
                         first = false;
                     }
 
-                    if (configRemoveDegenerates) {
-                        remove_me[a] = true;
+                    if ( mConfigRemoveDegenerates ) {
+                        remove_me[ a ] = true;
                         goto evil_jump_outside; // hrhrhrh ... yeah, this rocks baby!
                     }
                 }
             }
+
+            if ( mConfigCheckAreaOfTriangle ) {
+                if ( face.mNumIndices == 3 ) {
+                    ai_real area = calculateAreaOfTriangle( face, mesh );
+                    if ( area < 1e-6 ) {
+                        if ( mConfigRemoveDegenerates ) {
+                            remove_me[ a ] = true;
+                            goto evil_jump_outside;
+                        }
+
+                        // todo: check for index which is corrupt.
+                    }
+                }
+            }
         }
 
         // We need to update the primitive flags array of the mesh.
@@ -171,7 +211,7 @@ evil_jump_outside:
     }
 
     // If AI_CONFIG_PP_FD_REMOVE is true, remove degenerated faces from the import
-    if (configRemoveDegenerates && deg) {
+    if (mConfigRemoveDegenerates && deg) {
         unsigned int n = 0;
         for (unsigned int a = 0; a < mesh->mNumFaces; ++a)
         {

+ 40 - 19
code/FindDegenerates.h

@@ -54,15 +54,11 @@ namespace Assimp    {
 // ---------------------------------------------------------------------------
 /** FindDegeneratesProcess: Searches a mesh for degenerated triangles.
 */
-class ASSIMP_API FindDegeneratesProcess : public BaseProcess
-{
+class ASSIMP_API FindDegeneratesProcess : public BaseProcess {
 public:
-
     FindDegeneratesProcess();
     ~FindDegeneratesProcess();
 
-public:
-
     // -------------------------------------------------------------------
     // Check whether step is active
     bool IsActive( unsigned int pFlags) const;
@@ -79,28 +75,53 @@ public:
     // Execute step on a given mesh
     void ExecuteOnMesh( aiMesh* mesh);
 
+    // -------------------------------------------------------------------
+    /// @brief Enable the instant removal of degenerated primitives
+    /// @param enabled  true for enabled.
+    void EnableInstantRemoval(bool enabled);
+
+    // -------------------------------------------------------------------
+    /// @brief Check whether instant removal is currently enabled
+    /// @return The instant removal state.
+    bool IsInstantRemoval() const;
 
     // -------------------------------------------------------------------
-    /** @brief Enable the instant removal of degenerated primitives
-     *  @param d hm ... difficult to guess what this means, hu!?
-     */
-    void EnableInstantRemoval(bool d) {
-        configRemoveDegenerates = d;
-    }
+    /// @brief Enable the area check for triangles.
+    /// @param enabled  true for enabled.
+    void EnableAreaCheck( bool enabled );
 
     // -------------------------------------------------------------------
-    /** @brief Check whether instant removal is currently enabled
-     *  @return ...
-     */
-    bool IsInstantRemoval() const {
-        return configRemoveDegenerates;
-    }
+    /// @brief Check whether the area check is enabled.
+    /// @return The area check state.
+    bool isAreaCheckEnabled() const;
 
 private:
-
     //! Configuration option: remove degenerates faces immediately
-    bool configRemoveDegenerates;
+    bool mConfigRemoveDegenerates;
+    //! Configuration option: check for area
+    bool mConfigCheckAreaOfTriangle;
 };
+
+inline
+void FindDegeneratesProcess::EnableInstantRemoval(bool enabled) {
+    mConfigRemoveDegenerates = enabled;
 }
 
+inline
+bool FindDegeneratesProcess::IsInstantRemoval() const {
+    return mConfigRemoveDegenerates;
+}
+
+inline
+void FindDegeneratesProcess::EnableAreaCheck( bool enabled ) {
+    mConfigCheckAreaOfTriangle = enabled;
+}
+
+inline
+bool FindDegeneratesProcess::isAreaCheckEnabled() const {
+    return mConfigCheckAreaOfTriangle;
+}
+
+} // Namespace Assimp
+
 #endif // !! AI_FINDDEGENERATESPROCESS_H_INC

+ 0 - 6
code/STLLoader.cpp

@@ -207,12 +207,6 @@ void STLImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
         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->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();

+ 6 - 2
code/X3DExporter.cpp

@@ -240,8 +240,12 @@ list<SAttribute> attr_list;
 		if((rotate_angle != 0) && (rotate_axis.Length() > 0))
 			attr_list.push_back({"rotation", Rotation2String(rotate_axis, rotate_angle)});
 
-		if(!scale.Equal({1, 1, 1})) attr_list.push_back({"scale", Vector2String(scale)});
-		if(translate.Length() > 0) attr_list.push_back({"translation", Vector2String(translate)});
+        if(!scale.Equal({1.0,1.0,1.0})) {
+            attr_list.push_back({"scale", Vector2String(scale)});
+        }
+        if(translate.Length() > 0) {
+            attr_list.push_back({"translation", Vector2String(translate)});
+        }
 	}
 
 	// Begin node if need.

+ 1 - 4
code/XFileImporter.h

@@ -65,14 +65,11 @@ struct Node;
 /** The XFileImporter is a worker class capable of importing a scene from a
  * DirectX file .x
  */
-class XFileImporter : public BaseImporter
-{
+class XFileImporter : public BaseImporter {
 public:
     XFileImporter();
     ~XFileImporter();
 
-
-public:
     // -------------------------------------------------------------------
     /** Returns whether the class can handle the format of the given file.
      * See BaseImporter::CanRead() for details. */

+ 9 - 0
include/assimp/config.h.in

@@ -266,6 +266,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define AI_CONFIG_PP_FD_REMOVE \
     "PP_FD_REMOVE"
 
+// ---------------------------------------------------------------------------
+/**
+ *  @brief  Configures the #aiProcess_FindDegenerates to check the area of a
+ *  trinagle to be greates than e-6. If this is not the case the triangle will
+ *  be removed if #AI_CONFIG_PP_FD_REMOVE is set to true.
+ */
+#define AI_CONFIG_PP_FD_CHECKAREA \
+    "PP_FD_CHECKAREA"
+
 // ---------------------------------------------------------------------------
 /** @brief Configures the #aiProcess_OptimizeGraph step to preserve nodes
  * matching a name in a given list.

+ 4 - 5
include/assimp/vector3.h

@@ -65,11 +65,10 @@ template <typename TReal>
 class aiVector3t
 {
 public:
-
-    aiVector3t () : x(), y(), z() {}
-    aiVector3t (TReal _x, TReal _y, TReal _z) : x(_x), y(_y), z(_z) {}
-    explicit aiVector3t (TReal _xyz) : x(_xyz), y(_xyz), z(_xyz) {}
-    aiVector3t (const aiVector3t& o) : x(o.x), y(o.y), z(o.z) {}
+    aiVector3t() : x(), y(), z() {}
+    aiVector3t(TReal _x, TReal _y, TReal _z) : x(_x), y(_y), z(_z) {}
+    explicit aiVector3t (TReal _xyz ) : x(_xyz), y(_xyz), z(_xyz) {}
+    aiVector3t( const aiVector3t& o ) : x(o.x), y(o.y), z(o.z) {}
 
 public:
 

+ 12 - 11
test/unit/utFindDegenerates.cpp

@@ -58,8 +58,7 @@ protected:
 };
 
 // ------------------------------------------------------------------------------------------------
-void FindDegeneratesProcessTest::SetUp()
-{
+void FindDegeneratesProcessTest::SetUp() {
     mesh = new aiMesh();
     process = new FindDegeneratesProcess();
 
@@ -107,16 +106,12 @@ void FindDegeneratesProcessTest::SetUp()
     mesh->mNumUVComponents[1] = numFaces;
 }
 
-// ------------------------------------------------------------------------------------------------
-void FindDegeneratesProcessTest::TearDown()
-{
+void FindDegeneratesProcessTest::TearDown() {
     delete mesh;
     delete process;
 }
 
-// ------------------------------------------------------------------------------------------------
-TEST_F(FindDegeneratesProcessTest, testDegeneratesDetection)
-{
+TEST_F(FindDegeneratesProcessTest, testDegeneratesDetection) {
     process->EnableInstantRemoval(false);
     process->ExecuteOnMesh(mesh);
 
@@ -135,12 +130,18 @@ TEST_F(FindDegeneratesProcessTest, testDegeneratesDetection)
               mesh->mPrimitiveTypes);
 }
 
-// ------------------------------------------------------------------------------------------------
-TEST_F(FindDegeneratesProcessTest, testDegeneratesRemoval)
-{
+TEST_F(FindDegeneratesProcessTest, testDegeneratesRemoval) {
+    process->EnableAreaCheck(false);
     process->EnableInstantRemoval(true);
     process->ExecuteOnMesh(mesh);
 
     EXPECT_EQ(mesh->mNumUVComponents[1], mesh->mNumFaces);
 }
 
+TEST_F(FindDegeneratesProcessTest, testDegeneratesRemovalWithAreaCheck) {
+    process->EnableAreaCheck(true);
+    process->EnableInstantRemoval(true);
+    process->ExecuteOnMesh(mesh);
+
+    EXPECT_EQ(mesh->mNumUVComponents[1]-100, mesh->mNumFaces);
+}