mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Merge pull request #6820 from PeterPetrik/QgsMeshLayer_1_mesh
[FEATURE] QgsMeshLayer part 1: Reading raw mesh
This commit is contained in:
commit
ade216d02d
@ -95,6 +95,12 @@ IF(WITH_CORE)
|
||||
SET (HAVE_GUI TRUE) # used in qgsconfig.h
|
||||
ENDIF()
|
||||
|
||||
# try to configure and build MDAL support
|
||||
SET (WITH_INTERNAL_MDAL TRUE CACHE BOOL "Determines whether MDAL support should be built")
|
||||
IF (NOT WITH_INTERNAL_MDAL)
|
||||
SET (MDAL_PREFIX "" CACHE PATH "Path to MDAL base directory")
|
||||
ENDIF (NOT WITH_INTERNAL_MDAL)
|
||||
|
||||
# try to configure and build POSTGRESQL support
|
||||
SET (WITH_POSTGRESQL TRUE CACHE BOOL "Determines whether POSTGRESQL support should be built")
|
||||
IF (WITH_POSTGRESQL)
|
||||
@ -258,6 +264,10 @@ IF(WITH_CORE)
|
||||
FIND_PACKAGE(Postgres) # PostgreSQL provider
|
||||
ENDIF (WITH_POSTGRESQL)
|
||||
|
||||
IF (NOT WITH_INTERNAL_MDAL)
|
||||
FIND_PACKAGE(MDAL REQUIRED) # MDAL provider
|
||||
ENDIF (NOT WITH_INTERNAL_MDAL)
|
||||
|
||||
FIND_PACKAGE(SpatiaLite REQUIRED)
|
||||
|
||||
IF (NOT PROJ_FOUND OR NOT GEOS_FOUND OR NOT GDAL_FOUND)
|
||||
|
32
cmake/FindMDAL.cmake
Normal file
32
cmake/FindMDAL.cmake
Normal file
@ -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} )
|
@ -70,6 +70,7 @@ IF(WITH_APIDOC)
|
||||
${CMAKE_SOURCE_DIR}/src/core/layout
|
||||
${CMAKE_SOURCE_DIR}/src/core/locator
|
||||
${CMAKE_SOURCE_DIR}/src/core/metadata
|
||||
${CMAKE_SOURCE_DIR}/src/core/mesh
|
||||
${CMAKE_SOURCE_DIR}/src/core/pal
|
||||
${CMAKE_SOURCE_DIR}/src/core/processing
|
||||
${CMAKE_SOURCE_DIR}/src/core/providers
|
||||
|
89
external/mdal/api/mdal.h
vendored
Normal file
89
external/mdal/api/mdal.h
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
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
|
||||
|
||||
/* Statuses */
|
||||
enum MDAL_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 MDAL_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 int MDAL_M_vertexCount( MeshH mesh );
|
||||
//! Return vertex X coord for the mesh
|
||||
MDAL_EXPORT double MDAL_M_vertexXCoordinatesAt( MeshH mesh, int index );
|
||||
//! Return vertex Y coord for the mesh
|
||||
MDAL_EXPORT double MDAL_M_vertexYCoordinatesAt( MeshH mesh, int index );
|
||||
//! Return face count for the mesh
|
||||
MDAL_EXPORT int MDAL_M_faceCount( MeshH mesh );
|
||||
//! Return number of vertices face consist of, e.g. 3 for triangle
|
||||
MDAL_EXPORT int MDAL_M_faceVerticesCountAt( MeshH mesh, int index );
|
||||
//! Return vertex index for face
|
||||
MDAL_EXPORT int MDAL_M_faceVerticesIndexAt( MeshH mesh, int face_index, int vertex_index );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //MDAL_H
|
204
external/mdal/frmts/mdal_2dm.cpp
vendored
Normal file
204
external/mdal/frmts/mdal_2dm.cpp
vendored
Normal file
@ -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( MDAL_Status *status )
|
||||
{
|
||||
if ( status ) *status = MDAL_Status::None;
|
||||
|
||||
if ( !MDAL::fileExists( mMeshFile ) )
|
||||
{
|
||||
if ( status ) *status = MDAL_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 = MDAL_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 = MDAL_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 = MDAL_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 = MDAL_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 = MDAL_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 = MDAL_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 = MDAL_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;
|
||||
}
|
28
external/mdal/frmts/mdal_2dm.hpp
vendored
Normal file
28
external/mdal/frmts/mdal_2dm.hpp
vendored
Normal file
@ -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( MDAL_Status *status );
|
||||
|
||||
private:
|
||||
std::string mMeshFile;
|
||||
};
|
||||
|
||||
} // namespace MDAL
|
||||
#endif //MDAL_2DM_HPP
|
100
external/mdal/mdal.cpp
vendored
Normal file
100
external/mdal/mdal.cpp
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "mdal.h"
|
||||
#include "mdal_loader.hpp"
|
||||
#include "mdal_defines.hpp"
|
||||
|
||||
static MDAL_Status sLastStatus;
|
||||
|
||||
const char *MDAL_Version()
|
||||
{
|
||||
return "0.0.2";
|
||||
}
|
||||
|
||||
MDAL_Status MDAL_LastStatus()
|
||||
{
|
||||
return sLastStatus;
|
||||
}
|
||||
|
||||
MeshH MDAL_LoadMesh( const char *meshFile )
|
||||
{
|
||||
if ( !meshFile )
|
||||
return nullptr;
|
||||
|
||||
std::string filename( meshFile );
|
||||
return ( MeshH ) MDAL::Loader::load( filename, &sLastStatus );
|
||||
}
|
||||
|
||||
|
||||
void MDAL_CloseMesh( MeshH mesh )
|
||||
{
|
||||
if ( mesh )
|
||||
{
|
||||
MDAL::Mesh *m = ( MDAL::Mesh * ) mesh;
|
||||
delete m;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int MDAL_M_vertexCount( MeshH mesh )
|
||||
{
|
||||
assert( mesh );
|
||||
MDAL::Mesh *m = ( MDAL::Mesh * ) mesh;
|
||||
int len = static_cast<int>( m->vertices.size() );
|
||||
return len;
|
||||
}
|
||||
|
||||
double MDAL_M_vertexXCoordinatesAt( MeshH mesh, int index )
|
||||
{
|
||||
assert( mesh );
|
||||
MDAL::Mesh *m = ( MDAL::Mesh * ) mesh;
|
||||
assert( index > -1 );
|
||||
size_t i = static_cast<size_t>( index );
|
||||
assert( m->vertices.size() > i );
|
||||
return m->vertices[i].x;
|
||||
}
|
||||
|
||||
double MDAL_M_vertexYCoordinatesAt( MeshH mesh, int index )
|
||||
{
|
||||
assert( mesh );
|
||||
MDAL::Mesh *m = ( MDAL::Mesh * ) mesh;
|
||||
assert( index > -1 );
|
||||
size_t i = static_cast<size_t>( index );
|
||||
assert( m->vertices.size() > i );
|
||||
return m->vertices[i].y;
|
||||
}
|
||||
|
||||
int MDAL_M_faceCount( MeshH mesh )
|
||||
{
|
||||
assert( mesh );
|
||||
MDAL::Mesh *m = ( MDAL::Mesh * ) mesh;
|
||||
int len = static_cast<int>( m->faces.size() );
|
||||
return len;
|
||||
}
|
||||
|
||||
int MDAL_M_faceVerticesCountAt( MeshH mesh, int index )
|
||||
{
|
||||
assert( mesh );
|
||||
MDAL::Mesh *m = ( MDAL::Mesh * ) mesh;
|
||||
assert( index > -1 );
|
||||
size_t i = static_cast<size_t>( index );
|
||||
assert( m->faces.size() > i );
|
||||
int len = static_cast<int>( m->faces[i].size() );
|
||||
return len;
|
||||
}
|
||||
|
||||
int MDAL_M_faceVerticesIndexAt( MeshH mesh, int face_index, int vertex_index )
|
||||
{
|
||||
assert( mesh );
|
||||
MDAL::Mesh *m = ( MDAL::Mesh * ) mesh;
|
||||
assert( face_index > -1 );
|
||||
size_t fi = static_cast<size_t>( face_index );
|
||||
assert( m->faces.size() > fi );
|
||||
assert( vertex_index > -1 );
|
||||
size_t vi = static_cast<size_t>( vertex_index );
|
||||
assert( m->faces[fi].size() > vi );
|
||||
int len = static_cast<int>( m->faces[fi][vi] );
|
||||
return len;
|
||||
}
|
31
external/mdal/mdal_defines.hpp
vendored
Normal file
31
external/mdal/mdal_defines.hpp
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
MDAL - Mesh Data Abstraction Library (MIT License)
|
||||
Copyright (C) 2018 Peter Petrik (zilolv at gmail dot com)
|
||||
*/
|
||||
|
||||
#ifndef MDAL_DEFINES_HPP
|
||||
#define MDAL_DEFINES_HPP
|
||||
|
||||
#include <stddef.h>
|
||||
#include <vector>
|
||||
|
||||
namespace MDAL
|
||||
{
|
||||
|
||||
typedef struct
|
||||
{
|
||||
double x;
|
||||
double y;
|
||||
} Vertex;
|
||||
|
||||
typedef std::vector<size_t> Face;
|
||||
|
||||
struct Mesh
|
||||
{
|
||||
std::vector<Vertex> vertices;
|
||||
std::vector<Face> faces;
|
||||
};
|
||||
|
||||
} // namespace MDAL
|
||||
#endif //MDAL_DEFINES_HPP
|
||||
|
13
external/mdal/mdal_loader.cpp
vendored
Normal file
13
external/mdal/mdal_loader.cpp
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
MDAL - Mesh Data Abstraction Library (MIT License)
|
||||
Copyright (C) 2018 Peter Petrik (zilolv at gmail dot com)
|
||||
*/
|
||||
|
||||
#include "mdal_loader.hpp"
|
||||
#include "frmts/mdal_2dm.hpp"
|
||||
|
||||
MDAL::Mesh *MDAL::Loader::load( const std::string &meshFile, MDAL_Status *status )
|
||||
{
|
||||
MDAL::Loader2dm loader( meshFile );
|
||||
return loader.load( status );
|
||||
}
|
24
external/mdal/mdal_loader.hpp
vendored
Normal file
24
external/mdal/mdal_loader.hpp
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
MDAL - Mesh Data Abstraction Library (MIT License)
|
||||
Copyright (C) 2018 Peter Petrik (zilolv at gmail dot com)
|
||||
*/
|
||||
|
||||
#ifndef MDAL_LOADER_HPP
|
||||
#define MDAL_LOADER_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "mdal.h"
|
||||
#include "mdal_defines.hpp"
|
||||
|
||||
namespace MDAL
|
||||
{
|
||||
|
||||
class Loader
|
||||
{
|
||||
public:
|
||||
static Mesh *load( const std::string &meshFile, MDAL_Status *status );
|
||||
};
|
||||
|
||||
} // namespace MDAL
|
||||
#endif //MDAL_LOADER_HPP
|
56
external/mdal/mdal_utils.cpp
vendored
Normal file
56
external/mdal/mdal_utils.cpp
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
MDAL - Mesh Data Abstraction Library (MIT License)
|
||||
Copyright (C) 2018 Peter Petrik (zilolv at gmail dot com)
|
||||
*/
|
||||
|
||||
#include "mdal_utils.hpp"
|
||||
#include <fstream>
|
||||
|
||||
bool MDAL::fileExists( const std::string &filename )
|
||||
{
|
||||
std::ifstream in( filename );
|
||||
return in.good();
|
||||
}
|
||||
|
||||
|
||||
bool MDAL::startsWith( const std::string &str, const std::string &substr )
|
||||
{
|
||||
return str.rfind( substr, 0 ) == 0;
|
||||
}
|
||||
|
||||
std::vector<std::string> MDAL::split( const std::string &str, const std::string &delimiter, SplitBehaviour behaviour )
|
||||
{
|
||||
std::string remaining( str );
|
||||
std::vector<std::string> list;
|
||||
size_t pos = 0;
|
||||
std::string token;
|
||||
while ( ( pos = remaining.find( delimiter ) ) != std::string::npos )
|
||||
{
|
||||
token = remaining.substr( 0, pos );
|
||||
|
||||
if ( behaviour == SplitBehaviour::SkipEmptyParts )
|
||||
{
|
||||
if ( !token.empty() )
|
||||
list.push_back( token );
|
||||
}
|
||||
else
|
||||
list.push_back( token );
|
||||
|
||||
remaining.erase( 0, pos + delimiter.length() );
|
||||
}
|
||||
list.push_back( remaining );
|
||||
return list;
|
||||
}
|
||||
|
||||
size_t MDAL::toSizeT( const std::string &str )
|
||||
{
|
||||
int i = atoi( str.c_str() );
|
||||
if ( i < 0 ) // consistent with atoi return
|
||||
i = 0;
|
||||
return i;
|
||||
}
|
||||
|
||||
double MDAL::toDouble( const std::string &str )
|
||||
{
|
||||
return atof( str.c_str() );
|
||||
}
|
34
external/mdal/mdal_utils.hpp
vendored
Normal file
34
external/mdal/mdal_utils.hpp
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
MDAL - Mesh Data Abstraction Library (MIT License)
|
||||
Copyright (C) 2018 Peter Petrik (zilolv at gmail dot com)
|
||||
*/
|
||||
|
||||
#ifndef MDAL_UTILS_HPP
|
||||
#define MDAL_UTILS_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace MDAL
|
||||
{
|
||||
|
||||
/** Return whether file exists */
|
||||
bool fileExists( const std::string &filename );
|
||||
|
||||
// strings
|
||||
bool startsWith( const std::string &str, const std::string &substr );
|
||||
|
||||
/** Return 0 if not possible to convert */
|
||||
size_t toSizeT( const std::string &str );
|
||||
double toDouble( const std::string &str );
|
||||
|
||||
enum SplitBehaviour
|
||||
{
|
||||
SkipEmptyParts,
|
||||
KeepEmptyParts
|
||||
};
|
||||
std::vector<std::string> split( const std::string &str, const std::string &delimiter, SplitBehaviour behaviour );
|
||||
|
||||
} // namespace MDAL
|
||||
#endif //MDAL_UTILS_HPP
|
78
images/themes/default/mIconMeshLayer.svg
Normal file
78
images/themes/default/mIconMeshLayer.svg
Normal file
@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
height="16"
|
||||
width="16"
|
||||
version="1.1"
|
||||
id="svg10"
|
||||
sodipodi:docname="mIconMeshLayer.svg"
|
||||
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)">
|
||||
<metadata
|
||||
id="metadata16">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs14" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1680"
|
||||
inkscape:window-height="1021"
|
||||
id="namedview12"
|
||||
showgrid="false"
|
||||
inkscape:zoom="14.75"
|
||||
inkscape:cx="8"
|
||||
inkscape:cy="8"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="g8" />
|
||||
<g
|
||||
transform="translate(0.06779661,-15.457627)"
|
||||
id="g8"
|
||||
style="fill:#eeeeec;fill-rule:evenodd;stroke:#888a85;stroke-linecap:round;stroke-linejoin:round">
|
||||
<rect
|
||||
id="rect30"
|
||||
width="5.9661016"
|
||||
height="4.7457619"
|
||||
x="1.6949153"
|
||||
y="18.508474" />
|
||||
<rect
|
||||
id="rect32"
|
||||
width="5.762712"
|
||||
height="5.0847459"
|
||||
x="1.7627119"
|
||||
y="23.254236" />
|
||||
<rect
|
||||
id="rect34"
|
||||
width="5.6949148"
|
||||
height="4.7457619"
|
||||
x="7.525424"
|
||||
y="18.508474" />
|
||||
<rect
|
||||
id="rect36"
|
||||
width="5.5593219"
|
||||
height="5.0847468"
|
||||
x="7.6610169"
|
||||
y="23.254236" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.0 KiB |
@ -119,6 +119,7 @@ INCLUDE_DIRECTORIES(
|
||||
${CMAKE_SOURCE_DIR}/src/core/layout
|
||||
${CMAKE_SOURCE_DIR}/src/core/locator
|
||||
${CMAKE_SOURCE_DIR}/src/core/metadata
|
||||
${CMAKE_SOURCE_DIR}/src/core/mesh
|
||||
${CMAKE_SOURCE_DIR}/src/core/processing
|
||||
${CMAKE_SOURCE_DIR}/src/core/processing/models
|
||||
${CMAKE_SOURCE_DIR}/src/core/providers
|
||||
|
@ -378,6 +378,8 @@
|
||||
%Include raster/qgsrasterdataprovider.sip
|
||||
%Include raster/qgsrasterinterface.sip
|
||||
%Include raster/qgsrasterprojector.sip
|
||||
%Include mesh/qgsmeshdataprovider.sip
|
||||
%Include mesh/qgsmeshlayer.sip
|
||||
%Include geometry/qgsabstractgeometry.sip
|
||||
%Include geometry/qgsgeometry.sip
|
||||
%Include geometry/qgspoint.sip
|
||||
|
99
python/core/mesh/qgsmeshdataprovider.sip.in
Normal file
99
python/core/mesh/qgsmeshdataprovider.sip.in
Normal file
@ -0,0 +1,99 @@
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/core/mesh/qgsmeshdataprovider.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
typedef QgsPoint QgsMeshVertex; //xyz coords of vertex
|
||||
typedef QVector<int> QgsMeshFace; //list of vertex indexes
|
||||
|
||||
class QgsMeshSource /Abstract/
|
||||
{
|
||||
%Docstring
|
||||
Mesh is a collection of vertices and faces in 2D or 3D space
|
||||
- vertex - XY(Z) point (in the mesh's coordinate reference system)
|
||||
- faces - sets of vertices forming a closed shape - typically triangles or quadrilaterals
|
||||
|
||||
Base on the underlying data provider/format, whole mesh is either stored in memory or
|
||||
read on demand
|
||||
|
||||
.. versionadded:: 3.2
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsmeshdataprovider.h"
|
||||
%End
|
||||
public:
|
||||
virtual ~QgsMeshSource();
|
||||
|
||||
virtual int vertexCount() const = 0;
|
||||
%Docstring
|
||||
Return number of vertices in the native mesh
|
||||
|
||||
:return: Number of vertices in the mesh
|
||||
%End
|
||||
|
||||
virtual int faceCount() const = 0;
|
||||
%Docstring
|
||||
Return number of faces in the native mesh
|
||||
|
||||
:return: Number of faces in the mesh
|
||||
%End
|
||||
|
||||
virtual QgsMeshVertex vertex( int index ) const = 0;
|
||||
%Docstring
|
||||
Factory for mesh vertex with index
|
||||
|
||||
:return: new mesh vertex on index
|
||||
%End
|
||||
|
||||
virtual QgsMeshFace face( int index ) const = 0;
|
||||
%Docstring
|
||||
Factory for mesh face with index
|
||||
|
||||
:return: new mesh face on index
|
||||
%End
|
||||
};
|
||||
|
||||
class QgsMeshDataProvider: QgsDataProvider, QgsMeshSource
|
||||
{
|
||||
%Docstring
|
||||
Base class for providing data for :py:class:`QgsMeshLayer`
|
||||
|
||||
Responsible for reading native mesh data
|
||||
|
||||
.. seealso:: :py:class:`QgsMeshSource`
|
||||
|
||||
.. versionadded:: 3.2
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsmeshdataprovider.h"
|
||||
%End
|
||||
public:
|
||||
QgsMeshDataProvider( const QString &uri = QString() );
|
||||
%Docstring
|
||||
Ctor
|
||||
%End
|
||||
|
||||
virtual QgsRectangle extent() const;
|
||||
%Docstring
|
||||
Returns the extent of the layer
|
||||
|
||||
:return: QgsRectangle containing the extent of the layer
|
||||
%End
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/core/mesh/qgsmeshdataprovider.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
138
python/core/mesh/qgsmeshlayer.sip.in
Normal file
138
python/core/mesh/qgsmeshlayer.sip.in
Normal file
@ -0,0 +1,138 @@
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/core/mesh/qgsmeshlayer.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsMeshLayer : QgsMapLayer
|
||||
{
|
||||
%Docstring
|
||||
|
||||
Represents a mesh layer supporting display of data on structured or unstructured meshes
|
||||
|
||||
The QgsMeshLayer is instantiated by specifying the name of a data provider,
|
||||
such as mdal, and url defining the specific data set to connect to.
|
||||
The vector layer constructor in turn instantiates a QgsMeshDataProvider subclass
|
||||
corresponding to the provider type, and passes it the url. The data provider
|
||||
connects to the data source.
|
||||
|
||||
The QgsMeshLayer provides a common interface to the different data types. It does not
|
||||
yet support editing transactions.
|
||||
|
||||
The main data providers supported by QGIS are listed below.
|
||||
|
||||
\section mesh_providers Mesh data providers
|
||||
|
||||
\subsection mesh_memory Memory data providerType (mesh_memory)
|
||||
|
||||
The memory data provider is used to construct in memory data, for example scratch
|
||||
data. There is no inherent persistent storage of the data. The data source uri is constructed.
|
||||
Data can be populated by setMesh(const QString &vertices, const QString &faces), where
|
||||
vertices and faces is comma separated coordinates and connections for mesh.
|
||||
E.g. to create mesh with one quad and one triangle
|
||||
|
||||
.. code-block::
|
||||
|
||||
QString uri(
|
||||
"1.0, 2.0 \n" \
|
||||
"2.0, 2.0 \n" \
|
||||
"3.0, 2.0 \n" \
|
||||
"2.0, 3.0 \n" \
|
||||
"1.0, 3.0 \n" \
|
||||
"---"
|
||||
"0, 1, 3, 4 \n" \
|
||||
"1, 2, 3 \n"
|
||||
);
|
||||
QgsMeshLayer *scratchLayer = new QgsMeshLayer(uri, "My Scratch layer", "memory_mesh");
|
||||
|
||||
\subsection mdal MDAL data provider (mdal)
|
||||
|
||||
Accesses data using the MDAL drivers (https://github.com/lutraconsulting/MDAL). The url
|
||||
is the MDAL connection string. QGIS must be built with MDAL support to allow this provider.
|
||||
|
||||
.. code-block::
|
||||
|
||||
QString uri = "test/land.2dm";
|
||||
QgsMeshLayer *scratchLayer = new QgsMeshLayer(uri, "My Scratch Layer", "mdal");
|
||||
|
||||
.. versionadded:: 3.2
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsmeshlayer.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
explicit QgsMeshLayer( const QString &path = QString(), const QString &baseName = QString(), const QString &providerLib = "mesh_memory" );
|
||||
%Docstring
|
||||
Constructor - creates a mesh layer
|
||||
|
||||
The QgsMeshLayer is constructed by instantiating a data provider. The provider
|
||||
interprets the supplied path (url) of the data source to connect to and access the
|
||||
data.
|
||||
|
||||
:param path: The path or url of the parameter. Typically this encodes
|
||||
parameters used by the data provider as url query items.
|
||||
:param baseName: The name used to represent the layer in the legend
|
||||
:param providerLib: The name of the data provider, e.g., "mesh_memory", "mdal"
|
||||
%End
|
||||
~QgsMeshLayer();
|
||||
|
||||
|
||||
virtual QgsMeshDataProvider *dataProvider();
|
||||
|
||||
%Docstring
|
||||
QgsMeshLayer cannot be copied.
|
||||
%End
|
||||
virtual QgsMeshLayer *clone() const /Factory/;
|
||||
|
||||
virtual QgsRectangle extent() const;
|
||||
|
||||
virtual QgsMapLayerRenderer *createMapRenderer( QgsRenderContext &rendererContext ) /Factory/;
|
||||
virtual bool readSymbology( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context );
|
||||
|
||||
virtual bool writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context ) const;
|
||||
|
||||
|
||||
QString providerType() const;
|
||||
%Docstring
|
||||
Return the provider type for this layer
|
||||
%End
|
||||
|
||||
|
||||
|
||||
QgsSymbol *nativeMeshSymbol();
|
||||
%Docstring
|
||||
Returns a line symbol used for rendering native mesh.
|
||||
%End
|
||||
|
||||
QgsSymbol *triangularMeshSymbol();
|
||||
%Docstring
|
||||
Returns a line symbol used for rendering of triangular (derived) mesh.
|
||||
|
||||
.. seealso:: :py:func:`toggleTriangularMeshRendering`
|
||||
%End
|
||||
|
||||
void toggleTriangularMeshRendering( bool toggle );
|
||||
%Docstring
|
||||
Toggle rendering of triangular (derived) mesh. Off by default
|
||||
%End
|
||||
|
||||
private: // Private methods
|
||||
QgsMeshLayer( const QgsMeshLayer &rhs );
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/core/mesh/qgsmeshlayer.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
28
python/core/mesh/qgsnativemesh.sip.in
Normal file
28
python/core/mesh/qgsnativemesh.sip.in
Normal file
@ -0,0 +1,28 @@
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/core/mesh/qgsnativemesh.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
typedef QgsPoint QgsMeshVertex; //xyz coords of vertex
|
||||
typedef std::vector<int> QgsMeshFace; //list of vertex indexes
|
||||
|
||||
struct QgsNativeMesh
|
||||
{
|
||||
std::vector<QgsMeshVertex> vertices;
|
||||
std::vector<QgsMeshFace> faces;
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/core/mesh/qgsnativemesh.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
@ -394,7 +394,8 @@ Item that represents a layer that can be opened with one of the providers
|
||||
TableLayer,
|
||||
Database,
|
||||
Table,
|
||||
Plugin
|
||||
Plugin,
|
||||
Mesh
|
||||
};
|
||||
|
||||
|
||||
@ -470,6 +471,10 @@ Returns the icon name of the given ``layerType``
|
||||
static QIcon iconTable();
|
||||
static QIcon iconRaster();
|
||||
static QIcon iconDefault();
|
||||
static QIcon iconMesh();
|
||||
%Docstring
|
||||
Return icon for mesh layer type
|
||||
%End
|
||||
|
||||
virtual QString layerName() const;
|
||||
%Docstring
|
||||
|
@ -38,6 +38,10 @@ to generic QgsVectorDataProvider's) depends on it.
|
||||
{
|
||||
sipType = sipType_QgsRasterDataProvider;
|
||||
}
|
||||
else if ( qobject_cast<QgsMeshDataProvider *>( sipCpp ) )
|
||||
{
|
||||
sipType = sipType_QgsMeshDataProvider;
|
||||
}
|
||||
else
|
||||
{
|
||||
sipType = 0;
|
||||
|
@ -41,6 +41,9 @@ This is the base class for all map layer types (vector, raster).
|
||||
case QgsMapLayer::PluginLayer:
|
||||
sipType = sipType_QgsPluginLayer;
|
||||
break;
|
||||
case QgsMapLayer::MeshLayer:
|
||||
sipType = sipType_QgsMeshLayer;
|
||||
break;
|
||||
default:
|
||||
sipType = nullptr;
|
||||
break;
|
||||
@ -53,7 +56,8 @@ This is the base class for all map layer types (vector, raster).
|
||||
{
|
||||
VectorLayer,
|
||||
RasterLayer,
|
||||
PluginLayer
|
||||
PluginLayer,
|
||||
MeshLayer
|
||||
};
|
||||
|
||||
enum PropertyType
|
||||
|
@ -52,6 +52,14 @@ Get vector layer from uri if possible, otherwise returns 0 and error is set
|
||||
%Docstring
|
||||
Get raster layer from uri if possible, otherwise returns 0 and error is set
|
||||
|
||||
:param owner: set to true if caller becomes owner
|
||||
:param error: set to error message if cannot get raster
|
||||
%End
|
||||
|
||||
QgsMeshLayer *meshLayer( bool &owner, QString &error ) const;
|
||||
%Docstring
|
||||
Get mesh layer from uri if possible, otherwise returns 0 and error is set
|
||||
|
||||
:param owner: set to true if caller becomes owner
|
||||
:param error: set to error message if cannot get raster
|
||||
%End
|
||||
|
@ -162,6 +162,7 @@ buildSupportedRasterFileFilter to a string, which is then returned.
|
||||
|
||||
This replaces :py:func:`QgsRasterLayer.buildSupportedRasterFileFilter()`
|
||||
%End
|
||||
|
||||
virtual QString databaseDrivers() const;
|
||||
%Docstring
|
||||
Return a string containing the available database drivers
|
||||
|
@ -142,6 +142,12 @@ QVariantMap QgsPackageAlgorithm::processAlgorithm( const QVariantMap ¶meters
|
||||
feedback->pushDebugInfo( QObject::tr( "Packaging plugin layers is not supported." ) );
|
||||
errored = true;
|
||||
break;
|
||||
|
||||
case QgsMapLayer::MeshLayer:
|
||||
//not supported
|
||||
feedback->pushDebugInfo( QObject::tr( "Packaging mesh layers is not supported." ) );
|
||||
errored = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -599,6 +599,7 @@ INCLUDE_DIRECTORIES(
|
||||
${CMAKE_SOURCE_DIR}/src/core/geometry
|
||||
${CMAKE_SOURCE_DIR}/src/core/geocms/geonode
|
||||
${CMAKE_SOURCE_DIR}/src/core/metadata
|
||||
${CMAKE_SOURCE_DIR}/src/core/mesh
|
||||
${CMAKE_SOURCE_DIR}/src/core/layertree
|
||||
${CMAKE_SOURCE_DIR}/src/core/locator
|
||||
${CMAKE_SOURCE_DIR}/src/core/providers/memory
|
||||
|
@ -228,6 +228,7 @@ Q_GUI_EXPORT extern int qt_defaultDpiX();
|
||||
#include "qgsmessageviewer.h"
|
||||
#include "qgsmessagebar.h"
|
||||
#include "qgsmessagebaritem.h"
|
||||
#include "qgsmeshlayer.h"
|
||||
#include "qgsmemoryproviderutils.h"
|
||||
#include "qgsmimedatautils.h"
|
||||
#include "qgsmessagelog.h"
|
||||
@ -1667,6 +1668,11 @@ void QgisApp::handleDropUriList( const QgsMimeDataUtils::UriList &lst )
|
||||
{
|
||||
addRasterLayer( uri, u.name, u.providerKey );
|
||||
}
|
||||
else if ( u.layerType == QLatin1String( "mesh" ) )
|
||||
{
|
||||
QgsMeshLayer *layer = new QgsMeshLayer( uri, u.name, u.providerKey );
|
||||
addMapLayer( layer );
|
||||
}
|
||||
else if ( u.layerType == QLatin1String( "plugin" ) )
|
||||
{
|
||||
addPluginLayer( uri, u.name, u.providerKey );
|
||||
|
@ -447,6 +447,12 @@ SET(QGIS_CORE_SRCS
|
||||
raster/qgssinglebandpseudocolorrenderer.cpp
|
||||
raster/qgshillshaderenderer.cpp
|
||||
|
||||
mesh/qgsmeshdataprovider.cpp
|
||||
mesh/qgsmeshlayer.cpp
|
||||
mesh/qgsmeshlayerrenderer.cpp
|
||||
mesh/qgsmeshmemorydataprovider.cpp
|
||||
mesh/qgstriangularmesh.cpp
|
||||
|
||||
geometry/qgsabstractgeometry.cpp
|
||||
geometry/qgsbox3d.cpp
|
||||
geometry/qgscircle.cpp
|
||||
@ -684,6 +690,10 @@ SET(QGIS_CORE_MOC_HDRS
|
||||
raster/qgsrasterlayerrenderer.h
|
||||
raster/qgsrasterprojector.h
|
||||
|
||||
mesh/qgsmeshdataprovider.h
|
||||
mesh/qgsmeshlayer.h
|
||||
mesh/qgsmeshmemorydataprovider.h
|
||||
|
||||
geometry/qgsabstractgeometry.h
|
||||
geometry/qgsgeometry.h
|
||||
geometry/qgspoint.h
|
||||
@ -1061,6 +1071,9 @@ SET(QGIS_CORE_HDRS
|
||||
raster/qgssinglebandpseudocolorrenderer.h
|
||||
raster/qgshillshaderenderer.h
|
||||
|
||||
mesh/qgstriangularmesh.h
|
||||
mesh/qgsmeshlayerrenderer.h
|
||||
|
||||
scalebar/qgsdoubleboxscalebarrenderer.h
|
||||
scalebar/qgsnumericscalebarrenderer.h
|
||||
scalebar/qgsscalebarsettings.h
|
||||
@ -1181,6 +1194,7 @@ INCLUDE_DIRECTORIES(
|
||||
scalebar
|
||||
symbology
|
||||
metadata
|
||||
mesh
|
||||
${CMAKE_SOURCE_DIR}/external/nmea
|
||||
)
|
||||
IF (WITH_INTERNAL_QEXTSERIALPORT)
|
||||
|
@ -3642,6 +3642,8 @@ static QVariant fcnGetLayerProperty( const QVariantList &values, const QgsExpres
|
||||
return QCoreApplication::translate( "expressions", "Vector" );
|
||||
case QgsMapLayer::RasterLayer:
|
||||
return QCoreApplication::translate( "expressions", "Raster" );
|
||||
case QgsMapLayer::MeshLayer:
|
||||
return QCoreApplication::translate( "expressions", "Mesh" );
|
||||
case QgsMapLayer::PluginLayer:
|
||||
return QCoreApplication::translate( "expressions", "Plugin" );
|
||||
}
|
||||
|
40
src/core/mesh/qgsmeshdataprovider.cpp
Normal file
40
src/core/mesh/qgsmeshdataprovider.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
/***************************************************************************
|
||||
qgsmeshdataprovider.cpp
|
||||
-----------------------
|
||||
begin : April 2018
|
||||
copyright : (C) 2018 by Peter Petrik
|
||||
email : zilolv at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsmeshdataprovider.h"
|
||||
|
||||
QgsMeshDataProvider::QgsMeshDataProvider( const QString &uri )
|
||||
: QgsDataProvider( uri )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
QgsRectangle QgsMeshDataProvider::extent() const
|
||||
{
|
||||
QgsRectangle rec;
|
||||
rec.setMinimal();
|
||||
for ( int i = 0; i < vertexCount(); ++i )
|
||||
{
|
||||
QgsMeshVertex v = vertex( i );
|
||||
rec.setXMinimum( std::min( rec.xMinimum(), v.x() ) );
|
||||
rec.setYMinimum( std::min( rec.yMinimum(), v.y() ) );
|
||||
rec.setXMaximum( std::max( rec.xMaximum(), v.x() ) );
|
||||
rec.setYMaximum( std::max( rec.yMaximum(), v.y() ) );
|
||||
}
|
||||
return rec;
|
||||
|
||||
}
|
98
src/core/mesh/qgsmeshdataprovider.h
Normal file
98
src/core/mesh/qgsmeshdataprovider.h
Normal file
@ -0,0 +1,98 @@
|
||||
/***************************************************************************
|
||||
qgsmeshdataprovider.h
|
||||
---------------------
|
||||
begin : April 2018
|
||||
copyright : (C) 2018 by Peter Petrik
|
||||
email : zilolv at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSMESHDATAPROVIDER_H
|
||||
#define QGSMESHDATAPROVIDER_H
|
||||
|
||||
#include "qgis_core.h"
|
||||
#include "qgspoint.h"
|
||||
#include "qgsrectangle.h"
|
||||
#include "qgsdataprovider.h"
|
||||
|
||||
#include <QVector>
|
||||
#include <QString>
|
||||
|
||||
typedef QgsPoint QgsMeshVertex; //xyz coords of vertex
|
||||
typedef QVector<int> QgsMeshFace; //list of vertex indexes
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* Mesh is a collection of vertices and faces in 2D or 3D space
|
||||
* - vertex - XY(Z) point (in the mesh's coordinate reference system)
|
||||
* - faces - sets of vertices forming a closed shape - typically triangles or quadrilaterals
|
||||
*
|
||||
* Base on the underlying data provider/format, whole mesh is either stored in memory or
|
||||
* read on demand
|
||||
*
|
||||
* \since QGIS 3.2
|
||||
*/
|
||||
class CORE_EXPORT QgsMeshSource SIP_ABSTRACT
|
||||
{
|
||||
public:
|
||||
//! Dtor
|
||||
virtual ~QgsMeshSource() = default;
|
||||
|
||||
/**
|
||||
* \brief Return number of vertices in the native mesh
|
||||
* \returns Number of vertices in the mesh
|
||||
*/
|
||||
virtual int vertexCount() const = 0;
|
||||
|
||||
/**
|
||||
* \brief Return number of faces in the native mesh
|
||||
* \returns Number of faces in the mesh
|
||||
*/
|
||||
virtual int faceCount() const = 0;
|
||||
|
||||
/**
|
||||
* \brief Factory for mesh vertex with index
|
||||
* \returns new mesh vertex on index
|
||||
*/
|
||||
virtual QgsMeshVertex vertex( int index ) const = 0;
|
||||
|
||||
/**
|
||||
* \brief Factory for mesh face with index
|
||||
* \returns new mesh face on index
|
||||
*/
|
||||
virtual QgsMeshFace face( int index ) const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* Base class for providing data for QgsMeshLayer
|
||||
*
|
||||
* Responsible for reading native mesh data
|
||||
*
|
||||
* \see QgsMeshSource
|
||||
* \since QGIS 3.2
|
||||
*/
|
||||
class CORE_EXPORT QgsMeshDataProvider: public QgsDataProvider, public QgsMeshSource
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
//! Ctor
|
||||
QgsMeshDataProvider( const QString &uri = QString() );
|
||||
|
||||
/**
|
||||
* Returns the extent of the layer
|
||||
* \returns QgsRectangle containing the extent of the layer
|
||||
*/
|
||||
virtual QgsRectangle extent() const;
|
||||
};
|
||||
|
||||
#endif // QGSMESHDATAPROVIDER_H
|
214
src/core/mesh/qgsmeshlayer.cpp
Normal file
214
src/core/mesh/qgsmeshlayer.cpp
Normal file
@ -0,0 +1,214 @@
|
||||
/***************************************************************************
|
||||
qgsmeshlayer.cpp
|
||||
----------------
|
||||
begin : April 2018
|
||||
copyright : (C) 2018 by Peter Petrik
|
||||
email : zilolv at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <QUuid>
|
||||
|
||||
#include "qgsfillsymbollayer.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgsmeshdataprovider.h"
|
||||
#include "qgsmeshlayer.h"
|
||||
#include "qgsmeshlayerrenderer.h"
|
||||
#include "qgsproviderregistry.h"
|
||||
#include "qgstriangularmesh.h"
|
||||
|
||||
QgsMeshLayer::QgsMeshLayer( const QString &meshLayerPath,
|
||||
const QString &baseName,
|
||||
const QString &providerKey )
|
||||
: QgsMapLayer( MeshLayer, baseName, meshLayerPath )
|
||||
, mProviderKey( providerKey )
|
||||
{
|
||||
// load data
|
||||
setDataProvider( providerKey );
|
||||
|
||||
QgsSymbolLayerList l1;
|
||||
l1 << new QgsSimpleFillSymbolLayer( Qt::white, Qt::NoBrush, Qt::black, Qt::SolidLine, 1.0 );
|
||||
mNativeMeshSymbol.reset( new QgsFillSymbol( l1 ) );
|
||||
|
||||
|
||||
toggleTriangularMeshRendering( false );
|
||||
|
||||
} // QgsMeshLayer ctor
|
||||
|
||||
|
||||
|
||||
QgsMeshLayer::~QgsMeshLayer()
|
||||
{
|
||||
if ( mDataProvider )
|
||||
delete mDataProvider;
|
||||
}
|
||||
|
||||
QgsMeshDataProvider *QgsMeshLayer::dataProvider()
|
||||
{
|
||||
return mDataProvider;
|
||||
}
|
||||
|
||||
const QgsMeshDataProvider *QgsMeshLayer::dataProvider() const
|
||||
{
|
||||
return mDataProvider;
|
||||
}
|
||||
|
||||
QgsMeshLayer *QgsMeshLayer::clone() const
|
||||
{
|
||||
QgsMeshLayer *layer = new QgsMeshLayer( source(), name(), mProviderKey );
|
||||
QgsMapLayer::clone( layer );
|
||||
return layer;
|
||||
}
|
||||
|
||||
QgsRectangle QgsMeshLayer::extent() const
|
||||
{
|
||||
if ( mDataProvider )
|
||||
return mDataProvider->extent();
|
||||
else
|
||||
{
|
||||
QgsRectangle rec;
|
||||
rec.setMinimal();
|
||||
return rec;
|
||||
}
|
||||
}
|
||||
|
||||
QString QgsMeshLayer::providerType() const
|
||||
{
|
||||
return mProviderKey;
|
||||
}
|
||||
|
||||
QgsMesh *QgsMeshLayer::nativeMesh() SIP_SKIP
|
||||
{
|
||||
return mNativeMesh.get();
|
||||
}
|
||||
|
||||
|
||||
QgsTriangularMesh *QgsMeshLayer::triangularMesh() SIP_SKIP
|
||||
{
|
||||
return mTriangularMesh.get();
|
||||
}
|
||||
|
||||
QgsSymbol *QgsMeshLayer::nativeMeshSymbol()
|
||||
{
|
||||
return mNativeMeshSymbol.get();
|
||||
}
|
||||
|
||||
QgsSymbol *QgsMeshLayer::triangularMeshSymbol()
|
||||
{
|
||||
return mTriangularMeshSymbol.get();
|
||||
}
|
||||
|
||||
void QgsMeshLayer::toggleTriangularMeshRendering( bool toggle )
|
||||
{
|
||||
if ( toggle && mTriangularMeshSymbol )
|
||||
return;
|
||||
|
||||
if ( toggle )
|
||||
{
|
||||
QgsSymbolLayerList l2;
|
||||
l2 << new QgsSimpleFillSymbolLayer( Qt::white, Qt::NoBrush, Qt::red, Qt::SolidLine, 0.26 );
|
||||
mTriangularMeshSymbol.reset( new QgsFillSymbol( l2 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
mTriangularMeshSymbol.reset();
|
||||
}
|
||||
triggerRepaint();
|
||||
}
|
||||
|
||||
void QgsMeshLayer::fillNativeMesh()
|
||||
{
|
||||
Q_ASSERT( !mNativeMesh );
|
||||
|
||||
mNativeMesh.reset( new QgsMesh() );
|
||||
|
||||
if ( !( dataProvider() && dataProvider()->isValid() ) )
|
||||
return;
|
||||
|
||||
mNativeMesh->vertices.resize( dataProvider()->vertexCount() );
|
||||
for ( int i = 0; i < dataProvider()->vertexCount(); ++i )
|
||||
{
|
||||
mNativeMesh->vertices[i] = dataProvider()->vertex( i );
|
||||
}
|
||||
|
||||
mNativeMesh->faces.resize( dataProvider()->faceCount() );
|
||||
for ( int i = 0; i < dataProvider()->faceCount(); ++i )
|
||||
{
|
||||
mNativeMesh->faces[i] = dataProvider()->face( i );
|
||||
}
|
||||
}
|
||||
|
||||
QgsMapLayerRenderer *QgsMeshLayer::createMapRenderer( QgsRenderContext &rendererContext )
|
||||
{
|
||||
if ( !mNativeMesh )
|
||||
{
|
||||
// lazy loading of mesh data
|
||||
fillNativeMesh();
|
||||
}
|
||||
|
||||
if ( !mTriangularMesh )
|
||||
mTriangularMesh.reset( new QgsTriangularMesh() );
|
||||
|
||||
mTriangularMesh->update( mNativeMesh.get(), &rendererContext );
|
||||
return new QgsMeshLayerRenderer( this, rendererContext );
|
||||
}
|
||||
|
||||
bool QgsMeshLayer::readSymbology( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context )
|
||||
{
|
||||
Q_UNUSED( node );
|
||||
Q_UNUSED( errorMessage );
|
||||
Q_UNUSED( context );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QgsMeshLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context ) const
|
||||
{
|
||||
Q_UNUSED( node );
|
||||
Q_UNUSED( doc );
|
||||
Q_UNUSED( errorMessage );
|
||||
Q_UNUSED( context );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QgsMeshLayer::setDataProvider( QString const &provider )
|
||||
{
|
||||
Q_ASSERT( !mDataProvider ); //called from ctor
|
||||
|
||||
mProviderKey = provider;
|
||||
QString dataSource = mDataSource;
|
||||
|
||||
mDataProvider = qobject_cast<QgsMeshDataProvider *>( QgsProviderRegistry::instance()->createProvider( provider, dataSource ) );
|
||||
if ( !mDataProvider )
|
||||
{
|
||||
QgsDebugMsgLevel( QStringLiteral( "Unable to get mesh data provider" ), 2 );
|
||||
return false;
|
||||
}
|
||||
|
||||
mDataProvider->setParent( this );
|
||||
QgsDebugMsgLevel( QStringLiteral( "Instantiated the mesh data provider plugin" ), 2 );
|
||||
|
||||
mValid = mDataProvider->isValid();
|
||||
if ( !mValid )
|
||||
{
|
||||
QgsDebugMsgLevel( QStringLiteral( "Invalid mesh provider plugin %1" ).arg( QString( mDataSource.toUtf8() ) ), 2 );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( provider == QStringLiteral( "mesh_memory" ) )
|
||||
{
|
||||
// required so that source differs between memory layers
|
||||
mDataSource = mDataSource + QStringLiteral( "&uid=%1" ).arg( QUuid::createUuid().toString() );
|
||||
}
|
||||
|
||||
return true;
|
||||
} // QgsMeshLayer:: setDataProvider
|
179
src/core/mesh/qgsmeshlayer.h
Normal file
179
src/core/mesh/qgsmeshlayer.h
Normal file
@ -0,0 +1,179 @@
|
||||
/***************************************************************************
|
||||
qgsmeshlayer.h
|
||||
--------------
|
||||
begin : April 2018
|
||||
copyright : (C) 2018 by Peter Petrik
|
||||
email : zilolv at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSMESHLAYER_H
|
||||
#define QGSMESHLAYER_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "qgis_core.h"
|
||||
#include "qgsmaplayer.h"
|
||||
#include "qgsrendercontext.h"
|
||||
#include "qgsmeshdataprovider.h"
|
||||
|
||||
class QgsMapLayerRenderer;
|
||||
class QgsSymbol;
|
||||
class QgsTriangularMesh;
|
||||
struct QgsMesh;
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
*
|
||||
* Represents a mesh layer supporting display of data on structured or unstructured meshes
|
||||
*
|
||||
* The QgsMeshLayer is instantiated by specifying the name of a data provider,
|
||||
* such as mdal, and url defining the specific data set to connect to.
|
||||
* The vector layer constructor in turn instantiates a QgsMeshDataProvider subclass
|
||||
* corresponding to the provider type, and passes it the url. The data provider
|
||||
* connects to the data source.
|
||||
*
|
||||
* The QgsMeshLayer provides a common interface to the different data types. It does not
|
||||
* yet support editing transactions.
|
||||
*
|
||||
* The main data providers supported by QGIS are listed below.
|
||||
*
|
||||
* \section mesh_providers Mesh data providers
|
||||
*
|
||||
* \subsection mesh_memory Memory data providerType (mesh_memory)
|
||||
*
|
||||
* The memory data provider is used to construct in memory data, for example scratch
|
||||
* data. There is no inherent persistent storage of the data. The data source uri is constructed.
|
||||
* Data can be populated by setMesh(const QString &vertices, const QString &faces), where
|
||||
* vertices and faces is comma separated coordinates and connections for mesh.
|
||||
* E.g. to create mesh with one quad and one triangle
|
||||
*
|
||||
* \code
|
||||
* QString uri(
|
||||
* "1.0, 2.0 \n" \
|
||||
* "2.0, 2.0 \n" \
|
||||
* "3.0, 2.0 \n" \
|
||||
* "2.0, 3.0 \n" \
|
||||
* "1.0, 3.0 \n" \
|
||||
* "---"
|
||||
* "0, 1, 3, 4 \n" \
|
||||
* "1, 2, 3 \n"
|
||||
* );
|
||||
* QgsMeshLayer *scratchLayer = new QgsMeshLayer(uri, "My Scratch layer", "memory_mesh");
|
||||
* \endcode
|
||||
*
|
||||
* \subsection mdal MDAL data provider (mdal)
|
||||
*
|
||||
* Accesses data using the MDAL drivers (https://github.com/lutraconsulting/MDAL). The url
|
||||
* is the MDAL connection string. QGIS must be built with MDAL support to allow this provider.
|
||||
|
||||
* \code
|
||||
* QString uri = "test/land.2dm";
|
||||
* QgsMeshLayer *scratchLayer = new QgsMeshLayer(uri, "My Scratch Layer", "mdal");
|
||||
* \endcode
|
||||
*
|
||||
* \since QGIS 3.2
|
||||
*/
|
||||
class CORE_EXPORT QgsMeshLayer : public QgsMapLayer
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor - creates a mesh layer
|
||||
*
|
||||
* The QgsMeshLayer is constructed by instantiating a data provider. The provider
|
||||
* interprets the supplied path (url) of the data source to connect to and access the
|
||||
* data.
|
||||
*
|
||||
* \param path The path or url of the parameter. Typically this encodes
|
||||
* parameters used by the data provider as url query items.
|
||||
* \param baseName The name used to represent the layer in the legend
|
||||
* \param providerLib The name of the data provider, e.g., "mesh_memory", "mdal"
|
||||
*/
|
||||
explicit QgsMeshLayer( const QString &path = QString(), const QString &baseName = QString(), const QString &providerLib = "mesh_memory" );
|
||||
~QgsMeshLayer() override;
|
||||
|
||||
//! QgsMeshLayer cannot be copied.
|
||||
QgsMeshLayer( const QgsMeshLayer &rhs ) = delete;
|
||||
//! QgsMeshLayer cannot be copied.
|
||||
QgsMeshLayer &operator=( QgsMeshLayer const &rhs ) = delete;
|
||||
|
||||
QgsMeshDataProvider *dataProvider() override;
|
||||
const QgsMeshDataProvider *dataProvider() const override SIP_SKIP;
|
||||
QgsMeshLayer *clone() const override SIP_FACTORY;
|
||||
QgsRectangle extent() const override;
|
||||
virtual QgsMapLayerRenderer *createMapRenderer( QgsRenderContext &rendererContext ) override SIP_FACTORY;
|
||||
bool readSymbology( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context ) override;
|
||||
bool writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context ) const override;
|
||||
|
||||
//! Return the provider type for this layer
|
||||
QString providerType() const;
|
||||
|
||||
//! return native mesh (nullprt before rendering)
|
||||
QgsMesh *nativeMesh() SIP_SKIP;
|
||||
|
||||
//! return triangular mesh (nullprt before rendering)
|
||||
QgsTriangularMesh *triangularMesh() SIP_SKIP;
|
||||
|
||||
//! Returns a line symbol used for rendering native mesh.
|
||||
QgsSymbol *nativeMeshSymbol();
|
||||
|
||||
/**
|
||||
* Returns a line symbol used for rendering of triangular (derived) mesh.
|
||||
* \see toggleTriangularMeshRendering
|
||||
*/
|
||||
QgsSymbol *triangularMeshSymbol();
|
||||
|
||||
//! Toggle rendering of triangular (derived) mesh. Off by default
|
||||
void toggleTriangularMeshRendering( bool toggle );
|
||||
|
||||
private: // Private methods
|
||||
|
||||
/**
|
||||
* Returns true if the provider is in read-only mode
|
||||
*/
|
||||
bool isReadOnly() const override {return true;}
|
||||
|
||||
/**
|
||||
* Bind layer to a specific data provider
|
||||
* \param provider provider key string, must match a valid QgsMeshDataProvider key. E.g. "mesh_memory", etc.
|
||||
*/
|
||||
bool setDataProvider( QString const &provider );
|
||||
|
||||
#ifdef SIP_RUN
|
||||
QgsMeshLayer( const QgsMeshLayer &rhs );
|
||||
#endif
|
||||
|
||||
private:
|
||||
void fillNativeMesh();
|
||||
|
||||
private:
|
||||
//! Pointer to data provider derived from the abastract base class QgsMeshDataProvider
|
||||
QgsMeshDataProvider *mDataProvider = nullptr;
|
||||
|
||||
//! Data provider key
|
||||
QString mProviderKey;
|
||||
|
||||
//! Pointer to native mesh structure, used as cache for rendering
|
||||
std::unique_ptr<QgsMesh> mNativeMesh;
|
||||
|
||||
//! Pointer to derived mesh structure
|
||||
std::unique_ptr<QgsTriangularMesh> mTriangularMesh;
|
||||
|
||||
//! rendering native mesh
|
||||
std::unique_ptr<QgsSymbol> mNativeMeshSymbol;
|
||||
|
||||
//! rendering triangular mesh
|
||||
std::unique_ptr<QgsSymbol> mTriangularMeshSymbol;
|
||||
};
|
||||
|
||||
#endif //QGSMESHLAYER_H
|
93
src/core/mesh/qgsmeshlayerrenderer.cpp
Normal file
93
src/core/mesh/qgsmeshlayerrenderer.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
/***************************************************************************
|
||||
qgsmeshlayerrenderer.cpp
|
||||
------------------------
|
||||
begin : April 2018
|
||||
copyright : (C) 2018 by Peter Petrik
|
||||
email : zilolv at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsmeshlayerrenderer.h"
|
||||
|
||||
#include "qgsfield.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgsmeshlayer.h"
|
||||
#include "qgspointxy.h"
|
||||
#include "qgsrenderer.h"
|
||||
#include "qgssinglesymbolrenderer.h"
|
||||
#include "qgssymbol.h"
|
||||
|
||||
|
||||
|
||||
QgsMeshLayerRenderer::QgsMeshLayerRenderer( QgsMeshLayer *layer, QgsRenderContext &context )
|
||||
: QgsMapLayerRenderer( layer->id() )
|
||||
, mContext( context )
|
||||
{
|
||||
// make copies for mesh data
|
||||
Q_ASSERT( layer->nativeMesh() );
|
||||
Q_ASSERT( layer->triangularMesh() );
|
||||
mNativeMesh = *( layer->nativeMesh() );
|
||||
mTriangularMesh = *( layer->triangularMesh() );
|
||||
|
||||
// make copies for symbols
|
||||
if ( layer->nativeMeshSymbol() )
|
||||
{
|
||||
mNativeMeshSymbol.reset( layer->nativeMeshSymbol()->clone() );
|
||||
}
|
||||
|
||||
if ( layer->triangularMeshSymbol() )
|
||||
{
|
||||
mTriangularMeshSymbol.reset( layer->triangularMeshSymbol()->clone() );
|
||||
}
|
||||
}
|
||||
|
||||
bool QgsMeshLayerRenderer::render()
|
||||
{
|
||||
renderMesh( mNativeMeshSymbol, mNativeMesh.faces ); // native mesh
|
||||
renderMesh( mTriangularMeshSymbol, mTriangularMesh.triangles() ); // triangular mesh
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void QgsMeshLayerRenderer::renderMesh( const std::unique_ptr<QgsSymbol> &symbol, const QVector<QgsMeshFace> &faces )
|
||||
{
|
||||
if ( !symbol )
|
||||
return;
|
||||
|
||||
QgsFields fields;
|
||||
QgsSingleSymbolRenderer renderer( symbol->clone() );
|
||||
renderer.startRender( mContext, fields );
|
||||
|
||||
for ( int i = 0; i < faces.size(); ++i )
|
||||
{
|
||||
if ( mContext.renderingStopped() )
|
||||
break;
|
||||
|
||||
const QgsMeshFace &face = faces[i];
|
||||
QgsFeature feat;
|
||||
feat.setFields( fields );
|
||||
QVector<QgsPointXY> ring;
|
||||
for ( int j = 0; j < face.size(); ++j )
|
||||
{
|
||||
int vertex_id = face[j];
|
||||
Q_ASSERT( vertex_id < mTriangularMesh.vertices().size() ); //Triangular mesh vertices contains also native mesh vertices
|
||||
const QgsPoint &vertex = mTriangularMesh.vertices()[vertex_id];
|
||||
ring.append( vertex );
|
||||
}
|
||||
QgsPolygonXY polygon;
|
||||
polygon.append( ring );
|
||||
QgsGeometry geom = QgsGeometry::fromPolygonXY( polygon );
|
||||
feat.setGeometry( geom );
|
||||
renderer.renderFeature( feat, mContext );
|
||||
}
|
||||
|
||||
renderer.stopRender( mContext );
|
||||
}
|
72
src/core/mesh/qgsmeshlayerrenderer.h
Normal file
72
src/core/mesh/qgsmeshlayerrenderer.h
Normal file
@ -0,0 +1,72 @@
|
||||
/***************************************************************************
|
||||
qgsmeshlayerrenderer.h
|
||||
----------------------
|
||||
begin : April 2018
|
||||
copyright : (C) 2018 by Peter Petrik
|
||||
email : zilolv at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSMESHLAYERRENDERER_H
|
||||
#define QGSMESHLAYERRENDERER_H
|
||||
|
||||
class QgsMeshLayer;
|
||||
class QgsSymbol;
|
||||
|
||||
#define SIP_NO_FILE
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "qgis.h"
|
||||
|
||||
#include "qgsmaplayerrenderer.h"
|
||||
#include "qgsrendercontext.h"
|
||||
#include "qgstriangularmesh.h"
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* Implementation of threaded rendering for mesh layers.
|
||||
*
|
||||
* \since QGIS 3.2
|
||||
* \note not available in Python bindings
|
||||
*/
|
||||
class QgsMeshLayerRenderer : public QgsMapLayerRenderer
|
||||
{
|
||||
public:
|
||||
//! Ctor
|
||||
QgsMeshLayerRenderer( QgsMeshLayer *layer, QgsRenderContext &context );
|
||||
|
||||
~QgsMeshLayerRenderer() override = default;
|
||||
bool render() override;
|
||||
|
||||
private:
|
||||
void renderMesh( const std::unique_ptr<QgsSymbol> &symbol, const QVector<QgsMeshFace> &faces );
|
||||
|
||||
|
||||
protected:
|
||||
// copy from mesh layer
|
||||
QgsMesh mNativeMesh;
|
||||
|
||||
// copy from mesh layer
|
||||
QgsTriangularMesh mTriangularMesh;
|
||||
|
||||
// copy from mesh layer
|
||||
std::unique_ptr<QgsSymbol> mNativeMeshSymbol = nullptr;
|
||||
|
||||
// copy from mesh layer
|
||||
std::unique_ptr<QgsSymbol> mTriangularMeshSymbol = nullptr;
|
||||
|
||||
// rendering context
|
||||
QgsRenderContext &mContext;
|
||||
};
|
||||
|
||||
|
||||
#endif // QGSMESHLAYERRENDERER_H
|
169
src/core/mesh/qgsmeshmemorydataprovider.cpp
Normal file
169
src/core/mesh/qgsmeshmemorydataprovider.cpp
Normal file
@ -0,0 +1,169 @@
|
||||
/***************************************************************************
|
||||
qgsmeshmemorydataprovider.cpp
|
||||
-----------------------------
|
||||
begin : April 2018
|
||||
copyright : (C) 2018 by Peter Petrik
|
||||
email : zilolv at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
///@cond PRIVATE
|
||||
|
||||
#include "qgsmeshmemorydataprovider.h"
|
||||
|
||||
static const QString TEXT_PROVIDER_KEY = QStringLiteral( "mesh_memory" );
|
||||
static const QString TEXT_PROVIDER_DESCRIPTION = QStringLiteral( "Mesh memory provider" );
|
||||
|
||||
bool QgsMeshMemoryDataProvider::isValid() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
QString QgsMeshMemoryDataProvider::name() const
|
||||
{
|
||||
return TEXT_PROVIDER_KEY;
|
||||
}
|
||||
|
||||
QString QgsMeshMemoryDataProvider::description() const
|
||||
{
|
||||
return TEXT_PROVIDER_DESCRIPTION;
|
||||
}
|
||||
|
||||
QgsCoordinateReferenceSystem QgsMeshMemoryDataProvider::crs() const
|
||||
{
|
||||
return QgsCoordinateReferenceSystem();
|
||||
}
|
||||
|
||||
QgsMeshMemoryDataProvider::QgsMeshMemoryDataProvider( const QString &uri )
|
||||
: QgsMeshDataProvider( uri )
|
||||
{
|
||||
mIsValid = splitSections( uri );
|
||||
}
|
||||
|
||||
QgsMeshMemoryDataProvider::~QgsMeshMemoryDataProvider()
|
||||
{
|
||||
}
|
||||
|
||||
QString QgsMeshMemoryDataProvider::providerKey()
|
||||
{
|
||||
return TEXT_PROVIDER_KEY;
|
||||
}
|
||||
|
||||
QString QgsMeshMemoryDataProvider::providerDescription()
|
||||
{
|
||||
return TEXT_PROVIDER_DESCRIPTION;
|
||||
}
|
||||
|
||||
QgsMeshMemoryDataProvider *QgsMeshMemoryDataProvider::createProvider( const QString &uri )
|
||||
{
|
||||
return new QgsMeshMemoryDataProvider( uri );
|
||||
}
|
||||
|
||||
bool QgsMeshMemoryDataProvider::splitSections( const QString &uri )
|
||||
{
|
||||
const QStringList sections = uri.split( QStringLiteral( "---" ), QString::SkipEmptyParts );
|
||||
if ( sections.size() != 2 )
|
||||
{
|
||||
setError( QgsError( QStringLiteral( "Invalid mesh definition, does not contain 2 sections" ),
|
||||
QStringLiteral( "Mesh Memory Provider" ) ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( addVertices( sections[0] ) )
|
||||
return addFaces( sections[1] );
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QgsMeshMemoryDataProvider::addVertices( const QString &def )
|
||||
{
|
||||
QVector<QgsMeshVertex> vertices;
|
||||
|
||||
const QStringList verticesCoords = def.split( '\n', QString::SkipEmptyParts );
|
||||
for ( int i = 0; i < verticesCoords.size(); ++i )
|
||||
{
|
||||
const QStringList coords = verticesCoords[i].split( ',', QString::SkipEmptyParts );
|
||||
if ( coords.size() != 2 )
|
||||
{
|
||||
setError( QgsError( QStringLiteral( "Invalid mesh definition, vertex definition does not contain x, y" ),
|
||||
QStringLiteral( "Mesh Memory Provider" ) ) );
|
||||
return false;
|
||||
}
|
||||
double x = coords.at( 0 ).toDouble();
|
||||
double y = coords.at( 1 ).toDouble();
|
||||
QgsMeshVertex vertex( x, y );
|
||||
vertices.push_back( vertex );
|
||||
}
|
||||
|
||||
mVertices = vertices;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QgsMeshMemoryDataProvider::addFaces( const QString &def )
|
||||
{
|
||||
QVector<QgsMeshFace> faces;
|
||||
|
||||
const QStringList facesVertices = def.split( '\n', QString::SkipEmptyParts );
|
||||
for ( int i = 0; i < facesVertices.size(); ++i )
|
||||
{
|
||||
const QStringList vertices = facesVertices[i].split( ',', QString::SkipEmptyParts );
|
||||
if ( vertices.size() < 3 )
|
||||
{
|
||||
setError( QgsError( QStringLiteral( "Invalid mesh definition, face must contain at least 3 vertices" ),
|
||||
QStringLiteral( "Mesh Memory Provider" ) ) );
|
||||
return false;
|
||||
}
|
||||
QgsMeshFace face;
|
||||
for ( int j = 0; j < vertices.size(); ++j )
|
||||
{
|
||||
int vertex_id = vertices[j].toInt();
|
||||
if ( vertex_id < 0 )
|
||||
{
|
||||
setError( QgsError( QStringLiteral( "Invalid mesh definition, vertex index must be positive value" ), QStringLiteral( "Mesh Memory Provider" ) ) );
|
||||
return false;
|
||||
}
|
||||
if ( mVertices.size() < vertex_id )
|
||||
{
|
||||
setError( QgsError( QStringLiteral( "Invalid mesh definition, missing vertex id defined in face" ), QStringLiteral( "Mesh Memory Provider" ) ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
face.push_back( vertex_id );
|
||||
}
|
||||
faces.push_back( face );
|
||||
}
|
||||
|
||||
mFaces = faces;
|
||||
return true;
|
||||
}
|
||||
|
||||
int QgsMeshMemoryDataProvider::vertexCount() const
|
||||
{
|
||||
return mVertices.size();
|
||||
}
|
||||
|
||||
int QgsMeshMemoryDataProvider::faceCount() const
|
||||
{
|
||||
return mFaces.size();
|
||||
}
|
||||
|
||||
QgsMeshVertex QgsMeshMemoryDataProvider::vertex( int index ) const
|
||||
{
|
||||
Q_ASSERT( vertexCount() > index );
|
||||
return mVertices[index];
|
||||
}
|
||||
|
||||
QgsMeshFace QgsMeshMemoryDataProvider::face( int index ) const
|
||||
{
|
||||
Q_ASSERT( faceCount() > index );
|
||||
return mFaces[index];
|
||||
}
|
||||
|
||||
///@endcond
|
98
src/core/mesh/qgsmeshmemorydataprovider.h
Normal file
98
src/core/mesh/qgsmeshmemorydataprovider.h
Normal file
@ -0,0 +1,98 @@
|
||||
/***************************************************************************
|
||||
qgsmeshmemorydataprovider.h
|
||||
---------------------------
|
||||
begin : April 2018
|
||||
copyright : (C) 2018 by Peter Petrik
|
||||
email : zilolv at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSMESHMEMORYDATAPROVIDER_H
|
||||
#define QGSMESHMEMORYDATAPROVIDER_H
|
||||
|
||||
#define SIP_NO_FILE
|
||||
|
||||
///@cond PRIVATE
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include "qgis_core.h"
|
||||
#include "qgis.h"
|
||||
#include "qgsmeshdataprovider.h"
|
||||
#include "qgsrectangle.h"
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* Provides data stored in-memory for QgsMeshLayer. Useful for plugins or tests.
|
||||
* \since QGIS 3.2
|
||||
*/
|
||||
class QgsMeshMemoryDataProvider: public QgsMeshDataProvider
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Construct a mesh in-memory data provider from data string
|
||||
*
|
||||
* Data string constains simple definition of vertices and faces
|
||||
* Each entry is separated by "\n" sign and section deliminer "---"
|
||||
* vertex is x and y coordinate separated by comma
|
||||
* face is list of vertex indexes, numbered from 0
|
||||
* For example:
|
||||
*
|
||||
* \code
|
||||
* QString uri(
|
||||
* "1.0, 2.0 \n" \
|
||||
* "2.0, 2.0 \n" \
|
||||
* "3.0, 2.0 \n" \
|
||||
* "2.0, 3.0 \n" \
|
||||
* "1.0, 3.0 \n" \
|
||||
* "---"
|
||||
* "0, 1, 3, 4 \n" \
|
||||
* "1, 2, 3 \n"
|
||||
* );
|
||||
* \endcode
|
||||
*/
|
||||
QgsMeshMemoryDataProvider( const QString &uri = QString() );
|
||||
~QgsMeshMemoryDataProvider();
|
||||
|
||||
bool isValid() const override;
|
||||
QString name() const override;
|
||||
QString description() const override;
|
||||
QgsCoordinateReferenceSystem crs() const override;
|
||||
|
||||
int vertexCount() const override;
|
||||
int faceCount() const override;
|
||||
QgsMeshVertex vertex( int index ) const override;
|
||||
QgsMeshFace face( int index ) const override;
|
||||
|
||||
//! Returns the memory provider key
|
||||
static QString providerKey();
|
||||
//! Returns the memory provider description
|
||||
static QString providerDescription();
|
||||
//! Provider factory
|
||||
static QgsMeshMemoryDataProvider *createProvider( const QString &uri );
|
||||
private:
|
||||
bool splitSections( const QString &uri );
|
||||
|
||||
bool addVertices( const QString &def );
|
||||
bool addFaces( const QString &def );
|
||||
|
||||
QVector<QgsMeshVertex> mVertices;
|
||||
QVector<QgsMeshFace> mFaces;
|
||||
|
||||
bool mIsValid = false;
|
||||
};
|
||||
|
||||
///@endcond
|
||||
|
||||
#endif // QGSMESHMEMORYDATAPROVIDER_H
|
98
src/core/mesh/qgstriangularmesh.cpp
Normal file
98
src/core/mesh/qgstriangularmesh.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
/***************************************************************************
|
||||
qgstriangularmesh.cpp
|
||||
---------------------
|
||||
begin : April 2018
|
||||
copyright : (C) 2018 by Peter Petrik
|
||||
email : zilolv at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgstriangularmesh.h"
|
||||
#include "qgsrendercontext.h"
|
||||
#include "qgscoordinatetransform.h"
|
||||
|
||||
void QgsTriangularMesh::update( QgsMesh *nativeMesh, QgsRenderContext *context )
|
||||
{
|
||||
Q_ASSERT( nativeMesh );
|
||||
Q_ASSERT( context );
|
||||
|
||||
mTriangularMesh.vertices.clear();
|
||||
mTriangularMesh.faces.clear();
|
||||
mTrianglesToNativeFaces.clear();
|
||||
|
||||
// TRANSFORM VERTICES
|
||||
QgsCoordinateTransform transform = context->coordinateTransform();
|
||||
mTriangularMesh.vertices.resize( nativeMesh->vertices.size() );
|
||||
for ( int i = 0; i < nativeMesh->vertices.size(); ++i )
|
||||
{
|
||||
const QgsMeshVertex &vertex = nativeMesh->vertices.at( i );
|
||||
if ( transform.isValid() )
|
||||
{
|
||||
QgsPointXY mapPoint = transform.transform( QgsPointXY( vertex.x(), vertex.y() ) );
|
||||
QgsMeshVertex mapVertex( mapPoint );
|
||||
mapVertex.setZ( vertex.z() );
|
||||
mapVertex.setM( vertex.m() );
|
||||
mTriangularMesh.vertices[i] = mapVertex;
|
||||
}
|
||||
else
|
||||
{
|
||||
mTriangularMesh.vertices[i] = vertex;
|
||||
}
|
||||
}
|
||||
|
||||
// CREATE TRIANGULAR MESH
|
||||
for ( int i = 0; i < nativeMesh->faces.size(); ++i )
|
||||
{
|
||||
const QgsMeshFace &face = nativeMesh->faces.at( i ) ;
|
||||
if ( face.size() == 3 )
|
||||
{
|
||||
// triangle
|
||||
mTriangularMesh.faces.push_back( face );
|
||||
mTrianglesToNativeFaces.push_back( i );
|
||||
}
|
||||
else if ( face.size() == 4 )
|
||||
{
|
||||
// quad
|
||||
QgsMeshFace face1;
|
||||
face1.push_back( face[0] );
|
||||
face1.push_back( face[1] );
|
||||
face1.push_back( face[2] );
|
||||
|
||||
mTriangularMesh.faces.push_back( face1 );
|
||||
mTrianglesToNativeFaces.push_back( i );
|
||||
|
||||
QgsMeshFace face2;
|
||||
face2.push_back( face[0] );
|
||||
face2.push_back( face[2] );
|
||||
face2.push_back( face[3] );
|
||||
|
||||
mTriangularMesh.faces.push_back( face2 );
|
||||
mTrianglesToNativeFaces.push_back( i );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const QVector<QgsMeshVertex> &QgsTriangularMesh::vertices() const
|
||||
{
|
||||
return mTriangularMesh.vertices;
|
||||
}
|
||||
|
||||
const QVector<QgsMeshFace> &QgsTriangularMesh::triangles() const
|
||||
{
|
||||
return mTriangularMesh.faces;
|
||||
}
|
||||
|
||||
const QVector<int> &QgsTriangularMesh::trianglesToNativeFaces() const
|
||||
{
|
||||
return mTrianglesToNativeFaces;
|
||||
}
|
||||
|
82
src/core/mesh/qgstriangularmesh.h
Normal file
82
src/core/mesh/qgstriangularmesh.h
Normal file
@ -0,0 +1,82 @@
|
||||
/***************************************************************************
|
||||
qgstriangularmesh.h
|
||||
-------------------
|
||||
begin : April 2018
|
||||
copyright : (C) 2018 by Peter Petrik
|
||||
email : zilolv at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSTRIANGULARMESH_H
|
||||
#define QGSTRIANGULARMESH_H
|
||||
|
||||
|
||||
#define SIP_NO_FILE
|
||||
|
||||
#include <QVector>
|
||||
|
||||
#include "qgis_core.h"
|
||||
#include "qgsmeshdataprovider.h"
|
||||
|
||||
class QgsRenderContext;
|
||||
|
||||
//! Mesh - vertices and faces
|
||||
struct CORE_EXPORT QgsMesh
|
||||
{
|
||||
//! vertices
|
||||
QVector<QgsMeshVertex> vertices;
|
||||
//! faces
|
||||
QVector<QgsMeshFace> faces;
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
*
|
||||
* Triangular/Derived Mesh
|
||||
*
|
||||
* \since QGIS 3.2
|
||||
*/
|
||||
class CORE_EXPORT QgsTriangularMesh
|
||||
{
|
||||
public:
|
||||
//! Ctor
|
||||
QgsTriangularMesh() = default;
|
||||
//! Dtor
|
||||
~QgsTriangularMesh() = default;
|
||||
|
||||
/**
|
||||
* Construct triangular mesh from layer's native mesh and context
|
||||
* \param nativeMesh QgsMesh to access native vertices and faces
|
||||
* \param context Rendering context to estimate number of triagles to create for an face
|
||||
*/
|
||||
void update( QgsMesh *nativeMesh, QgsRenderContext *context );
|
||||
|
||||
/**
|
||||
* Return vertices in map CRS
|
||||
*
|
||||
* The list of consist of vertices from native mesh (0-N) and
|
||||
* extra vertices needed to create triangles (N+1 - len)
|
||||
*/
|
||||
const QVector<QgsMeshVertex> &vertices() const ;
|
||||
//! Return triangles
|
||||
const QVector<QgsMeshFace> &triangles() const ;
|
||||
//! Return mapping between triangles and original faces
|
||||
const QVector<int> &trianglesToNativeFaces() const ;
|
||||
|
||||
private:
|
||||
// vertices: map CRS; 0-N ... native vertices, N+1 - len ... extra vertices
|
||||
// faces are derived triangles
|
||||
QgsMesh mTriangularMesh;
|
||||
QVector<int> mTrianglesToNativeFaces; //len(mTrianglesToNativeFaces) == len(mTriangles). Mapping derived -> native
|
||||
};
|
||||
|
||||
|
||||
#endif // QGSTRIANGULARMESH_H
|
@ -111,6 +111,8 @@ QgsMapLayer *QgsProcessingUtils::mapLayerFromStore( const QString &string, QgsMa
|
||||
return !canUseLayer( qobject_cast< QgsRasterLayer * >( layer ) );
|
||||
case QgsMapLayer::PluginLayer:
|
||||
return true;
|
||||
case QgsMapLayer::MeshLayer:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} ), layers.end() );
|
||||
|
@ -74,6 +74,11 @@ QIcon QgsLayerItem::iconRaster()
|
||||
return QgsApplication::getThemeIcon( QStringLiteral( "/mIconRaster.svg" ) );
|
||||
}
|
||||
|
||||
QIcon QgsLayerItem::iconMesh()
|
||||
{
|
||||
return QgsApplication::getThemeIcon( QStringLiteral( "/mIconPointLayer.svg" ) );
|
||||
}
|
||||
|
||||
QIcon QgsLayerItem::iconDefault()
|
||||
{
|
||||
return QgsApplication::getThemeIcon( QStringLiteral( "/mIconLayer.png" ) );
|
||||
@ -602,6 +607,8 @@ QgsMapLayer::LayerType QgsLayerItem::mapLayerType() const
|
||||
{
|
||||
if ( mLayerType == QgsLayerItem::Raster )
|
||||
return QgsMapLayer::RasterLayer;
|
||||
if ( mLayerType == QgsLayerItem::Mesh )
|
||||
return QgsMapLayer::MeshLayer;
|
||||
if ( mLayerType == QgsLayerItem::Plugin )
|
||||
return QgsMapLayer::PluginLayer;
|
||||
return QgsMapLayer::VectorLayer;
|
||||
@ -637,6 +644,8 @@ QString QgsLayerItem::iconName( QgsLayerItem::LayerType layerType )
|
||||
case Raster:
|
||||
return QStringLiteral( "/mIconRaster.svg" );
|
||||
break;
|
||||
case Mesh:
|
||||
//TODO add icon!
|
||||
default:
|
||||
return QStringLiteral( "/mIconLayer.png" );
|
||||
break;
|
||||
@ -670,6 +679,9 @@ QgsMimeDataUtils::Uri QgsLayerItem::mimeUri() const
|
||||
case QgsMapLayer::RasterLayer:
|
||||
u.layerType = QStringLiteral( "raster" );
|
||||
break;
|
||||
case QgsMapLayer::MeshLayer:
|
||||
u.layerType = QStringLiteral( "mesh" );
|
||||
break;
|
||||
case QgsMapLayer::PluginLayer:
|
||||
u.layerType = QStringLiteral( "plugin" );
|
||||
break;
|
||||
|
@ -422,7 +422,8 @@ class CORE_EXPORT QgsLayerItem : public QgsDataItem
|
||||
TableLayer,
|
||||
Database,
|
||||
Table,
|
||||
Plugin //!< Added in 2.10
|
||||
Plugin, //!< Added in 2.10
|
||||
Mesh //!< Added in 3.2
|
||||
};
|
||||
|
||||
Q_ENUM( LayerType );
|
||||
@ -498,6 +499,8 @@ class CORE_EXPORT QgsLayerItem : public QgsDataItem
|
||||
static QIcon iconTable();
|
||||
static QIcon iconRaster();
|
||||
static QIcon iconDefault();
|
||||
//! Return icon for mesh layer type
|
||||
static QIcon iconMesh();
|
||||
|
||||
//! \returns the layer name
|
||||
virtual QString layerName() const { return name(); }
|
||||
|
@ -59,6 +59,10 @@ class CORE_EXPORT QgsDataProvider : public QObject
|
||||
{
|
||||
sipType = sipType_QgsRasterDataProvider;
|
||||
}
|
||||
else if ( qobject_cast<QgsMeshDataProvider *>( sipCpp ) )
|
||||
{
|
||||
sipType = sipType_QgsMeshDataProvider;
|
||||
}
|
||||
else
|
||||
{
|
||||
sipType = 0;
|
||||
|
@ -85,6 +85,9 @@ class CORE_EXPORT QgsMapLayer : public QObject
|
||||
case QgsMapLayer::PluginLayer:
|
||||
sipType = sipType_QgsPluginLayer;
|
||||
break;
|
||||
case QgsMapLayer::MeshLayer:
|
||||
sipType = sipType_QgsMeshLayer;
|
||||
break;
|
||||
default:
|
||||
sipType = nullptr;
|
||||
break;
|
||||
@ -100,7 +103,8 @@ class CORE_EXPORT QgsMapLayer : public QObject
|
||||
{
|
||||
VectorLayer,
|
||||
RasterLayer,
|
||||
PluginLayer
|
||||
PluginLayer,
|
||||
MeshLayer //!< Added in 3.2
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -359,6 +359,11 @@ QIcon QgsMapLayerModel::iconForLayer( QgsMapLayer *layer )
|
||||
return QgsLayerItem::iconRaster();
|
||||
}
|
||||
|
||||
case QgsMapLayer::MeshLayer:
|
||||
{
|
||||
return QgsLayerItem::iconMesh();
|
||||
}
|
||||
|
||||
case QgsMapLayer::VectorLayer:
|
||||
{
|
||||
QgsVectorLayer *vl = dynamic_cast<QgsVectorLayer *>( layer );
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "qgsrasterlayer.h"
|
||||
#include "qgsvectordataprovider.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsmeshlayer.h"
|
||||
|
||||
static const char *QGIS_URILIST_MIMETYPE = "application/x-vnd.qgis.qgis.uri";
|
||||
|
||||
@ -108,6 +109,18 @@ QgsRasterLayer *QgsMimeDataUtils::Uri::rasterLayer( bool &owner, QString &error
|
||||
return new QgsRasterLayer( uri, name, providerKey );
|
||||
}
|
||||
|
||||
QgsMeshLayer *QgsMimeDataUtils::Uri::meshLayer( bool &owner, QString &error ) const
|
||||
{
|
||||
owner = false;
|
||||
if ( layerType != QLatin1String( "mesh" ) )
|
||||
{
|
||||
error = QObject::tr( "%1: Not a mesh layer." ).arg( name );
|
||||
return nullptr;
|
||||
}
|
||||
owner = true;
|
||||
return new QgsMeshLayer( uri, name, providerKey );
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
bool QgsMimeDataUtils::isUriList( const QMimeData *data )
|
||||
|
@ -24,6 +24,7 @@ class QgsLayerItem;
|
||||
class QgsLayerTreeNode;
|
||||
class QgsVectorLayer;
|
||||
class QgsRasterLayer;
|
||||
class QgsMeshLayer;
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
@ -63,7 +64,14 @@ class CORE_EXPORT QgsMimeDataUtils
|
||||
*/
|
||||
QgsRasterLayer *rasterLayer( bool &owner, QString &error ) const;
|
||||
|
||||
//! Type of URI. Recognized types: "vector" / "raster" / "plugin" / "custom" / "project"
|
||||
/**
|
||||
* Get mesh layer from uri if possible, otherwise returns 0 and error is set
|
||||
* \param owner set to true if caller becomes owner
|
||||
* \param error set to error message if cannot get raster
|
||||
*/
|
||||
QgsMeshLayer *meshLayer( bool &owner, QString &error ) const;
|
||||
|
||||
//! Type of URI. Recognized types: "vector" / "raster" / "mesh" / "plugin" / "custom" / "project"
|
||||
QString layerType;
|
||||
|
||||
/**
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsproject.h"
|
||||
#include "providers/memory/qgsmemoryprovider.h"
|
||||
|
||||
#include "mesh/qgsmeshmemorydataprovider.h"
|
||||
|
||||
// typedefs for provider plugin functions of interest
|
||||
typedef QString providerkey_t();
|
||||
@ -87,6 +87,7 @@ void QgsProviderRegistry::init()
|
||||
{
|
||||
// add standard providers
|
||||
mProviders[ QgsMemoryProvider::providerKey() ] = new QgsProviderMetadata( QgsMemoryProvider::providerKey(), QgsMemoryProvider::providerDescription(), &QgsMemoryProvider::createProvider );
|
||||
mProviders[ QgsMeshMemoryDataProvider::providerKey() ] = new QgsProviderMetadata( QgsMeshMemoryDataProvider::providerKey(), QgsMeshMemoryDataProvider::providerDescription(), &QgsMeshMemoryDataProvider::createProvider );
|
||||
|
||||
mLibraryDirectory.setSorting( QDir::Name | QDir::IgnoreCase );
|
||||
mLibraryDirectory.setFilter( QDir::Files | QDir::NoSymLinks );
|
||||
|
@ -167,6 +167,7 @@ class CORE_EXPORT QgsProviderRegistry
|
||||
\note This replaces QgsRasterLayer::buildSupportedRasterFileFilter()
|
||||
*/
|
||||
virtual QString fileRasterFilters() const;
|
||||
|
||||
//! Return a string containing the available database drivers
|
||||
virtual QString databaseDrivers() const;
|
||||
//! Return a string containing the available directory drivers
|
||||
|
@ -890,6 +890,7 @@ INCLUDE_DIRECTORIES(
|
||||
${CMAKE_SOURCE_DIR}/src/core/locator
|
||||
${CMAKE_SOURCE_DIR}/src/core/metadata
|
||||
${CMAKE_SOURCE_DIR}/src/core/processing
|
||||
${CMAKE_SOURCE_DIR}/src/core/mesh
|
||||
${CMAKE_SOURCE_DIR}/src/core/providers/memory
|
||||
${CMAKE_SOURCE_DIR}/src/core/raster
|
||||
${CMAKE_SOURCE_DIR}/src/core/scalebar
|
||||
|
@ -19,6 +19,8 @@
|
||||
***************************************************************************/
|
||||
#include "qgsbrowserdockwidget_p.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QAbstractTextDocumentLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QTreeView>
|
||||
@ -35,7 +37,7 @@
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsproject.h"
|
||||
#include "qgssettings.h"
|
||||
|
||||
#include "qgsmeshlayer.h"
|
||||
|
||||
#include <QDragEnterEvent>
|
||||
|
||||
@ -143,7 +145,20 @@ void QgsBrowserLayerProperties::setItem( QgsDataItem *item )
|
||||
{
|
||||
QgsDebugMsg( "creating raster layer" );
|
||||
// should copy code from addLayer() to split uri ?
|
||||
QgsRasterLayer *layer = new QgsRasterLayer( layerItem->uri(), layerItem->uri(), layerItem->providerKey() );
|
||||
std::unique_ptr<QgsRasterLayer> layer( new QgsRasterLayer( layerItem->uri(), layerItem->uri(), layerItem->providerKey() ) );
|
||||
if ( layer )
|
||||
{
|
||||
if ( layer->isValid() )
|
||||
{
|
||||
layerCrs = layer->crs();
|
||||
layerMetadata = layer->htmlMetadata();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( type == QgsMapLayer::MeshLayer )
|
||||
{
|
||||
QgsDebugMsg( "creating mesh layer" );
|
||||
std::unique_ptr<QgsMeshLayer> layer( new QgsMeshLayer( layerItem->uri(), layerItem->uri(), layerItem->providerKey() ) );
|
||||
if ( layer )
|
||||
{
|
||||
if ( layer->isValid() )
|
||||
@ -151,13 +166,12 @@ void QgsBrowserLayerProperties::setItem( QgsDataItem *item )
|
||||
layerCrs = layer->crs();
|
||||
layerMetadata = layer->htmlMetadata();
|
||||
}
|
||||
delete layer;
|
||||
}
|
||||
}
|
||||
else if ( type == QgsMapLayer::VectorLayer )
|
||||
{
|
||||
QgsDebugMsg( "creating vector layer" );
|
||||
QgsVectorLayer *layer = new QgsVectorLayer( layerItem->uri(), layerItem->name(), layerItem->providerKey() );
|
||||
std::unique_ptr<QgsVectorLayer> layer( new QgsVectorLayer( layerItem->uri(), layerItem->name(), layerItem->providerKey() ) );
|
||||
if ( layer )
|
||||
{
|
||||
if ( layer->isValid() )
|
||||
@ -165,7 +179,6 @@ void QgsBrowserLayerProperties::setItem( QgsDataItem *item )
|
||||
layerCrs = layer->crs();
|
||||
layerMetadata = layer->htmlMetadata();
|
||||
}
|
||||
delete layer;
|
||||
}
|
||||
}
|
||||
else if ( type == QgsMapLayer::PluginLayer )
|
||||
|
@ -16,6 +16,7 @@ ADD_SUBDIRECTORY(wfs)
|
||||
ADD_SUBDIRECTORY(spatialite)
|
||||
ADD_SUBDIRECTORY(virtual)
|
||||
ADD_SUBDIRECTORY(db2)
|
||||
ADD_SUBDIRECTORY(mdal)
|
||||
|
||||
IF (WITH_ORACLE)
|
||||
ADD_SUBDIRECTORY(oracle)
|
||||
|
80
src/providers/mdal/CMakeLists.txt
Normal file
80
src/providers/mdal/CMakeLists.txt
Normal file
@ -0,0 +1,80 @@
|
||||
SET(MDAL_SRCS
|
||||
qgsmdalprovider.cpp
|
||||
qgsmdaldataitems.cpp
|
||||
)
|
||||
SET(MDAL_MOC_HDRS
|
||||
qgsmdalprovider.h
|
||||
qgsmdaldataitems.h
|
||||
)
|
||||
SET(MDAL_HDRS
|
||||
)
|
||||
|
||||
|
||||
########################################################
|
||||
# Compile internal MDAL
|
||||
IF (WITH_INTERNAL_MDAL)
|
||||
ADD_DEFINITIONS(-DMDAL_STATIC)
|
||||
|
||||
INCLUDE_DIRECTORIES(
|
||||
${CMAKE_SOURCE_DIR}/external/mdal
|
||||
${CMAKE_SOURCE_DIR}/external/mdal/api
|
||||
)
|
||||
|
||||
SET(MDAL_LIB_SRCS
|
||||
${CMAKE_SOURCE_DIR}/external/mdal/mdal.cpp
|
||||
${CMAKE_SOURCE_DIR}/external/mdal/mdal_utils.cpp
|
||||
${CMAKE_SOURCE_DIR}/external/mdal/mdal_loader.cpp
|
||||
${CMAKE_SOURCE_DIR}/external/mdal/frmts/mdal_2dm.cpp
|
||||
)
|
||||
|
||||
SET(MDAL_LIB_HDRS
|
||||
${CMAKE_SOURCE_DIR}/external/mdal/api/mdal.h
|
||||
${CMAKE_SOURCE_DIR}/external/mdal/mdal_utils.hpp
|
||||
${CMAKE_SOURCE_DIR}/external/mdal/mdal_loader.hpp
|
||||
${CMAKE_SOURCE_DIR}/external/mdal/mdal_defines.hpp
|
||||
${CMAKE_SOURCE_DIR}/external/mdal/frmts/mdal_2dm.hpp
|
||||
)
|
||||
|
||||
UNSET(MDAL_LIBRARY)
|
||||
UNSET(MDAL_INCLUDE_DIR)
|
||||
|
||||
ELSE (WITH_INTERNAL_MDAL)
|
||||
|
||||
INCLUDE_DIRECTORIES (SYSTEM
|
||||
${MDAL_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
ENDIF (WITH_INTERNAL_MDAL)
|
||||
|
||||
########################################################
|
||||
|
||||
INCLUDE_DIRECTORIES (
|
||||
${CMAKE_SOURCE_DIR}/src/core
|
||||
${CMAKE_SOURCE_DIR}/src/core/mesh
|
||||
${CMAKE_SOURCE_DIR}/src/core/expression
|
||||
${CMAKE_SOURCE_DIR}/src/core/geometry
|
||||
${CMAKE_SOURCE_DIR}/src/core/metadata
|
||||
|
||||
${CMAKE_BINARY_DIR}/src/core
|
||||
)
|
||||
|
||||
QT5_WRAP_CPP(MDAL_MOC_SRCS ${MDAL_MOC_HDRS})
|
||||
ADD_LIBRARY (mdalprovider MODULE ${MDAL_SRCS} ${MDAL_MOC_HDRS} ${MDAL_MOC_SRCS} ${MDAL_LIB_SRCS} ${MDAL_LIB_HDRS})
|
||||
|
||||
TARGET_LINK_LIBRARIES (mdalprovider
|
||||
qgis_core
|
||||
${MDAL_LIBRARY}
|
||||
)
|
||||
|
||||
# clang-tidy
|
||||
IF(CLANG_TIDY_EXE)
|
||||
SET_TARGET_PROPERTIES(
|
||||
mdalprovider PROPERTIES
|
||||
CXX_CLANG_TIDY "${DO_CLANG_TIDY}"
|
||||
)
|
||||
ENDIF(CLANG_TIDY_EXE)
|
||||
|
||||
INSTALL(TARGETS mdalprovider
|
||||
RUNTIME DESTINATION ${QGIS_PLUGIN_DIR}
|
||||
LIBRARY DESTINATION ${QGIS_PLUGIN_DIR})
|
||||
|
76
src/providers/mdal/qgsmdaldataitems.cpp
Normal file
76
src/providers/mdal/qgsmdaldataitems.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
/***************************************************************************
|
||||
qgsmdaldataitems.cpp
|
||||
---------------------
|
||||
begin : April 2018
|
||||
copyright : (C) 2018 by Peter Petrik
|
||||
email : zilolv at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#include "qgsmdaldataitems.h"
|
||||
#include "qgsmdalprovider.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgssettings.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
|
||||
QgsMdalLayerItem::QgsMdalLayerItem( QgsDataItem *parent,
|
||||
const QString &name, const QString &path, const QString &uri )
|
||||
: QgsLayerItem( parent, name, path, uri, QgsLayerItem::Mesh, QStringLiteral( "mdal" ) )
|
||||
{
|
||||
mToolTip = uri;
|
||||
setState( Populated );
|
||||
}
|
||||
|
||||
QString QgsMdalLayerItem::layerName() const
|
||||
{
|
||||
QFileInfo info( name() );
|
||||
return info.completeBaseName();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
static QStringList sExtensions = QStringList();
|
||||
|
||||
QGISEXTERN int dataCapabilities()
|
||||
{
|
||||
return QgsDataProvider::File;
|
||||
}
|
||||
|
||||
QGISEXTERN QgsDataItem *dataItem( QString path, QgsDataItem *parentItem )
|
||||
{
|
||||
if ( path.isEmpty() )
|
||||
return nullptr;
|
||||
|
||||
QgsDebugMsgLevel( "thePath = " + path, 2 );
|
||||
|
||||
// get suffix, removing .gz if present
|
||||
QFileInfo info( path );
|
||||
QString suffix = info.suffix().toLower();
|
||||
// extract basename with extension
|
||||
info.setFile( path );
|
||||
QString name = info.fileName();
|
||||
|
||||
// allow only normal files
|
||||
if ( !info.isFile() )
|
||||
return nullptr;
|
||||
|
||||
// get supported extensions
|
||||
if ( sExtensions.isEmpty() )
|
||||
{
|
||||
// TODO ask MDAL for extensions !
|
||||
sExtensions << QStringLiteral( "2dm" );
|
||||
}
|
||||
|
||||
// Filter files by extension
|
||||
if ( !sExtensions.contains( suffix ) )
|
||||
return nullptr;
|
||||
|
||||
return new QgsMdalLayerItem( parentItem, name, path, path );
|
||||
}
|
||||
|
31
src/providers/mdal/qgsmdaldataitems.h
Normal file
31
src/providers/mdal/qgsmdaldataitems.h
Normal file
@ -0,0 +1,31 @@
|
||||
/***************************************************************************
|
||||
qgsmdaldataitems.h
|
||||
------------------
|
||||
begin : April 2018
|
||||
copyright : (C) 2018 by Peter Petrik
|
||||
email : zilolv at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#ifndef QGSMDALDATAITEMS_H
|
||||
#define QGSMDALDATAITEMS_H
|
||||
|
||||
#include "qgsdataitem.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
class QgsMdalLayerItem : public QgsLayerItem
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QgsMdalLayerItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &uri );
|
||||
|
||||
QString layerName() const override;
|
||||
};
|
||||
|
||||
#endif // QGSMDALDATAITEMS_H
|
133
src/providers/mdal/qgsmdalprovider.cpp
Normal file
133
src/providers/mdal/qgsmdalprovider.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
/***************************************************************************
|
||||
qgsmeshmemorydataprovider.cpp
|
||||
-----------------------------
|
||||
begin : April 2018
|
||||
copyright : (C) 2018 by Peter Petrik
|
||||
email : zilolv at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsmdalprovider.h"
|
||||
|
||||
static const QString TEXT_PROVIDER_KEY = QStringLiteral( "mdal" );
|
||||
static const QString TEXT_PROVIDER_DESCRIPTION = QStringLiteral( "MDAL provider" );
|
||||
|
||||
bool QgsMdalProvider::isValid() const
|
||||
{
|
||||
return mMeshH != nullptr;
|
||||
}
|
||||
|
||||
QString QgsMdalProvider::name() const
|
||||
{
|
||||
return TEXT_PROVIDER_KEY;
|
||||
}
|
||||
|
||||
QString QgsMdalProvider::description() const
|
||||
{
|
||||
return TEXT_PROVIDER_DESCRIPTION;
|
||||
}
|
||||
|
||||
QgsCoordinateReferenceSystem QgsMdalProvider::crs() const
|
||||
{
|
||||
return QgsCoordinateReferenceSystem();
|
||||
}
|
||||
|
||||
QgsMdalProvider::QgsMdalProvider( const QString &uri )
|
||||
: QgsMeshDataProvider( uri )
|
||||
{
|
||||
QByteArray curi = uri.toAscii();
|
||||
mMeshH = MDAL_LoadMesh( curi.constData() );
|
||||
}
|
||||
|
||||
QgsMdalProvider::~QgsMdalProvider()
|
||||
{
|
||||
if ( mMeshH )
|
||||
MDAL_CloseMesh( mMeshH );
|
||||
}
|
||||
|
||||
int QgsMdalProvider::vertexCount() const
|
||||
{
|
||||
if ( mMeshH )
|
||||
return MDAL_M_vertexCount( mMeshH );
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int QgsMdalProvider::faceCount() const
|
||||
{
|
||||
if ( mMeshH )
|
||||
return MDAL_M_faceCount( mMeshH );
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
QgsMeshVertex QgsMdalProvider::vertex( int index ) const
|
||||
{
|
||||
Q_ASSERT( index < vertexCount() );
|
||||
double x = MDAL_M_vertexXCoordinatesAt( mMeshH, index );
|
||||
double y = MDAL_M_vertexYCoordinatesAt( mMeshH, index );
|
||||
QgsMeshVertex vertex( x, y );
|
||||
return vertex;
|
||||
}
|
||||
|
||||
QgsMeshFace QgsMdalProvider::face( int index ) const
|
||||
{
|
||||
Q_ASSERT( index < faceCount() );
|
||||
QgsMeshFace face;
|
||||
int n_face_vertices = MDAL_M_faceVerticesCountAt( mMeshH, index );
|
||||
for ( int j = 0; j < n_face_vertices; ++j )
|
||||
{
|
||||
int vertex_index = MDAL_M_faceVerticesIndexAt( mMeshH, index, j );
|
||||
face.push_back( vertex_index );
|
||||
}
|
||||
return face;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Class factory to return a pointer to a newly created
|
||||
* QgsGdalProvider object
|
||||
*/
|
||||
QGISEXTERN QgsMdalProvider *classFactory( const QString *uri )
|
||||
{
|
||||
return new QgsMdalProvider( *uri );
|
||||
}
|
||||
|
||||
/**
|
||||
* Required key function (used to map the plugin to a data store type)
|
||||
*/
|
||||
QGISEXTERN QString providerKey()
|
||||
{
|
||||
return TEXT_PROVIDER_KEY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Required description function
|
||||
*/
|
||||
QGISEXTERN QString description()
|
||||
{
|
||||
return TEXT_PROVIDER_DESCRIPTION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Required isProvider function. Used to determine if this shared library
|
||||
* is a data provider plugin
|
||||
*/
|
||||
QGISEXTERN bool isProvider()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
QGISEXTERN void cleanupProvider()
|
||||
{
|
||||
}
|
||||
|
63
src/providers/mdal/qgsmdalprovider.h
Normal file
63
src/providers/mdal/qgsmdalprovider.h
Normal file
@ -0,0 +1,63 @@
|
||||
/***************************************************************************
|
||||
qgsmdalprovider.h
|
||||
-----------------
|
||||
begin : April 2018
|
||||
copyright : (C) 2018 by Peter Petrik
|
||||
email : zilolv at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSMDALPROVIDER_H
|
||||
#define QGSGDALPROVIDER_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include <mdal.h>
|
||||
|
||||
#include "qgscoordinatereferencesystem.h"
|
||||
#include "qgsmeshdataprovider.h"
|
||||
|
||||
class QMutex;
|
||||
class QgsCoordinateTransform;
|
||||
|
||||
/**
|
||||
\brief Data provider for MDAL layers.
|
||||
*/
|
||||
class QgsMdalProvider : public QgsMeshDataProvider
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for the provider.
|
||||
*
|
||||
* \param uri file name
|
||||
* \param newDataset handle of newly created dataset.
|
||||
*
|
||||
*/
|
||||
QgsMdalProvider( const QString &uri = QString() );
|
||||
~QgsMdalProvider();
|
||||
|
||||
bool isValid() const override;
|
||||
QString name() const override;
|
||||
QString description() const override;
|
||||
QgsCoordinateReferenceSystem crs() const override;
|
||||
|
||||
int vertexCount() const override;
|
||||
int faceCount() const override;
|
||||
QgsMeshVertex vertex( int index ) const override;
|
||||
QgsMeshFace face( int index ) const override;
|
||||
|
||||
private:
|
||||
MeshH mMeshH;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -228,6 +228,12 @@ bool QgsGeoPackageCollectionItem::handleDrop( const QMimeData *data, Qt::DropAct
|
||||
srcLayer = dropUri.vectorLayer( owner, error );
|
||||
isVector = true;
|
||||
}
|
||||
else if ( dropUri.layerType == QStringLiteral( "mesh" ) )
|
||||
{
|
||||
// unsupported
|
||||
hasError = true;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
srcLayer = dropUri.rasterLayer( owner, error );
|
||||
|
@ -20,6 +20,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_SOURCE_DIR}/src/core/raster
|
||||
${CMAKE_SOURCE_DIR}/src/core/scalebar
|
||||
${CMAKE_SOURCE_DIR}/src/core/symbology
|
||||
${CMAKE_SOURCE_DIR}/src/core/mesh
|
||||
${CMAKE_SOURCE_DIR}/src/test
|
||||
${CMAKE_BINARY_DIR}/src/core
|
||||
)
|
||||
@ -188,7 +189,9 @@ SET(TESTS
|
||||
testqgsvectorlayerjoinbuffer.cpp
|
||||
testqgsvectorlayer.cpp
|
||||
testziplayer.cpp
|
||||
)
|
||||
testqgsmeshlayer.cpp
|
||||
testqgsmeshlayerrenderer.cpp
|
||||
)
|
||||
|
||||
IF(WITH_QTWEBKIT)
|
||||
SET(TESTS ${TESTS}
|
||||
|
124
tests/src/core/testqgsmeshlayer.cpp
Normal file
124
tests/src/core/testqgsmeshlayer.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
/***************************************************************************
|
||||
testqgsmeshlayer.cpp
|
||||
--------------------
|
||||
begin : April 2018
|
||||
copyright : (C) 2018 by Peter Petrik
|
||||
email : zilolv at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgstest.h"
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
//qgis includes...
|
||||
#include "qgsmaplayer.h"
|
||||
#include "qgsmeshlayer.h"
|
||||
#include "qgsapplication.h"
|
||||
#include "qgsproviderregistry.h"
|
||||
#include "qgsproject.h"
|
||||
|
||||
/**
|
||||
* \ingroup UnitTests
|
||||
* This is a unit test for a mesh layer
|
||||
*/
|
||||
class TestQgsMeshLayer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TestQgsMeshLayer() = default;
|
||||
|
||||
private:
|
||||
QgsMeshLayer *mMemoryLayer = nullptr;
|
||||
QgsMeshLayer *mMdalLayer = nullptr;
|
||||
|
||||
private slots:
|
||||
void initTestCase();// will be called before the first testfunction is executed.
|
||||
void cleanupTestCase();// will be called after the last testfunction was executed.
|
||||
void init() {} // will be called before each testfunction is executed.
|
||||
void cleanup() {} // will be called after every testfunction.
|
||||
|
||||
void test_data_provider();
|
||||
void test_extent();
|
||||
};
|
||||
|
||||
void TestQgsMeshLayer::initTestCase()
|
||||
{
|
||||
// init QGIS's paths - true means that all path will be inited from prefix
|
||||
QgsApplication::init();
|
||||
QgsApplication::initQgis();
|
||||
QgsApplication::showSettings();
|
||||
QString myDataDir( TEST_DATA_DIR ); //defined in CmakeLists.txt
|
||||
myDataDir += "/mesh";
|
||||
// Memory layer
|
||||
QFile f( myDataDir + "/quad_and_triangle.txt" );
|
||||
QVERIFY( f.open( QIODevice::ReadOnly | QIODevice::Text ) );
|
||||
QString uri( f.readAll() );
|
||||
QVERIFY( !uri.isEmpty() );
|
||||
mMemoryLayer = new QgsMeshLayer( uri, "Triangle and Quad Memory", "mesh_memory" );
|
||||
QVERIFY( mMemoryLayer->isValid() );
|
||||
QgsProject::instance()->addMapLayers(
|
||||
QList<QgsMapLayer *>() << mMemoryLayer );
|
||||
|
||||
// MDAL Layer
|
||||
uri = myDataDir + "/quad_and_triangle.2dm";
|
||||
mMdalLayer = new QgsMeshLayer( uri, "Triangle and Quad MDAL", "mdal" );
|
||||
QVERIFY( mMdalLayer->isValid() );
|
||||
QgsProject::instance()->addMapLayers(
|
||||
QList<QgsMapLayer *>() << mMdalLayer );
|
||||
}
|
||||
|
||||
void TestQgsMeshLayer::cleanupTestCase()
|
||||
{
|
||||
QgsApplication::exitQgis();
|
||||
}
|
||||
|
||||
void TestQgsMeshLayer::test_data_provider()
|
||||
{
|
||||
QList<const QgsMeshDataProvider *> dataProviders;
|
||||
dataProviders.append( mMemoryLayer->dataProvider() );
|
||||
dataProviders.append( mMdalLayer->dataProvider() );
|
||||
|
||||
QgsRectangle expectedExtent( 1000.0, 2000.0, 3000.0, 3000.0 );
|
||||
|
||||
foreach ( auto dp, dataProviders )
|
||||
{
|
||||
QVERIFY( dp != nullptr );
|
||||
QVERIFY( dp->isValid() );
|
||||
QCOMPARE( expectedExtent, dp->extent() );
|
||||
|
||||
QCOMPARE( 5, dp->vertexCount() );
|
||||
QCOMPARE( QgsMeshVertex( 1000.0, 2000.0 ), dp->vertex( 0 ) );
|
||||
QCOMPARE( QgsMeshVertex( 2000.0, 2000.0 ), dp->vertex( 1 ) );
|
||||
QCOMPARE( QgsMeshVertex( 3000.0, 2000.0 ), dp->vertex( 2 ) );
|
||||
QCOMPARE( QgsMeshVertex( 2000.0, 3000.0 ), dp->vertex( 3 ) );
|
||||
QCOMPARE( QgsMeshVertex( 1000.0, 3000.0 ), dp->vertex( 4 ) );
|
||||
|
||||
QCOMPARE( 2, dp->faceCount() );
|
||||
QgsMeshFace f1;
|
||||
f1 << 0 << 1 << 3 << 4;
|
||||
QCOMPARE( f1, dp->face( 0 ) );
|
||||
|
||||
QgsMeshFace f2;
|
||||
f2 << 1 << 2 << 3;
|
||||
QCOMPARE( f2, dp->face( 1 ) );
|
||||
}
|
||||
}
|
||||
|
||||
void TestQgsMeshLayer::test_extent()
|
||||
{
|
||||
QCOMPARE( mMemoryLayer->dataProvider()->extent(), mMemoryLayer->extent() );
|
||||
QCOMPARE( mMdalLayer->dataProvider()->extent(), mMdalLayer->extent() );
|
||||
}
|
||||
|
||||
QGSTEST_MAIN( TestQgsMeshLayer )
|
||||
#include "testqgsmeshlayer.moc"
|
123
tests/src/core/testqgsmeshlayerrenderer.cpp
Normal file
123
tests/src/core/testqgsmeshlayerrenderer.cpp
Normal file
@ -0,0 +1,123 @@
|
||||
/***************************************************************************
|
||||
testqgsmeshlayer.cpp
|
||||
--------------------
|
||||
begin : April 2018
|
||||
copyright : (C) 2018 by Peter Petrik
|
||||
email : zilolv at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgstest.h"
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QLabel>
|
||||
#include <QStringList>
|
||||
#include <QApplication>
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
#include <QDesktopServices>
|
||||
|
||||
//qgis includes...
|
||||
#include "qgsmaplayer.h"
|
||||
#include "qgsmeshlayer.h"
|
||||
#include "qgsapplication.h"
|
||||
#include "qgsproviderregistry.h"
|
||||
#include "qgsproject.h"
|
||||
#include "qgsmaprenderersequentialjob.h"
|
||||
#include "qgsmeshmemorydataprovider.h"
|
||||
|
||||
//qgis test includes
|
||||
#include "qgsrenderchecker.h"
|
||||
|
||||
/**
|
||||
* \ingroup UnitTests
|
||||
* This is a unit test for the different renderers for mesh layers.
|
||||
*/
|
||||
class TestQgsMeshRenderer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TestQgsMeshRenderer() = default;
|
||||
|
||||
private:
|
||||
QgsMeshLayer *mMemoryLayer = nullptr;
|
||||
QgsMapSettings *mMapSettings = nullptr;
|
||||
|
||||
private slots:
|
||||
void initTestCase();// will be called before the first testfunction is executed.
|
||||
void cleanupTestCase();// will be called after the last testfunction was executed.
|
||||
void init() {} // will be called before each testfunction is executed.
|
||||
void cleanup() {} // will be called after every testfunction.
|
||||
bool imageCheck( const QString &testType );
|
||||
|
||||
void test_native_mesh_rendering();
|
||||
void test_triangular_mesh_rendering();
|
||||
};
|
||||
|
||||
void TestQgsMeshRenderer::initTestCase()
|
||||
{
|
||||
// init QGIS's paths - true means that all path will be inited from prefix
|
||||
QgsApplication::init();
|
||||
QgsApplication::initQgis();
|
||||
QgsApplication::showSettings();
|
||||
QString myDataDir( TEST_DATA_DIR ); //defined in CmakeLists.txt
|
||||
myDataDir += "/mesh";
|
||||
|
||||
mMapSettings = new QgsMapSettings();
|
||||
|
||||
// Memory layer
|
||||
QFile f( myDataDir + "/quad_and_triangle.txt" );
|
||||
QVERIFY( f.open( QIODevice::ReadOnly | QIODevice::Text ) );
|
||||
QString uri( f.readAll() );
|
||||
QVERIFY( !uri.isEmpty() );
|
||||
mMemoryLayer = new QgsMeshLayer( uri, "Triangle and Quad Memory", "mesh_memory" );
|
||||
QVERIFY( mMemoryLayer->isValid() );
|
||||
QgsProject::instance()->addMapLayers(
|
||||
QList<QgsMapLayer *>() << mMemoryLayer );
|
||||
mMapSettings->setLayers(
|
||||
QList<QgsMapLayer *>() << mMemoryLayer );
|
||||
}
|
||||
void TestQgsMeshRenderer::cleanupTestCase()
|
||||
{
|
||||
QgsApplication::exitQgis();
|
||||
}
|
||||
|
||||
bool TestQgsMeshRenderer::imageCheck( const QString &testType )
|
||||
{
|
||||
mMapSettings->setExtent( mMemoryLayer->extent() );
|
||||
mMapSettings->setDestinationCrs( mMemoryLayer->crs() );
|
||||
mMapSettings->setOutputDpi( 96 );
|
||||
QgsRenderChecker myChecker;
|
||||
myChecker.setControlPathPrefix( QStringLiteral( "mesh" ) );
|
||||
myChecker.setControlName( "expected_" + testType );
|
||||
myChecker.setMapSettings( *mMapSettings );
|
||||
myChecker.setColorTolerance( 15 );
|
||||
bool myResultFlag = myChecker.runTest( testType, 0 );
|
||||
return myResultFlag;
|
||||
}
|
||||
|
||||
void TestQgsMeshRenderer::test_native_mesh_rendering()
|
||||
{
|
||||
mMemoryLayer->toggleTriangularMeshRendering( false );
|
||||
QVERIFY( mMemoryLayer->triangularMeshSymbol() == nullptr );
|
||||
QVERIFY( imageCheck( "quad_and_triangle_native_mesh" ) );
|
||||
}
|
||||
|
||||
void TestQgsMeshRenderer::test_triangular_mesh_rendering()
|
||||
{
|
||||
mMemoryLayer->toggleTriangularMeshRendering( true );
|
||||
QVERIFY( mMemoryLayer->triangularMeshSymbol() != nullptr );
|
||||
QVERIFY( imageCheck( "quad_and_triangle_triangular_mesh" ) );
|
||||
}
|
||||
|
||||
QGSTEST_MAIN( TestQgsMeshRenderer )
|
||||
#include "testqgsmeshlayerrenderer.moc"
|
Binary file not shown.
After Width: | Height: | Size: 78 KiB |
Binary file not shown.
After Width: | Height: | Size: 78 KiB |
8
tests/testdata/mesh/quad_and_triangle.2dm
vendored
Normal file
8
tests/testdata/mesh/quad_and_triangle.2dm
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
MESH2D 1000.000 2000.000 0.000000 200 300 1.000 1.000
|
||||
ND 1 1000.000 2000.000 20.000
|
||||
ND 2 2000.000 2000.000 30.000
|
||||
ND 3 3000.000 2000.000 40.000
|
||||
ND 4 2000.000 3000.000 50.000
|
||||
ND 5 1000.000 3000.000 10.000
|
||||
E4Q 1 1 2 4 5 1
|
||||
E3T 2 2 3 4 1
|
8
tests/testdata/mesh/quad_and_triangle.txt
vendored
Normal file
8
tests/testdata/mesh/quad_and_triangle.txt
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
1000.0, 2000.0
|
||||
2000.0, 2000.0
|
||||
3000.0, 2000.0
|
||||
2000.0, 3000.0
|
||||
1000.0, 3000.0
|
||||
---
|
||||
0, 1, 3, 4
|
||||
1, 2, 3
|
Loading…
x
Reference in New Issue
Block a user