mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-22 00:06:12 -05:00
[FEATURE] QgsMeshLayer part 1: Reading raw mesh
Introducting MDAL, QgsMeshLayer, mesh data providers (mesh_memory, mdal) to read and visualize raw meshes: vertices and faces. Support dragging 2dm files from browser on canvas to visualize 2dm meshes. Support for QgsMeshLayer in Python API.
This commit is contained in:
parent
3b59ccc7ce
commit
50422a1165
@ -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} )
|
91
external/mdal/api/mdal.h
vendored
Normal file
91
external/mdal/api/mdal.h
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
MDAL - Mesh Data Abstraction Library (MIT License)
|
||||
Copyright (C) 2018 Peter Petrik (zilolv at gmail dot com)
|
||||
*/
|
||||
|
||||
#ifndef MDAL_H
|
||||
#define MDAL_H
|
||||
|
||||
#ifdef MDAL_STATIC
|
||||
# define MDAL_EXPORT
|
||||
#else
|
||||
# if defined _WIN32 || defined __CYGWIN__
|
||||
# ifdef mdal_EXPORTS
|
||||
# ifdef __GNUC__
|
||||
# define MDAL_EXPORT __attribute__ ((dllexport))
|
||||
# else
|
||||
# define MDAL_EXPORT __declspec(dllexport) // Note: actually gcc seems to also supports this syntax.
|
||||
# endif
|
||||
# else
|
||||
# ifdef __GNUC__
|
||||
# define MDAL_EXPORT __attribute__ ((dllimport))
|
||||
# else
|
||||
# define MDAL_EXPORT __declspec(dllimport) // Note: actually gcc seems to also supports this syntax.
|
||||
# endif
|
||||
# endif
|
||||
# else
|
||||
# if __GNUC__ >= 4
|
||||
# define MDAL_EXPORT __attribute__ ((visibility ("default")))
|
||||
# else
|
||||
# define MDAL_EXPORT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* Statuses */
|
||||
enum Status
|
||||
{
|
||||
None,
|
||||
// Errors
|
||||
Err_NotEnoughMemory,
|
||||
Err_FileNotFound,
|
||||
Err_UnknownFormat,
|
||||
Err_IncompatibleMesh,
|
||||
Err_InvalidData,
|
||||
Err_MissingDriver,
|
||||
// Warnings
|
||||
Warn_UnsupportedElement,
|
||||
Warn_InvalidElements,
|
||||
Warn_ElementWithInvalidNode,
|
||||
Warn_ElementNotUnique,
|
||||
Warn_NodeNotUnique
|
||||
};
|
||||
|
||||
/* Mesh */
|
||||
typedef void *MeshH;
|
||||
|
||||
//! Return MDAL version
|
||||
MDAL_EXPORT const char *MDAL_Version();
|
||||
|
||||
//! Return last status message
|
||||
MDAL_EXPORT Status MDAL_LastStatus();
|
||||
|
||||
//! Load mesh file. On error see MDAL_LastStatus for error type This effectively loads whole mesh in-memory
|
||||
MDAL_EXPORT MeshH MDAL_LoadMesh( const char *meshFile );
|
||||
//! Close mesh, free the memory
|
||||
MDAL_EXPORT void MDAL_CloseMesh( MeshH mesh );
|
||||
|
||||
//! Return vertex count for the mesh
|
||||
MDAL_EXPORT size_t MDAL_M_vertexCount( MeshH mesh );
|
||||
//! Return vertex X coord for the mesh
|
||||
MDAL_EXPORT double MDAL_M_vertexXCoordinatesAt( MeshH mesh, size_t index );
|
||||
//! Return vertex Y coord for the mesh
|
||||
MDAL_EXPORT double MDAL_M_vertexYCoordinatesAt( MeshH mesh, size_t index );
|
||||
//! Return face count for the mesh
|
||||
MDAL_EXPORT size_t MDAL_M_faceCount( MeshH mesh );
|
||||
//! Return number of vertices face consist of, e.g. 3 for triangle
|
||||
MDAL_EXPORT size_t MDAL_M_faceVerticesCountAt( MeshH mesh, size_t index );
|
||||
//! Return vertex index for face
|
||||
MDAL_EXPORT size_t MDAL_M_faceVerticesIndexAt( MeshH mesh, size_t face_index, size_t vertex_index );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //MDAL_H
|
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( Status *status )
|
||||
{
|
||||
if ( status ) *status = Status::None;
|
||||
|
||||
if ( !MDAL::fileExists( mMeshFile ) )
|
||||
{
|
||||
if ( status ) *status = Status::Err_FileNotFound;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::ifstream in( mMeshFile, std::ifstream::in );
|
||||
std::string line;
|
||||
if ( !std::getline( in, line ) || !startsWith( line, "MESH2D" ) )
|
||||
{
|
||||
if ( status ) *status = Status::Err_UnknownFormat;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t elemCount = 0;
|
||||
size_t nodeCount = 0;
|
||||
|
||||
// Find out how many nodes and elements are contained in the .2dm mesh file
|
||||
while ( std::getline( in, line ) )
|
||||
{
|
||||
if ( startsWith( line, "E4Q" ) ||
|
||||
startsWith( line, "E3T" ) )
|
||||
{
|
||||
elemCount++;
|
||||
}
|
||||
else if ( startsWith( line, "ND" ) )
|
||||
{
|
||||
nodeCount++;
|
||||
}
|
||||
else if ( startsWith( line, "E2L" ) ||
|
||||
startsWith( line, "E3L" ) ||
|
||||
startsWith( line, "E6T" ) ||
|
||||
startsWith( line, "E8Q" ) ||
|
||||
startsWith( line, "E9Q" ) )
|
||||
{
|
||||
if ( status ) *status = Status::Warn_UnsupportedElement;
|
||||
elemCount += 1; // We still count them as elements
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate memory
|
||||
std::vector<Vertex> vertices( nodeCount );
|
||||
std::vector<Face> faces( elemCount );
|
||||
|
||||
in.clear();
|
||||
in.seekg( 0, std::ios::beg );
|
||||
|
||||
std::vector<std::string> chunks;
|
||||
|
||||
size_t elemIndex = 0;
|
||||
size_t nodeIndex = 0;
|
||||
std::map<size_t, size_t> elemIDtoIndex;
|
||||
std::map<size_t, size_t> nodeIDtoIndex;
|
||||
|
||||
while ( std::getline( in, line ) )
|
||||
{
|
||||
if ( startsWith( line, "E4Q" ) )
|
||||
{
|
||||
chunks = split( line, " ", SplitBehaviour::SkipEmptyParts );
|
||||
assert( elemIndex < elemCount );
|
||||
|
||||
size_t elemID = toSizeT( chunks[1] );
|
||||
|
||||
std::map<size_t, size_t>::iterator search = elemIDtoIndex.find( elemID );
|
||||
if ( search != elemIDtoIndex.end() )
|
||||
{
|
||||
if ( status ) *status = Status::Warn_ElementNotUnique;
|
||||
continue;
|
||||
}
|
||||
elemIDtoIndex[elemID] = elemIndex;
|
||||
Face &face = faces[elemIndex];
|
||||
face.resize( 4 );
|
||||
// Right now we just store node IDs here - we will convert them to node indices afterwards
|
||||
for ( size_t i = 0; i < 4; ++i )
|
||||
face[i] = toSizeT( chunks[i + 2] );
|
||||
|
||||
elemIndex++;
|
||||
}
|
||||
else if ( startsWith( line, "E3T" ) )
|
||||
{
|
||||
chunks = split( line, " ", SplitBehaviour::SkipEmptyParts );
|
||||
assert( elemIndex < elemCount );
|
||||
|
||||
size_t elemID = toSizeT( chunks[1] );
|
||||
|
||||
std::map<size_t, size_t>::iterator search = elemIDtoIndex.find( elemID );
|
||||
if ( search != elemIDtoIndex.end() )
|
||||
{
|
||||
if ( status ) *status = Status::Warn_ElementNotUnique;
|
||||
continue;
|
||||
}
|
||||
elemIDtoIndex[elemID] = elemIndex;
|
||||
Face &face = faces[elemIndex];
|
||||
face.resize( 3 );
|
||||
// Right now we just store node IDs here - we will convert them to node indices afterwards
|
||||
for ( size_t i = 0; i < 3; ++i )
|
||||
{
|
||||
face[i] = toSizeT( chunks[i + 2] );
|
||||
}
|
||||
|
||||
elemIndex++;
|
||||
}
|
||||
else if ( startsWith( line, "E2L" ) ||
|
||||
startsWith( line, "E3L" ) ||
|
||||
startsWith( line, "E6T" ) ||
|
||||
startsWith( line, "E8Q" ) ||
|
||||
startsWith( line, "E9Q" ) )
|
||||
{
|
||||
// We do not yet support these elements
|
||||
chunks = split( line, " ", SplitBehaviour::SkipEmptyParts );
|
||||
assert( elemIndex < elemCount );
|
||||
|
||||
size_t elemID = toSizeT( chunks[1] );
|
||||
|
||||
std::map<size_t, size_t>::iterator search = elemIDtoIndex.find( elemID );
|
||||
if ( search != elemIDtoIndex.end() )
|
||||
{
|
||||
if ( status ) *status = Status::Warn_ElementNotUnique;
|
||||
continue;
|
||||
}
|
||||
elemIDtoIndex[elemID] = elemIndex;
|
||||
assert( false ); //TODO mark element as unusable
|
||||
|
||||
elemIndex++;
|
||||
}
|
||||
else if ( startsWith( line, "ND" ) )
|
||||
{
|
||||
chunks = split( line, " ", SplitBehaviour::SkipEmptyParts );
|
||||
size_t nodeID = toSizeT( chunks[1] );
|
||||
|
||||
std::map<size_t, size_t>::iterator search = nodeIDtoIndex.find( nodeID );
|
||||
if ( search != nodeIDtoIndex.end() )
|
||||
{
|
||||
if ( status ) *status = Status::Warn_NodeNotUnique;
|
||||
continue;
|
||||
}
|
||||
nodeIDtoIndex[nodeID] = nodeIndex;
|
||||
assert( nodeIndex < nodeCount );
|
||||
Vertex &vertex = vertices[nodeIndex];
|
||||
vertex.x = toDouble( chunks[2] );
|
||||
vertex.y = toDouble( chunks[3] );
|
||||
|
||||
nodeIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
for ( std::vector<Face>::iterator it = faces.begin(); it != faces.end(); ++it )
|
||||
{
|
||||
Face &face = *it;
|
||||
for ( Face::size_type nd = 0; nd < face.size(); ++nd )
|
||||
{
|
||||
size_t nodeID = face[nd];
|
||||
|
||||
std::map<size_t, size_t>::iterator ni2i = nodeIDtoIndex.find( nodeID );
|
||||
if ( ni2i != nodeIDtoIndex.end() )
|
||||
{
|
||||
face[nd] = ni2i->second; // convert from ID to index
|
||||
}
|
||||
else
|
||||
{
|
||||
assert( false ); //TODO mark element as unusable
|
||||
|
||||
if ( status ) *status = Status::Warn_ElementWithInvalidNode;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO check validity of the face
|
||||
//check that we have distinct nodes
|
||||
}
|
||||
|
||||
Mesh *mesh = new Mesh;
|
||||
mesh->faces = faces;
|
||||
mesh->vertices = vertices;
|
||||
|
||||
return mesh;
|
||||
}
|
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( Status *status );
|
||||
|
||||
private:
|
||||
std::string mMeshFile;
|
||||
};
|
||||
|
||||
} // namespace MDAL
|
||||
#endif //MDAL_2DM_HPP
|
86
external/mdal/mdal.cpp
vendored
Normal file
86
external/mdal/mdal.cpp
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "mdal.h"
|
||||
#include "mdal_loader.hpp"
|
||||
#include "mdal_defines.hpp"
|
||||
|
||||
static Status sLastStatus;
|
||||
|
||||
const char *MDAL_Version()
|
||||
{
|
||||
return "0.0.1";
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t MDAL_M_vertexCount( MeshH mesh )
|
||||
{
|
||||
assert( mesh );
|
||||
MDAL::Mesh *m = ( MDAL::Mesh * ) mesh;
|
||||
return m->vertices.size();
|
||||
}
|
||||
|
||||
double MDAL_M_vertexXCoordinatesAt( MeshH mesh, size_t index )
|
||||
{
|
||||
assert( mesh );
|
||||
MDAL::Mesh *m = ( MDAL::Mesh * ) mesh;
|
||||
assert( m->vertices.size() > index );
|
||||
return m->vertices[index].x;
|
||||
}
|
||||
|
||||
double MDAL_M_vertexYCoordinatesAt( MeshH mesh, size_t index )
|
||||
{
|
||||
assert( mesh );
|
||||
MDAL::Mesh *m = ( MDAL::Mesh * ) mesh;
|
||||
assert( m->vertices.size() > index );
|
||||
return m->vertices[index].y;
|
||||
}
|
||||
|
||||
size_t MDAL_M_faceCount( MeshH mesh )
|
||||
{
|
||||
assert( mesh );
|
||||
MDAL::Mesh *m = ( MDAL::Mesh * ) mesh;
|
||||
return m->faces.size();
|
||||
}
|
||||
|
||||
size_t MDAL_M_faceVerticesCountAt( MeshH mesh, size_t index )
|
||||
{
|
||||
assert( mesh );
|
||||
MDAL::Mesh *m = ( MDAL::Mesh * ) mesh;
|
||||
assert( m->faces.size() > index );
|
||||
return m->faces[index].size();
|
||||
}
|
||||
|
||||
size_t MDAL_M_faceVerticesIndexAt( MeshH mesh, size_t face_index, size_t vertex_index )
|
||||
{
|
||||
assert( mesh );
|
||||
MDAL::Mesh *m = ( MDAL::Mesh * ) mesh;
|
||||
assert( m->faces.size() > face_index );
|
||||
assert( m->faces[face_index].size() > vertex_index );
|
||||
return m->faces[face_index][vertex_index];
|
||||
}
|
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, 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, 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
|
@ -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
|
||||
|
@ -433,3 +433,6 @@
|
||||
%Include qgsuserprofilemanager.sip
|
||||
%Include symbology/qgsarrowsymbollayer.sip
|
||||
%Include qgsuserprofile.sip
|
||||
%Include mesh/qgsmeshdataprovider.sip
|
||||
%Include mesh/qgsmeshlayer.sip
|
||||
|
||||
|
98
python/core/mesh/qgsmeshdataprovider.sip.in
Normal file
98
python/core/mesh/qgsmeshdataprovider.sip.in
Normal file
@ -0,0 +1,98 @@
|
||||
/************************************************************************
|
||||
* 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<size_t> 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 size_t vertexCount() const = 0;
|
||||
%Docstring
|
||||
Return number of vertexes in the native mesh
|
||||
|
||||
:return: Number of vertexes in the mesh
|
||||
%End
|
||||
|
||||
virtual size_t faceCount() const = 0;
|
||||
%Docstring
|
||||
Return number of faces in the native mesh
|
||||
|
||||
:return: Number of faces in the mesh
|
||||
%End
|
||||
|
||||
virtual QgsMeshVertex vertex( size_t index ) const = 0;
|
||||
%Docstring
|
||||
Factory for mesh vertex with index
|
||||
|
||||
:return: new mesh vertex on index
|
||||
%End
|
||||
|
||||
virtual QgsMeshFace face( size_t 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`
|
||||
%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 *
|
||||
************************************************************************/
|
174
python/core/mesh/qgsmeshlayer.sip.in
Normal file
174
python/core/mesh/qgsmeshlayer.sip.in
Normal file
@ -0,0 +1,174 @@
|
||||
/************************************************************************
|
||||
* 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 providers Mesh data providers
|
||||
|
||||
\subsection 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
|
||||
Return data provider
|
||||
%End
|
||||
|
||||
|
||||
virtual QgsMeshLayer *clone() const /Factory/;
|
||||
|
||||
%Docstring
|
||||
Returns a new instance equivalent to this one. A new provider is
|
||||
created for the same data source and renderers are cloned too.
|
||||
|
||||
:return: a new layer instance
|
||||
%End
|
||||
|
||||
virtual QgsRectangle extent() const;
|
||||
|
||||
%Docstring
|
||||
Returns the extent of the layer.
|
||||
%End
|
||||
|
||||
virtual QgsMapLayerRenderer *createMapRenderer( QgsRenderContext &rendererContext ) /Factory/;
|
||||
%Docstring
|
||||
Return new instance of QgsMapLayerRenderer that will be used for rendering of given context
|
||||
%End
|
||||
|
||||
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
|
||||
|
||||
bool readSymbology( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context );
|
||||
%Docstring
|
||||
Read the symbology for the current layer from the Dom node supplied.
|
||||
|
||||
:param node: node that will contain the symbology definition for this layer.
|
||||
:param errorMessage: reference to string that will be updated with any error messages
|
||||
:param context: reading context (used for transform from relative to absolute paths)
|
||||
|
||||
:return: true in case of success.
|
||||
%End
|
||||
|
||||
bool writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context ) const;
|
||||
%Docstring
|
||||
Write the symbology for the layer into the docment provided.
|
||||
|
||||
:param node: the node that will have the style element added to it.
|
||||
:param doc: the document that will have the QDomNode added.
|
||||
:param errorMessage: reference to string that will be updated with any error messages
|
||||
:param context: writing context (used for transform from absolute to relative paths)
|
||||
|
||||
:return: true in case of success.
|
||||
%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,7 @@ Returns the icon name of the given ``layerType``
|
||||
static QIcon iconTable();
|
||||
static QIcon iconRaster();
|
||||
static QIcon iconDefault();
|
||||
static QIcon iconMesh();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -597,6 +597,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 );
|
||||
|
@ -446,6 +446,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
|
||||
@ -682,6 +688,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
|
||||
@ -1058,6 +1068,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
|
||||
@ -1177,6 +1190,7 @@ INCLUDE_DIRECTORIES(
|
||||
scalebar
|
||||
symbology
|
||||
metadata
|
||||
mesh
|
||||
${CMAKE_SOURCE_DIR}/external/nmea
|
||||
)
|
||||
IF (WITH_INTERNAL_QEXTSERIALPORT)
|
||||
|
@ -3622,6 +3622,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 ( size_t 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;
|
||||
|
||||
}
|
104
src/core/mesh/qgsmeshdataprovider.h
Normal file
104
src/core/mesh/qgsmeshdataprovider.h
Normal file
@ -0,0 +1,104 @@
|
||||
/***************************************************************************
|
||||
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 <cstddef>
|
||||
|
||||
#include "qgis_core.h"
|
||||
#include "qgis.h"
|
||||
#include "qgspoint.h"
|
||||
#include "qgsrectangle.h"
|
||||
#include "qgsdataprovider.h"
|
||||
#include "qgscoordinatereferencesystem.h"
|
||||
|
||||
#include <QVector>
|
||||
#include <QHash>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
typedef QgsPoint QgsMeshVertex; //xyz coords of vertex
|
||||
typedef QVector<size_t> 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 vertexes in the native mesh
|
||||
* \returns Number of vertexes in the mesh
|
||||
*/
|
||||
virtual size_t vertexCount() const = 0;
|
||||
|
||||
/**
|
||||
* \brief Return number of faces in the native mesh
|
||||
* \returns Number of faces in the mesh
|
||||
*/
|
||||
virtual size_t faceCount() const = 0;
|
||||
|
||||
/**
|
||||
* \brief Factory for mesh vertex with index
|
||||
* \returns new mesh vertex on index
|
||||
*/
|
||||
virtual QgsMeshVertex vertex( size_t index ) const = 0;
|
||||
|
||||
/**
|
||||
* \brief Factory for mesh face with index
|
||||
* \returns new mesh face on index
|
||||
*/
|
||||
virtual QgsMeshFace face( size_t index ) const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* Base class for providing data for QgsMeshLayer
|
||||
*
|
||||
* Responsible for reading native mesh data
|
||||
*
|
||||
* \see QgsMeshSource
|
||||
*
|
||||
*/
|
||||
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
|
217
src/core/mesh/qgsmeshlayer.cpp
Normal file
217
src/core/mesh/qgsmeshlayer.cpp
Normal file
@ -0,0 +1,217 @@
|
||||
/***************************************************************************
|
||||
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 <QUuid>
|
||||
|
||||
#include "qgsmeshlayer.h"
|
||||
#include "qgis.h"
|
||||
#include "qgsmaplayerrenderer.h"
|
||||
#include "qgsmeshdataprovider.h"
|
||||
#include "qgsmeshlayerrenderer.h"
|
||||
#include "qgstriangularmesh.h"
|
||||
#include "qgssinglesymbolrenderer.h"
|
||||
#include "qgsmeshmemorydataprovider.h"
|
||||
#include "qgsfillsymbollayer.h"
|
||||
#include "qgsproviderregistry.h"
|
||||
#include "qgslogger.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 = new QgsFillSymbol( l1 );
|
||||
|
||||
|
||||
toggleTriangularMeshRendering( false );
|
||||
|
||||
} // QgsMeshLayer ctor
|
||||
|
||||
|
||||
|
||||
QgsMeshLayer::~QgsMeshLayer()
|
||||
{
|
||||
clearMeshes();
|
||||
|
||||
if ( mDataProvider )
|
||||
delete mDataProvider;
|
||||
|
||||
if ( mNativeMeshSymbol )
|
||||
delete mNativeMeshSymbol;
|
||||
|
||||
if ( mTriangularMeshSymbol )
|
||||
delete mTriangularMeshSymbol;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void QgsMeshLayer::toggleTriangularMeshRendering( bool toggle )
|
||||
{
|
||||
if ( toggle && mTriangularMeshSymbol )
|
||||
return;
|
||||
|
||||
if ( mTriangularMeshSymbol )
|
||||
delete mTriangularMeshSymbol;
|
||||
|
||||
if ( toggle )
|
||||
{
|
||||
QgsSymbolLayerList l2;
|
||||
l2 << new QgsSimpleFillSymbolLayer( Qt::white, Qt::NoBrush, Qt::red, Qt::SolidLine, 0.26 );
|
||||
mTriangularMeshSymbol = new QgsFillSymbol( l2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
mTriangularMeshSymbol = nullptr;
|
||||
}
|
||||
triggerRepaint();
|
||||
}
|
||||
|
||||
void QgsMeshLayer::fillNativeMesh()
|
||||
{
|
||||
Q_ASSERT( !mNativeMesh );
|
||||
|
||||
mNativeMesh = new QgsMesh();
|
||||
|
||||
if ( !( dataProvider() && dataProvider()->isValid() ) )
|
||||
return;
|
||||
|
||||
mNativeMesh->vertices.resize( dataProvider()->vertexCount() );
|
||||
for ( size_t i = 0; i < dataProvider()->vertexCount(); ++i )
|
||||
{
|
||||
mNativeMesh->vertices[i] = dataProvider()->vertex( i );
|
||||
}
|
||||
|
||||
mNativeMesh->faces.resize( dataProvider()->faceCount() );
|
||||
for ( size_t i = 0; i < dataProvider()->faceCount(); ++i )
|
||||
{
|
||||
mNativeMesh->faces[i] = dataProvider()->face( i );
|
||||
}
|
||||
}
|
||||
|
||||
QgsMapLayerRenderer *QgsMeshLayer::createMapRenderer( QgsRenderContext &rendererContext )
|
||||
{
|
||||
if ( !mNativeMesh )
|
||||
{
|
||||
fillNativeMesh();
|
||||
}
|
||||
|
||||
if ( !mTriangularMesh )
|
||||
mTriangularMesh = new QgsTriangularMesh();
|
||||
|
||||
triangularMesh()->update( mNativeMesh, &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;
|
||||
}
|
||||
|
||||
void QgsMeshLayer::clearMeshes()
|
||||
{
|
||||
if ( mTriangularMesh )
|
||||
delete mTriangularMesh;
|
||||
|
||||
if ( mNativeMesh )
|
||||
delete mNativeMesh;
|
||||
|
||||
}
|
||||
|
||||
bool QgsMeshLayer::setDataProvider( QString const &provider )
|
||||
{
|
||||
clearMeshes();
|
||||
|
||||
mProviderKey = provider;
|
||||
QString dataSource = mDataSource;
|
||||
|
||||
if ( mDataProvider )
|
||||
delete mDataProvider;
|
||||
|
||||
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
|
224
src/core/mesh/qgsmeshlayer.h
Normal file
224
src/core/mesh/qgsmeshlayer.h
Normal file
@ -0,0 +1,224 @@
|
||||
/***************************************************************************
|
||||
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 "qgis_core.h"
|
||||
#include <QMap>
|
||||
#include <QSet>
|
||||
#include <QSharedPointer>
|
||||
#include <QList>
|
||||
#include <QStringList>
|
||||
#include <QFont>
|
||||
#include <QMutex>
|
||||
|
||||
#include "qgis.h"
|
||||
#include "qgsmaplayer.h"
|
||||
#include "qgsrendercontext.h"
|
||||
#include "qgsmeshdataprovider.h"
|
||||
|
||||
class QgsMapLayerRenderer;
|
||||
class QgsSymbol;
|
||||
|
||||
class QgsMeshDataProvider;
|
||||
class QgsNativeMesh;
|
||||
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 providers Mesh data providers
|
||||
*
|
||||
* \subsection 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" );
|
||||
//! Dtor
|
||||
~QgsMeshLayer() override;
|
||||
|
||||
//! QgsMeshLayer cannot be copied.
|
||||
QgsMeshLayer( const QgsMeshLayer &rhs ) = delete;
|
||||
//! QgsMeshLayer cannot be copied.
|
||||
QgsMeshLayer &operator=( QgsMeshLayer const &rhs ) = delete;
|
||||
|
||||
//! Return data provider
|
||||
QgsMeshDataProvider *dataProvider() override;
|
||||
|
||||
//! Return const data provider
|
||||
const QgsMeshDataProvider *dataProvider() const override SIP_SKIP;
|
||||
|
||||
/**
|
||||
* Returns a new instance equivalent to this one. A new provider is
|
||||
* created for the same data source and renderers are cloned too.
|
||||
* \returns a new layer instance
|
||||
*/
|
||||
QgsMeshLayer *clone() const override SIP_FACTORY;
|
||||
|
||||
//! Returns the extent of the layer.
|
||||
QgsRectangle extent() const override;
|
||||
|
||||
/**
|
||||
* Return new instance of QgsMapLayerRenderer that will be used for rendering of given context
|
||||
*/
|
||||
virtual QgsMapLayerRenderer *createMapRenderer( QgsRenderContext &rendererContext ) SIP_FACTORY;
|
||||
|
||||
//! Return the provider type for this layer
|
||||
QString providerType() const;
|
||||
|
||||
//! return native mesh (nullprt before rendering)
|
||||
QgsMesh *nativeMesh() SIP_SKIP {return mNativeMesh;}
|
||||
|
||||
//! return triangular mesh (nullprt before rendering)
|
||||
QgsTriangularMesh *triangularMesh() SIP_SKIP {return mTriangularMesh;}
|
||||
|
||||
//! Returns a line symbol used for rendering native mesh.
|
||||
QgsSymbol *nativeMeshSymbol() {return mNativeMeshSymbol;}
|
||||
|
||||
/**
|
||||
* Returns a line symbol used for rendering of triangular (derived) mesh.
|
||||
* \see toggleTriangularMeshRendering
|
||||
*/
|
||||
QgsSymbol *triangularMeshSymbol() {return mTriangularMeshSymbol;}
|
||||
|
||||
//! Toggle rendering of triangular (derived) mesh. Off by default
|
||||
void toggleTriangularMeshRendering( bool toggle );
|
||||
|
||||
/**
|
||||
* Read the symbology for the current layer from the Dom node supplied.
|
||||
* \param node node that will contain the symbology definition for this layer.
|
||||
* \param errorMessage reference to string that will be updated with any error messages
|
||||
* \param context reading context (used for transform from relative to absolute paths)
|
||||
* \returns true in case of success.
|
||||
*/
|
||||
bool readSymbology( const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context );
|
||||
|
||||
/**
|
||||
* Write the symbology for the layer into the docment provided.
|
||||
* \param node the node that will have the style element added to it.
|
||||
* \param doc the document that will have the QDomNode added.
|
||||
* \param errorMessage reference to string that will be updated with any error messages
|
||||
* \param context writing context (used for transform from absolute to relative paths)
|
||||
* \returns true in case of success.
|
||||
*/
|
||||
bool writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context ) const;
|
||||
|
||||
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:
|
||||
//! Clear native and triangular mesh
|
||||
void clearMeshes();
|
||||
void fillNativeMesh();
|
||||
|
||||
private:
|
||||
//! Pointer to native mesh structure, used as cache for rendering
|
||||
QgsMesh *mNativeMesh = nullptr;
|
||||
|
||||
//! Pointer to derived mesh structure
|
||||
QgsTriangularMesh *mTriangularMesh = nullptr;
|
||||
|
||||
//! Pointer to data provider derived from the abastract base class QgsMeshDataProvider
|
||||
QgsMeshDataProvider *mDataProvider = nullptr;
|
||||
|
||||
//! Data provider key
|
||||
QString mProviderKey;
|
||||
|
||||
//! rendering native mesh
|
||||
QgsSymbol *mNativeMeshSymbol = nullptr;
|
||||
|
||||
//! rendering triangular mesh
|
||||
QgsSymbol *mTriangularMeshSymbol = nullptr;
|
||||
};
|
||||
|
||||
#endif //QGSMESHLAYER_H
|
109
src/core/mesh/qgsmeshlayerrenderer.cpp
Normal file
109
src/core/mesh/qgsmeshlayerrenderer.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
/***************************************************************************
|
||||
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 "qgsrenderer.h"
|
||||
#include "qgsrendercontext.h"
|
||||
#include "qgsmeshlayer.h"
|
||||
#include "qgsexception.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgssettings.h"
|
||||
#include "qgssinglesymbolrenderer.h"
|
||||
#include "qgsfield.h"
|
||||
#include "qgstriangularmesh.h"
|
||||
#include "qgspointxy.h"
|
||||
|
||||
#include <QPicture>
|
||||
|
||||
|
||||
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 = layer->nativeMeshSymbol()->clone();
|
||||
}
|
||||
|
||||
if ( layer->triangularMeshSymbol() )
|
||||
{
|
||||
mTriangularMeshSymbol = layer->triangularMeshSymbol()->clone();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QgsMeshLayerRenderer::~QgsMeshLayerRenderer()
|
||||
{
|
||||
if ( mNativeMeshSymbol )
|
||||
delete mNativeMeshSymbol;
|
||||
|
||||
if ( mTriangularMeshSymbol )
|
||||
delete mTriangularMeshSymbol;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool QgsMeshLayerRenderer::render()
|
||||
{
|
||||
renderMesh( mNativeMeshSymbol, mNativeMesh.faces ); // native mesh
|
||||
renderMesh( mTriangularMeshSymbol, mTriangularMesh.triangles() ); // triangular mesh
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void QgsMeshLayerRenderer::renderMesh( 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 );
|
||||
}
|
79
src/core/mesh/qgsmeshlayerrenderer.h
Normal file
79
src/core/mesh/qgsmeshlayerrenderer.h
Normal file
@ -0,0 +1,79 @@
|
||||
/***************************************************************************
|
||||
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 QgsRenderContext;
|
||||
class QgsMeshLayer;
|
||||
class QgsMeshVectorFieldRenderer;
|
||||
class QgsSingleSymbolRenderer;
|
||||
class QgsTriangularMesh;
|
||||
class QgsSymbol;
|
||||
|
||||
#define SIP_NO_FILE
|
||||
|
||||
#include <QList>
|
||||
#include <QPainter>
|
||||
|
||||
#include "qgis.h"
|
||||
#include "qgsfeedback.h"
|
||||
|
||||
#include "qgsmaplayerrenderer.h"
|
||||
#include "qgsmeshdataprovider.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:
|
||||
QgsMeshLayerRenderer( QgsMeshLayer *layer, QgsRenderContext &context );
|
||||
~QgsMeshLayerRenderer() override;
|
||||
|
||||
bool render() override;
|
||||
|
||||
private:
|
||||
void renderMesh( QgsSymbol *symbol, const QVector<QgsMeshFace> &faces );
|
||||
|
||||
|
||||
protected:
|
||||
// copy from mesh layer
|
||||
QgsMesh mNativeMesh;
|
||||
|
||||
// copy from mesh layer
|
||||
QgsTriangularMesh mTriangularMesh;
|
||||
|
||||
// copy from mesh layer
|
||||
QgsSymbol *mNativeMeshSymbol = nullptr;
|
||||
|
||||
// copy from mesh layer
|
||||
QgsSymbol *mTriangularMeshSymbol = nullptr;
|
||||
|
||||
// rendering context
|
||||
QgsRenderContext &mContext;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // QGSMESHLAYERRENDERER_H
|
166
src/core/mesh/qgsmeshmemorydataprovider.cpp
Normal file
166
src/core/mesh/qgsmeshmemorydataprovider.cpp
Normal file
@ -0,0 +1,166 @@
|
||||
/***************************************************************************
|
||||
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 "qgsmeshmemorydataprovider.h"
|
||||
#include <QFile>
|
||||
#include <QJsonDocument>
|
||||
#include <limits>
|
||||
|
||||
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 "mesh_memory";
|
||||
}
|
||||
|
||||
QString QgsMeshMemoryDataProvider::description() const
|
||||
{
|
||||
return "memory data provider for mesh layer";
|
||||
}
|
||||
|
||||
QgsCoordinateReferenceSystem QgsMeshMemoryDataProvider::crs() const
|
||||
{
|
||||
return QgsCoordinateReferenceSystem();
|
||||
}
|
||||
|
||||
QgsMeshMemoryDataProvider::QgsMeshMemoryDataProvider( const QString &uri )
|
||||
: QgsMeshDataProvider( uri )
|
||||
, mIsValid( false )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
QStringList sections = uri.split( "---", 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;
|
||||
|
||||
QStringList verticesCoords = def.split( "\n", QString::SkipEmptyParts );
|
||||
for ( int i = 0; i < verticesCoords.size(); ++i )
|
||||
{
|
||||
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;
|
||||
|
||||
QStringList facesVertices = def.split( "\n", QString::SkipEmptyParts );
|
||||
for ( int i = 0; i < facesVertices.size(); ++i )
|
||||
{
|
||||
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();
|
||||
face.push_back( vertex_id );
|
||||
if ( face[j] >= mVertices.size() )
|
||||
{
|
||||
setError( QgsError( QStringLiteral( "Invalid mesh definition, missing vertex id defined in face" ), QStringLiteral( "Mesh Memory Provider" ) ) );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
faces.push_back( face );
|
||||
}
|
||||
|
||||
mFaces = faces;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t QgsMeshMemoryDataProvider::vertexCount() const
|
||||
{
|
||||
return mVertices.size();
|
||||
}
|
||||
|
||||
size_t QgsMeshMemoryDataProvider::faceCount() const
|
||||
{
|
||||
return mFaces.size();
|
||||
}
|
||||
|
||||
QgsMeshVertex QgsMeshMemoryDataProvider::vertex( size_t index ) const
|
||||
{
|
||||
Q_ASSERT( vertexCount() > index );
|
||||
return mVertices[index];
|
||||
}
|
||||
|
||||
QgsMeshFace QgsMeshMemoryDataProvider::face( size_t index ) const
|
||||
{
|
||||
Q_ASSERT( faceCount() > index );
|
||||
return mFaces[index];
|
||||
}
|
||||
|
||||
|
100
src/core/mesh/qgsmeshmemorydataprovider.h
Normal file
100
src/core/mesh/qgsmeshmemorydataprovider.h
Normal file
@ -0,0 +1,100 @@
|
||||
/***************************************************************************
|
||||
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 <cstddef>
|
||||
|
||||
#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;
|
||||
|
||||
size_t vertexCount() const override;
|
||||
size_t faceCount() const override;
|
||||
QgsMeshVertex vertex( size_t index ) const override;
|
||||
QgsMeshFace face( size_t 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;
|
||||
};
|
||||
|
||||
///@endcond
|
||||
|
||||
#endif // QGSMESHMEMORYDATAPROVIDER_H
|
110
src/core/mesh/qgstriangularmesh.cpp
Normal file
110
src/core/mesh/qgstriangularmesh.cpp
Normal file
@ -0,0 +1,110 @@
|
||||
/***************************************************************************
|
||||
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 "qgsmeshdataprovider.h"
|
||||
#include "qgsrendercontext.h"
|
||||
#include "qgscoordinatereferencesystem.h"
|
||||
#include "qgscoordinatetransform.h"
|
||||
#include "qgsmeshlayer.h"
|
||||
|
||||
|
||||
QgsTriangularMesh::QgsTriangularMesh( )
|
||||
{
|
||||
}
|
||||
|
||||
QgsTriangularMesh::~QgsTriangularMesh()
|
||||
{
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
QgsMeshVertex vertex = nativeMesh->vertices[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 )
|
||||
{
|
||||
QgsMeshFace face = nativeMesh->faces[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;
|
||||
}
|
||||
|
83
src/core/mesh/qgstriangularmesh.h
Normal file
83
src/core/mesh/qgstriangularmesh.h
Normal file
@ -0,0 +1,83 @@
|
||||
/***************************************************************************
|
||||
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 <QList>
|
||||
#include <QPainter>
|
||||
#include <QVector>
|
||||
|
||||
#include "qgis.h"
|
||||
#include "qgis_core.h"
|
||||
#include "qgsmeshdataprovider.h"
|
||||
#include "qgscoordinatereferencesystem.h"
|
||||
|
||||
class QgsRenderContext;
|
||||
|
||||
//! Mesh - vertices and faces
|
||||
struct CORE_EXPORT QgsMesh
|
||||
{
|
||||
//! vertices
|
||||
QVector<QgsMeshVertex> vertices;
|
||||
//! faces
|
||||
QVector<QgsMeshFace> faces;
|
||||
};
|
||||
|
||||
/**
|
||||
* Triangular/Derived Mesh
|
||||
* \since QGIS 3.2
|
||||
*/
|
||||
class CORE_EXPORT QgsTriangularMesh
|
||||
{
|
||||
public:
|
||||
//! Ctor
|
||||
QgsTriangularMesh();
|
||||
//! Dtor
|
||||
~QgsTriangularMesh();
|
||||
|
||||
/**
|
||||
* Construct triangular mesh from layer's native mesh and context
|
||||
* \param layer QgsMeshLayer to get native mesh data
|
||||
* \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,12 @@ QIcon QgsLayerItem::iconRaster()
|
||||
return QgsApplication::getThemeIcon( QStringLiteral( "/mIconRaster.svg" ) );
|
||||
}
|
||||
|
||||
QIcon QgsLayerItem::iconMesh()
|
||||
{
|
||||
// TODO new icon!
|
||||
return QgsApplication::getThemeIcon( QStringLiteral( "/mIconPointLayer.svg" ) );
|
||||
}
|
||||
|
||||
QIcon QgsLayerItem::iconDefault()
|
||||
{
|
||||
return QgsApplication::getThemeIcon( QStringLiteral( "/mIconLayer.png" ) );
|
||||
@ -602,6 +608,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 +645,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 +680,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,7 @@ class CORE_EXPORT QgsLayerItem : public QgsDataItem
|
||||
static QIcon iconTable();
|
||||
static QIcon iconRaster();
|
||||
static QIcon iconDefault();
|
||||
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
|
||||
|
@ -35,7 +35,7 @@
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsproject.h"
|
||||
#include "qgssettings.h"
|
||||
|
||||
#include "qgsmeshlayer.h"
|
||||
|
||||
#include <QDragEnterEvent>
|
||||
|
||||
@ -154,6 +154,20 @@ void QgsBrowserLayerProperties::setItem( QgsDataItem *item )
|
||||
delete layer;
|
||||
}
|
||||
}
|
||||
else if ( type == QgsMapLayer::MeshLayer )
|
||||
{
|
||||
QgsDebugMsg( "creating mesh layer" );
|
||||
QgsMeshLayer *layer = new QgsMeshLayer( layerItem->uri(), layerItem->uri(), layerItem->providerKey() );
|
||||
if ( layer )
|
||||
{
|
||||
if ( layer->isValid() )
|
||||
{
|
||||
layerCrs = layer->crs();
|
||||
layerMetadata = layer->htmlMetadata();
|
||||
}
|
||||
delete layer;
|
||||
}
|
||||
}
|
||||
else if ( type == QgsMapLayer::VectorLayer )
|
||||
{
|
||||
QgsDebugMsg( "creating vector layer" );
|
||||
|
@ -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 );
|
||||
}
|
||||
|
29
src/providers/mdal/qgsmdaldataitems.h
Normal file
29
src/providers/mdal/qgsmdaldataitems.h
Normal file
@ -0,0 +1,29 @@
|
||||
/***************************************************************************
|
||||
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"
|
||||
|
||||
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
|
137
src/providers/mdal/qgsmdalprovider.cpp
Normal file
137
src/providers/mdal/qgsmdalprovider.cpp
Normal file
@ -0,0 +1,137 @@
|
||||
/***************************************************************************
|
||||
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"
|
||||
#include <QFile>
|
||||
#include <QJsonDocument>
|
||||
#include <limits>
|
||||
#include "mdal.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 );
|
||||
}
|
||||
|
||||
size_t QgsMdalProvider::vertexCount() const
|
||||
{
|
||||
if ( mMeshH )
|
||||
return MDAL_M_vertexCount( mMeshH );
|
||||
else
|
||||
return ( size_t ) 0;
|
||||
}
|
||||
|
||||
size_t QgsMdalProvider::faceCount() const
|
||||
{
|
||||
if ( mMeshH )
|
||||
return MDAL_M_faceCount( mMeshH );
|
||||
else
|
||||
return ( size_t ) 0;
|
||||
}
|
||||
|
||||
QgsMeshVertex QgsMdalProvider::vertex( size_t 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( size_t index ) const
|
||||
{
|
||||
Q_ASSERT( index < faceCount() );
|
||||
QgsMeshFace face;
|
||||
int n_face_vertices = MDAL_M_faceVerticesCountAt( mMeshH, index );
|
||||
for ( size_t 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()
|
||||
{
|
||||
}
|
||||
|
71
src/providers/mdal/qgsmdalprovider.h
Normal file
71
src/providers/mdal/qgsmdalprovider.h
Normal file
@ -0,0 +1,71 @@
|
||||
/***************************************************************************
|
||||
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 <cstddef>
|
||||
|
||||
#include "qgscoordinatereferencesystem.h"
|
||||
#include "qgsdataitem.h"
|
||||
#include "qgsmeshdataprovider.h"
|
||||
#include "qgsrectangle.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QDomElement>
|
||||
#include <QMap>
|
||||
#include <QVector>
|
||||
|
||||
#include <mdal.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;
|
||||
|
||||
size_t vertexCount() const override;
|
||||
size_t faceCount() const override;
|
||||
QgsMeshVertex vertex( size_t index ) const override;
|
||||
QgsMeshFace face( size_t 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" ) )
|
||||
{
|
||||
// unsuported
|
||||
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
|
||||
)
|
||||
@ -186,7 +187,9 @@ SET(TESTS
|
||||
testqgsvectorlayerjoinbuffer.cpp
|
||||
testqgsvectorlayer.cpp
|
||||
testziplayer.cpp
|
||||
)
|
||||
testqgsmeshlayer.cpp
|
||||
testqgsmeshlayerrenderer.cpp
|
||||
)
|
||||
|
||||
IF(WITH_QTWEBKIT)
|
||||
SET(TESTS ${TESTS}
|
||||
|
132
tests/src/core/testqgsmeshlayer.cpp
Normal file
132
tests/src/core/testqgsmeshlayer.cpp
Normal file
@ -0,0 +1,132 @@
|
||||
/***************************************************************************
|
||||
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"
|
||||
|
||||
/**
|
||||
* \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( ( size_t ) 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( ( size_t ) 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