QGIS Extract Nodes with M-Values for Linear Referencing
From what I can find there doesn't appear to be an existing solution for this exact situation, but I still wanted to be able to do this in QGIS, so I took the plunge into python scripting.
A guide for writing processing algorithms can be found here https://docs.qgis.org/2.18/en/docs/user_manual/processing/scripts.html
To use this code open up the Processing toolbox, then expand Scripts, then expand Tools. Select "Create new script" and copy and paste the code below into the script window (use caution when copying and pasting python code since whitespace is syntactically significant. If you are having problems put the code into a text editor that shows whitespace and make sure that it copied correctly). Save it wherever you want and there is an execute script button at the top of the window. After you save it you can "Add script from file" and permanently have the script under "User scripts".
When the processing window comes up select the layer that contains the vector geometry and select run. The script behaves the same way as "Extract Nodes" except that it adds a column called MValues
and or ZValues
depending on what is available in the input geometry.
##input_layer=vector
##output_layer=output vector
from qgis.core import QgsWKBTypes, QgsField, QgsVectorFileWriter, QgsFeature, QgsGeometry
from PyQt4.QtCore import QVariant
def addVertices( geometry, writer, inFeature ):
coordinateSequence = geometry.coordinateSequence()
for rings in coordinateSequence:
for points in rings:
for point in points:
feature = QgsFeature( fields )
feature.setGeometry( QgsGeometry( point ) )
type = point.wkbType()
attributes = inFeature.attributes()
if QgsWKBTypes.hasM( type ):
attributes.append( point.m() )
if QgsWKBTypes.hasZ( type ):
attributes.append(point.z())
feature.setAttributes( attributes )
writer.addFeature( feature )
return
inlayer = processing.getObject( input_layer )
provider = inlayer.dataProvider()
fields = provider.fields()
geomType = QgsWKBTypes.Type(inlayer.wkbType())
outputGeomType = QgsWKBTypes.Point
if QgsWKBTypes.hasM( geomType ):
outputGeomType = QgsWKBTypes.addM( outputGeomType )
fields.append( QgsField( "MValue", QVariant.Double ) )
if QgsWKBTypes.hasZ( geomType ):
outputGeomType = QgsWKBTypes.addZ( outputGeomType )
fields.append( QgsField( "ZValue", QVariant.Double ) )
layer_options = 'SHPT=' + QgsWKBTypes.displayString(outputGeomType)
writer = QgsVectorFileWriter( output_layer, 'UTF-8', fields, outputGeomType , inlayer.crs(), layerOptions=[layer_options] )
features = inlayer.getFeatures()
featureCount = inlayer.featureCount()
featureIndex = 0
for f in features:
percent = ( featureIndex/float( featureCount ) ) * 100
progress.setPercentage( percent )
g = f.geometry().geometry()
addVertices( g, writer, f )
featureIndex +=1
del writer
With QGIS 3.0 or newer this task is trivial. In the "Processing Toolbox" (Open with ctrl+alt+t or Processing -> Toolbox) search for "Extract vertices" and run that algorithm.
Select your M or ZM line or polygon geometry as the Input layer, and run.
The vertices will be extracted with M and Z values intact depending on what is in the original geometry.
If the M value is needed as a field in the attribute table, then the field calculator can be used with an expression like m($geometry)