-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[FEATURE] QgsMeshLayer part 1: Reading raw mesh
Introducting MDAL, QgsMeshLayer, mesh data providers (mesh_memory, mdal) to read and visualize raw meshes: vertices and faces. Support dragging 2dm files from browser on canvas to visualize 2dm meshes. Support for QgsMeshLayer in Python API.
- Loading branch information
1 parent
3b59ccc
commit 50422a1
Showing
62 changed files
with
2,943 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# Find MDAL | ||
# ~~~~~~~~~ | ||
# Copyright (c) 2018, Peter Petrik <zilolv at gmail dot com> | ||
# Redistribution and use is allowed according to the terms of the BSD license. | ||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file. | ||
# | ||
# | ||
# Once run this will define: | ||
# MDAL_FOUND - System has MDAL | ||
# MDAL_INCLUDE_DIRS - The MDAL include directories | ||
# MDAL_LIBRARIES - The libraries needed to use MDAL | ||
# MDAL_DEFINITIONS - Compiler switches required for using MDAL | ||
|
||
FIND_PACKAGE(PkgConfig) | ||
PKG_CHECK_MODULES(PC_MDAL QUIET libmdal) | ||
SET(MDAL_DEFINITIONS ${PC_MDAL_CFLAGS_OTHER}) | ||
|
||
FIND_PATH(MDAL_INCLUDE_DIR mdal.h | ||
HINTS ${PC_MDAL_INCLUDEDIR} ${PC_MDAL_INCLUDE_DIRS} ${MDAL_PREFIX}/include | ||
PATH_SUFFIXES libmdal ) | ||
|
||
FIND_LIBRARY(MDAL_LIBRARY NAMES mdal libmdal | ||
HINTS ${PC_MDAL_LIBDIR} ${PC_MDAL_LIBRARY_DIRS} ${MDAL_PREFIX}/lib) | ||
|
||
INCLUDE(FindPackageHandleStandardArgs) | ||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(MDAL DEFAULT_MSG | ||
MDAL_LIBRARY MDAL_INCLUDE_DIR) | ||
|
||
MARK_AS_ADVANCED(MDAL_INCLUDE_DIR MDAL_LIBRARY ) | ||
|
||
SET(MDAL_LIBRARIES ${MDAL_LIBRARY} ) | ||
SET(MDAL_INCLUDE_DIRS ${MDAL_INCLUDE_DIR} ) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
/* | ||
MDAL - Mesh Data Abstraction Library (MIT License) | ||
Copyright (C) 2018 Peter Petrik (zilolv at gmail dot com) | ||
*/ | ||
|
||
#ifndef MDAL_H | ||
#define MDAL_H | ||
|
||
#ifdef MDAL_STATIC | ||
# define MDAL_EXPORT | ||
#else | ||
# if defined _WIN32 || defined __CYGWIN__ | ||
# ifdef mdal_EXPORTS | ||
# ifdef __GNUC__ | ||
# define MDAL_EXPORT __attribute__ ((dllexport)) | ||
# else | ||
# define MDAL_EXPORT __declspec(dllexport) // Note: actually gcc seems to also supports this syntax. | ||
# endif | ||
# else | ||
# ifdef __GNUC__ | ||
# define MDAL_EXPORT __attribute__ ((dllimport)) | ||
# else | ||
# define MDAL_EXPORT __declspec(dllimport) // Note: actually gcc seems to also supports this syntax. | ||
# endif | ||
# endif | ||
# else | ||
# if __GNUC__ >= 4 | ||
# define MDAL_EXPORT __attribute__ ((visibility ("default"))) | ||
# else | ||
# define MDAL_EXPORT | ||
# endif | ||
# endif | ||
#endif | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
#include <stddef.h> | ||
|
||
/* Statuses */ | ||
enum Status | ||
{ | ||
None, | ||
// Errors | ||
Err_NotEnoughMemory, | ||
Err_FileNotFound, | ||
Err_UnknownFormat, | ||
Err_IncompatibleMesh, | ||
Err_InvalidData, | ||
Err_MissingDriver, | ||
// Warnings | ||
Warn_UnsupportedElement, | ||
Warn_InvalidElements, | ||
Warn_ElementWithInvalidNode, | ||
Warn_ElementNotUnique, | ||
Warn_NodeNotUnique | ||
}; | ||
|
||
/* Mesh */ | ||
typedef void *MeshH; | ||
|
||
//! Return MDAL version | ||
MDAL_EXPORT const char *MDAL_Version(); | ||
|
||
//! Return last status message | ||
MDAL_EXPORT Status MDAL_LastStatus(); | ||
|
||
//! Load mesh file. On error see MDAL_LastStatus for error type This effectively loads whole mesh in-memory | ||
MDAL_EXPORT MeshH MDAL_LoadMesh( const char *meshFile ); | ||
//! Close mesh, free the memory | ||
MDAL_EXPORT void MDAL_CloseMesh( MeshH mesh ); | ||
|
||
//! Return vertex count for the mesh | ||
MDAL_EXPORT size_t MDAL_M_vertexCount( MeshH mesh ); | ||
//! Return vertex X coord for the mesh | ||
MDAL_EXPORT double MDAL_M_vertexXCoordinatesAt( MeshH mesh, size_t index ); | ||
//! Return vertex Y coord for the mesh | ||
MDAL_EXPORT double MDAL_M_vertexYCoordinatesAt( MeshH mesh, size_t index ); | ||
//! Return face count for the mesh | ||
MDAL_EXPORT size_t MDAL_M_faceCount( MeshH mesh ); | ||
//! Return number of vertices face consist of, e.g. 3 for triangle | ||
MDAL_EXPORT size_t MDAL_M_faceVerticesCountAt( MeshH mesh, size_t index ); | ||
//! Return vertex index for face | ||
MDAL_EXPORT size_t MDAL_M_faceVerticesIndexAt( MeshH mesh, size_t face_index, size_t vertex_index ); | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
#endif //MDAL_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
/* | ||
MDAL - Mesh Data Abstraction Library (MIT License) | ||
Copyright (C) 2018 Peter Petrik (zilolv at gmail dot com) | ||
*/ | ||
|
||
#include <stddef.h> | ||
#include <iosfwd> | ||
#include <iostream> | ||
#include <fstream> | ||
#include <sstream> | ||
#include <string> | ||
#include <vector> | ||
#include <map> | ||
#include <cassert> | ||
|
||
#include "mdal_2dm.hpp" | ||
#include "mdal.h" | ||
#include "mdal_utils.hpp" | ||
|
||
MDAL::Loader2dm::Loader2dm( const std::string &meshFile ): | ||
mMeshFile( meshFile ) | ||
{ | ||
} | ||
|
||
MDAL::Mesh *MDAL::Loader2dm::load( Status *status ) | ||
{ | ||
if ( status ) *status = Status::None; | ||
|
||
if ( !MDAL::fileExists( mMeshFile ) ) | ||
{ | ||
if ( status ) *status = Status::Err_FileNotFound; | ||
return 0; | ||
} | ||
|
||
std::ifstream in( mMeshFile, std::ifstream::in ); | ||
std::string line; | ||
if ( !std::getline( in, line ) || !startsWith( line, "MESH2D" ) ) | ||
{ | ||
if ( status ) *status = Status::Err_UnknownFormat; | ||
return 0; | ||
} | ||
|
||
size_t elemCount = 0; | ||
size_t nodeCount = 0; | ||
|
||
// Find out how many nodes and elements are contained in the .2dm mesh file | ||
while ( std::getline( in, line ) ) | ||
{ | ||
if ( startsWith( line, "E4Q" ) || | ||
startsWith( line, "E3T" ) ) | ||
{ | ||
elemCount++; | ||
} | ||
else if ( startsWith( line, "ND" ) ) | ||
{ | ||
nodeCount++; | ||
} | ||
else if ( startsWith( line, "E2L" ) || | ||
startsWith( line, "E3L" ) || | ||
startsWith( line, "E6T" ) || | ||
startsWith( line, "E8Q" ) || | ||
startsWith( line, "E9Q" ) ) | ||
{ | ||
if ( status ) *status = Status::Warn_UnsupportedElement; | ||
elemCount += 1; // We still count them as elements | ||
} | ||
} | ||
|
||
// Allocate memory | ||
std::vector<Vertex> vertices( nodeCount ); | ||
std::vector<Face> faces( elemCount ); | ||
|
||
in.clear(); | ||
in.seekg( 0, std::ios::beg ); | ||
|
||
std::vector<std::string> chunks; | ||
|
||
size_t elemIndex = 0; | ||
size_t nodeIndex = 0; | ||
std::map<size_t, size_t> elemIDtoIndex; | ||
std::map<size_t, size_t> nodeIDtoIndex; | ||
|
||
while ( std::getline( in, line ) ) | ||
{ | ||
if ( startsWith( line, "E4Q" ) ) | ||
{ | ||
chunks = split( line, " ", SplitBehaviour::SkipEmptyParts ); | ||
assert( elemIndex < elemCount ); | ||
|
||
size_t elemID = toSizeT( chunks[1] ); | ||
|
||
std::map<size_t, size_t>::iterator search = elemIDtoIndex.find( elemID ); | ||
if ( search != elemIDtoIndex.end() ) | ||
{ | ||
if ( status ) *status = Status::Warn_ElementNotUnique; | ||
continue; | ||
} | ||
elemIDtoIndex[elemID] = elemIndex; | ||
Face &face = faces[elemIndex]; | ||
face.resize( 4 ); | ||
// Right now we just store node IDs here - we will convert them to node indices afterwards | ||
for ( size_t i = 0; i < 4; ++i ) | ||
face[i] = toSizeT( chunks[i + 2] ); | ||
|
||
elemIndex++; | ||
} | ||
else if ( startsWith( line, "E3T" ) ) | ||
{ | ||
chunks = split( line, " ", SplitBehaviour::SkipEmptyParts ); | ||
assert( elemIndex < elemCount ); | ||
|
||
size_t elemID = toSizeT( chunks[1] ); | ||
|
||
std::map<size_t, size_t>::iterator search = elemIDtoIndex.find( elemID ); | ||
if ( search != elemIDtoIndex.end() ) | ||
{ | ||
if ( status ) *status = Status::Warn_ElementNotUnique; | ||
continue; | ||
} | ||
elemIDtoIndex[elemID] = elemIndex; | ||
Face &face = faces[elemIndex]; | ||
face.resize( 3 ); | ||
// Right now we just store node IDs here - we will convert them to node indices afterwards | ||
for ( size_t i = 0; i < 3; ++i ) | ||
{ | ||
face[i] = toSizeT( chunks[i + 2] ); | ||
} | ||
|
||
elemIndex++; | ||
} | ||
else if ( startsWith( line, "E2L" ) || | ||
startsWith( line, "E3L" ) || | ||
startsWith( line, "E6T" ) || | ||
startsWith( line, "E8Q" ) || | ||
startsWith( line, "E9Q" ) ) | ||
{ | ||
// We do not yet support these elements | ||
chunks = split( line, " ", SplitBehaviour::SkipEmptyParts ); | ||
assert( elemIndex < elemCount ); | ||
|
||
size_t elemID = toSizeT( chunks[1] ); | ||
|
||
std::map<size_t, size_t>::iterator search = elemIDtoIndex.find( elemID ); | ||
if ( search != elemIDtoIndex.end() ) | ||
{ | ||
if ( status ) *status = Status::Warn_ElementNotUnique; | ||
continue; | ||
} | ||
elemIDtoIndex[elemID] = elemIndex; | ||
assert( false ); //TODO mark element as unusable | ||
|
||
elemIndex++; | ||
} | ||
else if ( startsWith( line, "ND" ) ) | ||
{ | ||
chunks = split( line, " ", SplitBehaviour::SkipEmptyParts ); | ||
size_t nodeID = toSizeT( chunks[1] ); | ||
|
||
std::map<size_t, size_t>::iterator search = nodeIDtoIndex.find( nodeID ); | ||
if ( search != nodeIDtoIndex.end() ) | ||
{ | ||
if ( status ) *status = Status::Warn_NodeNotUnique; | ||
continue; | ||
} | ||
nodeIDtoIndex[nodeID] = nodeIndex; | ||
assert( nodeIndex < nodeCount ); | ||
Vertex &vertex = vertices[nodeIndex]; | ||
vertex.x = toDouble( chunks[2] ); | ||
vertex.y = toDouble( chunks[3] ); | ||
|
||
nodeIndex++; | ||
} | ||
} | ||
|
||
for ( std::vector<Face>::iterator it = faces.begin(); it != faces.end(); ++it ) | ||
{ | ||
Face &face = *it; | ||
for ( Face::size_type nd = 0; nd < face.size(); ++nd ) | ||
{ | ||
size_t nodeID = face[nd]; | ||
|
||
std::map<size_t, size_t>::iterator ni2i = nodeIDtoIndex.find( nodeID ); | ||
if ( ni2i != nodeIDtoIndex.end() ) | ||
{ | ||
face[nd] = ni2i->second; // convert from ID to index | ||
} | ||
else | ||
{ | ||
assert( false ); //TODO mark element as unusable | ||
|
||
if ( status ) *status = Status::Warn_ElementWithInvalidNode; | ||
} | ||
} | ||
|
||
//TODO check validity of the face | ||
//check that we have distinct nodes | ||
} | ||
|
||
Mesh *mesh = new Mesh; | ||
mesh->faces = faces; | ||
mesh->vertices = vertices; | ||
|
||
return mesh; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/* | ||
MDAL - Mesh Data Abstraction Library (MIT License) | ||
Copyright (C) 2018 Peter Petrik (zilolv at gmail dot com) | ||
*/ | ||
|
||
#ifndef MDAL_2DM_HPP | ||
#define MDAL_2DM_HPP | ||
|
||
#include <string> | ||
|
||
#include "mdal_defines.hpp" | ||
#include "mdal.h" | ||
|
||
namespace MDAL | ||
{ | ||
|
||
class Loader2dm | ||
{ | ||
public: | ||
Loader2dm( const std::string &meshFile ); | ||
Mesh *load( Status *status ); | ||
|
||
private: | ||
std::string mMeshFile; | ||
}; | ||
|
||
} // namespace MDAL | ||
#endif //MDAL_2DM_HPP |
Oops, something went wrong.