def simpleMeasure(geom, method=0, ellips=None, crs=None): # Method defines calculation type: # 0 - layer CRS # 1 - project CRS # 2 - ellipsoidal if geom.type() == QgsWkbTypes.PointGeometry: if not geom.isMultipart(): pt = geom.geometry() attr1 = pt.x() attr2 = pt.y() else: pt = geom.asMultiPoint() attr1 = pt[0].x() attr2 = pt[0].y() else: measure = QgsDistanceArea() if method == 2: measure.setSourceCrs(crs) measure.setEllipsoid(ellips) measure.setEllipsoidalMode(True) if geom.type() == QgsWkbTypes.PolygonGeometry: attr1 = measure.measureArea(geom) attr2 = measure.measurePerimeter(geom) else: attr1 = measure.measureLength(geom) attr2 = None return (attr1, attr2)
def regularMatrix(self, inLayer, inField, targetLayer, targetField, nPoints, progress): features = vector.features(inLayer) total = 100.0 / len(features) if len(features) > 0 else 1 targetIdx = targetLayer.fieldNameIndex(targetField) first = True distArea = QgsDistanceArea() index = vector.spatialindex(targetLayer) for current, inFeat in enumerate(features): inGeom = inFeat.geometry() if first: featList = index.nearestNeighbor(inGeom.asPoint(), nPoints) first = False data = ['ID'] request = QgsFeatureRequest().setFilterFids(featList).setSubsetOfAttributes([targetIdx]) for f in targetLayer.getFeatures(request): data.append(unicode(f[targetField])) self.writer.addRecord(data) data = [unicode(inFeat[inField])] for f in targetLayer.getFeatures(request): outGeom = f.geometry() dist = distArea.measureLine(inGeom.asPoint(), outGeom.asPoint()) data.append(unicode(float(dist))) self.writer.addRecord(data) progress.setPercentage(int(current * total))
def prepareAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, 'INPUT', context) mapping = self.parameterAsFieldsMapping(parameters, self.FIELDS_MAPPING, context) self.fields = QgsFields() self.expressions = [] da = QgsDistanceArea() da.setSourceCrs(source.sourceCrs()) da.setEllipsoid(context.project().ellipsoid()) # create an expression context using thread safe processing context self.expr_context = self.createExpressionContext(parameters, context, source) for field_def in mapping: self.fields.append(QgsField(name=field_def['name'], type=field_def['type'], typeName="", len=field_def.get('length', 0), prec=field_def.get('precision', 0))) expression = QgsExpression(field_def['expression']) expression.setGeomCalculator(da) expression.setDistanceUnits(context.project().distanceUnits()) expression.setAreaUnits(context.project().areaUnits()) if expression.hasParserError(): raise QgsProcessingException( self.tr(u'Parser error in expression "{}": {}') .format(str(expression.expression()), str(expression.parserErrorString()))) self.expressions.append(expression) return True
def nearest_neighbour_analysis(self, vlayer): vprovider = vlayer.dataProvider() sumDist = 0.00 distance = QgsDistanceArea() A = vlayer.extent() A = float(A.width() * A.height()) index = ftools_utils.createIndex(vprovider) nFeat = vprovider.featureCount() nElement = 0 if nFeat > 0: self.emit(SIGNAL("runStatus(PyQt_PyObject)"), 0) self.emit(SIGNAL("runRange(PyQt_PyObject)"), (0, nFeat)) feat = QgsFeature() neighbour = QgsFeature() fit = vprovider.getFeatures() while fit.nextFeature(feat): neighbourID = index.nearestNeighbor(feat.geometry().asPoint(), 2)[1] vprovider.getFeatures(QgsFeatureRequest().setFilterFid(neighbourID).setSubsetOfAttributes([])).nextFeature(neighbour) nearDist = distance.measureLine(neighbour.geometry().asPoint(), feat.geometry().asPoint()) sumDist += nearDist nElement += 1 self.emit(SIGNAL("runStatus(PyQt_PyObject)"), nElement) nVal = vprovider.featureCount() do = float(sumDist) / nVal de = float(0.5 / math.sqrt(nVal / A)) d = float(do / de) SE = float(0.26136 / math.sqrt((nVal * nVal) / A)) zscore = float((do - de) / SE) lstStats = [] lstStats.append(self.tr("Observed mean distance:") + unicode(do)) lstStats.append(self.tr("Expected mean distance:") + unicode(de)) lstStats.append(self.tr("Nearest neighbour index:") + unicode(d)) lstStats.append(self.tr("N:") + unicode(nVal)) lstStats.append(self.tr("Z-Score:") + unicode(zscore)) return (lstStats, [])
def regularMatrix(self, inLayer, inField, targetLayer, targetField, nPoints, progress): index = vector.spatialindex(targetLayer) inIdx = inLayer.fields().lookupField(inField) distArea = QgsDistanceArea() first = True features = vector.features(inLayer) total = 100.0 / len(features) for current, inFeat in enumerate(features): inGeom = inFeat.geometry() inID = str(inFeat.attributes()[inIdx]) featList = index.nearestNeighbor(inGeom.asPoint(), nPoints) if first: first = False data = ['ID'] for i in range(len(featList)): data.append('DIST_{0}'.format(i + 1)) self.writer.addRecord(data) data = [inID] for i in featList: request = QgsFeatureRequest().setFilterFid(i) outFeat = next(targetLayer.getFeatures(request)) outGeom = outFeat.geometry() dist = distArea.measureLine(inGeom.asPoint(), outGeom.asPoint()) data.append(str(float(dist))) self.writer.addRecord(data) progress.setPercentage(int(current * total))
def measurePerimeter(geom): measure = QgsDistanceArea() value = 0.00 polygon = geom.asPolygon() for line in polygon: value += measure.measureLine(line) return value
def testMeasurePolygon(self): # +-+-+ # | | # + +-+ # | | # +-+ polygon = QgsGeometry.fromPolygon( [ [ QgsPoint(0, 0), QgsPoint(1, 0), QgsPoint(1, 1), QgsPoint(2, 1), QgsPoint(2, 2), QgsPoint(0, 2), QgsPoint(0, 0), ] ] ) da = QgsDistanceArea() area = da.measure(polygon) assert area == 3, "Expected:\n%f\nGot:\n%f\n" % (3, area) perimeter = da.measurePerimeter(polygon) assert perimeter == 8, "Expected:\n%f\nGot:\n%f\n" % (8, perimeter)
def loopThruPolygons(self, inLayer, numRand, design): sProvider = inLayer.dataProvider() sFeat = QgsFeature() sGeom = QgsGeometry() sPoints = [] if design == self.tr("field"): index = sProvider.fieldNameIndex(numRand) count = 10.00 add = 60.00 / sProvider.featureCount() sFit = sProvider.getFeatures() featureErrors = [] while sFit.nextFeature(sFeat): sGeom = sFeat.geometry() if design == self.tr("density"): sDistArea = QgsDistanceArea() value = int(round(numRand * sDistArea.measure(sGeom))) elif design == self.tr("field"): sAtMap = sFeat.attributes() try: value = int(sAtMap[index]) except (ValueError,TypeError): featureErrors.append(sFeat) continue else: value = numRand sExt = sGeom.boundingBox() sPoints.extend(self.simpleRandom(value, sGeom, sExt.xMinimum(), sExt.xMaximum(), sExt.yMinimum(), sExt.yMaximum())) count = count + add self.progressBar.setValue(count) return sPoints, featureErrors
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) layer = self.parameterAsVectorLayer(parameters, self.INPUT, context) field_name = self.parameterAsString(parameters, self.FIELD_NAME, context) field_type = self.TYPES[self.parameterAsEnum(parameters, self.FIELD_TYPE, context)] width = self.parameterAsInt(parameters, self.FIELD_LENGTH, context) precision = self.parameterAsInt(parameters, self.FIELD_PRECISION, context) new_field = self.parameterAsBool(parameters, self.NEW_FIELD, context) formula = self.parameterAsString(parameters, self.FORMULA, context) expression = QgsExpression(formula) da = QgsDistanceArea() da.setSourceCrs(source.sourceCrs()) da.setEllipsoid(context.project().ellipsoid()) expression.setGeomCalculator(da) expression.setDistanceUnits(context.project().distanceUnits()) expression.setAreaUnits(context.project().areaUnits()) fields = source.fields() field_index = fields.lookupField(field_name) if new_field or field_index < 0: fields.append(QgsField(field_name, field_type, '', width, precision)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, source.wkbType(), source.sourceCrs()) exp_context = self.createExpressionContext(parameters, context) if layer is not None: exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer)) if not expression.prepare(exp_context): raise QgsProcessingException( self.tr('Evaluation error: {0}').format(expression.parserErrorString())) features = source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break rownum = current + 1 exp_context.setFeature(f) exp_context.lastScope().setVariable("row_number", rownum) value = expression.evaluate(exp_context) if expression.hasEvalError(): feedback.reportError(expression.evalErrorString()) else: attrs = f.attributes() if new_field or field_index < 0: attrs.append(value) else: attrs[field_index] = value f.setAttributes(attrs) sink.addFeature(f, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def testCrs(self): # test setting/getting the source CRS da = QgsDistanceArea() # try setting using a CRS object crs = QgsCoordinateReferenceSystem(3111, QgsCoordinateReferenceSystem.EpsgCrsId) da.setSourceCrs(crs, QgsProject.instance().transformContext()) self.assertEqual(da.sourceCrs().srsid(), crs.srsid())
def getSemiMajorAndSemiMinorAxis(self): """Obtains the semi major axis and semi minor axis from the used ellipsoid """ currentLayer = self.iface.mapCanvas().currentLayer() distanceArea = QgsDistanceArea() distanceArea.setEllipsoid(currentLayer.crs().ellipsoidAcronym()) a = distanceArea.ellipsoidSemiMajor() b = distanceArea.ellipsoidSemiMinor() return (a,b)
def simpleMeasure(geom, method=0, ellips=None, crs=None): # Method defines calculation type: # 0 - layer CRS # 1 - project CRS # 2 - ellipsoidal if geom.wkbType() in [QGis.WKBPoint, QGis.WKBPoint25D]: pt = geom.asPoint() attr1 = pt.x() attr2 = pt.y() elif geom.wkbType() in [QGis.WKBMultiPoint, QGis.WKBMultiPoint25D]: pt = geom.asMultiPoint() attr1 = pt[0].x() attr2 = pt[0].y() else: measure = QgsDistanceArea() if method == 2: measure.setSourceCrs(crs) measure.setEllipsoid(ellips) measure.setEllipsoidalMode(True) attr1 = measure.measure(geom) if geom.type() == QGis.Polygon: attr2 = measure.measurePerimeter(geom) else: attr2 = None return (attr1, attr2)
def testMeasureLine(self): # +-+ # | | # +-+ + linestring = QgsGeometry.fromPolyline( [QgsPoint(0, 0), QgsPoint(1, 0), QgsPoint(1, 1), QgsPoint(2, 1), QgsPoint(2, 0)] ) da = QgsDistanceArea() length = da.measure(linestring) myMessage = "Expected:\n%f\nGot:\n%f\n" % (4, length) assert length == 4, myMessage
def compute(self, inPoly, inLns, inField, outPath, progressBar): polyLayer = ftools_utils.getVectorLayerByName(inPoly) lineLayer = ftools_utils.getVectorLayerByName(inLns) polyProvider = polyLayer.dataProvider() lineProvider = lineLayer.dataProvider() if polyProvider.crs() != lineProvider.crs(): QMessageBox.warning(self, self.tr("CRS warning!"), self.tr("Warning: Input layers have non-matching CRS.\nThis may cause unexpected results.")) fieldList = ftools_utils.getFieldList(polyLayer) index = polyProvider.fieldNameIndex(unicode(inField)) if index == -1: index = polyProvider.fields().count() fieldList.append(QgsField(unicode(inField), QVariant.Double, "real", 24, 15, self.tr("length field"))) sRs = polyProvider.crs() inFeat = QgsFeature() inFeatB = QgsFeature() outFeat = QgsFeature() inGeom = QgsGeometry() outGeom = QgsGeometry() distArea = QgsDistanceArea() start = 0.00 add = 100.00 / polyProvider.featureCount() check = QFile(self.shapefileName) if check.exists(): if not QgsVectorFileWriter.deleteShapeFile(self.shapefileName): return writer = QgsVectorFileWriter(self.shapefileName, self.encoding, fieldList, polyProvider.geometryType(), sRs) spatialIndex = ftools_utils.createIndex(lineProvider) polyFit = polyProvider.getFeatures() while polyFit.nextFeature(inFeat): inGeom = QgsGeometry(inFeat.geometry()) atMap = inFeat.attributes() lineList = [] length = 0 lineList = spatialIndex.intersects(inGeom.boundingBox()) if len(lineList) > 0: check = 0 else: check = 1 if check == 0: for i in lineList: lineProvider.getFeatures(QgsFeatureRequest().setFilterFid(int(i))).nextFeature(inFeatB) tmpGeom = QgsGeometry(inFeatB.geometry()) if inGeom.intersects(tmpGeom): outGeom = inGeom.intersection(tmpGeom) length = length + distArea.measure(outGeom) outFeat.setGeometry(inGeom) atMap.append(length) outFeat.setAttributes(atMap) writer.addFeature(outFeat) start = start + 1 progressBar.setValue(start * (add)) del writer
def _calc_north(self): extent = self.canvas.extent() if self.canvas.layerCount() == 0 or extent.isEmpty(): print "No layers or extent" return 0 outcrs = self.canvas.mapSettings().destinationCrs() if outcrs.isValid() and not outcrs.geographicFlag(): crs = QgsCoordinateReferenceSystem() crs.createFromOgcWmsCrs("EPSG:4326") transform = QgsCoordinateTransform(outcrs, crs) p1 = QgsPoint(extent.center()) p2 = QgsPoint(p1.x(), p1.y() + extent.height() * 0.25) try: pp1 = transform.transform(p1) pp2 = transform.transform(p2) except QgsCsException: roam.utils.warning("North arrow. Error transforming.") return None area = QgsDistanceArea() area.setEllipsoid(crs.ellipsoidAcronym()) area.setEllipsoidalMode(True) area.setSourceCrs(crs) distance, angle, _ = area.computeDistanceBearing(pp1, pp2) angle = math.degrees(angle) return angle else: return 0
def testMeasureMultiLine(self): # +-+ +-+-+ # | | | | # +-+ + + +-+ linestring = QgsGeometry.fromMultiPolyline( [ [QgsPoint(0, 0), QgsPoint(1, 0), QgsPoint(1, 1), QgsPoint(2, 1), QgsPoint(2, 0)], [QgsPoint(3, 0), QgsPoint(3, 1), QgsPoint(5, 1), QgsPoint(5, 0), QgsPoint(6, 0)], ] ) da = QgsDistanceArea() length = da.measure(linestring) myMessage = "Expected:\n%f\nGot:\n%f\n" % (9, length) assert length == 9, myMessage
def linearMatrix(self, inLayer, inField, targetLayer, targetField, matType, nPoints, progress): if matType == 0: self.writer.addRecord(['InputID', 'TargetID', 'Distance']) else: self.writer.addRecord(['InputID', 'MEAN', 'STDDEV', 'MIN', 'MAX']) index = vector.spatialindex(targetLayer) inIdx = inLayer.fieldNameIndex(inField) outIdx = targetLayer.fieldNameIndex(targetField) outFeat = QgsFeature() inGeom = QgsGeometry() outGeom = QgsGeometry() distArea = QgsDistanceArea() features = vector.features(inLayer) current = 0 total = 100.0 / float(len(features)) for inFeat in features: inGeom = inFeat.geometry() inID = unicode(inFeat.attributes()[inIdx]) featList = index.nearestNeighbor(inGeom.asPoint(), nPoints) distList = [] vari = 0.0 for i in featList: request = QgsFeatureRequest().setFilterFid(i) outFeat = targetLayer.getFeatures(request).next() outID = outFeat.attributes()[outIdx] outGeom = outFeat.geometry() dist = distArea.measureLine(inGeom.asPoint(), outGeom.asPoint()) if matType == 0: self.writer.addRecord([inID, unicode(outID), unicode(dist)]) else: distList.append(float(dist)) if matType != 0: mean = sum(distList) / len(distList) for i in distList: vari += (i - mean) * (i - mean) vari = math.sqrt(vari / len(distList)) self.writer.addRecord([inID, unicode(mean), unicode(vari), unicode(min(distList)), unicode(max(distList))]) current += 1 progress.setPercentage(int(current * total))
def calculateDistance(self, p1, p2): distance = QgsDistanceArea() distance.setSourceCrs(self.iface.activeLayer().crs()) distance.setEllipsoidalMode(True) # Sirgas 2000 distance.setEllipsoid('GRS1980') m = distance.measureLine(p1, p2) return m
def testMeasureMultiLine(self): # +-+ +-+-+ # | | | | # +-+ + + +-+ linestring = QgsGeometry.fromMultiPolylineXY( [ [QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(2, 1), QgsPointXY(2, 0), ], [QgsPointXY(3, 0), QgsPointXY(3, 1), QgsPointXY(5, 1), QgsPointXY(5, 0), QgsPointXY(6, 0), ] ] ) da = QgsDistanceArea() length = da.measureLength(linestring) myMessage = ('Expected:\n%f\nGot:\n%f\n' % (9, length)) assert length == 9, myMessage
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri(self.getParameterValue(self.POINTS)) output = self.getOutputValue(self.OUTPUT) spatialIndex = vector.spatialindex(layer) neighbour = QgsFeature() distance = QgsDistanceArea() sumDist = 0.00 A = layer.extent() A = float(A.width() * A.height()) current = 0 features = vector.features(layer) count = len(features) total = 100.0 / float(len(features)) for feat in features: neighbourID = spatialIndex.nearestNeighbor( feat.geometry().asPoint(), 2)[1] request = QgsFeatureRequest().setFilterFid(neighbourID) neighbour = layer.getFeatures(request).next() sumDist += distance.measureLine(neighbour.geometry().asPoint(), feat.geometry().asPoint()) current += 1 progress.setPercentage(int(current * total)) do = float(sumDist) / count de = float(0.5 / math.sqrt(count / A)) d = float(do / de) SE = float(0.26136 / math.sqrt(count ** 2 / A)) zscore = float((do - de) / SE) data = [] data.append('Observed mean distance: ' + unicode(do)) data.append('Expected mean distance: ' + unicode(de)) data.append('Nearest neighbour index: ' + unicode(d)) data.append('Number of points: ' + unicode(count)) data.append('Z-Score: ' + unicode(zscore)) self.createHTML(output, data) self.setOutputValue(self.OBSERVED_MD, float(data[0].split(': ')[1])) self.setOutputValue(self.EXPECTED_MD, float(data[1].split(': ')[1])) self.setOutputValue(self.NN_INDEX, float(data[2].split(': ')[1])) self.setOutputValue(self.POINT_COUNT, float(data[3].split(': ')[1])) self.setOutputValue(self.Z_SCORE, float(data[4].split(': ')[1]))
def linearMatrix(self, inLayer, inField, targetLayer, targetField, matType, nPoints, feedback): if matType == 0: self.writer.addRecord(['InputID', 'TargetID', 'Distance']) else: self.writer.addRecord(['InputID', 'MEAN', 'STDDEV', 'MIN', 'MAX']) index = vector.spatialindex(targetLayer) inIdx = inLayer.fields().lookupField(inField) outIdx = targetLayer.fields().lookupField(targetField) distArea = QgsDistanceArea() features = vector.features(inLayer) total = 100.0 / len(features) for current, inFeat in enumerate(features): inGeom = inFeat.geometry() inID = str(inFeat.attributes()[inIdx]) featList = index.nearestNeighbor(inGeom.asPoint(), nPoints) distList = [] vari = 0.0 request = QgsFeatureRequest().setFilterFids( featList).setSubsetOfAttributes([outIdx]) for outFeat in targetLayer.getFeatures(request): outID = outFeat.attributes()[outIdx] outGeom = outFeat.geometry() dist = distArea.measureLine(inGeom.asPoint(), outGeom.asPoint()) if matType == 0: self.writer.addRecord([inID, str(outID), str(dist)]) else: distList.append(float(dist)) if matType != 0: mean = sum(distList) / len(distList) for i in distList: vari += (i - mean) * (i - mean) vari = math.sqrt(vari / len(distList)) self.writer.addRecord([ inID, str(mean), str(vari), str(min(distList)), str(max(distList)) ]) feedback.setProgress(int(current * total))
def __init__(self, parent=None): ''' Constructor ''' super(GuidanceDock, self).__init__(parent) self.setupUi(self) self.compass = CompassWidget() self.compass.setMinimumHeight(80) self.verticalLayout.addWidget(self.compass) self.verticalLayout.setStretch(5, 8) self.distArea = QgsDistanceArea() self.distArea.setEllipsoid(u'WGS84') self.distArea.setEllipsoidalMode(True) self.distArea.setSourceCrs(3452L) self.fontSize = 11 self.source = None self.target = None self.srcPos = [None, 0.0] self.trgPos = [None, 0.0] self.srcHeading = 0.0 self.trgHeading = 0.0 s = QSettings() self.format = s.value('PosiView/Guidance/Format', defaultValue=1, type=int) self.showUtc = s.value('PosiView/Misc/ShowUtcClock', defaultValue=False, type=bool) self.timer = 0 self.setUtcClock()
def __init__( self, coordinate_reference_system, geometry_type, exposure_key): """Constructor for the size calculator. :param coordinate_reference_system: The Coordinate Reference System of the layer. :type coordinate_reference_system: QgsCoordinateReferenceSystem :param exposure_key: The geometry type of the layer. :type exposure_key: qgis.core.QgsWkbTypes.GeometryType """ self.calculator = QgsDistanceArea() self.calculator.setSourceCrs( coordinate_reference_system, QgsProject.instance().transformContext() ) self.calculator.setEllipsoid('WGS84') if geometry_type == QgsWkbTypes.LineGeometry: self.default_unit = unit_metres LOGGER.info('The size calculator is set to use {unit}'.format( unit=distance_unit[self.calculator.lengthUnits()])) else: self.default_unit = unit_square_metres LOGGER.info('The size calculator is set to use {unit}'.format( unit=distance_unit[self.calculator.areaUnits()])) self.geometry_type = geometry_type self.output_unit = None if exposure_key: exposure_definition = definition(exposure_key) self.output_unit = exposure_definition['size_unit']
def __init__(self, canvas, params={}): ''' Constructor :param iface: An interface instance that will be passed to this class which provides the hook by which you can manipulate the QGIS application at run time. :type iface: QgsInterface :param params: A dictionary defining all the properties of the position marker :type params: dictionary ''' self.canvas = canvas self.type = params.get('type', 'BOX').upper() self.size = int(params.get('size', 16)) self.bounding = 1.414213562 * self.size self.length = float(params.get('length', 98.0)) self.width = float(params.get('width', 17.0)) self.shape = params.get('shape', ((0.0, -0.5), (0.5, -0.3), (0.5, 0.5), (-0.5, 0.50), (-0.5, -0.3))) s = (self.size - 1) / 2 self.paintShape = QPolygonF([QPointF(-s, -s), QPointF(s, -s), QPointF(s, s), QPointF(-s, s)]) self.color = self.getColor(params.get('color', 'black')) self.fillColor = self.getColor(params.get('fillColor', 'lime')) self.penWidth = int(params.get('penWidth', 1)) if self.type in ('CROSS', 'X'): self.penWidth = 5 self.trackLen = int(params.get('trackLength', 100)) self.trackColor = self.getColor(params.get('trackColor', self.fillColor)) self.track = deque() self.pos = None self.heading = 0 super(PositionMarker, self).__init__(canvas) self.setZValue(int(params.get('zValue', 100))) self.distArea = QgsDistanceArea() self.distArea.setEllipsoid(u'WGS84') self.distArea.setEllipsoidalMode(True) self.updateSize()
def processAlgorithm(self, parameters, context, feedback): layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.POINTS), context) output = self.getOutputValue(self.OUTPUT) spatialIndex = QgsProcessingUtils.createSpatialIndex(layer, context) neighbour = QgsFeature() distance = QgsDistanceArea() sumDist = 0.00 A = layer.extent() A = float(A.width() * A.height()) features = QgsProcessingUtils.getFeatures(layer, context) count = QgsProcessingUtils.featureCount(layer, context) total = 100.0 / count for current, feat in enumerate(features): neighbourID = spatialIndex.nearestNeighbor( feat.geometry().asPoint(), 2)[1] request = QgsFeatureRequest().setFilterFid(neighbourID).setSubsetOfAttributes([]) neighbour = next(layer.getFeatures(request)) sumDist += distance.measureLine(neighbour.geometry().asPoint(), feat.geometry().asPoint()) feedback.setProgress(int(current * total)) do = float(sumDist) / count de = float(0.5 / math.sqrt(count / A)) d = float(do / de) SE = float(0.26136 / math.sqrt(count ** 2 / A)) zscore = float((do - de) / SE) data = [] data.append('Observed mean distance: ' + str(do)) data.append('Expected mean distance: ' + str(de)) data.append('Nearest neighbour index: ' + str(d)) data.append('Number of points: ' + str(count)) data.append('Z-Score: ' + str(zscore)) self.createHTML(output, data) self.setOutputValue(self.OBSERVED_MD, float(data[0].split(': ')[1])) self.setOutputValue(self.EXPECTED_MD, float(data[1].split(': ')[1])) self.setOutputValue(self.NN_INDEX, float(data[2].split(': ')[1])) self.setOutputValue(self.POINT_COUNT, float(data[3].split(': ')[1])) self.setOutputValue(self.Z_SCORE, float(data[4].split(': ')[1]))
def processAlgorithm(self, parameters, context, feedback): if parameters[self.INPUT] == parameters[self.HUBS]: raise QgsProcessingException( self.tr('Same layer given for both hubs and spokes')) point_source = self.parameterAsSource(parameters, self.INPUT, context) hub_source = self.parameterAsSource(parameters, self.HUBS, context) fieldName = self.parameterAsString(parameters, self.FIELD, context) units = self.UNITS[self.parameterAsEnum(parameters, self.UNIT, context)] fields = point_source.fields() fields.append(QgsField('HubName', QVariant.String)) fields.append(QgsField('HubDist', QVariant.Double)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Point, point_source.sourceCrs()) index = QgsSpatialIndex(hub_source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(point_source.sourceCrs(), context.transformContext()))) distance = QgsDistanceArea() distance.setSourceCrs(point_source.sourceCrs(), context.transformContext()) distance.setEllipsoid(context.project().ellipsoid()) # Scan source points, find nearest hub, and write to output file features = point_source.getFeatures() total = 100.0 / point_source.featureCount() if point_source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break if not f.hasGeometry(): sink.addFeature(f, QgsFeatureSink.FastInsert) continue src = f.geometry().boundingBox().center() neighbors = index.nearestNeighbor(src, 1) ft = next(hub_source.getFeatures(QgsFeatureRequest().setFilterFid(neighbors[0]).setSubsetOfAttributes([fieldName], hub_source.fields()).setDestinationCrs(point_source.sourceCrs(), context.transformContext()))) closest = ft.geometry().boundingBox().center() hubDist = distance.measureLine(src, closest) if units != self.LAYER_UNITS: hub_dist_in_desired_units = distance.convertLengthMeasurement(hubDist, units) else: hub_dist_in_desired_units = hubDist attributes = f.attributes() attributes.append(ft[fieldName]) attributes.append(hub_dist_in_desired_units) feat = QgsFeature() feat.setAttributes(attributes) feat.setGeometry(QgsGeometry.fromPointXY(src)) sink.addFeature(feat, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def testMeasureMultiPolygon(self): # +-+-+ +-+-+ # | | | | # + +-+ +-+ + # | | | | # +-+ +-+ polygon = QgsGeometry.fromMultiPolygon( [ [[QgsPoint(0, 0), QgsPoint(1, 0), QgsPoint(1, 1), QgsPoint(2, 1), QgsPoint(2, 2), QgsPoint(0, 2), QgsPoint(0, 0), ]], [[QgsPoint(4, 0), QgsPoint(5, 0), QgsPoint(5, 2), QgsPoint(3, 2), QgsPoint(3, 1), QgsPoint(4, 1), QgsPoint(4, 0), ]] ] ) da = QgsDistanceArea() area = da.measureArea(polygon) assert area == 6, 'Expected:\n%f\nGot:\n%f\n' % (6, area) perimeter = da.measurePerimeter(polygon) assert perimeter == 16, "Expected:\n%f\nGot:\n%f\n" % (16, perimeter)
def testWillUseEllipsoid(self): """test QgsDistanceArea::willUseEllipsoid """ da = QgsDistanceArea() da.setEllipsoid("NONE") self.assertFalse(da.willUseEllipsoid()) da.setEllipsoid("WGS84") self.assertTrue(da.willUseEllipsoid())
def prepareAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) group_by = self.parameterAsExpression(parameters, self.GROUP_BY, context) aggregates = self.parameterAsAggregates(parameters, self.AGGREGATES, context) da = QgsDistanceArea() da.setSourceCrs(source.sourceCrs(), context.transformContext()) da.setEllipsoid(context.project().ellipsoid()) self.source = source self.group_by = group_by self.group_by_expr = self.createExpression(group_by, da, context) self.geometry_expr = self.createExpression('collect($geometry, {})'.format(group_by), da, context) self.fields = QgsFields() self.fields_expr = [] for field_def in aggregates: self.fields.append(QgsField(name=field_def['name'], type=field_def['type'], typeName="", len=field_def['length'], prec=field_def['precision'])) aggregate = field_def['aggregate'] if aggregate == 'first_value': expression = field_def['input'] elif aggregate == 'concatenate': expression = ('{}({}, {}, {}, \'{}\')' .format(field_def['aggregate'], field_def['input'], group_by, 'TRUE', field_def['delimiter'])) else: expression = '{}({}, {})'.format(field_def['aggregate'], field_def['input'], group_by) expr = self.createExpression(expression, da, context) self.fields_expr.append(expr) return True
def testMeasurePolygonWithHole(self): # +-+-+-+ # | | # + +-+ + # | | | | # + +-+ + # | | # +-+-+-+ polygon = QgsGeometry.fromPolygon( [ [ QgsPoint(0,0), QgsPoint(3,0), QgsPoint(3,3), QgsPoint(0,3), QgsPoint(0,0) ], [ QgsPoint(1,1), QgsPoint(2,1), QgsPoint(2,2), QgsPoint(1,2), QgsPoint(1,1) ], ] ) da = QgsDistanceArea() area = da.measure(polygon) assert area == 8, "Expected:\n%f\nGot:\n%f\n" % (8, area) perimeter = da.measurePerimeter(polygon) assert perimeter == 12, "Expected:\n%f\nGot:\n%f\n" % (12, perimeter)
def processAlgorithm(self, feedback): layer = dataobjects.getObjectFromUri( self.getParameterValue(self.VECTOR)) pointCount = float(self.getParameterValue(self.POINT_NUMBER)) minDistance = float(self.getParameterValue(self.MIN_DISTANCE)) fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, QgsWkbTypes.Point, layer.crs()) nPoints = 0 nIterations = 0 maxIterations = pointCount * 200 featureCount = layer.featureCount() total = 100.0 / pointCount index = QgsSpatialIndex() points = dict() da = QgsDistanceArea() request = QgsFeatureRequest() random.seed() while nIterations < maxIterations and nPoints < pointCount: # pick random feature fid = random.randint(0, featureCount - 1) f = next(layer.getFeatures(request.setFilterFid(fid).setSubsetOfAttributes([]))) fGeom = f.geometry() if fGeom.isMultipart(): lines = fGeom.asMultiPolyline() # pick random line lineId = random.randint(0, len(lines) - 1) vertices = lines[lineId] else: vertices = fGeom.asPolyline() # pick random segment if len(vertices) == 2: vid = 0 else: vid = random.randint(0, len(vertices) - 2) startPoint = vertices[vid] endPoint = vertices[vid + 1] length = da.measureLine(startPoint, endPoint) dist = length * random.random() if dist > minDistance: d = dist / (length - dist) rx = (startPoint.x() + d * endPoint.x()) / (1 + d) ry = (startPoint.y() + d * endPoint.y()) / (1 + d) # generate random point pnt = QgsPoint(rx, ry) geom = QgsGeometry.fromPoint(pnt) if vector.checkMinDistance(pnt, index, minDistance, points): f = QgsFeature(nPoints) f.initAttributes(1) f.setFields(fields) f.setAttribute('id', nPoints) f.setGeometry(geom) writer.addFeature(f) index.insertFeature(f) points[nPoints] = pnt nPoints += 1 feedback.setProgress(int(nPoints * total)) nIterations += 1 if nPoints < pointCount: ProcessingLog.addToLog(ProcessingLog.LOG_INFO, self.tr('Can not generate requested number of random points. ' 'Maximum number of attempts exceeded.')) del writer
def processAlgorithm(self, parameters, context, feedback): if parameters[self.INPUT] == parameters[self.HUBS]: raise QgsProcessingException( self.tr('Same layer given for both hubs and spokes')) point_source = self.parameterAsSource(parameters, self.INPUT, context) if point_source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT)) hub_source = self.parameterAsSource(parameters, self.HUBS, context) if hub_source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.HUBS)) fieldName = self.parameterAsString(parameters, self.FIELD, context) units = self.UNITS[self.parameterAsEnum(parameters, self.UNIT, context)] fields = point_source.fields() fields.append(QgsField('HubName', QVariant.String)) fields.append(QgsField('HubDist', QVariant.Double)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Point, point_source.sourceCrs()) if sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT)) index = QgsSpatialIndex( hub_source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes( []).setDestinationCrs(point_source.sourceCrs(), context.transformContext()))) distance = QgsDistanceArea() distance.setSourceCrs(point_source.sourceCrs(), context.transformContext()) distance.setEllipsoid(context.project().ellipsoid()) # Scan source points, find nearest hub, and write to output file features = point_source.getFeatures() total = 100.0 / point_source.featureCount( ) if point_source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break if not f.hasGeometry(): sink.addFeature(f, QgsFeatureSink.FastInsert) continue src = f.geometry().boundingBox().center() neighbors = index.nearestNeighbor(src, 1) ft = next( hub_source.getFeatures(QgsFeatureRequest().setFilterFid( neighbors[0]).setSubsetOfAttributes( [fieldName], hub_source.fields()).setDestinationCrs( point_source.sourceCrs(), context.transformContext()))) closest = ft.geometry().boundingBox().center() hubDist = distance.measureLine(src, closest) if units != self.LAYER_UNITS: hub_dist_in_desired_units = distance.convertLengthMeasurement( hubDist, units) else: hub_dist_in_desired_units = hubDist attributes = f.attributes() attributes.append(ft[fieldName]) attributes.append(hub_dist_in_desired_units) feat = QgsFeature() feat.setAttributes(attributes) feat.setGeometry(QgsGeometry.fromPointXY(src)) sink.addFeature(feat, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def processAlgorithm(self, feedback): layerPoints = dataobjects.getObjectFromUri( self.getParameterValue(self.POINTS)) layerHubs = dataobjects.getObjectFromUri( self.getParameterValue(self.HUBS)) fieldName = self.getParameterValue(self.FIELD) addLines = self.getParameterValue(self.GEOMETRY) units = self.UNITS[self.getParameterValue(self.UNIT)] if layerPoints.source() == layerHubs.source(): raise GeoAlgorithmExecutionException( self.tr('Same layer given for both hubs and spokes')) fields = layerPoints.fields() fields.append(QgsField('HubName', QVariant.String)) fields.append(QgsField('HubDist', QVariant.Double)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, QgsWkbTypes.LineString, layerPoints.crs()) index = vector.spatialindex(layerHubs) distance = QgsDistanceArea() distance.setSourceCrs(layerPoints.crs()) distance.setEllipsoidalMode(True) # Scan source points, find nearest hub, and write to output file features = vector.features(layerPoints) total = 100.0 / len(features) for current, f in enumerate(features): src = f.geometry().boundingBox().center() neighbors = index.nearestNeighbor(src, 1) ft = next( layerHubs.getFeatures(QgsFeatureRequest().setFilterFid( neighbors[0]).setSubsetOfAttributes([fieldName], layerHubs.fields()))) closest = ft.geometry().boundingBox().center() hubDist = distance.measureLine(src, closest) attributes = f.attributes() attributes.append(ft[fieldName]) if units == 'Feet': attributes.append(hubDist * 3.2808399) elif units == 'Miles': attributes.append(hubDist * 0.000621371192) elif units == 'Kilometers': attributes.append(hubDist / 1000.0) elif units != 'Meters': attributes.append( sqrt( pow(src.x() - closest.x(), 2.0) + pow(src.y() - closest.y(), 2.0))) else: attributes.append(hubDist) feat = QgsFeature() feat.setAttributes(attributes) feat.setGeometry(QgsGeometry.fromPolyline([src, closest])) writer.addFeature(feat) feedback.setProgress(int(current * total)) del writer
def processAlgorithm(self, progress): layerPoints = dataobjects.getObjectFromUri( self.getParameterValue(self.POINTS)) layerHubs = dataobjects.getObjectFromUri( self.getParameterValue(self.HUBS)) fieldName = self.getParameterValue(self.FIELD) addLines = self.getParameterValue(self.GEOMETRY) units = self.UNITS[self.getParameterValue(self.UNIT)] if layerPoints.source() == layerHubs.source(): raise GeoAlgorithmExecutionException( self.tr('Same layer given for both hubs and spokes')) geomType = QGis.WKBPoint if addLines: geomType = QGis.WKBLineString fields = layerPoints.pendingFields() fields.append(QgsField('HubName', QVariant.String)) fields.append(QgsField('HubDist', QVariant.Double)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, geomType, layerPoints.crs()) # Create array of hubs in memory hubs = [] features = vector.features(layerHubs) for f in features: hubs.append( Hub(f.geometry().boundingBox().center(), unicode(f[fieldName]))) distance = QgsDistanceArea() distance.setSourceCrs(layerPoints.crs().srsid()) distance.setEllipsoidalMode(True) # Scan source points, find nearest hub, and write to output file features = vector.features(layerPoints) total = 100.0 / len(features) for current, f in enumerate(features): src = f.geometry().boundingBox().center() closest = hubs[0] hubDist = distance.measureLine(src, closest.point) for hub in hubs: dist = distance.measureLine(src, hub.point) if dist < hubDist: closest = hub hubDist = dist attributes = f.attributes() attributes.append(closest.name) if units == 'Feet': attributes.append(hubDist * 3.2808399) elif units == 'Miles': attributes.append(hubDist * 0.000621371192) elif units == 'Kilometers': attributes.append(hubDist / 1000.0) elif units != 'Meters': attributes.append( sqrt( pow(src.x() - closest.point.x(), 2.0) + pow(src.y() - closest.point.y(), 2.0))) else: attributes.append(hubDist) feat = QgsFeature() feat.setAttributes(attributes) if geomType == QGis.WKBPoint: feat.setGeometry(QgsGeometry.fromPoint(src)) else: feat.setGeometry(QgsGeometry.fromPolyline([src, closest.point])) writer.addFeature(feat) progress.setPercentage(int(current * total)) del writer
def testWillUseEllipsoid(self): """test QgsDistanceArea::willUseEllipsoid """ da = QgsDistanceArea() da.setEllipsoidalMode(False) da.setEllipsoid("NONE") self.assertFalse(da.willUseEllipsoid()) da.setEllipsoidalMode(True) self.assertFalse(da.willUseEllipsoid()) da.setEllipsoid("WGS84") assert da.willUseEllipsoid() da.setEllipsoidalMode(False) self.assertFalse(da.willUseEllipsoid())
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT)) close_path = self.parameterAsBool(parameters, self.CLOSE_PATH, context) group_field_name = self.parameterAsString(parameters, self.GROUP_FIELD, context) order_field_name = self.parameterAsString(parameters, self.ORDER_FIELD, context) date_format = self.parameterAsString(parameters, self.DATE_FORMAT, context) text_dir = self.parameterAsString(parameters, self.OUTPUT_TEXT_DIR, context) group_field_index = source.fields().lookupField(group_field_name) order_field_index = source.fields().lookupField(order_field_name) if group_field_index >= 0: group_field_def = source.fields().at(group_field_index) else: group_field_def = None order_field_def = source.fields().at(order_field_index) fields = QgsFields() if group_field_def is not None: fields.append(group_field_def) begin_field = QgsField(order_field_def) begin_field.setName('begin') fields.append(begin_field) end_field = QgsField(order_field_def) end_field.setName('end') fields.append(end_field) output_wkb = QgsWkbTypes.LineString if QgsWkbTypes.hasM(source.wkbType()): output_wkb = QgsWkbTypes.addM(output_wkb) if QgsWkbTypes.hasZ(source.wkbType()): output_wkb = QgsWkbTypes.addZ(output_wkb) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, output_wkb, source.sourceCrs()) if sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT)) points = dict() features = source.getFeatures( QgsFeatureRequest().setSubsetOfAttributes( [group_field_index, order_field_index]), QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks) total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break if not f.hasGeometry(): continue point = f.geometry().constGet().clone() if group_field_index >= 0: group = f[group_field_index] else: group = 1 order = f[order_field_index] if date_format != '': order = datetime.strptime(str(order), date_format) if group in points: points[group].append((order, point)) else: points[group] = [(order, point)] feedback.setProgress(int(current * total)) feedback.setProgress(0) da = QgsDistanceArea() da.setSourceCrs(source.sourceCrs(), context.transformContext()) da.setEllipsoid(context.ellipsoid()) current = 0 total = 100.0 / len(points) if points else 1 for group, vertices in points.items(): if feedback.isCanceled(): break vertices.sort(key=lambda x: (x[0] is None, x[0])) f = QgsFeature() attributes = [] if group_field_index >= 0: attributes.append(group) attributes.extend([vertices[0][0], vertices[-1][0]]) f.setAttributes(attributes) line = [node[1] for node in vertices] if close_path is True: if line[0] != line[-1]: line.append(line[0]) if text_dir: fileName = os.path.join(text_dir, '%s.txt' % group) with open(fileName, 'w') as fl: fl.write('angle=Azimuth\n') fl.write('heading=Coordinate_System\n') fl.write('dist_units=Default\n') for i in range(len(line)): if i == 0: fl.write('startAt=%f;%f;90\n' % (line[i].x(), line[i].y())) fl.write('survey=Polygonal\n') fl.write('[data]\n') else: angle = line[i - 1].azimuth(line[i]) distance = da.measureLine(QgsPointXY(line[i - 1]), QgsPointXY(line[i])) fl.write('%f;%f;90\n' % (angle, distance)) f.setGeometry(QgsGeometry(QgsLineString(line))) sink.addFeature(f, QgsFeatureSink.FastInsert) current += 1 feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def testAreaMeasureAndUnits(self): """Test a variety of area measurements in different CRS and ellipsoid modes, to check that the calculated areas and units are always consistent """ da = QgsDistanceArea() da.setSourceCrs(3452) da.setEllipsoidalMode(False) da.setEllipsoid("NONE") polygon = QgsGeometry.fromPolygon([[ QgsPoint(0, 0), QgsPoint(1, 0), QgsPoint(1, 1), QgsPoint(2, 1), QgsPoint(2, 2), QgsPoint(0, 2), QgsPoint(0, 0), ]]) # We check both the measured area AND the units, in case the logic regarding # ellipsoids and units changes in future area = da.measureArea(polygon) units = da.areaUnits() print(("measured {} in {}".format(area, QgsUnitTypes.toString(units)))) assert ((abs(area - 3.0) < 0.00000001 and units == QgsUnitTypes.AreaSquareDegrees) or (abs(area - 37176087091.5) < 0.1 and units == QgsUnitTypes.AreaSquareMeters)) da.setEllipsoid("WGS84") area = da.measureArea(polygon) units = da.areaUnits() print(("measured {} in {}".format(area, QgsUnitTypes.toString(units)))) assert ((abs(area - 3.0) < 0.00000001 and units == QgsUnitTypes.AreaSquareDegrees) or (abs(area - 37176087091.5) < 0.1 and units == QgsUnitTypes.AreaSquareMeters)) da.setEllipsoidalMode(True) area = da.measureArea(polygon) units = da.areaUnits() print(("measured {} in {}".format(area, QgsUnitTypes.toString(units)))) # should always be in Meters Squared self.assertAlmostEqual(area, 37416879192.9, delta=0.1) self.assertEqual(units, QgsUnitTypes.AreaSquareMeters) # test converting the resultant area area = da.convertAreaMeasurement(area, QgsUnitTypes.AreaSquareMiles) self.assertAlmostEqual(area, 14446.7378, delta=0.001) # now try with a source CRS which is in feet polygon = QgsGeometry.fromPolygon([[ QgsPoint(1850000, 4423000), QgsPoint(1851000, 4423000), QgsPoint(1851000, 4424000), QgsPoint(1852000, 4424000), QgsPoint(1852000, 4425000), QgsPoint(1851000, 4425000), QgsPoint(1850000, 4423000) ]]) da.setSourceCrs(27469) da.setEllipsoidalMode(False) # measurement should be in square feet area = da.measureArea(polygon) units = da.areaUnits() print(("measured {} in {}".format(area, QgsUnitTypes.toString(units)))) self.assertAlmostEqual(area, 2000000, delta=0.001) self.assertEqual(units, QgsUnitTypes.AreaSquareFeet) # test converting the resultant area area = da.convertAreaMeasurement(area, QgsUnitTypes.AreaSquareYards) self.assertAlmostEqual(area, 222222.2222, delta=0.001) da.setEllipsoidalMode(True) # now should be in Square Meters again area = da.measureArea(polygon) units = da.areaUnits() print(("measured {} in {}".format(area, QgsUnitTypes.toString(units)))) self.assertAlmostEqual(area, 184149.37, delta=1.0) self.assertEqual(units, QgsUnitTypes.AreaSquareMeters) # test converting the resultant area area = da.convertAreaMeasurement(area, QgsUnitTypes.AreaSquareYards) self.assertAlmostEqual(area, 220240.8172549, delta=1.0)
def testMeasureLineProjected(self): # +-+ # | | # +-+ + # test setting/getting the source CRS da_3068 = QgsDistanceArea() da_wsg84 = QgsDistanceArea() da_3068.setSourceCrs(QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:3068'), QgsProject.instance().transformContext()) if (da_3068.sourceCrs().isGeographic()): da_3068.setEllipsoid(da_3068.sourceCrs().ellipsoidAcronym()) print(("setting [{}] srid [{}] description [{}]".format(u'Soldner Berlin', da_3068.sourceCrs().authid(), da_3068.sourceCrs().description()))) self.assertEqual(da_3068.sourceCrs().authid(), 'EPSG:3068') da_wsg84.setSourceCrs(QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:4326'), QgsProject.instance().transformContext()) if (da_wsg84.sourceCrs().isGeographic()): da_wsg84.setEllipsoid(da_wsg84.sourceCrs().ellipsoidAcronym()) self.assertEqual(da_wsg84.sourceCrs().authid(), 'EPSG:4326') print(("setting [{}] srid [{}] description [{}] isGeographic[{}]".format(u'Wsg84', da_wsg84.sourceCrs().authid(), da_wsg84.sourceCrs().description(), da_wsg84.sourceCrs().isGeographic()))) # print(("-- projectionAcronym[{}] ellipsoidAcronym[{}] toWkt[{}] mapUnits[{}] toProj4[{}]".format(da_wsg84.sourceCrs().projectionAcronym(),da_wsg84.sourceCrs().ellipsoidAcronym(), da_wsg84.sourceCrs().toWkt(),da_wsg84.sourceCrs().mapUnits(),da_wsg84.sourceCrs().toProj4()))) print(("Testing Position change for[{}] years[{}]".format(u'Ampelanlage - Potsdamer Platz, Verkehrsinsel', u'1924 and 1998'))) # 1924-10-24 SRID=3068;POINT(23099.49 20296.69) # 1924-10-24 SRID=4326;POINT(13.37650707988041 52.50952361017194) # 1998-10-02 SRID=3068;POINT(23082.30 20267.80) # 1998-10-02 SRID=4326;POINT(13.37625537334001 52.50926345498337) # values returned by SpatiaLite point_soldner_1924 = QgsPointXY(23099.49, 20296.69) point_soldner_1998 = QgsPointXY(23082.30, 20267.80) distance_soldner_meters = 33.617379 azimuth_soldner_1924 = 3.678339 # ST_Transform(point_soldner_1924,point_soldner_1998,4326) point_wsg84_1924 = QgsPointXY(13.37650707988041, 52.50952361017194) point_wsg84_1998 = QgsPointXY(13.37625537334001, 52.50926345498337) # ST_Distance(point_wsg84_1924,point_wsg84_1998,1) distance_wsg84_meters = 33.617302 # ST_Distance(point_wsg84_1924,point_wsg84_1998) # distance_wsg84_mapunits=0.000362 distance_wsg84_mapunits_format = QgsDistanceArea.formatDistance(0.000362, 7, QgsUnitTypes.DistanceDegrees, True) # ST_Azimuth(point_wsg84_1924,point_wsg84_1998) azimuth_wsg84_1924 = 3.674878 # ST_Azimuth(point_wsg84_1998,point_wsg84_1998) azimuth_wsg84_1998 = 0.533282 # ST_Project(point_wsg84_1924,33.617302,3.674878) # SRID=4326;POINT(13.37625537318728 52.50926345503591) point_soldner_1998_project = QgsPointXY(13.37625537318728, 52.50926345503591) # ST_Project(point_wsg84_1998,33.617302,0.533282) # SRID=4326;POINT(13.37650708009255 52.50952361009799) point_soldner_1924_project = QgsPointXY(13.37650708009255, 52.50952361009799) distance_qpoint = point_soldner_1924.distance(point_soldner_1998) azimuth_qpoint = point_soldner_1924.azimuth(point_soldner_1998) point_soldner_1998_result = point_soldner_1924.project(distance_qpoint, azimuth_qpoint) point_soldner_1924_result = QgsPointXY(0, 0) point_soldner_1998_result = QgsPointXY(0, 0) # Test meter based projected point from point_1924 to point_1998 length_1998_mapunits, point_soldner_1998_result = da_3068.measureLineProjected(point_soldner_1924, distance_soldner_meters, azimuth_qpoint) self.assertEqual(point_soldner_1998_result.toString(6), point_soldner_1998.toString(6)) # Test degree based projected point from point_1924 1 meter due East point_wsg84_meter_result = QgsPointXY(0, 0) point_wsg84_1927_meter = QgsPointXY(13.37652180838435, 52.50952361017102) length_meter_mapunits, point_wsg84_meter_result = da_wsg84.measureLineProjected(point_wsg84_1924, 1.0, (math.pi / 2)) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, QgsUnitTypes.DistanceDegrees, True), '0.0000147 deg') self.assertEqual(point_wsg84_meter_result.toString(7), point_wsg84_1927_meter.toString(7)) point_wsg84_1998_result = QgsPointXY(0, 0) length_1928_mapunits, point_wsg84_1998_result = da_wsg84.measureLineProjected(point_wsg84_1924, distance_wsg84_meters, azimuth_wsg84_1924) self.assertEqual(QgsDistanceArea.formatDistance(length_1928_mapunits, 7, QgsUnitTypes.DistanceDegrees, True), distance_wsg84_mapunits_format) self.assertEqual(point_wsg84_1998_result.toString(7), point_wsg84_1998.toString(7))
class ScaleBar(QgsMapCanvasItem): def __init__(self, proj, canvas): super(ScaleBar, self).__init__(canvas) self.proj = proj self.canvas = canvas # set font self.myfont = QFont("helvetica", 10) self.myfontmetrics = QFontMetrics(self.myfont) # set crs and ellipsoid crs = self.canvas.mapSettings().destinationCrs() self.distance_calc = QgsDistanceArea() self.distance_calc.setSourceCrs( crs, QgsProject.instance().transformContext()) self.distance_calc.setEllipsoid(crs.ellipsoidAcronym()) def paint(self, painter, xxx, xxx2): """Paint scalebar on painter.""" mymajorticksize = 8 mypreferredsize = 1 mytextoffsetx = 3 myscalebarunit = "m" mymapunits = QgsUnitTypes.DistanceMeters # get height and width canvasheight = painter.device().height() canvaswidth = painter.device().width() # set origins myoriginx = canvaswidth - 40 myoriginy = canvasheight - 20 # save previous painter painter.save() # set rotation painter.rotate(-self.canvas.rotation()) # set translation painter.translate(myoriginx, myoriginy) # calculate size of scale bar for preferred number of map units myscalebarwidth = mypreferredsize # if scale bar is very small reset to 1/4 of the canvs wide if myscalebarwidth < 30: # pixels myscalebarwidth = canvaswidth / 4.0 # if scale bar is more than half the cnavs wide keep halving until not while myscalebarwidth > canvaswidth / 3.0: myscalebarwidth = myscalebarwidth / 3.0 # get the distance between 2 points transform = self.canvas.getCoordinateTransform() start_point = transform.toMapCoordinates(0 - myscalebarwidth, 0) end_point = transform.toMapCoordinates(0, 0) distance = self.distance_calc.measureLine([start_point, end_point]) # change scale (km,m,cm,mm) if mymapunits == QgsUnitTypes.DistanceMeters: if distance > 1000.0: myscalebarunit = "km" distance = distance / 1000 rounddist = round(distance, 1) elif distance < 0.01: myscalebarunit = "mm" distance = distance * 1000 rounddist = round(distance, 4) elif distance < 0.1: myscalebarunit = "cm" distance = distance * 100 rounddist = round(distance, 2) else: myscalebarunit = "m" rounddist = round(distance, 1) # set new scalebarwidth myroundscalebarwidth = (rounddist * myscalebarwidth / distance) # set qpen mybackgroundpen = QPen(Qt.black, 4) # create bar mybararray = QPolygon(2) mybararray.putPoints(0, 0 - myroundscalebarwidth, 0 + mymajorticksize / 2, 0, 0 + mymajorticksize / 2) painter.setPen(mybackgroundpen) # draw line painter.drawPolyline(mybararray) # draw 0 painter.drawText( 0 - myroundscalebarwidth - (self.myfontmetrics.width("0") / 2), 0 - (self.myfontmetrics.height() / 4), "0") # draw max painter.drawText(0 - (self.myfontmetrics.width(str(rounddist)) / 2), 0 - (self.myfontmetrics.height() / 4), str(rounddist)) # draw unit label painter.drawText((0 + mytextoffsetx), (0 + mymajorticksize), str(myscalebarunit)) # restore painter painter.restore()
def linearMatrix(self, parameters, context, source, inField, target_source, targetField, same_source_and_target, matType, nPoints, feedback): if same_source_and_target: # need to fetch an extra point from the index, since the closest match will always be the same # as the input feature nPoints += 1 inIdx = source.fields().lookupField(inField) outIdx = target_source.fields().lookupField(targetField) fields = QgsFields() input_id_field = source.fields()[inIdx] input_id_field.setName('InputID') fields.append(input_id_field) if matType == 0: target_id_field = target_source.fields()[outIdx] target_id_field.setName('TargetID') fields.append(target_id_field) fields.append(QgsField('Distance', QVariant.Double)) else: fields.append(QgsField('MEAN', QVariant.Double)) fields.append(QgsField('STDDEV', QVariant.Double)) fields.append(QgsField('MIN', QVariant.Double)) fields.append(QgsField('MAX', QVariant.Double)) out_wkb = QgsWkbTypes.multiType(source.wkbType()) if matType == 0 else source.wkbType() (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, out_wkb, source.sourceCrs()) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) index = QgsSpatialIndex(target_source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(source.sourceCrs(), context.transformContext())), feedback) distArea = QgsDistanceArea() distArea.setSourceCrs(source.sourceCrs(), context.transformContext()) distArea.setEllipsoid(context.project().ellipsoid()) features = source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([inIdx])) total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, inFeat in enumerate(features): if feedback.isCanceled(): break inGeom = inFeat.geometry() inID = str(inFeat.attributes()[inIdx]) featList = index.nearestNeighbor(inGeom.asPoint(), nPoints) distList = [] vari = 0.0 request = QgsFeatureRequest().setFilterFids(featList).setSubsetOfAttributes([outIdx]).setDestinationCrs(source.sourceCrs(), context.transformContext()) for outFeat in target_source.getFeatures(request): if feedback.isCanceled(): break if same_source_and_target and inFeat.id() == outFeat.id(): continue outID = outFeat.attributes()[outIdx] outGeom = outFeat.geometry() dist = distArea.measureLine(inGeom.asPoint(), outGeom.asPoint()) if matType == 0: out_feature = QgsFeature() out_geom = QgsGeometry.unaryUnion([inFeat.geometry(), outFeat.geometry()]) out_feature.setGeometry(out_geom) out_feature.setAttributes([inID, outID, dist]) sink.addFeature(out_feature, QgsFeatureSink.FastInsert) else: distList.append(float(dist)) if matType != 0: mean = sum(distList) / len(distList) for i in distList: vari += (i - mean) * (i - mean) vari = math.sqrt(vari / len(distList)) out_feature = QgsFeature() out_feature.setGeometry(inFeat.geometry()) out_feature.setAttributes([inID, mean, vari, min(distList), max(distList)]) sink.addFeature(out_feature, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def processAlgorithm(self, progress): layer = self.getParameterValue(self.INPUT_LAYER) mapping = self.getParameterValue(self.FIELDS_MAPPING) output = self.getOutputFromName(self.OUTPUT_LAYER) layer = dataobjects.getObjectFromUri(layer) fields = [] expressions = [] da = QgsDistanceArea() da.setSourceCrs(layer.crs().srsid()) da.setEllipsoidalMode( iface.mapCanvas().mapSettings().hasCrsTransformEnabled()) da.setEllipsoid(QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE)[0]) exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope(QgsExpressionContextUtils.projectScope()) exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer)) for field_def in mapping: fields.append( QgsField(name=field_def['name'], type=field_def['type'], len=field_def['length'], prec=field_def['precision'])) expression = QgsExpression(field_def['expression']) expression.setGeomCalculator(da) expression.setDistanceUnits(QgsProject.instance().distanceUnits()) expression.setAreaUnits(QgsProject.instance().areaUnits()) if expression.hasParserError(): raise GeoAlgorithmExecutionException( self.tr(u'Parser error in expression "{}": {}').format( str(field_def['expression']), str(expression.parserErrorString()))) expression.prepare(exp_context) if expression.hasEvalError(): raise GeoAlgorithmExecutionException( self.tr(u'Evaluation error in expression "{}": {}').format( str(field_def['expression']), str(expression.evalErrorString()))) expressions.append(expression) writer = output.getVectorWriter(fields, layer.wkbType(), layer.crs()) # Create output vector layer with new attributes error = '' calculationSuccess = True inFeat = QgsFeature() outFeat = QgsFeature() features = vector.features(layer) total = 100.0 / len(features) for current, inFeat in enumerate(features): rownum = current + 1 geometry = inFeat.geometry() outFeat.setGeometry(geometry) attrs = [] for i in range(0, len(mapping)): field_def = mapping[i] expression = expressions[i] exp_context.setFeature(inFeat) exp_context.lastScope().setVariable("row_number", rownum) value = expression.evaluate(exp_context) if expression.hasEvalError(): calculationSuccess = False error = expression.evalErrorString() break attrs.append(value) outFeat.setAttributes(attrs) writer.addFeature(outFeat) progress.setPercentage(int(current * total)) del writer if not calculationSuccess: raise GeoAlgorithmExecutionException( self.tr('An error occurred while evaluating the calculation' ' string:\n') + error)
def testRenderMetersInMapUnits(self): crs_wsg84 = QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:4326') rt_extent = QgsRectangle(13.37768985634235, 52.51625705830762, 13.37771931686235, 52.51628651882762) point_berlin_wsg84 = QgsPointXY(13.37770458660236, 52.51627178856762) length_wsg84_mapunits = 0.00001473026350140572 meters_test = 2.40 da_wsg84 = QgsDistanceArea() da_wsg84.setSourceCrs(crs_wsg84) if (da_wsg84.sourceCrs().isGeographic()): da_wsg84.setEllipsoid(da_wsg84.sourceCrs().ellipsoidAcronym()) length_meter_mapunits = da_wsg84.measureLineProjected( point_berlin_wsg84, 1.0, (math.pi / 2)) meters_test_mapunits = meters_test * length_wsg84_mapunits meters_test_pixel = meters_test * length_wsg84_mapunits ms = QgsMapSettings() ms.setDestinationCrs(crs_wsg84) ms.setExtent(rt_extent) r = QgsRenderContext.fromMapSettings(ms) r.setExtent(rt_extent) self.assertEqual(r.extent().center().toString(7), point_berlin_wsg84.toString(7)) c = QgsMapUnitScale() r.setDistanceArea(da_wsg84) result_test_painterunits = r.convertToPainterUnits( meters_test, QgsUnitTypes.RenderMetersInMapUnits, c) self.assertEqual( QgsDistanceArea.formatDistance(result_test_painterunits, 7, QgsUnitTypes.DistanceUnknownUnit, True), QgsDistanceArea.formatDistance(meters_test_mapunits, 7, QgsUnitTypes.DistanceUnknownUnit, True)) result_test_mapunits = r.convertToMapUnits( meters_test, QgsUnitTypes.RenderMetersInMapUnits, c) self.assertEqual( QgsDistanceArea.formatDistance(result_test_mapunits, 7, QgsUnitTypes.DistanceDegrees, True), QgsDistanceArea.formatDistance(meters_test_mapunits, 7, QgsUnitTypes.DistanceDegrees, True)) result_test_meters = r.convertFromMapUnits( meters_test_mapunits, QgsUnitTypes.RenderMetersInMapUnits) self.assertEqual( QgsDistanceArea.formatDistance(result_test_meters, 1, QgsUnitTypes.DistanceMeters, True), QgsDistanceArea.formatDistance(meters_test, 1, QgsUnitTypes.DistanceMeters, True))
def processAlgorithm(self, context, feedback): layer = dataobjects.getLayerFromString( self.getParameterValue(self.VECTOR)) fieldName = self.getParameterValue(self.FIELD) minDistance = float(self.getParameterValue(self.MIN_DISTANCE)) strategy = self.getParameterValue(self.STRATEGY) fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, QgsWkbTypes.Point, layer.crs(), context) da = QgsDistanceArea() features = QgsProcessingUtils.getFeatures(layer, context) for current, f in enumerate(features): fGeom = f.geometry() bbox = fGeom.boundingBox() if strategy == 0: pointCount = int(f[fieldName]) else: pointCount = int(round(f[fieldName] * da.measureArea(fGeom))) if pointCount == 0: feedback.pushInfo("Skip feature {} as number of points for it is 0.") continue index = QgsSpatialIndex() points = dict() nPoints = 0 nIterations = 0 maxIterations = pointCount * 200 total = 100.0 / pointCount random.seed() while nIterations < maxIterations and nPoints < pointCount: rx = bbox.xMinimum() + bbox.width() * random.random() ry = bbox.yMinimum() + bbox.height() * random.random() pnt = QgsPoint(rx, ry) geom = QgsGeometry.fromPoint(pnt) if geom.within(fGeom) and \ vector.checkMinDistance(pnt, index, minDistance, points): f = QgsFeature(nPoints) f.initAttributes(1) f.setFields(fields) f.setAttribute('id', nPoints) f.setGeometry(geom) writer.addFeature(f) index.insertFeature(f) points[nPoints] = pnt nPoints += 1 feedback.setProgress(int(nPoints * total)) nIterations += 1 if nPoints < pointCount: QgsMessageLog.logMessage(self.tr('Can not generate requested number of random ' 'points. Maximum number of attempts exceeded.'), self.tr('Processing'), QgsMessageLog.INFO) feedback.setProgress(0) del writer
def processAlgorithm(self, parameters, context, feedback): line_source = self.parameterAsSource(parameters, self.LINES, context) if line_source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.LINES)) poly_source = self.parameterAsSource(parameters, self.POLYGONS, context) if poly_source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.POLYGONS)) length_field_name = self.parameterAsString(parameters, self.LEN_FIELD, context) count_field_name = self.parameterAsString(parameters, self.COUNT_FIELD, context) fields = poly_source.fields() if fields.lookupField(length_field_name) < 0: fields.append(QgsField(length_field_name, QVariant.Double)) length_field_index = fields.lookupField(length_field_name) if fields.lookupField(count_field_name) < 0: fields.append(QgsField(count_field_name, QVariant.Int)) count_field_index = fields.lookupField(count_field_name) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, poly_source.wkbType(), poly_source.sourceCrs()) if sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT)) spatialIndex = QgsSpatialIndex( line_source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes( []).setDestinationCrs(poly_source.sourceCrs(), context.transformContext())), feedback) distArea = QgsDistanceArea() distArea.setSourceCrs(poly_source.sourceCrs(), context.transformContext()) distArea.setEllipsoid(context.project().ellipsoid()) features = poly_source.getFeatures() total = 100.0 / poly_source.featureCount() if poly_source.featureCount( ) else 0 for current, poly_feature in enumerate(features): if feedback.isCanceled(): break output_feature = QgsFeature() count = 0 length = 0 if poly_feature.hasGeometry(): poly_geom = poly_feature.geometry() has_intersections = False lines = spatialIndex.intersects(poly_geom.boundingBox()) engine = None if len(lines) > 0: has_intersections = True # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine( poly_geom.constGet()) engine.prepareGeometry() if has_intersections: request = QgsFeatureRequest().setFilterFids( lines).setSubsetOfAttributes([]).setDestinationCrs( poly_source.sourceCrs(), context.transformContext()) for line_feature in line_source.getFeatures(request): if feedback.isCanceled(): break if engine.intersects( line_feature.geometry().constGet()): outGeom = poly_geom.intersection( line_feature.geometry()) length += distArea.measureLength(outGeom) count += 1 output_feature.setGeometry(poly_geom) attrs = poly_feature.attributes() if length_field_index == len(attrs): attrs.append(length) else: attrs[length_field_index] = length if count_field_index == len(attrs): attrs.append(count) else: attrs[count_field_index] = count output_feature.setAttributes(attrs) sink.addFeature(output_feature, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def processAlgorithm(self, context, feedback): layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.VECTOR), context) groupField = self.getParameterValue(self.GROUP_FIELD) orderField = self.getParameterValue(self.ORDER_FIELD) dateFormat = str(self.getParameterValue(self.DATE_FORMAT)) #gap = int(self.getParameterValue(self.GAP_PERIOD)) dirName = self.getOutputValue(self.OUTPUT_TEXT) fields = QgsFields() fields.append(QgsField('group', QVariant.String, '', 254, 0)) fields.append(QgsField('begin', QVariant.String, '', 254, 0)) fields.append(QgsField('end', QVariant.String, '', 254, 0)) writer = self.getOutputFromName(self.OUTPUT_LINES).getVectorWriter(fields, QgsWkbTypes.LineString, layer.crs(), context) points = dict() features = QgsProcessingUtils.getFeatures(layer, context) total = 100.0 / QgsProcessingUtils.featureCount(layer, context) for current, f in enumerate(features): point = f.geometry().asPoint() group = f[groupField] order = f[orderField] if dateFormat != '': order = datetime.strptime(str(order), dateFormat) if group in points: points[group].append((order, point)) else: points[group] = [(order, point)] feedback.setProgress(int(current * total)) feedback.setProgress(0) da = QgsDistanceArea() current = 0 total = 100.0 / len(points) for group, vertices in list(points.items()): vertices.sort() f = QgsFeature() f.initAttributes(len(fields)) f.setFields(fields) f['group'] = group f['begin'] = vertices[0][0] f['end'] = vertices[-1][0] fileName = os.path.join(dirName, '%s.txt' % group) with open(fileName, 'w') as fl: fl.write('angle=Azimuth\n') fl.write('heading=Coordinate_System\n') fl.write('dist_units=Default\n') line = [] i = 0 for node in vertices: line.append(node[1]) if i == 0: fl.write('startAt=%f;%f;90\n' % (node[1].x(), node[1].y())) fl.write('survey=Polygonal\n') fl.write('[data]\n') else: angle = line[i - 1].azimuth(line[i]) distance = da.measureLine(line[i - 1], line[i]) fl.write('%f;%f;90\n' % (angle, distance)) i += 1 f.setGeometry(QgsGeometry.fromPolyline(line)) writer.addFeature(f) current += 1 feedback.setProgress(int(current * total)) del writer
class ExportGeometryInfo(QgisAlgorithm): INPUT = 'INPUT' METHOD = 'CALC_METHOD' OUTPUT = 'OUTPUT' def icon(self): return QgsApplication.getThemeIcon( "/algorithms/mAlgorithmAddGeometryAttributes.svg") def svgIconPath(self): return QgsApplication.iconPath( "/algorithms/mAlgorithmAddGeometryAttributes.svg") def tags(self): return self.tr( 'export,add,information,measurements,areas,lengths,perimeters,latitudes,longitudes,x,y,z,extract,points,lines,polygons,sinuosity,fields' ).split(',') def group(self): return self.tr('Vector geometry') def groupId(self): return 'vectorgeometry' def __init__(self): super().__init__() self.export_z = False self.export_m = False self.distance_area = None self.calc_methods = [ self.tr('Layer CRS'), self.tr('Project CRS'), self.tr('Ellipsoidal') ] def initAlgorithm(self, config=None): self.addParameter( QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'))) self.addParameter( QgsProcessingParameterEnum(self.METHOD, self.tr('Calculate using'), options=self.calc_methods, defaultValue=0)) self.addParameter( QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Added geom info'))) def name(self): return 'exportaddgeometrycolumns' def displayName(self): return self.tr('Add geometry attributes') def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT)) method = self.parameterAsEnum(parameters, self.METHOD, context) wkb_type = source.wkbType() fields = source.fields() new_fields = QgsFields() if QgsWkbTypes.geometryType(wkb_type) == QgsWkbTypes.PolygonGeometry: new_fields.append(QgsField('area', QVariant.Double)) new_fields.append(QgsField('perimeter', QVariant.Double)) elif QgsWkbTypes.geometryType(wkb_type) == QgsWkbTypes.LineGeometry: new_fields.append(QgsField('length', QVariant.Double)) if not QgsWkbTypes.isMultiType(source.wkbType()): new_fields.append(QgsField('straightdis', QVariant.Double)) new_fields.append(QgsField('sinuosity', QVariant.Double)) else: new_fields.append(QgsField('xcoord', QVariant.Double)) new_fields.append(QgsField('ycoord', QVariant.Double)) if QgsWkbTypes.hasZ(source.wkbType()): self.export_z = True new_fields.append(QgsField('zcoord', QVariant.Double)) if QgsWkbTypes.hasM(source.wkbType()): self.export_m = True new_fields.append(QgsField('mvalue', QVariant.Double)) fields = QgsProcessingUtils.combineFields(fields, new_fields) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, wkb_type, source.sourceCrs()) if sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT)) coordTransform = None # Calculate with: # 0 - layer CRS # 1 - project CRS # 2 - ellipsoidal self.distance_area = QgsDistanceArea() if method == 2: self.distance_area.setSourceCrs(source.sourceCrs(), context.transformContext()) self.distance_area.setEllipsoid(context.project().ellipsoid()) elif method == 1: coordTransform = QgsCoordinateTransform(source.sourceCrs(), context.project().crs(), context.project()) features = source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break outFeat = f attrs = f.attributes() inGeom = f.geometry() if inGeom: if coordTransform is not None: inGeom.transform(coordTransform) if inGeom.type() == QgsWkbTypes.PointGeometry: attrs.extend(self.point_attributes(inGeom)) elif inGeom.type() == QgsWkbTypes.PolygonGeometry: attrs.extend(self.polygon_attributes(inGeom)) else: attrs.extend(self.line_attributes(inGeom)) # ensure consistent count of attributes - otherwise null # geometry features will have incorrect attribute length # and provider may reject them if len(attrs) < len(fields): attrs += [NULL] * (len(fields) - len(attrs)) outFeat.setAttributes(attrs) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id} def point_attributes(self, geometry): pt = None if not geometry.isMultipart(): pt = geometry.constGet() else: if geometry.numGeometries() > 0: pt = geometry.geometryN(0) attrs = [] if pt: attrs.append(pt.x()) attrs.append(pt.y()) # add point z/m if self.export_z: attrs.append(pt.z()) if self.export_m: attrs.append(pt.m()) return attrs def line_attributes(self, geometry): if geometry.isMultipart(): return [self.distance_area.measureLength(geometry)] else: curve = geometry.constGet() p1 = curve.startPoint() p2 = curve.endPoint() straight_distance = self.distance_area.measureLine( QgsPointXY(p1), QgsPointXY(p2)) sinuosity = curve.sinuosity() if math.isnan(sinuosity): sinuosity = NULL return [ self.distance_area.measureLength(geometry), straight_distance, sinuosity ] def polygon_attributes(self, geometry): area = self.distance_area.measureArea(geometry) perimeter = self.distance_area.measurePerimeter(geometry) return [area, perimeter]
class ExportGeometryInfo(QgisAlgorithm): INPUT = 'INPUT' METHOD = 'CALC_METHOD' OUTPUT = 'OUTPUT' def icon(self): return QIcon( os.path.join(pluginPath, 'images', 'ftools', 'export_geometry.png')) def tags(self): return self.tr( 'export,add,information,measurements,areas,lengths,perimeters,latitudes,longitudes,x,y,z,extract,points,lines,polygons' ).split(',') def group(self): return self.tr('Vector geometry') def groupId(self): return 'vectorgeometry' def __init__(self): super().__init__() self.export_z = False self.export_m = False self.distance_area = None self.calc_methods = [ self.tr('Layer CRS'), self.tr('Project CRS'), self.tr('Ellipsoidal') ] def initAlgorithm(self, config=None): self.addParameter( QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'))) self.addParameter( QgsProcessingParameterEnum(self.METHOD, self.tr('Calculate using'), options=self.calc_methods, defaultValue=0)) self.addParameter( QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Added geom info'))) def name(self): return 'exportaddgeometrycolumns' def displayName(self): return self.tr('Export geometry columns') def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) method = self.parameterAsEnum(parameters, self.METHOD, context) wkb_type = source.wkbType() fields = source.fields() new_fields = QgsFields() if QgsWkbTypes.geometryType(wkb_type) == QgsWkbTypes.PolygonGeometry: new_fields.append(QgsField('area', QVariant.Double)) new_fields.append(QgsField('perimeter', QVariant.Double)) elif QgsWkbTypes.geometryType(wkb_type) == QgsWkbTypes.LineGeometry: new_fields.append(QgsField('length', QVariant.Double)) else: new_fields.append(QgsField('xcoord', QVariant.Double)) new_fields.append(QgsField('ycoord', QVariant.Double)) if QgsWkbTypes.hasZ(source.wkbType()): self.export_z = True new_fields.append(QgsField('zcoord', QVariant.Double)) if QgsWkbTypes.hasM(source.wkbType()): self.export_m = True new_fields.append(QgsField('mvalue', QVariant.Double)) fields = QgsProcessingUtils.combineFields(fields, new_fields) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, wkb_type, source.sourceCrs()) coordTransform = None # Calculate with: # 0 - layer CRS # 1 - project CRS # 2 - ellipsoidal self.distance_area = QgsDistanceArea() if method == 2: self.distance_area.setSourceCrs(source.sourceCrs(), context.transformContext()) self.distance_area.setEllipsoid(context.project().ellipsoid()) elif method == 1: coordTransform = QgsCoordinateTransform(source.sourceCrs(), context.project().crs(), context.project()) features = source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break outFeat = f attrs = f.attributes() inGeom = f.geometry() if inGeom: if coordTransform is not None: inGeom.transform(coordTransform) if inGeom.type() == QgsWkbTypes.PointGeometry: attrs.extend(self.point_attributes(inGeom)) elif inGeom.type() == QgsWkbTypes.PolygonGeometry: attrs.extend(self.polygon_attributes(inGeom)) else: attrs.extend(self.line_attributes(inGeom)) outFeat.setAttributes(attrs) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id} def point_attributes(self, geometry): pt = None if not geometry.isMultipart(): pt = geometry.constGet() else: if geometry.numGeometries() > 0: pt = geometry.geometryN(0) attrs = [] if pt: attrs.append(pt.x()) attrs.append(pt.y()) # add point z/m if self.export_z: attrs.append(pt.z()) if self.export_m: attrs.append(pt.m()) return attrs def line_attributes(self, geometry): return [self.distance_area.measureLength(geometry)] def polygon_attributes(self, geometry): area = self.distance_area.measureArea(geometry) perimeter = self.distance_area.measurePerimeter(geometry) return [area, perimeter]
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT)) output_file = self.parameterAsFileOutput(parameters, self.OUTPUT_HTML_FILE, context) spatialIndex = QgsSpatialIndex(source, feedback) distance = QgsDistanceArea() distance.setSourceCrs(source.sourceCrs(), context.transformContext()) distance.setEllipsoid(context.project().ellipsoid()) sumDist = 0.00 A = source.sourceExtent() A = float(A.width() * A.height()) features = source.getFeatures() count = source.featureCount() total = 100.0 / count if count else 1 for current, feat in enumerate(features): if feedback.isCanceled(): break neighbourID = spatialIndex.nearestNeighbor( feat.geometry().asPoint(), 2)[1] request = QgsFeatureRequest().setFilterFid( neighbourID).setSubsetOfAttributes([]) neighbour = next(source.getFeatures(request)) sumDist += distance.measureLine(neighbour.geometry().asPoint(), feat.geometry().asPoint()) feedback.setProgress(int(current * total)) do = float(sumDist) / count de = float(0.5 / math.sqrt(count / A)) d = float(do / de) SE = float(0.26136 / math.sqrt(count**2 / A)) zscore = float((do - de) / SE) results = {} results[self.OBSERVED_MD] = do results[self.EXPECTED_MD] = de results[self.NN_INDEX] = d results[self.POINT_COUNT] = count results[self.Z_SCORE] = zscore if output_file: data = [] data.append('Observed mean distance: ' + str(do)) data.append('Expected mean distance: ' + str(de)) data.append('Nearest neighbour index: ' + str(d)) data.append('Number of points: ' + str(count)) data.append('Z-Score: ' + str(zscore)) self.createHTML(output_file, data) results[self.OUTPUT_HTML_FILE] = output_file return results
def testFormatDistance(self): """Test formatting distances""" QLocale.setDefault(QLocale.c()) self.assertEqual( QgsDistanceArea.formatDistance(45, 3, QgsUnitTypes.DistanceMeters), '45.000 m') self.assertEqual( QgsDistanceArea.formatDistance(1300, 1, QgsUnitTypes.DistanceMeters, False), '1.3 km') self.assertEqual( QgsDistanceArea.formatDistance(.005, 1, QgsUnitTypes.DistanceMeters, False), '5.0 mm') self.assertEqual( QgsDistanceArea.formatDistance(.05, 1, QgsUnitTypes.DistanceMeters, False), '5.0 cm') self.assertEqual( QgsDistanceArea.formatDistance(1.5, 3, QgsUnitTypes.DistanceKilometers, True), '1.500 km') self.assertEqual( QgsDistanceArea.formatDistance(1.5, 3, QgsUnitTypes.DistanceKilometers, False), '1.500 km') self.assertEqual( QgsDistanceArea.formatDistance(0.5, 3, QgsUnitTypes.DistanceKilometers, True), '0.500 km') self.assertEqual( QgsDistanceArea.formatDistance(0.5, 3, QgsUnitTypes.DistanceKilometers, False), '500.000 m') self.assertEqual( QgsDistanceArea.formatDistance(6000, 0, QgsUnitTypes.DistanceFeet, True), '6,000 ft') self.assertEqual( QgsDistanceArea.formatDistance(6000, 3, QgsUnitTypes.DistanceFeet, False), '1.136 mi') self.assertEqual( QgsDistanceArea.formatDistance(300, 0, QgsUnitTypes.DistanceFeet, True), '300 ft') self.assertEqual( QgsDistanceArea.formatDistance(300, 0, QgsUnitTypes.DistanceFeet, False), '300 ft') self.assertEqual( QgsDistanceArea.formatDistance(3000, 0, QgsUnitTypes.DistanceYards, True), '3,000 yd') self.assertEqual( QgsDistanceArea.formatDistance(3000, 3, QgsUnitTypes.DistanceYards, False), '1.705 mi') self.assertEqual( QgsDistanceArea.formatDistance(300, 0, QgsUnitTypes.DistanceYards, True), '300 yd') self.assertEqual( QgsDistanceArea.formatDistance(300, 0, QgsUnitTypes.DistanceYards, False), '300 yd') self.assertEqual( QgsDistanceArea.formatDistance(1.5, 3, QgsUnitTypes.DistanceMiles, True), '1.500 mi') self.assertEqual( QgsDistanceArea.formatDistance(1.5, 3, QgsUnitTypes.DistanceMiles, False), '1.500 mi') self.assertEqual( QgsDistanceArea.formatDistance(0.5, 3, QgsUnitTypes.DistanceMiles, True), '0.500 mi') self.assertEqual( QgsDistanceArea.formatDistance(0.5, 0, QgsUnitTypes.DistanceMiles, False), '2,640 ft') self.assertEqual( QgsDistanceArea.formatDistance(0.5, 1, QgsUnitTypes.DistanceNauticalMiles, True), '0.5 NM') self.assertEqual( QgsDistanceArea.formatDistance(0.5, 1, QgsUnitTypes.DistanceNauticalMiles, False), '0.5 NM') self.assertEqual( QgsDistanceArea.formatDistance(1.5, 1, QgsUnitTypes.DistanceNauticalMiles, True), '1.5 NM') self.assertEqual( QgsDistanceArea.formatDistance(1.5, 1, QgsUnitTypes.DistanceNauticalMiles, False), '1.5 NM') self.assertEqual( QgsDistanceArea.formatDistance(1.5, 1, QgsUnitTypes.DistanceDegrees, True), '1.5 deg') self.assertEqual( QgsDistanceArea.formatDistance(1.0, 1, QgsUnitTypes.DistanceDegrees, False), '1.0 deg') self.assertEqual( QgsDistanceArea.formatDistance(1.0, 1, QgsUnitTypes.DistanceUnknownUnit, False), '1.0') QLocale.setDefault(QLocale.system())
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT)) strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) minDistance = self.parameterAsDouble(parameters, self.MIN_DISTANCE, context) expression = QgsExpression( self.parameterAsString(parameters, self.EXPRESSION, context)) if expression.hasParserError(): raise QgsProcessingException(expression.parserErrorString()) expressionContext = self.createExpressionContext( parameters, context, source) expression.prepare(expressionContext) fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Point, source.sourceCrs()) if sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT)) da = QgsDistanceArea() da.setSourceCrs(source.sourceCrs(), context.transformContext()) da.setEllipsoid(context.project().ellipsoid()) total = 100.0 / source.featureCount() if source.featureCount() else 0 current_progress = 0 for current, f in enumerate(source.getFeatures()): if feedback.isCanceled(): break if not f.hasGeometry(): continue current_progress = total * current feedback.setProgress(current_progress) expressionContext.setFeature(f) value = expression.evaluate(expressionContext) if expression.hasEvalError(): feedback.pushInfo( self.tr('Evaluation error for feature ID {}: {}').format( f.id(), expression.evalErrorString())) continue fGeom = f.geometry() engine = QgsGeometry.createGeometryEngine(fGeom.constGet()) engine.prepareGeometry() bbox = fGeom.boundingBox() if strategy == 0: pointCount = int(value) else: pointCount = int(round(value * da.measureArea(fGeom))) if pointCount == 0: feedback.pushInfo( "Skip feature {} as number of points for it is 0.".format( f.id())) continue index = QgsSpatialIndex() points = dict() nPoints = 0 nIterations = 0 maxIterations = pointCount * 200 feature_total = total / pointCount if pointCount else 1 random.seed() while nIterations < maxIterations and nPoints < pointCount: if feedback.isCanceled(): break rx = bbox.xMinimum() + bbox.width() * random.random() ry = bbox.yMinimum() + bbox.height() * random.random() p = QgsPointXY(rx, ry) geom = QgsGeometry.fromPointXY(p) if engine.contains(geom.constGet()) and \ vector.checkMinDistance(p, index, minDistance, points): f = QgsFeature(nPoints) f.initAttributes(1) f.setFields(fields) f.setAttribute('id', nPoints) f.setGeometry(geom) sink.addFeature(f, QgsFeatureSink.FastInsert) index.addFeature(f) points[nPoints] = p nPoints += 1 feedback.setProgress(current_progress + int(nPoints * feature_total)) nIterations += 1 if nPoints < pointCount: feedback.pushInfo( self.tr('Could not generate requested number of random ' 'points. Maximum number of attempts exceeded.')) feedback.setProgress(100) return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) method = self.parameterAsEnum(parameters, self.METHOD, context) wkb_type = source.wkbType() fields = source.fields() new_fields = QgsFields() if QgsWkbTypes.geometryType(wkb_type) == QgsWkbTypes.PolygonGeometry: new_fields.append(QgsField('area', QVariant.Double)) new_fields.append(QgsField('perimeter', QVariant.Double)) elif QgsWkbTypes.geometryType(wkb_type) == QgsWkbTypes.LineGeometry: new_fields.append(QgsField('length', QVariant.Double)) else: new_fields.append(QgsField('xcoord', QVariant.Double)) new_fields.append(QgsField('ycoord', QVariant.Double)) if QgsWkbTypes.hasZ(source.wkbType()): self.export_z = True new_fields.append(QgsField('zcoord', QVariant.Double)) if QgsWkbTypes.hasM(source.wkbType()): self.export_m = True new_fields.append(QgsField('mvalue', QVariant.Double)) fields = QgsProcessingUtils.combineFields(fields, new_fields) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, wkb_type, source.sourceCrs()) coordTransform = None # Calculate with: # 0 - layer CRS # 1 - project CRS # 2 - ellipsoidal self.distance_area = QgsDistanceArea() if method == 2: self.distance_area.setSourceCrs(source.sourceCrs()) self.distance_area.setEllipsoid(context.project().ellipsoid()) elif method == 1: coordTransform = QgsCoordinateTransform(source.sourceCrs(), context.project().crs()) features = source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break outFeat = f attrs = f.attributes() inGeom = f.geometry() if inGeom: if coordTransform is not None: inGeom.transform(coordTransform) if inGeom.type() == QgsWkbTypes.PointGeometry: attrs.extend(self.point_attributes(inGeom)) elif inGeom.type() == QgsWkbTypes.PolygonGeometry: attrs.extend(self.polygon_attributes(inGeom)) else: attrs.extend(self.line_attributes(inGeom)) outFeat.setAttributes(attrs) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def regularMatrix(self, parameters, context, source, inField, target_source, targetField, nPoints, feedback): distArea = QgsDistanceArea() distArea.setSourceCrs(source.sourceCrs(), context.transformContext()) distArea.setEllipsoid(context.project().ellipsoid()) inIdx = source.fields().lookupField(inField) targetIdx = target_source.fields().lookupField(targetField) index = QgsSpatialIndex( target_source.getFeatures( QgsFeatureRequest().setSubsetOfAttributes( []).setDestinationCrs(source.sourceCrs(), context.transformContext())), feedback) first = True sink = None dest_id = None features = source.getFeatures( QgsFeatureRequest().setSubsetOfAttributes([inIdx])) total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, inFeat in enumerate(features): if feedback.isCanceled(): break inGeom = inFeat.geometry() if first: featList = index.nearestNeighbor(inGeom.asPoint(), nPoints) first = False fields = QgsFields() input_id_field = source.fields()[inIdx] input_id_field.setName('ID') fields.append(input_id_field) for f in target_source.getFeatures( QgsFeatureRequest().setFilterFids( featList).setSubsetOfAttributes([ targetIdx ]).setDestinationCrs(source.sourceCrs(), context.transformContext())): fields.append( QgsField(str(f[targetField]), QVariant.Double)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, source.wkbType(), source.sourceCrs()) if sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT)) data = [inFeat[inField]] for target in target_source.getFeatures( QgsFeatureRequest().setSubsetOfAttributes( []).setFilterFids(featList).setDestinationCrs( source.sourceCrs(), context.transformContext())): if feedback.isCanceled(): break outGeom = target.geometry() dist = distArea.measureLine(inGeom.asPoint(), outGeom.asPoint()) data.append(dist) out_feature = QgsFeature() out_feature.setGeometry(inGeom) out_feature.setAttributes(data) sink.addFeature(out_feature, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def testLengthMeasureAndUnits(self): """Test a variety of length measurements in different CRS and ellipsoid modes, to check that the calculated lengths and units are always consistent """ da = QgsDistanceArea() da.setSourceCrs(3452) da.setEllipsoidalMode(False) da.setEllipsoid("NONE") # We check both the measured length AND the units, in case the logic regarding # ellipsoids and units changes in future distance = da.measureLine(QgsPoint(1, 1), QgsPoint(2, 3)) units = da.lengthUnits() print(("measured {} in {}".format(distance, QgsUnitTypes.toString(units)))) assert ((abs(distance - 2.23606797) < 0.00000001 and units == QgsUnitTypes.DistanceDegrees) or (abs(distance - 248.52) < 0.01 and units == QgsUnitTypes.DistanceMeters)) da.setEllipsoid("WGS84") distance = da.measureLine(QgsPoint(1, 1), QgsPoint(2, 3)) units = da.lengthUnits() print(("measured {} in {}".format(distance, QgsUnitTypes.toString(units)))) assert ((abs(distance - 2.23606797) < 0.00000001 and units == QgsUnitTypes.DistanceDegrees) or (abs(distance - 248.52) < 0.01 and units == QgsUnitTypes.DistanceMeters)) da.setEllipsoidalMode(True) distance = da.measureLine(QgsPoint(1, 1), QgsPoint(2, 3)) units = da.lengthUnits() print(("measured {} in {}".format(distance, QgsUnitTypes.toString(units)))) # should always be in Meters self.assertAlmostEqual(distance, 247555.57, delta=0.01) self.assertEqual(units, QgsUnitTypes.DistanceMeters) # test converting the resultant length distance = da.convertLengthMeasurement( distance, QgsUnitTypes.DistanceNauticalMiles) self.assertAlmostEqual(distance, 133.669, delta=0.01) # now try with a source CRS which is in feet da.setSourceCrs(27469) da.setEllipsoidalMode(False) # measurement should be in feet distance = da.measureLine(QgsPoint(1, 1), QgsPoint(2, 3)) units = da.lengthUnits() print(("measured {} in {}".format(distance, QgsUnitTypes.toString(units)))) self.assertAlmostEqual(distance, 2.23606797, delta=0.000001) self.assertEqual(units, QgsUnitTypes.DistanceFeet) # test converting the resultant length distance = da.convertLengthMeasurement(distance, QgsUnitTypes.DistanceMeters) self.assertAlmostEqual(distance, 0.6815, delta=0.001) da.setEllipsoidalMode(True) # now should be in Meters again distance = da.measureLine(QgsPoint(1, 1), QgsPoint(2, 3)) units = da.lengthUnits() print(("measured {} in {}".format(distance, QgsUnitTypes.toString(units)))) self.assertAlmostEqual(distance, 0.67953772, delta=0.000001) self.assertEqual(units, QgsUnitTypes.DistanceMeters) # test converting the resultant length distance = da.convertLengthMeasurement(distance, QgsUnitTypes.DistanceFeet) self.assertAlmostEqual(distance, 2.2294, delta=0.001)
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) layer = self.parameterAsVectorLayer(parameters, self.INPUT, context) field_name = self.parameterAsString(parameters, self.FIELD_NAME, context) field_type = self.TYPES[self.parameterAsEnum(parameters, self.FIELD_TYPE, context)] width = self.parameterAsInt(parameters, self.FIELD_LENGTH, context) precision = self.parameterAsInt(parameters, self.FIELD_PRECISION, context) new_field = self.parameterAsBool(parameters, self.NEW_FIELD, context) formula = self.parameterAsString(parameters, self.FORMULA, context) expression = QgsExpression(formula) da = QgsDistanceArea() da.setSourceCrs(source.sourceCrs(), context.transformContext()) da.setEllipsoid(context.project().ellipsoid()) expression.setGeomCalculator(da) expression.setDistanceUnits(context.project().distanceUnits()) expression.setAreaUnits(context.project().areaUnits()) fields = source.fields() field_index = fields.lookupField(field_name) if new_field or field_index < 0: fields.append( QgsField(field_name, field_type, '', width, precision)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, source.wkbType(), source.sourceCrs()) exp_context = self.createExpressionContext(parameters, context) if layer is not None: exp_context.appendScope( QgsExpressionContextUtils.layerScope(layer)) if not expression.prepare(exp_context): raise QgsProcessingException( self.tr('Evaluation error: {0}').format( expression.parserErrorString())) features = source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break rownum = current + 1 exp_context.setFeature(f) exp_context.lastScope().setVariable("row_number", rownum) value = expression.evaluate(exp_context) if expression.hasEvalError(): feedback.reportError(expression.evalErrorString()) else: attrs = f.attributes() if new_field or field_index < 0: attrs.append(value) else: attrs[field_index] = value f.setAttributes(attrs) sink.addFeature(f, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def draw_scalebar(self, composer_map, top_offset): """Add a numeric scale to the bottom left of the map. We draw the scale bar manually because QGIS does not yet support rendering a scale bar for a geographic map in km. .. seealso:: :meth:`drawNativeScaleBar` :param composer_map: Composer map on which to draw the scalebar. :type composer_map: QgsComposerMap :param top_offset: Vertical offset at which the logo should be drawn. :type top_offset: int """ LOGGER.debug('InaSAFE Map drawScaleBar called') myCanvas = self.iface.mapCanvas() myRenderer = myCanvas.mapRenderer() # # Add a linear map scale # myDistanceArea = QgsDistanceArea() myDistanceArea.setSourceCrs(myRenderer.destinationCrs().srsid()) myDistanceArea.setProjectionsEnabled(True) # Determine how wide our map is in km/m # Starting point at BL corner myComposerExtent = composer_map.extent() myStartPoint = QgsPoint(myComposerExtent.xMinimum(), myComposerExtent.yMinimum()) # Ending point at BR corner myEndPoint = QgsPoint(myComposerExtent.xMaximum(), myComposerExtent.yMinimum()) myGroundDistance = myDistanceArea.measureLine(myStartPoint, myEndPoint) # Get the equivalent map distance per page mm myMapWidth = self.mapWidth # How far is 1mm on map on the ground in meters? myMMToGroundDistance = myGroundDistance / myMapWidth #print 'MM:', myMMDistance # How long we want the scale bar to be in relation to the map myScaleBarToMapRatio = 0.5 # How many divisions the scale bar should have myTickCount = 5 myScaleBarWidthMM = myMapWidth * myScaleBarToMapRatio myPrintSegmentWidthMM = myScaleBarWidthMM / myTickCount # Segment width in real world (m) # We apply some logic here so that segments are displayed in meters # if each segment is less that 1000m otherwise km. Also the segment # lengths are rounded down to human looking numbers e.g. 1km not 1.1km myUnits = '' myGroundSegmentWidth = myPrintSegmentWidthMM * myMMToGroundDistance if myGroundSegmentWidth < 1000: myUnits = 'm' myGroundSegmentWidth = round(myGroundSegmentWidth) # adjust the segment width now to account for rounding myPrintSegmentWidthMM = myGroundSegmentWidth / myMMToGroundDistance else: myUnits = 'km' # Segment with in real world (km) myGroundSegmentWidth = round(myGroundSegmentWidth / 1000) myPrintSegmentWidthMM = ((myGroundSegmentWidth * 1000) / myMMToGroundDistance) # Now adjust the scalebar width to account for rounding myScaleBarWidthMM = myTickCount * myPrintSegmentWidthMM #print "SBWMM:", myScaleBarWidthMM #print "SWMM:", myPrintSegmentWidthMM #print "SWM:", myGroundSegmentWidthM #print "SWKM:", myGroundSegmentWidthKM # start drawing in line segments myScaleBarHeight = 5 # mm myLineWidth = 0.3 # mm myInsetDistance = 7 # how much to inset the scalebar into the map by myScaleBarX = self.pageMargin + myInsetDistance myScaleBarY = (top_offset + self.mapHeight - myInsetDistance - myScaleBarHeight) # mm # Draw an outer background box - shamelessly hardcoded buffer myRect = QgsComposerShape( myScaleBarX - 4, # left edge myScaleBarY - 3, # top edge myScaleBarWidthMM + 13, # right edge myScaleBarHeight + 6, # bottom edge self.composition) myRect.setShapeType(QgsComposerShape.Rectangle) myRect.setLineWidth(myLineWidth) myRect.setFrame(False) myBrush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) # workaround for missing setTransparentFill missing from python api myRect.setBrush(myBrush) self.composition.addItem(myRect) # Set up the tick label font myFontWeight = QtGui.QFont.Normal myFontSize = 6 myItalicsFlag = False myFont = QtGui.QFont('verdana', myFontSize, myFontWeight, myItalicsFlag) # Draw the bottom line myUpshift = 0.3 # shift the bottom line up for better rendering myRect = QgsComposerShape(myScaleBarX, myScaleBarY + myScaleBarHeight - myUpshift, myScaleBarWidthMM, 0.1, self.composition) myRect.setShapeType(QgsComposerShape.Rectangle) myRect.setLineWidth(myLineWidth) myRect.setFrame(False) self.composition.addItem(myRect) # Now draw the scalebar ticks for myTickCountIterator in range(0, myTickCount + 1): myDistanceSuffix = '' if myTickCountIterator == myTickCount: myDistanceSuffix = ' ' + myUnits myRealWorldDistance = ( '%.0f%s' % (myTickCountIterator * myGroundSegmentWidth, myDistanceSuffix)) #print 'RW:', myRealWorldDistance myMMOffset = myScaleBarX + (myTickCountIterator * myPrintSegmentWidthMM) #print 'MM:', myMMOffset myTickHeight = myScaleBarHeight / 2 # Lines are not exposed by the api yet so we # bodge drawing lines using rectangles with 1px height or width myTickWidth = 0.1 # width or rectangle to be drawn myUpTickLine = QgsComposerShape( myMMOffset, myScaleBarY + myScaleBarHeight - myTickHeight, myTickWidth, myTickHeight, self.composition) myUpTickLine.setShapeType(QgsComposerShape.Rectangle) myUpTickLine.setLineWidth(myLineWidth) myUpTickLine.setFrame(False) self.composition.addItem(myUpTickLine) # # Add a tick label # myLabel = QgsComposerLabel(self.composition) myLabel.setFont(myFont) myLabel.setText(myRealWorldDistance) myLabel.adjustSizeToText() myLabel.setItemPosition(myMMOffset - 3, myScaleBarY - myTickHeight) myLabel.setFrame(self.showFramesFlag) self.composition.addItem(myLabel)
def testMeasureLineProjectedWorldPoints(self): # +-+ # | | # +-+ + # checking returned length_mapunits/projected_points of diffferent world points with results from SpatiaLite ST_Project da_3068 = QgsDistanceArea() da_3068.setSourceCrs(QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:3068'), QgsProject.instance().transformContext()) if (da_3068.sourceCrs().isGeographic()): da_3068.setEllipsoid(da_3068.sourceCrs().ellipsoidAcronym()) self.assertEqual(da_3068.sourceCrs().authid(), 'EPSG:3068') print(("setting [{}] srid [{}] description [{}] isGeographic[{}] lengthUnits[{}] projectionAcronym[{}] ellipsoidAcronym[{}]".format(u'EPSG:3068', da_3068.sourceCrs().authid(), da_3068.sourceCrs().description(), da_3068.sourceCrs().isGeographic(), QgsUnitTypes.toString(da_3068.lengthUnits()), da_3068.sourceCrs().projectionAcronym(), da_3068.sourceCrs().ellipsoidAcronym()))) da_wsg84 = QgsDistanceArea() da_wsg84.setSourceCrs(QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:4326'), QgsProject.instance().transformContext()) if (da_wsg84.sourceCrs().isGeographic()): da_wsg84.setEllipsoid(da_wsg84.sourceCrs().ellipsoidAcronym()) self.assertEqual(da_wsg84.sourceCrs().authid(), 'EPSG:4326') print(("setting [{}] srid [{}] description [{}] isGeographic[{}] lengthUnits[{}] projectionAcronym[{}] ellipsoidAcronym[{}] ellipsoid[{}]".format(u'EPSG:4326', da_wsg84.sourceCrs().authid(), da_wsg84.sourceCrs().description(), da_wsg84.sourceCrs().isGeographic(), QgsUnitTypes.toString(da_wsg84.lengthUnits()), da_wsg84.sourceCrs().projectionAcronym(), da_wsg84.sourceCrs().ellipsoidAcronym(), da_wsg84.ellipsoid()))) da_4314 = QgsDistanceArea() da_4314.setSourceCrs(QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:4314'), QgsProject.instance().transformContext()) if (da_4314.sourceCrs().isGeographic()): da_4314.setEllipsoid(da_4314.sourceCrs().ellipsoidAcronym()) self.assertEqual(da_4314.sourceCrs().authid(), 'EPSG:4314') print(("setting [{}] srid [{}] description [{}] isGeographic[{}] lengthUnits[{}] projectionAcronym[{}] ellipsoidAcronym[{}]".format(u'EPSG:4314', da_4314.sourceCrs().authid(), da_4314.sourceCrs().description(), da_4314.sourceCrs().isGeographic(), QgsUnitTypes.toString(da_4314.lengthUnits()), da_4314.sourceCrs().projectionAcronym(), da_4314.sourceCrs().ellipsoidAcronym()))) da_4805 = QgsDistanceArea() da_4805.setSourceCrs(QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:4805'), QgsProject.instance().transformContext()) if (da_4805.sourceCrs().isGeographic()): da_4805.setEllipsoid(da_4805.sourceCrs().ellipsoidAcronym()) self.assertEqual(da_4805.sourceCrs().authid(), 'EPSG:4805') print(("setting [{}] srid [{}] description [{}] isGeographic[{}] lengthUnits[{}] projectionAcronym[{}] ellipsoidAcronym[{}]".format(u'EPSG:4805', da_4805.sourceCrs().authid(), da_4805.sourceCrs().description(), da_4805.sourceCrs().isGeographic(), QgsUnitTypes.toString(da_4805.lengthUnits()), da_4805.sourceCrs().projectionAcronym(), da_4805.sourceCrs().ellipsoidAcronym()))) # EPSG:5665 unknown, why? da_5665 = QgsDistanceArea() da_5665.setSourceCrs(QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:5665'), QgsProject.instance().transformContext()) if (da_5665.sourceCrs().isGeographic()): da_5665.setEllipsoid(da_5665.sourceCrs().ellipsoidAcronym()) print(("setting [{}] srid [{}] description [{}] isGeographic[{}] lengthUnits[{}] projectionAcronym[{}] ellipsoidAcronym[{}]".format(u'EPSG:5665', da_5665.sourceCrs().authid(), da_5665.sourceCrs().description(), da_5665.sourceCrs().isGeographic(), QgsUnitTypes.toString(da_5665.lengthUnits()), da_5665.sourceCrs().projectionAcronym(), da_5665.sourceCrs().ellipsoidAcronym()))) #self.assertEqual(da_5665.sourceCrs().authid(), 'EPSG:5665') da_25833 = QgsDistanceArea() da_25833.setSourceCrs(QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:25833'), QgsProject.instance().transformContext()) if (da_25833.sourceCrs().isGeographic()): da_25833.setEllipsoid(da_25833.sourceCrs().ellipsoidAcronym()) print(("setting [{}] srid [{}] description [{}] isGeographic[{}] lengthUnits[{}] projectionAcronym[{}] ellipsoidAcronym[{}]".format(u'EPSG:25833', da_25833.sourceCrs().authid(), da_25833.sourceCrs().description(), da_25833.sourceCrs().isGeographic(), QgsUnitTypes.toString(da_25833.lengthUnits()), da_25833.sourceCrs().projectionAcronym(), da_25833.sourceCrs().ellipsoidAcronym()))) self.assertEqual(da_25833.sourceCrs().authid(), 'EPSG:25833') # Berlin - Brandenburg Gate - Quadriga point_berlin_3068 = QgsPointXY(23183.38449999984, 21047.3225000017) point_berlin_3068_project = point_berlin_3068.project(1, (math.pi / 2)) point_meter_result = QgsPointXY(0, 0) length_meter_mapunits, point_meter_result = da_3068.measureLineProjected(point_berlin_3068, 1.0, (math.pi / 2)) pprint(point_meter_result) print('-I-> Berlin 3068 length_meter_mapunits[{}] point_meter_result[{}]'.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_3068.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 1, da_3068.lengthUnits(), True), '1.0 m') self.assertEqual(point_meter_result.toString(7), point_berlin_3068_project.toString(7)) point_berlin_wsg84 = QgsPointXY(13.37770458660236, 52.51627178856762) point_berlin_wsg84_project = QgsPointXY(13.37771931736259, 52.51627178856669) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_berlin_wsg84, 1.0, (math.pi / 2)) print('-I-> Berlin Wsg84 length_meter_mapunits[{}] point_meter_result[{}] ellipsoid[{}]'.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 20, da_wsg84.lengthUnits(), True), point_meter_result.asWkt(), da_wsg84.ellipsoid())) # for unknown reasons, this is returning '0.00001473026 m' instead of '0.00001473026 deg' when using da_wsg84.lengthUnits() # self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits,11,da_wsg84.lengthUnits(),True), '0.00001473026 deg') self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 11, QgsUnitTypes.DistanceDegrees, True), '0.00001473026 deg') self.assertEqual(point_meter_result.toString(7), point_berlin_wsg84_project.toString(7)) point_berlin_4314 = QgsPointXY(13.37944343021465, 52.51767872437083) point_berlin_4314_project = QgsPointXY(13.37945816324759, 52.5176787243699) length_meter_mapunits, point_meter_result = da_4314.measureLineProjected(point_berlin_4314, 1.0, (math.pi / 2)) print('-I-> Berlin 4314 length_meter_mapunits[{}] point_meter_result[{}]'.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_4314.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 9, QgsUnitTypes.DistanceDegrees, True), '0.000014733 deg') self.assertEqual(point_meter_result.toString(7), point_berlin_4314_project.toString(7)) point_berlin_4805 = QgsPointXY(31.04960570069176, 52.5174657497405) point_berlin_4805_project = QgsPointXY(31.04962043365347, 52.51746574973957) length_meter_mapunits, point_meter_result = da_4805.measureLineProjected(point_berlin_4805, 1.0, (math.pi / 2)) print('-I-> Berlin 4805 length_meter_mapunits[{}] point_meter_result[{}]'.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_4805.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 9, QgsUnitTypes.DistanceDegrees, True), '0.000014733 deg') self.assertEqual(point_meter_result.toString(7), point_berlin_4805_project.toString(7)) point_berlin_25833 = QgsPointXY(389918.0748318382, 5819698.772194743) point_berlin_25833_project = point_berlin_25833.project(1, (math.pi / 2)) length_meter_mapunits, point_meter_result = da_25833.measureLineProjected(point_berlin_25833, 1.0, (math.pi / 2)) print('-I-> Berlin 25833 length_meter_mapunits[{}] point_meter_result[{}]'.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_25833.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_25833.lengthUnits(), True), '1.0000000 m') self.assertEqual(point_meter_result.toString(7), point_berlin_25833_project.toString(7)) if da_5665.sourceCrs().authid() != "": point_berlin_5665 = QgsPointXY(3389996.871728864, 5822169.719727578) point_berlin_5665_project = point_berlin_5665.project(1, (math.pi / 2)) length_meter_mapunits, point_meter_result = da_5665.measureLineProjected(point_berlin_5665, 1.0, (math.pi / 2)) print('-I-> Berlin 5665 length_meter_mapunits[{}] point_meter_result[{}]'.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_5665.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 1.0, da_5665.lengthUnits(), True), '1.0 m') self.assertEqual(point_meter_result.toString(7), point_berlin_5665_project.toString(7)) print('\n12 points ''above over'' and on the Equator') point_wsg84 = QgsPointXY(25.7844, 71.1725) point_wsg84_project = QgsPointXY(25.78442775215388, 71.17249999999795) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Nordkap, Norway - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, QgsUnitTypes.DistanceDegrees, True), '0.0000278 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(24.95995, 60.16841) point_wsg84_project = QgsPointXY(24.95996801277454, 60.16840999999877) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Helsinki, Finnland - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00001801 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(12.599278, 55.692861) point_wsg84_project = QgsPointXY(12.59929390161872, 55.69286099999897) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Copenhagen, Denmark - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00001590 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(-0.001389, 51.477778) point_wsg84_project = QgsPointXY(-0.001374606184398, 51.4777779999991) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Royal Greenwich Observatory, United Kingdom - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00001439 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(7.58769, 47.55814) point_wsg84_project = QgsPointXY(7.587703287209086, 47.55813999999922) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Basel, Switzerland - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00001329 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(11.255278, 43.775278) point_wsg84_project = QgsPointXY(11.25529042107924, 43.77527799999933) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Florenz, Italy - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00001242 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(14.514722, 35.899722) point_wsg84_project = QgsPointXY(14.51473307693308, 35.89972199999949) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Valletta, Malta - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00001108 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(-79.933333, 32.783333) point_wsg84_project = QgsPointXY(-79.93332232547254, 32.78333299999955) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Charlston, South Carolina - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00001067 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(-17.6666666, 27.733333) point_wsg84_project = QgsPointXY(-17.66665645831515, 27.73333299999962) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Ferro, Spain - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00001014 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(-99.133333, 19.433333) point_wsg84_project = QgsPointXY(-99.1333234776827, 19.43333299999975) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Mexico City, Mexico - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00000952 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(-79.894444, 9.341667) point_wsg84_project = QgsPointXY(-79.89443489691369, 9.341666999999882) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Colón, Panama - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00000910 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(-74.075833, 4.598056) point_wsg84_project = QgsPointXY(-74.07582398803629, 4.598055999999943) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Bogotá, Colombia - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00000901 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(0, 0) point_wsg84_project = QgsPointXY(0.000008983152841, 0) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Equator, Atlantic Ocean - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00000898 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) print('\n12 points ''down under'' and 1 point that should be considered invalid') point_wsg84 = QgsPointXY(-78.509722, -0.218611) point_wsg84_project = QgsPointXY(-78.50971301678221, -0.218610999999997) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Quito, Ecuador - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00000898 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(106.816667, -6.2) point_wsg84_project = QgsPointXY(106.8166760356519, -6.199999999999922) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Jakarta, Indonesia - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00000904 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(-77.018611, -12.035) point_wsg84_project = QgsPointXY(-77.01860181630058, -12.03499999999985) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Lima, Peru - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00000918 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(25.466667, -10.716667) point_wsg84_project = QgsPointXY(25.46667614155322, -10.71666699999986) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Kolwezi, Congo - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00000914 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(-70.333333, -18.483333) point_wsg84_project = QgsPointXY(-70.3333235314429, -18.48333299999976) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Arica, Chile - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00000947 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(-70.666667, -33.45) point_wsg84_project = QgsPointXY(-70.66665624452817, -33.44999999999953) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Santiago, Chile - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00001076 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(144.9604, -37.8191) point_wsg84_project = QgsPointXY(144.96041135746983741, -37.81909999999945171) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Melbourne, Australia - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00001136 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(147.29, -42.88) point_wsg84_project = QgsPointXY(147.2900122399815, -42.87999999999934) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Hobart City,Tasmania, Australia - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00001224 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(168.101667, -46.899722) point_wsg84_project = QgsPointXY(168.101680123673, -46.89972199999923) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Ryan''s Creek Aerodrome, New Zealand - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00001312 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(-69.216667, -51.633333) point_wsg84_project = QgsPointXY(-69.21665255700216, -51.6333329999991) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Río Gallegos, Argentina - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00001444 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(-68.3, -54.8) point_wsg84_project = QgsPointXY(-68.29998445081456, -54.79999999999899) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Ushuaia, Tierra del Fuego, Argentina - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00001555 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(-63.494444, -64.825278) point_wsg84_project = QgsPointXY(-63.49442294002932, -64.82527799999851) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Port Lockroy, Antarctica - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00002106 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(-180, -84.863272250) point_wsg84_project = QgsPointXY(-179.9999000000025, -84.8632722499922) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-I-> Someware, Antarctica - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00010000 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7)) point_wsg84 = QgsPointXY(-180, -85.0511300) point_wsg84_project = QgsPointXY(-179.9998962142197, -85.05112999999191) length_meter_mapunits, point_meter_result = da_wsg84.measureLineProjected(point_wsg84, 1.0, (math.pi / 2)) print('-W-> Mercator''s Last Stop, Antarctica - Wsg84 - length_meter_mapunits[{}] point_meter_result[{}] '.format(QgsDistanceArea.formatDistance(length_meter_mapunits, 7, da_wsg84.lengthUnits(), True), point_meter_result.asWkt())) self.assertEqual(QgsDistanceArea.formatDistance(length_meter_mapunits, 8, QgsUnitTypes.DistanceDegrees, True), '0.00010379 deg') self.assertEqual(point_meter_result.toString(7), point_wsg84_project.toString(7))
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT)) pointCount = self.parameterAsDouble(parameters, self.POINTS_NUMBER, context) minDistance = self.parameterAsDouble(parameters, self.MIN_DISTANCE, context) fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Point, source.sourceCrs()) if sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT)) nPoints = 0 nIterations = 0 maxIterations = pointCount * 200 featureCount = source.featureCount() total = 100.0 / pointCount if pointCount else 1 index = QgsSpatialIndex() points = dict() da = QgsDistanceArea() da.setSourceCrs(source.sourceCrs(), context.transformContext()) da.setEllipsoid(context.project().ellipsoid()) request = QgsFeatureRequest() random.seed() while nIterations < maxIterations and nPoints < pointCount: if feedback.isCanceled(): break # pick random feature fid = random.randint(0, featureCount - 1) f = next( source.getFeatures( request.setFilterFid(fid).setSubsetOfAttributes([]))) fGeom = f.geometry() if fGeom.isMultipart(): lines = fGeom.asMultiPolyline() # pick random line lineId = random.randint(0, len(lines) - 1) vertices = lines[lineId] else: vertices = fGeom.asPolyline() # pick random segment if len(vertices) == 2: vid = 0 else: vid = random.randint(0, len(vertices) - 2) startPoint = vertices[vid] endPoint = vertices[vid + 1] length = da.measureLine(startPoint, endPoint) dist = length * random.random() if dist > minDistance: d = dist / (length - dist) rx = (startPoint.x() + d * endPoint.x()) / (1 + d) ry = (startPoint.y() + d * endPoint.y()) / (1 + d) # generate random point p = QgsPointXY(rx, ry) geom = QgsGeometry.fromPointXY(p) if vector.checkMinDistance(p, index, minDistance, points): f = QgsFeature(nPoints) f.initAttributes(1) f.setFields(fields) f.setAttribute('id', nPoints) f.setGeometry(geom) sink.addFeature(f, QgsFeatureSink.FastInsert) index.insertFeature(f) points[nPoints] = p nPoints += 1 feedback.setProgress(int(nPoints * total)) nIterations += 1 if nPoints < pointCount: feedback.pushInfo( self.tr( 'Could not generate requested number of random points. ' 'Maximum number of attempts exceeded.')) return {self.OUTPUT: dest_id}
def processAlgorithm(self, context, feedback): layer = QgsProcessingUtils.mapLayerFromString( self.getParameterValue(self.INPUT_LAYER), context) fieldName = self.getParameterValue(self.FIELD_NAME) fieldType = self.TYPES[self.getParameterValue(self.FIELD_TYPE)] width = self.getParameterValue(self.FIELD_LENGTH) precision = self.getParameterValue(self.FIELD_PRECISION) newField = self.getParameterValue(self.NEW_FIELD) formula = self.getParameterValue(self.FORMULA) output = self.getOutputFromName(self.OUTPUT_LAYER) fields = layer.fields() if newField: fields.append(QgsField(fieldName, fieldType, '', width, precision)) writer = output.getVectorWriter(fields, layer.wkbType(), layer.crs(), context) exp = QgsExpression(formula) da = QgsDistanceArea() da.setSourceCrs(layer.crs()) da.setEllipsoid(QgsProject.instance().ellipsoid()) exp.setGeomCalculator(da) exp.setDistanceUnits(QgsProject.instance().distanceUnits()) exp.setAreaUnits(QgsProject.instance().areaUnits()) exp_context = QgsExpressionContext( QgsExpressionContextUtils.globalProjectLayerScopes(layer)) if not exp.prepare(exp_context): raise GeoAlgorithmExecutionException( self.tr('Evaluation error: {0}').format(exp.evalErrorString())) outFeature = QgsFeature() outFeature.initAttributes(len(fields)) outFeature.setFields(fields) error = '' calculationSuccess = True features = QgsProcessingUtils.getFeatures(layer, context) total = 100.0 / QgsProcessingUtils.featureCount(layer, context) rownum = 1 for current, f in enumerate(features): rownum = current + 1 exp_context.setFeature(f) exp_context.lastScope().setVariable("row_number", rownum) value = exp.evaluate(exp_context) if exp.hasEvalError(): calculationSuccess = False error = exp.evalErrorString() break else: outFeature.setGeometry(f.geometry()) for fld in f.fields(): outFeature[fld.name()] = f[fld.name()] outFeature[fieldName] = value writer.addFeature(outFeature) feedback.setProgress(int(current * total)) del writer if not calculationSuccess: raise GeoAlgorithmExecutionException( self.tr('An error occurred while evaluating the calculation ' 'string:\n{0}').format(error))
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT)) method = self.parameterAsEnum(parameters, self.METHOD, context) wkb_type = source.wkbType() fields = source.fields() new_fields = QgsFields() if QgsWkbTypes.geometryType(wkb_type) == QgsWkbTypes.PolygonGeometry: new_fields.append(QgsField('area', QVariant.Double)) new_fields.append(QgsField('perimeter', QVariant.Double)) elif QgsWkbTypes.geometryType(wkb_type) == QgsWkbTypes.LineGeometry: new_fields.append(QgsField('length', QVariant.Double)) if not QgsWkbTypes.isMultiType(source.wkbType()): new_fields.append(QgsField('straightdis', QVariant.Double)) new_fields.append(QgsField('sinuosity', QVariant.Double)) else: new_fields.append(QgsField('xcoord', QVariant.Double)) new_fields.append(QgsField('ycoord', QVariant.Double)) if QgsWkbTypes.hasZ(source.wkbType()): self.export_z = True new_fields.append(QgsField('zcoord', QVariant.Double)) if QgsWkbTypes.hasM(source.wkbType()): self.export_m = True new_fields.append(QgsField('mvalue', QVariant.Double)) fields = QgsProcessingUtils.combineFields(fields, new_fields) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, wkb_type, source.sourceCrs()) if sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT)) coordTransform = None # Calculate with: # 0 - layer CRS # 1 - project CRS # 2 - ellipsoidal self.distance_area = QgsDistanceArea() if method == 2: self.distance_area.setSourceCrs(source.sourceCrs(), context.transformContext()) self.distance_area.setEllipsoid(context.project().ellipsoid()) elif method == 1: coordTransform = QgsCoordinateTransform(source.sourceCrs(), context.project().crs(), context.project()) features = source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break outFeat = f attrs = f.attributes() inGeom = f.geometry() if inGeom: if coordTransform is not None: inGeom.transform(coordTransform) if inGeom.type() == QgsWkbTypes.PointGeometry: attrs.extend(self.point_attributes(inGeom)) elif inGeom.type() == QgsWkbTypes.PolygonGeometry: attrs.extend(self.polygon_attributes(inGeom)) else: attrs.extend(self.line_attributes(inGeom)) # ensure consistent count of attributes - otherwise null # geometry features will have incorrect attribute length # and provider may reject them if len(attrs) < len(fields): attrs += [NULL] * (len(fields) - len(attrs)) outFeat.setAttributes(attrs) sink.addFeature(outFeat, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}