Show / Hide Table of Contents
    ///////////////////////////////////////////////////////////////////////////
    //
    //  System:    Simplygon
    //  File:      GeometryValidityTesting.cpp
    //  Language:  C++
    //
    //  Copyright (c) 2019 Microsoft. All rights reserved.
    //
    //  This is private property, and it is illegal to copy or distribute in
    //  any form, without written authorization by the copyright owner(s).
    //
    ///////////////////////////////////////////////////////////////////////////
    //
    //  #Description#
    //
    //  This example demonstrates how to look through a GeometryData-object and 
    //  make sure all stored data inside is valid, and that it is stored 
    //  correctly. The local function ValidateGeometry() gives an example of how
    //  the geometry can be validated manually.
    //
    //  The IGeometryValidator class is also used on the geometry to display 
    //  how you can simply use it to validate your geometries and get a string
    //  error message with description of any non-valid parts with the geometry.
    //
    ///////////////////////////////////////////////////////////////////////////
    
    #include "../Common/Example.h"
    
    void RunExample( const std::string& readFrom );
    bool CheckArray( IValueArray* arr, unsigned int tuplecount, unsigned int tuplesize );
    bool CheckGeometry( IGeometryData* geom );
    void ValidateGeometry( IGeometryData* geom );
    
    int main( int argc, char* argv[] )
        {
        try
        {
            // Initiate
            InitExample();
    
            // Run the example code
            std::string assetPath = GetAssetPath();
            RunExample(assetPath + "testobject.obj");
    
            // Deinitialize the SDK
            DeinitExample();
        }
        catch (const std::exception& ex)
        {
            std::cerr << ex.what() << std::endl;
            return -1;
        }
    
        return 0;
        }
    
    void RunExample( const std::string& readFrom )
        {
        // Load from file
        spWavefrontImporter objReader = sg->CreateWavefrontImporter();
        objReader->SetImportFilePath( readFrom.c_str() );
        if( !objReader->RunImport() )
            throw std::exception("Failed to load input file!");
    
        // Get the scene from the importer
        spScene scene = objReader->GetScene();
    
        // First running the loaded scene. Should be ok!
        if( true )
            {
            std::cout << "Validating the original geometry." << std::endl;
            spGeometryData geometry = scene->NewCombinedGeometry();
            ValidateGeometry( geometry );
    
            //Using the IGeometryValidator class
            spGeometryValidator geometryValidator = sg->CreateGeometryValidator();
            geometryValidator->ValidateGeometry( geometry );
            rid error_value = geometryValidator->GetErrorValue();
            rstring error_string = geometryValidator->GetErrorString();
            printf( "\nIGeometryValidator: %s\n\n\n", error_string.GetText() );
            }
    
        // Now we mess up the Geometry some.
        // Here we set the vertex index to an invalid index.
        if( true )
            {
            std::cout << "\nValidating the geometry with invalid index." << std::endl;
            spGeometryData geometry = scene->NewCombinedGeometry();
            geometry->GetVertexIds()->SetItem( 73, geometry->GetVertexCount() + 1 );
            // Lets validate again!
            ValidateGeometry( geometry );
    
            //Using the IGeometryValidator class
            spGeometryValidator geometryValidator = sg->CreateGeometryValidator();
            geometryValidator->ValidateGeometry( geometry );
            rid error_value = geometryValidator->GetErrorValue();
            rstring error_string = geometryValidator->GetErrorString();
            printf( "\nIGeometryValidator: %s\n\n\n", error_string.GetText() );
            }
    
        // Another way to mess up the Geometry.
        // This time we set an illegal tuplesize.
        if( true )
            {
            std::cout << "\nValidating the geometry with invalid tuplesize." << std::endl;
            spGeometryData geometry = scene->NewCombinedGeometry();
            geometry->GetCoords()->SetTupleSize( 4 );
            // Lets validate again!
            ValidateGeometry( geometry );
    
            //Using the IGeometryValidator class
            spGeometryValidator geometryValidator = sg->CreateGeometryValidator();
            geometryValidator->ValidateGeometry( geometry );
            rid error_value = geometryValidator->GetErrorValue();
            rstring error_string = geometryValidator->GetErrorString();
            printf( "\nIGeometryValidator: %s\n\n\n", error_string.GetText() );
            }
    
    
        // Another way to mess up the Geometry.
        // Create a degenerate triangle where two vertices in the triangle are the same vertex
        if( true )
            {
            std::cout << "\nValidating the geometry with a degenerate triangle." << std::endl;
            spGeometryData geometry = scene->NewCombinedGeometry();
            geometry->GetVertexIds()->SetItem( 10 * 3 + 0, geometry->GetVertexIds()->GetItem( 10 * 3 + 1 ) );
    
            //Using the IGeometryValidator class
            spGeometryValidator geometryValidator = sg->CreateGeometryValidator();
            geometryValidator->ValidateGeometry( geometry );
            rid error_value = geometryValidator->GetErrorValue();
            rstring error_string = geometryValidator->GetErrorString();
            printf( "\nIGeometryValidator: %s\n\n\n", error_string.GetText() );
            }
    
    
        // Another way to mess up the Geometry.
        // Create a zero area triangle
        if( true )
            {
            std::cout << "\nValidating the geometry with a zero area triangle." << std::endl;
            spGeometryData geometry = scene->NewCombinedGeometry();
    
            geometry->GetCoords()->SetItem( 0, geometry->GetCoords()->GetItem( 3 ) );
            geometry->GetCoords()->SetItem( 1, geometry->GetCoords()->GetItem( 4 ) );
            geometry->GetCoords()->SetItem( 2, geometry->GetCoords()->GetItem( 5 ) );
    
            //Using the IGeometryValidator class
            spGeometryValidator geometryValidator = sg->CreateGeometryValidator();
            geometryValidator->ValidateGeometry( geometry );
            rid error_value = geometryValidator->GetErrorValue();
            rstring error_string = geometryValidator->GetErrorString();
            printf( "\nIGeometryValidator: %s\n\n\n", error_string.GetText() );
            }
        }
    
    void ValidateGeometry( IGeometryData* geom )
        {
        //bool passedtest = CheckGeometry( geom );
        spGeometryValidator validator = sg->CreateGeometryValidator();
        bool passedtest = validator->ValidateGeometry( geom );
    
        if( !passedtest )
            std::cout << "Geometry failed test" << std::endl;
        else
            std::cout << "Geometry passed test" << std::endl;
        }
    
    bool CheckGeometry( IGeometryData* geom )
        {
        // Check geometry for consistency
        unsigned int vertex_count = geom->GetVertexCount();
        unsigned int triangle_count = geom->GetTriangleCount();
        unsigned int corner_count = triangle_count * 3;
    
        if( triangle_count < 1 || vertex_count < 3 )
            {
            std::cout << "Illegal mesh: too few vertices or triangles" << std::endl;
            return false;
            }
    
        // Load indices for the vertices belonging to the 3 corners of each triangle.
        // It should have the size 3 x triangle_count.
        // TupleCount should be same as number of triangle-corners in the geometry, i.e 3 x triangle_count,
        // and TupleSize should be 1. This one might be confusing, because its stored per-corner-basis, and not on
        // per-triangle-basis, and that is why tuplesize is 1 and not 3.
        spRidArray VertexIds = geom->GetVertexIds();
        if( !CheckArray( VertexIds, corner_count, 1 ) )
            return false;
    
        // Check that the Coords-array is of correct size
        spRealArray Coords = geom->GetCoords();
        if( !CheckArray( Coords, vertex_count, 3 ) )
            return false;
    
        // Check that all VertexIds has correct index, i.e 0 <= index < vertex_count;
        std::cout << "Checking if the indices contains valid values..." << std::endl;
        rid index[3];
    
        for( unsigned int i = 0; i < triangle_count; i++ )
            {
            for( int n = 0; n < 3; n++ )
                {
                index[n] = VertexIds->GetItem( i * 3 + n );
    
                if( index[n] < 0 || rid( vertex_count ) <= index[n] )
                    {
                    std::cout << "error: Index for triangle: " << i << ", corner: " << n << " out of bounds!" << std::endl;
                    return false;
                    }
                }
    
            if( index[0] == index[1] ||
                index[0] == index[2] ||
                index[1] == index[2] )
                {
                std::cout << "warning: Triangle " << i << " contains same vertices atleast twice" << std::endl;
                }
            }
    
        // Check texcoords, levels 0-3
        spRealArray texcoordsarray;
    
        for( int i = 0; i < 4; i++ )
            {
            texcoordsarray = geom->GetTexCoords( i );
            if( !texcoordsarray.IsNull() )
                {
                if( !CheckArray( texcoordsarray, corner_count, 2 ) )
                    return false;
                }
            }
    
        //Check normals
        spRealArray Normals = geom->GetNormals();
        if( !Normals.IsNull() )
            {
            if( !CheckArray( Normals, corner_count, 3 ) )
                return false;
            }
    
        //Check material-ids
        spRidArray Materials = geom->GetMaterialIds();
        if( !Materials.IsNull() )
            {
            if( !CheckArray( Materials, triangle_count, 1 ) )
                return false;
            }
    
        //Check group-ids
        spRidArray Groups = geom->GetGroupIds();
        if( !Groups.IsNull() )
            {
            if( !CheckArray( Groups, triangle_count, 1 ) )
                return false;
            }
    
        return true;
        }
    
    bool CheckArray( IValueArray* arr, unsigned int tuplecount, unsigned int tuplesize )
        {
        rstring name = arr->GetName();
    
        std::cout << "Checking size information on: " << name.GetText() << std::endl;
    
        unsigned int count = arr->GetTupleCount();
        if( tuplecount != count )
            {
            std::cout << "error: " << name.GetText() << " does not contain correct number of tuples" << std::endl;
            std::cout << "tuplecount should be " << tuplecount << " but was " << count << std::endl;
            return false;
            }
    
        count = arr->GetTupleSize();
        if( tuplesize != count )
            {
            std::cout << "error: " << name.GetText() << " does not have the correct tuple-size" << std::endl;
            std::cout << "tuplesize should be " << tuplesize << " but was " << count << std::endl;
            return false;
            }
    
        count = arr->GetItemCount();
        if( tuplecount * tuplesize != count )
            {
            std::cout << "error: " << name.GetText() << " does not contain correct number of items" << std::endl;
            std::cout << "itemcount should be " << tuplecount * tuplesize << " but was " << count << std::endl;
            return false;
            }
        return true;
    
        }
    
    Back to top Terms of Use | Privacy and cookies | Trademarks | Copyright © 2019 Microsoft