QgsProcessingParameterDistance,
QgsVectorDataProvider,
QgsFields,
- QgsField)
+ QgsField,
+ QgsUnitTypes)
import processing
-
+import re
+from operator import itemgetter
class SpanCoordinatesAlgorithm(QgsProcessingAlgorithm):
"""
PIPE = 'PIPE'
SPAN = 'SPAN'
TOLERANCE = 'TOLERANCE'
+ MINIMUM_LENGTH = 'MINIMUM_LENGTH'
OUTPUT = 'OUTPUT'
# Constants for feature field names
FATHER_ID = 'FatherId'
LINESTRING = 'LineString'
+
+ # RegExp for DN values in
+ DN_PATTERN = re.compile(r"DN(\d+)(-.*)?")
def tr(self, string):
"""
)
)
- self.addParameter(
- QgsProcessingParameterDistance(
- self.TOLERANCE,
- self.tr('Location tolerance'),
- 0.0,
- minValue = 0.0
- )
+ tol = QgsProcessingParameterDistance(
+ self.TOLERANCE,
+ self.tr('Location tolerance'),
+ 0.001,
+ minValue = 0.0
+ )
+ tol.setDefaultUnit(QgsUnitTypes.DistanceMeters)
+ self.addParameter( tol )
+
+ dist = QgsProcessingParameterDistance(
+ self.MINIMUM_LENGTH,
+ self.tr('Minimum span length'),
+ 0.25,
+ minValue = 0.0
)
+ dist.setDefaultUnit(QgsUnitTypes.DistanceMeters)
+ self.addParameter( dist )
self.addParameter(
QgsProcessingParameterFeatureSink(
context
)
+ minLength = self.parameterAsDouble(
+ parameters,
+ self.MINIMUM_LENGTH,
+ context
+ )
+
+ feedback.pushInfo('Tolerance: {} m\nMinimum span length: {} m'.format(eps, minLength))
+
sourceFields = span.fields()
sourceNames = sourceFields.names()
outputFields = QgsFields(sourceFields)
if not ('z2' in sourceNames): outputFields.append(QgsField('z2', QVariant.Double))
if not ('Length' in sourceNames): outputFields.append(QgsField('Length', QVariant.Double))
if not ('LineString' in sourceNames): outputFields.append(QgsField('LineString', QVariant.String))
+ if not ('DimensionDN' in sourceNames): outputFields.append(QgsField('DimensionDN', QVariant.Int))
+ if not ('PipeStruct' in sourceNames): outputFields.append(QgsField('PipeStruct', QVariant.String))
(output, outputId) = self.parameterAsSink(
parameters,
# Dictionary from span feature ids to lists of lists of QgsPoint objects
strings = dict()
+ # Dictionary for the PipeStruct field values
+ types = dict()
+
spanFeatures = span.getFeatures()
pipeFeatures = pipe.getFeatures()
fatherID = feature[self.FATHER_ID]
# Length
- length = geometry.length()
+ myLength = feature['Length']
+ if myLength == None:
+ myLength = geometry.length()
oldLength = lengths.get(fatherID, 0.0)
- lengths[fatherID] = oldLength + length
+ lengths[fatherID] = oldLength + myLength
# Segment points
pointList = strings.get(fatherID, [])
pointList.append(mylist)
strings[fatherID] = pointList
+ # Store the value of PipeStruct
+ t = feature['PipeStruct']
+ tt = types.get(fatherID, {})
+ types[fatherID] = tt
+ c = tt.get(t, 0)
+ c += myLength
+ tt[t] = c
+
# Update the progress bar
feedback.setProgress(int(counter * total))
#feedback.pushInfo(str(id))
# Length
- length = lengths.get(id, None)
+ myLength = feature['Length']
+
+ # Ignore short stumps
+ if myLength <= minLength:
+ continue
# Vertices
+ mypoints = list(feature.geometry().vertices())
mylist = strings.get(id, None)
if mylist == None:
feedback.pushInfo('No points for feature {}'.format(id))
- continue
+ mylist = [mypoints]
#feedback.pushInfo('Points: {}'.format("|".join(map(lambda x: ";".join(('{} {}'.format(p.x(), p.y()) for p in x)), mylist))))
- mypoints = list(feature.geometry().vertices())
head = feature.geometry().vertices().next()
resultList = [head]
mylist = list(map(lambda x: list(reversed(x)), mylist))
i = next((i for i, x in enumerate(mylist) if head.distance(x[0]) <= eps), None)
if i == None:
- feedback.pushInfo('No matching start vertex for feature {}'.format(id))
- continue
+ feedback.pushInfo('Warning: No matching start vertex for feature {}'.format(id))
+ mylist = [mypoints]
+ i = 0
+
+ vertices = mylist.pop(i)
while i != None:
- vertices = mylist.pop(i)
tail = vertices[-1]
resultList.extend(vertices[1:])
+ if tail.distance(mypoints[-1]) <= eps:
+ break
+
i = next((i for i, x in enumerate(mylist) if tail.distance(x[0]) <= eps), None)
+ if i != None:
+ vertices = mylist.pop(i)
+ else:
+ i = next((i for i, x in enumerate(mylist) if tail.distance(x[-1]) <= eps), None)
+ if i != None:
+ vertices = list(reversed(mylist.pop(i)))
# feedback.pushInfo(str(resultList))
# Convert to string
result = ";".join(('{} {}'.format(p.x(), p.y()) for p in resultList))
- feedback.pushInfo('Feature {}: {}'.format(id, result))
+ # feedback.pushInfo('Feature {}: {}'.format(id, result))
outputFeature = QgsFeature()
outputFeature.setFields(outputFields)
outputFeature['x2'] = feature['x2']
outputFeature['y2'] = feature['y2']
outputFeature['z2'] = feature['z2']
- outputFeature['Length'] = feature['length'] # length
+ outputFeature['Length'] = feature['Length'] # myLength
outputFeature['LineString'] = result
+ # Handle pipe type codes
+ mytypes = list(types.get(id, {}).items())
+ if len(mytypes) == 0:
+ feedback.pushInfo('No type codes for feature {}'.format(id))
+ else:
+ if len(mytypes) > 1:
+ mytypes.sort(key = itemgetter(1))
+ feedback.pushInfo('No unique type code for feature {}: {}'.format(id, mytypes))
+ outputFeature['PipeStruct'] = mytypes[-1][0]
+
+ label = feature['Label']
+ m = self.DN_PATTERN.fullmatch(label)
+ if m:
+ outputFeature['DimensionDN'] = int(m.group(1))
+
output.addFeature(outputFeature)
feedback.pushInfo('Loop done')