Skip to content

Commit

Permalink
use combineField and handle exceptions better
Browse files Browse the repository at this point in the history
  • Loading branch information
ghtmtt committed May 17, 2019
1 parent aa2aed9 commit 17000a4
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 53 deletions.
2 changes: 1 addition & 1 deletion python/plugins/processing/algs/help/qgis.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ qgis:checkvalidity: >
qgis:climbalongline: >
This algorithm calculates the total climb and descent along line geometries.

It works only if the geometries have Z values. If it does not, and you have a DEM, you can use the Drape (set z-value from raster) algorithm to add Z values.
Input layers must have Z values present. If Z values are not available, the "Drape" (set Z value from raster) algorithm may be used to add Z values from a DEM layer.

The output layer is a copy of the input layer with additional fields that contain the total climb, total descent, the minimum elevation and the maximum elevation for each line geometry. If the input layer contains fields with the same names as these added fields, they will be overwritten.

Expand Down
84 changes: 32 additions & 52 deletions python/plugins/processing/algs/qgis/Climb.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsProcessingOutputNumber,
QgsProcessingException,
QgsProcessingUtils,
QgsWkbTypes,
QgsFields,
QgsField)
Expand Down Expand Up @@ -127,12 +129,13 @@ def processAlgorithm(self, parameters, context, feedback):
)

fcount = source.featureCount()
source_fields = source.fields()

hasZ = QgsWkbTypes.hasZ(source.wkbType())

if not hasZ:
feedback.reportError(self.tr('The layer does not have Z values. If you have a DEM, use the Drape algorithm to extract Z values.'))
return
raise QgsProcessingException(self.tr('The layer does not have Z values. If you have a DEM, use the Drape algorithm to extract Z values.'))
return {}

thefields = QgsFields()
climbindex = -1
Expand All @@ -141,51 +144,21 @@ def processAlgorithm(self, parameters, context, feedback):
maxelevindex = -1
fieldnumber = 0

# Skip fields with names that are equal to the generated ones
for field in source.fields():
if field.name() == self.CLIMBATTRIBUTE:
feedback.pushInfo(self.tr(
'{attr_name} attribute found and removed'.format(
attr_name=self.CLIMBATTRIBUTE)
)
)
climbindex = fieldnumber
elif field.name() == self.DESCENTATTRIBUTE:
feedback.pushInfo(self.tr(
'{attr_name} attribute found and removed'.format(
attr_name=self.DESCENTATTRIBUTE)
)
)
descentindex = fieldnumber
elif field.name() == self.MINELEVATTRIBUTE:
feedback.pushInfo(self.tr(
'{attr_name} attribute found and removed'.format(
attr_name=self.MINELEVATTRIBUTE)
)
)
minelevindex = fieldnumber
elif field.name() == self.MAXELEVATTRIBUTE:
feedback.pushInfo(self.tr(
'{attr_name} attribute found and removed'.format(
attr_name=self.MAXELEVATTRIBUTE)
)
)
maxelevindex = fieldnumber
else:
thefields.append(field)
fieldnumber = fieldnumber + 1

# Create new fields for climb and descent
thefields.append(QgsField(self.CLIMBATTRIBUTE, QVariant.Double))
thefields.append(QgsField(self.DESCENTATTRIBUTE, QVariant.Double))
thefields.append(QgsField(self.MINELEVATTRIBUTE, QVariant.Double))
thefields.append(QgsField(self.MAXELEVATTRIBUTE, QVariant.Double))

# combine all the vector fields
out_fields = QgsProcessingUtils.combineFields(source_fields, thefields)

layerwithz = source

(sink, dest_id) = self.parameterAsSink(parameters,
self.OUTPUT,
context, thefields,
context,
out_fields,
layerwithz.wkbType(),
source.sourceCrs())

Expand All @@ -197,6 +170,7 @@ def processAlgorithm(self, parameters, context, feedback):
maxelevation = float('-Infinity')

no_z_nodes = []
no_geometry = []

for current, feature in enumerate(features):
if feedback.isCanceled():
Expand All @@ -208,6 +182,12 @@ def processAlgorithm(self, parameters, context, feedback):
# In case of multigeometries we need to do the parts
parts = feature.geometry().constParts()
partnumber = 0
if not feature.hasGeometry():
no_geometry.append(self.tr(
'Feature: {feature_id}'.format(
feature_id=feature.id())
)
)
for part in parts:
# Calculate the climb
first = True
Expand Down Expand Up @@ -244,20 +224,14 @@ def processAlgorithm(self, parameters, context, feedback):
partnumber += 1
# Set the attribute values
attrs = feature.attributes()
outattrs = []
attrindex = 0
for attr in attrs:
# Skip attributes from the input layer that had names
# that were equal to the generated ones
if not (attrindex == climbindex or
attrindex == descentindex or
attrindex == minelevindex or
attrindex == maxelevindex):
outattrs.append(attr)
attrindex = attrindex + 1
# feature.setAttributes(outattrs + [climb, descent])
feature.setAttributes(outattrs +
[climb, descent, minelev, maxelev])
# Append the attributes to the end of the existing ones
attrs.append(climb)
attrs.append(descent)
attrs.append(minelev)
attrs.append(maxelev)

# Set the final attribute list
feature.setAttributes(attrs)
# Add a feature to the sink
sink.addFeature(feature, QgsFeatureSink.FastInsert)
if minelevation > minelev:
Expand All @@ -269,7 +243,13 @@ def processAlgorithm(self, parameters, context, feedback):
feedback.setProgress(int(100 * current / fcount))

feedback.pushInfo(self.tr(
'The following points to not have Z values: {no_z_report}'.format(
'The following features do not have geometry: {no_geometry_report}'.format(
no_geometry_report=str(no_geometry))
)
)

feedback.pushInfo(self.tr(
'The following points do not have Z values: {no_z_report}'.format(
no_z_report=str(no_z_nodes))
)
)
Expand Down

0 comments on commit 17000a4

Please sign in to comment.