Skip to content

Commit

Permalink
TIN Mesh creation
Browse files Browse the repository at this point in the history
  • Loading branch information
vcloarec committed Sep 10, 2020
1 parent fa18514 commit d2f4c40
Show file tree
Hide file tree
Showing 25 changed files with 1,269 additions and 19 deletions.
1 change: 0 additions & 1 deletion external/mdal/mdal_data_model.hpp
Expand Up @@ -279,7 +279,6 @@ namespace MDAL

private:
const std::string mDriverName;
size_t mFaceVerticesMaximumCount = 0; //typically 3 or 4, sometimes up to 9
const std::string mUri; // file/uri from where it came
std::string mCrs;
};
Expand Down
1 change: 1 addition & 0 deletions python/analysis/analysis_auto.sip
Expand Up @@ -5,6 +5,7 @@
%Include auto_generated/interpolation/qgsinterpolator.sip
%Include auto_generated/interpolation/qgstininterpolator.sip
%Include auto_generated/mesh/qgsmeshcontours.sip
%Include auto_generated/mesh/qgsmeshtriangulation.sip
%Include auto_generated/network/qgsgraph.sip
%Include auto_generated/network/qgsgraphanalyzer.sip
%Include auto_generated/network/qgsgraphbuilder.sip
Expand Down
114 changes: 114 additions & 0 deletions python/analysis/auto_generated/mesh/qgsmeshtriangulation.sip.in
@@ -0,0 +1,114 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/analysis/mesh/qgsmeshtriangulation.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/





class QgsMeshTriangulation : QObject
{
%Docstring

Class that handles mesh creation with Delaunay constrained triangulation

.. versionadded:: 3.16
%End

%TypeHeaderCode
#include "qgsmeshtriangulation.h"
%End
public:

QgsMeshTriangulation();
%Docstring
Contructor
%End

~QgsMeshTriangulation();

bool addVertices( QgsVectorLayer *vectorLayer, int valueAttribute, const QgsCoordinateTransformContext &transformContext, QgsFeedback *feedback = 0 );
%Docstring
Adds vertices to the triangulation from a vector layer, return true if success.

:param vectorLayer: the vector layer with vertices to insert
:param valueAttribute: the index of the attribute that represents the value of vertices, if -1 uses Z coordinate of vertices
:param transformContext: the transform context used to transform coordinates
%End

bool addBreakLines( QgsVectorLayer *linesSource, int valueAttribute, const QgsCoordinateTransformContext &transformContext, QgsFeedback *feedback = 0 );
%Docstring
Adds break lines from a vector layer, return true if success

:param vectorLayer: the vector layer with break lines to insert
:param valueAttribute: the index of the attribute that represents the value of vertices, if -1 uses Z coordinate of vertices
:param transformContext: the transform context used to transform coordinates

.. note::

if the vector layer contain point, only vertices will be added without breaklines
%End

QgsMesh triangulatedMesh() const;
%Docstring
Returns the triangulated mesh
%End

void setCrs( const QgsCoordinateReferenceSystem &crs );
%Docstring
Sets the coordinate reference system used for the triangulation
%End

private:
QgsMeshTriangulation( const QgsMeshTriangulation &rhs );
};


class QgsMeshZValueDatasetGroup: QgsMeshDatasetGroup
{
%Docstring

Convenient class that can be used to obtain a datasetgroup on vertices that represents the Z value of the mesh vertices

.. versionadded:: 3.16
%End

%TypeHeaderCode
#include "qgsmeshtriangulation.h"
%End
public:
QgsMeshZValueDatasetGroup( const QString &datasetGroupName, const QgsMesh &mesh );
%Docstring
Constructor

:param datasetGroupName: the name of the dataset group
:param mesh: the mesh used to create the Z value dataset
%End

virtual void initialize();

virtual QgsMeshDatasetMetadata datasetMetadata( int datasetIndex ) const;

virtual int datasetCount() const;

virtual QgsMeshDataset *dataset( int index ) const;

virtual QgsMeshDatasetGroup::Type type() const;
virtual QDomElement writeXml( QDomDocument &doc, const QgsReadWriteContext &context ) const;


private:
QgsMeshZValueDatasetGroup( const QgsMeshZValueDatasetGroup &rhs );
};

/************************************************************************
* This file has been generated automatically from *
* *
* src/analysis/mesh/qgsmeshtriangulation.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
10 changes: 10 additions & 0 deletions python/core/auto_generated/mesh/qgsmeshlayer.sip.in
Expand Up @@ -164,6 +164,16 @@ Adds datasets to the mesh from file with ``path``. Use the the time ``defaultRef
.. versionadded:: 3.14
%End

bool addDatasets( QgsMeshDatasetGroup *datasetGroup /Transfer/ );
%Docstring
Adds extra datasets to the mesh. Take ownership.

:param datasetGroup: the extra dataset group

:return: whether the dataset is effectively added

.. versionadded:: 3.16
%End

bool saveDataset( const QString &path, int datasetGroupIndex, QString driver );
%Docstring
Expand Down
12 changes: 12 additions & 0 deletions python/core/auto_generated/qgsprovidermetadata.sip.in
Expand Up @@ -34,6 +34,7 @@ Holds metadata about mesh driver
CanWriteFaceDatasets,
CanWriteVertexDatasets,
CanWriteEdgeDatasets,
CanWriteMeshData,
};

typedef QFlags<QgsMeshDriverMetadata::MeshDriverCapability> MeshDriverCapabilities;
Expand Down Expand Up @@ -219,6 +220,17 @@ eg. "yes" value will be returned as true, 0 will be returned as false
Creates a new instance of the raster data provider.

.. versionadded:: 3.10
%End

virtual bool createMeshData(
const QgsMesh &mesh,
const QString uri,
const QString &driverName,
const QgsCoordinateReferenceSystem &crs ) const;
%Docstring
Creates mesh data source (depending of the provider)

.. versionadded:: 3.16
%End

virtual QList<QPair<QString, QString> > pyramidResamplingMethods();
Expand Down
2 changes: 2 additions & 0 deletions python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py
Expand Up @@ -83,6 +83,7 @@
from .TextToFloat import TextToFloat
from .TilesXYZ import TilesXYZAlgorithmDirectory, TilesXYZAlgorithmMBTiles
from .TinInterpolation import TinInterpolation
from .TinMeshCreation import TinMeshCreation
from .TopoColors import TopoColor
from .UniqueValues import UniqueValues
from .VariableDistanceBuffer import VariableDistanceBuffer
Expand Down Expand Up @@ -155,6 +156,7 @@ def getAlgs(self):
TilesXYZAlgorithmDirectory(),
TilesXYZAlgorithmMBTiles(),
TinInterpolation(),
TinMeshCreation(),
TopoColor(),
UniqueValues(),
VariableDistanceBuffer(),
Expand Down
142 changes: 142 additions & 0 deletions python/plugins/processing/algs/qgis/TinMeshCreation.py
@@ -0,0 +1,142 @@
# -*- coding: utf-8 -*-

"""
***************************************************************************
TinInterpolation.py
---------------------
Date : August 2020
Copyright : (C) 2020 by Vincent Cloarec
Email : vcloarec 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. *
* *
***************************************************************************
"""

__author__ = 'Vincent Cloarec'
__date__ = 'August 2020'
__copyright__ = '(C) 2020, Vincent Cloarec'

import os

from qgis.PyQt.QtGui import QIcon
from qgis.utils import iface

from qgis.core import (QgsProcessingUtils,
QgsProcessingContext,
QgsProcessingParameterCrs,
QgsProcessingParameterEnum,
QgsProcessingParameterFileDestination,
QgsProcessingException,
QgsProviderRegistry,
QgsMeshDriverMetadata,
QgsMeshLayer)
from qgis.analysis import (QgsMeshTriangulation,
QgsMeshZValueDatasetGroup)

from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.algs.qgis.ui.TinMeshWidgets import ParameterTinMeshData

pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]


class TinMeshCreation(QgisAlgorithm):
SOURCE_DATA = 'SOURCE_DATA'
EXTENT = 'EXTENT'
MESH_FORMAT = 'MESH_FORMAT'
CRS = 'CRS_OUTPUT'
OUTPUT_MESH = 'OUTPUT_MESH'

def group(self):
return self.tr('Mesh')

def groupId(self):
return 'mesh'

def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(ParameterTinMeshData(self.SOURCE_DATA, self.tr('Input layer(s)')))

self.FORMATS = []
self.providerMetaData = QgsProviderRegistry.instance().providerMetadata("mdal")
meshDriverMetaList = self.providerMetaData.meshDriversMetadata()
meshDriverAvailable = []
for driver in meshDriverMetaList:
if bool(driver.capabilities() & QgsMeshDriverMetadata.CanWriteMeshData):
meshDriverAvailable.append(driver)
self.FORMATS.append(driver.name())

self.addParameter(QgsProcessingParameterEnum(self.MESH_FORMAT,
self.tr('Output format'),
options=self.FORMATS,
defaultValue=0))

self.addParameter(QgsProcessingParameterCrs(self.CRS,
self.tr('Output coordinate system'),
optional=True))

self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT_MESH,
self.tr('Output file'),
optional=False))

def name(self):
return 'tinmeshcreation'

def displayName(self):
return self.tr('TIN mesh creation')

def processAlgorithm(self, parameters, context, feedback):
sourceData = ParameterTinMeshData.parseValue(parameters[self.SOURCE_DATA])

if sourceData is None:
raise QgsProcessingException(
self.tr('You need to specify at least one input layer.'))

crs = self.parameterAsCrs(parameters, self.CRS, context)
if not crs.isValid():
crs = iface.mapCanvas().mapSettings().destinationCrs()

meshTriangulation = QgsMeshTriangulation()

for i, row in enumerate(sourceData.split('::|::')):
v = row.split('::~::')
layer = QgsProcessingUtils.mapLayerFromString(v[0], context)
if not crs.isValid():
crs = layer.sourceCrs()

valueAttribute = int(v[1])

if v[2] == '0': # points
meshTriangulation.addVertices(layer, valueAttribute, context.transformContext(), feedback)
else: # lines
meshTriangulation.addBreakLines(layer, valueAttribute, context.transformContext(), feedback)

fileName = self.parameterAsFile(parameters, self.OUTPUT_MESH, context)
driverIndex = self.parameterAsEnum(parameters, self.MESH_FORMAT, context)
mesh = meshTriangulation.triangulatedMesh()
self.providerMetaData.createMeshData(mesh, fileName, self.FORMATS[driverIndex], crs)

#SELAFIN format doesn't support saving Z value on mesh vertices, so create a specific dataset group
if self.FORMATS[driverIndex] == "SELAFIN":
self.addZValueDataset(fileName, mesh)

context.addLayerToLoadOnCompletion(fileName, QgsProcessingContext.LayerDetails('TIN Mesh',
context.project(),
'TIN', QgsProcessingUtils.LayerHint.Mesh))

return {self.OUTPUT_MESH: fileName}

def addZValueDataset(self, fileName, mesh):

tempLayer = QgsMeshLayer(fileName, "temp", "mdal")

zValueDatasetGroup = QgsMeshZValueDatasetGroup(self.tr("Terrain Elevation"), mesh)
tempLayer.addDatasets(zValueDatasetGroup)
datasetGroupIndex = tempLayer.datasetGroupCount() - 1
tempLayer.saveDataset(fileName, datasetGroupIndex, "SELAFIN")

0 comments on commit d2f4c40

Please sign in to comment.