diff --git a/mdal/api/mdal.h b/mdal/api/mdal.h index 40242225..305e4d56 100644 --- a/mdal/api/mdal.h +++ b/mdal/api/mdal.h @@ -331,6 +331,22 @@ MDAL_EXPORT void MDAL_M_addFaces( MDAL_MeshH mesh, int *faceSizes, int *vertexIndices ); +/** + * Adds edges to the mesh + * \param mesh the mesh which the faces are added + * \param edgeCount the count of edges + * \param startVertexIndices must be allocated to edgesCount items to store start vertex indices for edges + * \param endVertexIndices must be allocated to edgesCount items to store end vertex indices for edges + * + * \note to avoid incompatible datasets, adding edges removes all the existing dataset group + * + * \since MDAL 0.9.0 + */ +MDAL_EXPORT void MDAL_M_addEdges( MDAL_MeshH mesh, + int edgesCount, + int *startVertexIndices, + int *endVertexIndices ); + /** * Returns vertex count for the mesh */ @@ -368,7 +384,7 @@ MDAL_EXPORT void MDAL_M_LoadDatasets( MDAL_MeshH mesh, const char *datasetFile ) MDAL_EXPORT int MDAL_M_metadataCount( MDAL_MeshH mesh ); /** - * Returns dataset metadata key + * Returns mesh metadata key * not thread-safe and valid only till next call * * \since MDAL 0.9.0 @@ -376,7 +392,7 @@ MDAL_EXPORT int MDAL_M_metadataCount( MDAL_MeshH mesh ); MDAL_EXPORT const char *MDAL_M_metadataKey( MDAL_MeshH mesh, int index ); /** - * Returns dataset metadata value + * Returns mesh metadata value * not thread-safe and valid only till next call * * \since MDAL 0.9.0 @@ -647,6 +663,8 @@ MDAL_EXPORT MDAL_DatasetH MDAL_G_addDataset( * \param verticalExtrusion Double Array holding the vertical level values for the voxels * Size must be Face count + Volume count * \returns empty pointer if not possible to create dataset (e.g. group opened in read mode), otherwise handle to new dataset + * + * \since MDAL 0.9.0 */ MDAL_EXPORT MDAL_DatasetH MDAL_G_addDataset3D( diff --git a/mdal/mdal.cpp b/mdal/mdal.cpp index b13f7d08..0f91a9c3 100644 --- a/mdal/mdal.cpp +++ b/mdal/mdal.cpp @@ -522,6 +522,7 @@ MDAL_DatasetGroupH MDAL_M_datasetGroup( MDAL_MeshH mesh, int index ) return nullptr; } size_t i = static_cast( index ); + return static_cast< MDAL_DatasetH >( m->datasetGroups[i].get() ); } @@ -1495,3 +1496,28 @@ void MDAL_M_setProjection( MDAL_MeshH mesh, const char *projection ) static_cast( mesh )->setSourceCrsFromWKT( std::string( projection ) ); } + +void MDAL_M_addEdges( MDAL_MeshH mesh, + int edgesCount, + int *startVertexIndices, + int *endVertexIndices ) +{ + MDAL::Log::resetLastStatus(); + if ( !mesh ) + { + MDAL::Log::error( MDAL_Status::Err_IncompatibleMesh, "Mesh is not valid (null)" ); + return; + } + + MDAL::Mesh *m = static_cast( mesh ); + + if ( ! m->isEditable() ) + { + MDAL::Log::error( MDAL_Status::Err_IncompatibleMesh, "Mesh is not editable" ); + } + + m->datasetGroups.clear(); + std::shared_ptr driver = MDAL::DriverManager::instance().driver( m->driverName() ); + + m->addEdges( edgesCount, startVertexIndices, endVertexIndices ); +} diff --git a/mdal/mdal_data_model.cpp b/mdal/mdal_data_model.cpp index d1c53173..6d768676 100644 --- a/mdal/mdal_data_model.cpp +++ b/mdal/mdal_data_model.cpp @@ -431,6 +431,14 @@ void MDAL::Mesh::addFaces( size_t faceCount, size_t driverMaxVerticesPerFace, in MDAL_UNUSED( vertexIndices ); } +void MDAL::Mesh::addEdges( size_t edgeCount, int *startVertexIndices, int *endVertexIndices ) +{ + MDAL_UNUSED( edgeCount ); + MDAL_UNUSED( startVertexIndices ); + MDAL_UNUSED( endVertexIndices ); +} + + MDAL::MeshVertexIterator::~MeshVertexIterator() = default; MDAL::MeshFaceIterator::~MeshFaceIterator() = default; diff --git a/mdal/mdal_data_model.hpp b/mdal/mdal_data_model.hpp index 5b6a1f14..425831a3 100644 --- a/mdal/mdal_data_model.hpp +++ b/mdal/mdal_data_model.hpp @@ -279,6 +279,8 @@ namespace MDAL virtual void addVertices( size_t vertexCount, double *coordinates ); virtual void addFaces( size_t faceCount, size_t driverMaxVerticesPerFace, int *faceSizes, int *vertexIndices ); + virtual void addEdges( size_t edgeCount, int *startVertexIndices, int *endVertexIndices ); + protected: void setFaceVerticesMaximumCount( const size_t &faceVerticesMaximumCount ); diff --git a/mdal/mdal_memory_data_model.cpp b/mdal/mdal_memory_data_model.cpp index 024d10d2..5e4e6e13 100644 --- a/mdal/mdal_memory_data_model.cpp +++ b/mdal/mdal_memory_data_model.cpp @@ -328,6 +328,24 @@ void MDAL::MemoryMesh::addFaces( size_t faceCount, size_t driverMaxVerticesPerFa std::move( newFaces.begin(), newFaces.end(), std::back_inserter( mFaces ) ); } +void MDAL::MemoryMesh::addEdges( size_t edgeCount, int *startVertexIndices, int *endVertexIndices ) +{ + int maxVertex = mVertices.size(); + for ( size_t edgeIndex = 0 ; edgeIndex < edgeCount; ++edgeIndex ) + { + Edge edge; + if ( startVertexIndices[edgeIndex] >= maxVertex || endVertexIndices[edgeIndex] >= maxVertex ) + { + MDAL::Log::error( Err_InvalidData, "Invalid vertex index when adding edges" ); + return; + } + edge.startVertex = startVertexIndices[edgeIndex]; + edge.endVertex = endVertexIndices[edgeIndex]; + + mEdges.push_back( std::move( edge ) ); + } +} + MDAL::MemoryMesh::~MemoryMesh() = default; MDAL::MemoryMeshVertexIterator::MemoryMeshVertexIterator( const MDAL::MemoryMesh *mesh ) diff --git a/mdal/mdal_memory_data_model.hpp b/mdal/mdal_memory_data_model.hpp index 6678f795..cde01ab5 100644 --- a/mdal/mdal_memory_data_model.hpp +++ b/mdal/mdal_memory_data_model.hpp @@ -320,6 +320,7 @@ namespace MDAL BBox extent() const override; void addVertices( size_t vertexCount, double *coordinates ) override; void addFaces( size_t faceCount, size_t driverMaxVerticesPerFace, int *faceSizes, int *vertexIndices ) override; + void addEdges( size_t edgeCount, int *startVertexIndices, int *endVertexIndices ) override; bool isEditable() const override {return true;} diff --git a/tests/test_api.cpp b/tests/test_api.cpp index 62078214..0f1f1121 100644 --- a/tests/test_api.cpp +++ b/tests/test_api.cpp @@ -242,6 +242,91 @@ TEST( ApiTest, VerticesApi ) EXPECT_EQ( MDAL_FI_next( nullptr, 0, nullptr, 0, nullptr ), 0 ); } +void _populateEdges( MDAL_MeshH m, std::vector &start, std::vector &stop, size_t itemsLen ) +{ + int edgesCount = MDAL_M_edgeCount( m ); + start.resize( 0 ); + stop.resize( 0 ); + std::vector buffer1( itemsLen ); + std::vector buffer2( itemsLen ); + + MDAL_MeshEdgeIteratorH it = MDAL_M_edgeIterator( m ); + int edgeIndex = 0; + while ( edgeIndex < edgesCount ) + { + int edgesRead = MDAL_EI_next( it, + static_cast( itemsLen ), + buffer1.data(), + buffer2.data() ); + if ( edgesRead == 0 ) + break; + + ASSERT_TRUE( edgesRead <= static_cast( itemsLen ) ); + + start.insert( start.end(), + buffer1.begin(), + buffer1.begin() + edgesRead ); + + stop.insert( stop.end(), + buffer1.begin(), + buffer1.begin() + edgesRead ); + + edgeIndex += edgesRead; + } + MDAL_EI_close( it ); +} + +TEST( ApiTest, EdgesApi ) +{ + std::string path = test_file( "/ply/all_features.ply" ); + MDAL_MeshH m = MDAL_LoadMesh( path.c_str() ); + EXPECT_NE( m, nullptr ); + MDAL_Status s = MDAL_LastStatus(); + ASSERT_EQ( MDAL_Status::None, s ); + + // reference buffer where taken in one go + std::vector refStart; + std::vector refStop; + _populateEdges( + m, + refStart, + refStop, + static_cast( MDAL_M_edgeCount( m ) ) + ); + + std::vector start; + std::vector stop; + { + std::vector start; + std::vector stop; + _populateEdges( m, + start, + stop, + 10 + ); + + EXPECT_TRUE( compareVectors( refStart, start ) ); + EXPECT_TRUE( compareVectors( refStop, stop ) ); + } + + { + std::vector coords; + _populateEdges( m, + start, + stop, + 10000 + ); + + EXPECT_TRUE( compareVectors( refStart, start ) ); + EXPECT_TRUE( compareVectors( refStop, stop ) ); + } + MDAL_CloseMesh( m ); + + // Some wrong calls tests + EXPECT_EQ( MDAL_M_edgeIterator( nullptr ), nullptr ); + EXPECT_EQ( MDAL_EI_next( nullptr, 0, nullptr, nullptr ), 0 ); +} + TEST( ApiTest, GroupsApi ) { EXPECT_EQ( MDAL_G_mesh( nullptr ), nullptr ); @@ -432,11 +517,16 @@ TEST( ApiTest, MeshCreationApi ) 0, 2, 1 } ); + std::vector startIndices( {0, 1, 2, 3, 4, 5} ); + std::vector endIndices( {1, 2, 3, 4, 5, 0} ); + MDAL_MeshH mesh = nullptr; MDAL_M_addVertices( mesh, 6, coordinates.data() ); EXPECT_EQ( MDAL_LastStatus(), Err_IncompatibleMesh ); MDAL_M_addFaces( mesh, 4, faceSizes.data(), invalidVertexIndices.data() ); EXPECT_EQ( MDAL_LastStatus(), Err_IncompatibleMesh ); + MDAL_M_addEdges( mesh, 6, startIndices.data(), endIndices.data() ); + EXPECT_EQ( MDAL_LastStatus(), Err_IncompatibleMesh ); MDAL_M_setProjection( mesh, "EPSG:32620" ); EXPECT_EQ( MDAL_LastStatus(), Err_IncompatibleMesh ); @@ -450,6 +540,7 @@ TEST( ApiTest, MeshCreationApi ) EXPECT_EQ( MDAL_M_vertexCount( mesh ), 0 ); EXPECT_EQ( MDAL_M_faceCount( mesh ), 0 ); + EXPECT_EQ( MDAL_M_edgeCount( mesh ), 0 ); EXPECT_EQ( MDAL_M_faceVerticesMaximumCount( mesh ), 0 ); std::string createdMeshFile = tmp_file( "/createdMeshVoid" ); @@ -467,6 +558,10 @@ TEST( ApiTest, MeshCreationApi ) EXPECT_EQ( MDAL_M_faceCount( mesh ), 4 ); EXPECT_EQ( MDAL_M_faceVerticesMaximumCount( mesh ), 4 ); + MDAL_M_addEdges( mesh, 6, startIndices.data(), endIndices.data() ); + EXPECT_EQ( MDAL_LastStatus(), None ); + EXPECT_EQ( MDAL_M_edgeCount( mesh ), 6 ); + createdMeshFile = tmp_file( "/createdMesh" ); MDAL_SaveMesh( mesh, createdMeshFile.c_str(), "Ugrid" ); EXPECT_EQ( MDAL_LastStatus(), None );