Ejemplo n.º 1
0
    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(QgsCoordinateReferenceSystem.fromSrsId(3452), QgsProject.instance().transformContext())
        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(QgsPointXY(1, 1), QgsPointXY(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(QgsPointXY(1, 1), QgsPointXY(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(QgsCoordinateReferenceSystem.fromSrsId(27469), QgsProject.instance().transformContext())
        da.setEllipsoid("NONE")
        # measurement should be in feet
        distance = da.measureLine(QgsPointXY(1, 1), QgsPointXY(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.setEllipsoid("WGS84")
        # now should be in Meters again
        distance = da.measureLine(QgsPointXY(1, 1), QgsPointXY(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)
Ejemplo n.º 2
0
    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")
        daCRS = QgsCoordinateReferenceSystem()
        daCRS.createFromSrsId(da.sourceCrs())

        # 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 == QGis.Degrees) or
                (abs(distance - 248.52) < 0.01 and units == QGis.Meters))

        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 == QGis.Degrees) or
                (abs(distance - 248.52) < 0.01 and units == QGis.Meters))

        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, QGis.Meters)

        # 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, QGis.Feet)

        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, QGis.Meters)
Ejemplo n.º 3
0
 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, [])
Ejemplo n.º 4
0
    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}
Ejemplo n.º 5
0
    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))
Ejemplo n.º 6
0
def measurePerimeter(geom):
    measure = QgsDistanceArea()
    value = 0.00
    polygon = geom.asPolygon()
    for line in polygon:
        value += measure.measureLine(line)
    return value
Ejemplo n.º 7
0
    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))
Ejemplo n.º 8
0
    def processAlgorithm(self, parameters, context, feedback):
        layerPoints = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.POINTS), context)
        layerHubs = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.HUBS), context)
        fieldName = self.getParameterValue(self.FIELD)

        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(),
                                                                     context)

        index = QgsProcessingUtils.createSpatialIndex(layerHubs, context)

        distance = QgsDistanceArea()
        distance.setSourceCrs(layerPoints.crs())
        distance.setEllipsoid(QgsProject.instance().ellipsoid())

        # Scan source points, find nearest hub, and write to output file
        features = QgsProcessingUtils.getFeatures(layerPoints, context)
        total = 100.0 / layerPoints.featureCount() if layerPoints.featureCount() else 0
        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, QgsFeatureSink.FastInsert)
            feedback.setProgress(int(current * total))

        del writer
Ejemplo n.º 9
0
	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 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
Ejemplo n.º 11
0
    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}
Ejemplo n.º 12
0
    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 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]))
Ejemplo n.º 14
0
    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))
Ejemplo n.º 15
0
    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]))
Ejemplo n.º 16
0
    def calculate_accuracy(self, polygon_layer, point_layer):
        """
        Calculate the distance of each centroid on a point-layer to their surrounding polygons
        :param polygon_layer: A layer containing polygons
        :type polygon_layer: QgsVectorLayer
        :param point_layer: A layer containing the (supposed to be) centroids of that polygon
        :type point_layer: QgsVectorLayer
        :return:
        :rtype:
        """
        point_provider = point_layer.dataProvider()
        add_attributes_if_not_exists(point_layer, [QgsField('DIST', QtCore.QVariant.Double)])

        distance_area = QgsDistanceArea()
        poly_iterator = polygon_layer.dataProvider().getFeatures()
        point_iterator = point_provider.getFeatures()
        poly_feature = QgsFeature()
        point_feature = QgsFeature()
        field_index = point_provider.fieldNameIndex('DIST')

        while (poly_iterator.nextFeature(poly_feature) and
               point_iterator.nextFeature(point_feature)):
            geom= poly_feature.geometry()
            if geom is not None:
                try:
                        poly_point = geom.asPolygon()[0]
                        centroid = geom.asPoint()
                except IndexError:
                    continue
                distances = {}
                for i, point in enumerate(poly_point):
                    end = poly_point[(i+1) % len(poly_point)]
                    try:
                        intersect = self.intersect_point_to_line(centroid, point, end)
                        if intersect != centroid:
                            dist = distance_area.measureLine(centroid, intersect)
                            distances[intersect] = dist
                    except ZeroDivisionError as InvalidMath:
                        continue
                values = {field_index: min(distances.values())}
                point_provider.changeAttributeValues({point_feature.id(): values})
Ejemplo n.º 17
0
    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.addFeature(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}
Ejemplo n.º 18
0
    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
Ejemplo n.º 19
0
    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.setEllipsoidalMode(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)
        myPen = QtGui.QPen()
        myPen.setColor(QtGui.QColor(255, 255, 255))
        myPen.setWidthF(myLineWidth)
        myRect.setPen(myPen)
        #myRect.setLineWidth(myLineWidth)
        myRect.setFrameEnabled(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)
        myPen = QtGui.QPen()
        myPen.setColor(QtGui.QColor(255, 255, 255))
        myPen.setWidthF(myLineWidth)
        myRect.setPen(myPen)
        #myRect.setLineWidth(myLineWidth)
        myRect.setFrameEnabled(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)
            myPen = QtGui.QPen()
            myPen.setWidthF(myLineWidth)
            myUpTickLine.setPen(myPen)
            #myUpTickLine.setLineWidth(myLineWidth)
            myUpTickLine.setFrameEnabled(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.setFrameEnabled(self.showFramesFlag)
            self.composition.addItem(myLabel)
Ejemplo n.º 20
0
class PositionMarker(QgsMapCanvasItem):
    '''
    MapCanvasItem for showing the MobileItem on the MapCanvas
    Can have different appearences, fixed ones like corss, x or box
    or a userdefined shape.
    Can display also a label on the canvas
    '''

    MIN_SIZE = 30
    CIRLCE_SIZE = 30

    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.showLabel = bool(params.get('showLabel', True))
        s = (self.size - 1) / 2
        self.length = float(params.get('length', 98.0))
        self.width = float(params.get('width', 17.0))
        self.offsetX = float(params.get('offsetX', 0.0))
        self.offsetY = float(params.get('offsetY', 0.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)))
        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.defaultIcon = bool(params.get('defaultIcon', True))
        self.defaultIconFilled = bool(params.get('defaultIconFilled', False))
        self.paintCircle = False
        self.penWidth = int(params.get('penWidth', 1))
        spw = s + self.penWidth + 1
        self.bounding = QRectF(-spw, -spw, spw * 2, spw * 2)
        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.position = None
        self.heading = 0
        self.northAlign = 0.0
        super(PositionMarker, self).__init__(canvas)
        self.setZValue(int(params.get('zValue', 100)))
        self.distArea = QgsDistanceArea()
        self.distArea.setEllipsoid(u'WGS84')
        if self.showLabel:
            self.label = MarkerLabel(self.canvas, params)
            self.label.setZValue(self.zValue() + 0.1)
        self.updateSize()

    def properties(self):
        return {
            'type': self.type,
            'size': self.size,
            'length': self.length,
            'width': self.width,
            'defaultIcon': self.defaultIcon,
            'defaultIconFilled': self.defaultIconFilled,
            'offsetX': self.offsetX,
            'offsetY': self.offsetY,
            'shape': self.shape,
            'color': self.color.rgba(),
            'fillColor': self.fillColor.rgba(),
            'penWidth': self.penWidth,
            'trackLength': self.trackLen,
            'trackColor': self.trackColor.rgba(),
            'zValue': self.zValue(),
            'showLabel': self.showLabel
        }

    def setMapPosition(self, pos):
        if self.position != pos:
            self.updateTrack()
            self.position = pos
            self.setPos(self.toCanvasCoordinates(self.position))
            if self.showLabel:
                self.label.setMapPosition(pos)
            self.update()

    def newHeading(self, heading):
        if self.heading != heading:
            self.heading = heading
            self.setRotation(self.canvas.rotation() + self.heading -
                             self.northAlign)
            self.update()

    def resetPosition(self):
        self.position = None
        if self.showLabel:
            self.label.resetPosition()

    def updatePosition(self):
        if self.position:
            self.prepareGeometryChange()
            self.updateSize()
            self.setPos(self.toCanvasCoordinates(self.position))
            self.setRotation(self.canvas.rotation() + self.heading -
                             self.northAlign)

    def updateMapMagnification(self):
        self.updatePosition()
        if self.showLabel:
            self.label.updatePosition()
        for tp in self.track:
            tp[0].updatePosition()

    def updateSize(self):
        if self.type != 'SHAPE':
            return
        s = self.canvas.mapSettings()
        self.distArea.setSourceCrs(s.destinationCrs(),
                                   QgsProject.instance().transformContext())
        try:
            if self.position:
                p1 = self.position
                p = self.toCanvasCoordinates(self.position)
                p2 = self.toMapCoordinates(QPoint(p.x(), p.y() + 100.0))
            else:
                p = self.canvas.viewport().rect().center()
                p1 = self.toMapCoordinates(p)
                p2 = self.toMapCoordinates(QPoint(p.x(), p.y() + 100))
            lngth = self.distArea.measureLine(p1, p2)
            f = 100.0 / lngth
            self.northAlign = fmod(
                self.distArea.bearing(p2, p1) * 180.0 / pi +
                self.canvas.rotation(), 360.0)
        except Exception:
            f = s.outputDpi() / 0.0254 / s.scale()
        paintLength = max(self.length * f, self.MIN_SIZE)
        paintWidth = paintLength * self.width / self.length
        offsY = self.offsetX / self.length * paintLength
        offsX = self.offsetY / self.width * paintWidth
        self.paintShape.clear()
        if (self.length * f) < self.MIN_SIZE and self.defaultIcon:
            self.paintCircle = True
            self.bounding = QRectF(-self.CIRLCE_SIZE * 0.5,
                                   -self.CIRLCE_SIZE - 2, self.CIRLCE_SIZE,
                                   self.CIRLCE_SIZE * 1.5)
        else:
            self.paintCircle = False
            for v in self.shape:
                self.paintShape << QPointF(v[0] * paintWidth - offsX,
                                           v[1] * paintLength + offsY)
            self.bounding = self.paintShape.boundingRect()
        self.size = max(paintLength, paintWidth)

    def newTrackPoint(self, pos):
        tp = QgsVertexMarker(self.canvas)
        tp.setCenter(pos)
        tp.setIconType(QgsVertexMarker.ICON_CROSS)
        tp.setColor(self.trackColor)
        tp.setZValue(self.zValue() - 0.1)
        tp.setIconSize(3)
        tp.setPenWidth(3)
        return tp

    def updateTrack(self):
        if self.position and self.trackLen:
            if len(self.track) >= self.trackLen:
                tpr = self.track.popleft()
                self.canvas.scene().removeItem(tpr[0])
                del (tpr)
            tp = self.newTrackPoint(self.position)
            self.track.append((tp, self.position))

    def setVisible(self, visible):
        for tp in self.track:
            tp[0].setVisible(visible)
        QgsMapCanvasItem.setVisible(self, visible)
        if self.showLabel:
            self.label.setVisible(visible)

    def deleteTrack(self):
        for tp in self.track:
            self.canvas.scene().removeItem(tp[0])
        self.track.clear()

    def setTrack(self, track):
        self.track.clear()
        for tp in track:
            tpn = self.newTrackPoint(tp)
            self.track.append((tpn, tp))

    def paint(self, painter, xxx, xxx2):
        if not self.position:
            return

        s = (self.size - 1) / 2
        pen = QPen(self.color)
        pen.setWidth(self.penWidth)
        painter.setPen(pen)
        painter.setRenderHint(QPainter.Antialiasing, True)
        if self.type == 'CROSS':
            painter.drawLine(QLineF(-s, 0, s, 0))
            painter.drawLine(QLineF(0, -s, 0, s))
        elif self.type == 'X':
            painter.drawLine(QLineF(-s, -s, s, s))
            painter.drawLine(QLineF(-s, s, s, -s))
        elif self.type == 'BOX':
            brush = QBrush(self.fillColor)
            painter.setBrush(brush)
            painter.drawConvexPolygon(self.paintShape)
        elif self.type == 'SHAPE':
            if self.paintCircle:
                pen.setWidth(self.penWidth * 2)
                if self.defaultIconFilled:
                    brush = QBrush(self.fillColor)
                    painter.setBrush(brush)
                painter.setPen(pen)
                painter.drawEllipse(QPointF(0, 0), self.CIRLCE_SIZE * 0.4,
                                    self.CIRLCE_SIZE * 0.4)
                painter.drawLine(
                    QLineF(0, -self.CIRLCE_SIZE * 0.4, 0, -self.CIRLCE_SIZE))
            else:
                brush = QBrush(self.fillColor)
                painter.setBrush(brush)
                painter.drawConvexPolygon(self.paintShape)

    def boundingRect(self):
        return self.bounding

    def getColor(self, value):
        try:
            return QColor.fromRgba(int(value))
        except ValueError:
            return QColor(value)

    def removeFromCanvas(self):
        self.deleteTrack()
        if self.showLabel:
            self.canvas.scene().removeItem(self.label)
        self.canvas.scene().removeItem(self)
Ejemplo n.º 21
0
    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"))

        fields = layerPoints.fields()
        fields.append(QgsField("HubName", QVariant.String))
        fields.append(QgsField("HubDist", QVariant.Double))

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, QgsWkbTypes.Point, layerPoints.crs())

        index = vector.spatialindex(layerHubs)

        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()

            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.fromPoint(src))

            writer.addFeature(feat)
            progress.setPercentage(int(current * total))

        del writer
Ejemplo n.º 22
0
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]
Ejemplo n.º 23
0
    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")
        daCRS = QgsCoordinateReferenceSystem()
        daCRS.createFromSrsId(da.sourceCrs())

        # 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 == QGis.Degrees)
                or (abs(distance - 248.52) < 0.01 and units == QGis.Meters))

        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 == QGis.Degrees)
                or (abs(distance - 248.52) < 0.01 and units == QGis.Meters))

        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, QGis.Meters)

        # test converting the resultant length
        distance = da.convertLengthMeasurement(distance, QGis.NauticalMiles)
        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, QGis.Feet)

        # test converting the resultant length
        distance = da.convertLengthMeasurement(distance, QGis.Meters)
        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, QGis.Meters)

        # test converting the resultant length
        distance = da.convertLengthMeasurement(distance, QGis.Feet)
        self.assertAlmostEqual(distance, 2.2294, delta=0.001)
Ejemplo n.º 24
0
    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())

        index = vector.spatialindex(layerHubs)

        distance = QgsDistanceArea()
        distance.setSourceCrs(layerPoints.crs().srsid())
        distance.setEllipsoidalMode(True)
        project_ellipsoid = QgsProject.instance().readEntry('Measure', '/Ellipsoid',
                                                            'NONE')[0]
        distance.setEllipsoid(project_ellipsoid)

        # Scan source points, find nearest hub, and write to output file
        features = vector.features(layerPoints)
        total = 100.0 / len(features) if len(features) > 0 else 1
        for current, f in enumerate(features):
            src = f.geometry().boundingBox().center()

            neighbors = index.nearestNeighbor(src, 1)
            ft = layerHubs.getFeatures(QgsFeatureRequest().setFilterFid(neighbors[0])).next()
            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)

            if geomType == QGis.WKBPoint:
                feat.setGeometry(QgsGeometry.fromPoint(src))
            else:
                feat.setGeometry(QgsGeometry.fromPolyline([src, closest]))

            writer.addFeature(feat)
            progress.setPercentage(int(current * total))

        del writer
Ejemplo n.º 25
0
    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}
Ejemplo n.º 26
0
    def processAlgorithm(self, feedback):
        layer = dataobjects.getLayerFromString(
            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
Ejemplo n.º 27
0
    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'))

        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().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()

            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)
            progress.setPercentage(int(current * total))

        del writer
Ejemplo n.º 28
0
    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}
Ejemplo n.º 29
0
    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.addFeature(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}
Ejemplo n.º 30
0
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]
Ejemplo n.º 31
0
    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}
Ejemplo n.º 32
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.VECTOR))
        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())

        points = dict()
        features = vector.features(layer)
        total = 100.0 / len(features)
        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)]

            progress.setPercentage(int(current * total))

        progress.setPercentage(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)

            fl = open(fileName, 'w')
            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
            progress.setPercentage(int(current * total))

        del writer
        fl.close()
Ejemplo n.º 33
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        if source is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

        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.attributes()[group_field_index]
            else:
                group = 1
            order = f.attributes()[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.project().ellipsoid())

        current = 0
        total = 100.0 / len(points) if points else 1
        for group, vertices in list(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 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}
Ejemplo n.º 34
0
    def drawScaleBar(self, theComposerMap, theTopOffset):
        """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 scalebar for a geographic map in km.

        .. seealso:: :meth:`drawNativeScaleBar`

        Args:
            * theComposerMap - QgsComposerMap instance used as the basis
              scale calculations.
            * theTopOffset - vertical offset at which the map should be drawn
        Returns:
            None
        Raises:
            Any exceptions raised by the InaSAFE library will be propagated.
        """
        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 = theComposerMap.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 = (theTopOffset + 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)
Ejemplo n.º 35
0
    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
Ejemplo n.º 36
0
 def getDistance(self, geomOne, geomTwo):
     distance = QgsDistanceArea()
     distance.setEllipsoid('WGS84')
     m = round(distance.measureLine(geomOne, geomTwo), 2)
     return m
Ejemplo n.º 37
0
class PositionMarker(QgsMapCanvasItem):
    '''
    classdocs
    '''

    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 properties(self):
        return {'type': self.type,
                'size': self.size,
                'length': self.length,
                'width': self.width,
                'shape': self.shape,
                'color': self.color.rgba(),
                'fillColor': self.fillColor.rgba(),
                'penWidth': self.penWidth,
                'trackLength': self.trackLen,
                'trackColor' : self.trackColor.rgba(),
                'zValue': self.zValue()}

    def setMapPosition(self, pos):
        if self.pos != pos:
            self.updateTrack()
            self.pos = pos
            self.setPos(self.toCanvasCoordinates(self.pos))
            self.update()

    def newHeading(self, heading):
        if self.heading != heading:
            self.heading = heading
            self.setRotation(self.canvas.rotation() + self.heading)
            self.update()

    def resetPosition(self):
        self.pos = None

    def updatePosition(self):
        if self.pos:
            self.prepareGeometryChange()
            self.updateSize()
            self.setPos(self.toCanvasCoordinates(self.pos))
            self.setRotation(self.canvas.rotation() + self.heading)
            self.update()

    def updateSize(self):
        if self.type != 'SHAPE':
            return
        s = self.canvas.mapSettings()
        self.distArea.setSourceCrs(s.destinationCrs())
        try:
            p1 = self.toMapCoordinates(QPoint(0, 0))
            p2 = self.toMapCoordinates(QPoint(0, 100))
            l = self.distArea.measureLine(p1, p2)
            f = 100 / l
        except:
            f = s.outputDpi() / 0.0254 / s.scale()
        paintLength = max(self.length * f, 50)
        paintWidth = paintLength * self.width / self.length
        self.paintShape.clear()
        for v in self.shape:
            self.paintShape << QPointF(v[0] * paintWidth, v[1] * paintLength)
        self.size = max(paintLength, paintWidth)
        self.bounding = sqrt(pow(paintLength, 2) + pow(paintLength, 2))

    def updateTrack(self):
        if self.pos and self.trackLen:
            if len(self.track) >= self.trackLen:
                tpr = self.track.popleft()
                self.canvas.scene().removeItem(tpr)
                del(tpr)
            tp = QgsVertexMarker(self.canvas)
            tp.setCenter(self.pos)
            tp.setIconType(QgsVertexMarker.ICON_CROSS)
            tp.setColor(self.trackColor)
            tp.setZValue(self.zValue() - 0.1)
            tp.setIconSize(3)
            tp.setPenWidth(3)
            self.track.append(tp)

    def setVisible(self, visible):
        for tp in self.track:
            tp.setVisible(visible)
        QgsMapCanvasItem.setVisible(self, visible)

    def deleteTrack(self):
        for tp in self.track:
            self.canvas.scene().removeItem(tp)
        self.track.clear()

    def paint(self, painter, xxx, xxx2):
        if not self.pos:
            return

        s = (self.size - 1) / 2
        pen = QPen(self.color)
        pen.setWidth(self.penWidth)
        painter.setPen(pen)
        if self.type == 'CROSS':
            painter.drawLine(QLineF(-s, 0, s, 0))
            painter.drawLine(QLineF(0, -s, 0, s))
        elif self.type == 'X':
            painter.drawLine(QLineF(-s, -s, s, s))
            painter.drawLine(QLineF(-s, s, s, -s))
        elif self.type == 'BOX':
            brush = QBrush(self.fillColor)
            painter.setBrush(brush)
            painter.drawConvexPolygon(self.paintShape)
        elif self.type == 'SHAPE':
            painter.setRenderHint(QPainter.Antialiasing, True)
            brush = QBrush(self.fillColor)
            painter.setBrush(brush)
            painter.drawConvexPolygon(self.paintShape)

    def boundingRect(self):
        s = self.bounding / 2
        return QRectF(QPointF(-s, -s), QPointF(s, s))

    def getColor(self, value):
        try:
            return QColor.fromRgba(int(value))
        except ValueError:
            return QColor(value)

    def removeFromCanvas(self):
        self.deleteTrack()
        self.canvas.scene().removeItem(self)
Ejemplo n.º 38
0
    def processAlgorithm(self, feedback):
        layer = dataobjects.getLayerFromString(
            self.getParameterValue(self.VECTOR))
        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())

        points = dict()
        features = vector.features(layer)
        total = 100.0 / len(features)
        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
Ejemplo n.º 39
0
    def processAlgorithm(self, context, feedback):
        layerPoints = QgsProcessingUtils.mapLayerFromString(
            self.getParameterValue(self.POINTS), context)
        layerHubs = QgsProcessingUtils.mapLayerFromString(
            self.getParameterValue(self.HUBS), context)
        fieldName = self.getParameterValue(self.FIELD)

        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.Point, layerPoints.crs(), context)

        index = QgsProcessingUtils.createSpatialIndex(layerHubs, context)

        distance = QgsDistanceArea()
        distance.setSourceCrs(layerPoints.crs())
        distance.setEllipsoid(QgsProject.instance().ellipsoid())

        # Scan source points, find nearest hub, and write to output file
        features = QgsProcessingUtils.getFeatures(layerPoints, context)
        total = 100.0 / QgsProcessingUtils.featureCount(layerPoints, context)
        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.fromPoint(src))

            writer.addFeature(feat)
            feedback.setProgress(int(current * total))

        del writer
Ejemplo n.º 40
0
class MeasureDistanceTool(QgsMapTool):
    finished = pyqtSignal()

    def __init__(self, canvas, msglog):
        super().__init__(canvas)
        self.canvas = canvas
        self.msglog = msglog
        self.start_point = self.end_point = None
        self.rubber_band = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry)
        self.rubber_band.setColor(QColor(255, 0, 0, 100))
        self.rubber_band.setWidth(3)
        self.rubber_band_points = QgsRubberBand(self.canvas,
                                                QgsWkbTypes.PointGeometry)
        self.rubber_band_points.setIcon(QgsRubberBand.ICON_CIRCLE)
        self.rubber_band_points.setIconSize(10)
        self.rubber_band_points.setColor(QColor(255, 0, 0, 150))
        crs = self.canvas.mapSettings().destinationCrs()
        self.distance_calc = QgsDistanceArea()
        self.distance_calc.setSourceCrs(
            crs,
            QgsProject.instance().transformContext())
        self.distance_calc.setEllipsoid(crs.ellipsoidAcronym())
        self.reset()

    def reset(self):
        self.msglog.logMessage("")
        self.start_point = self.end_point = None
        self.rubber_band.reset(QgsWkbTypes.LineGeometry)
        self.rubber_band_points.reset(QgsWkbTypes.PointGeometry)

    def canvasPressEvent(self, event):
        pass

    def canvasReleaseEvent(self, event):
        transform = self.canvas.getCoordinateTransform()
        point = transform.toMapCoordinates(event.pos().x(), event.pos().y())
        if self.start_point:
            self.end_point = point
            self.rubber_band.addPoint(self.end_point)
            self.rubber_band_points.addPoint(self.end_point)
            distance = self.distance_calc.measureLine(
                [self.start_point, self.end_point])
            bearing = self.distance_calc.bearing(self.start_point, point)
            distancemsg = QMessageBox(self.parent())
            distancemsg.finished.connect(self.deactivate)
            distancemsg.setWindowTitle("Measure tool")
            distancemsg.setText("Distance: {:.3F} m. Bearing: {:.3F} º".format(
                distance, degrees(bearing)))
            distancemsg.exec()
            self.finish()

        else:
            self.start_point = point
            self.rubber_band.addPoint(self.start_point)
            self.rubber_band_points.addPoint(self.start_point)

    def canvasMoveEvent(self, e):
        if self.start_point and not self.end_point:
            transform = self.canvas.getCoordinateTransform()
            point = transform.toMapCoordinates(e.pos().x(), e.pos().y())
            self.rubber_band.movePoint(point)
            distance = self.distance_calc.measureLine(
                [self.start_point, point])
            bearing = self.distance_calc.bearing(self.start_point, point)
            self.msglog.logMessage("")
            self.msglog.logMessage(
                "Current distance: {:.3F} m. Bearing: {:.3F} º".format(
                    distance, degrees(bearing)), "Measure distance:", 0)

    def keyPressEvent(self, event):
        """
        When escape key is pressed, line is restarted
        """
        if event.key() == Qt.Key_Escape:
            self.reset()

    def finish(self):
        self.reset()
        self.finished.emit()
Ejemplo n.º 41
0
    def point2nb(self):
        lst = []
        # geoms = [geom.geometry() for geom in self.lyr.getFeatures()
        # feats = self.lyr.getFeatures()
        # for f1, f2 in itertools.product(feats, repeat=2):
        #     if f1!=f2:
        #         d = f1.geometry().asPoint().distance(f2.geometry().asPoint())
        #         self.plainTextEdit.insertPlainText("%s %s: %s\n" % (f1.id(), f2.id(), d))

        featA = QgsFeature()
        featsA = self.lyr.getFeatures()
        trh = float(self.lineEdit.text())

        if self.comboBox_6.currentText() == 'km':
            # psrid = self.iface.mapCanvas().mapRenderer().destinationCrs().srsid()
            prv = self.lyr.dataProvider()
            psrid = prv.crs().srsid()

            dist = QgsDistanceArea()
            dist.setEllipsoid('WGS84')
            dist.setEllipsoidalMode(True)

            # self.plainTextEdit.insertPlainText("%s\n" % psrid)

            if psrid != 3452:
                trafo = QgsCoordinateTransform(psrid, 3452)
                while featsA.nextFeature(featA):
                    featB = QgsFeature()
                    featsB = self.lyr.getFeatures()
                    sor = []
                    while featsB.nextFeature(featB):
                        if featA.id() != featB.id():
                            tav = dist.measureLine(trafo.transform(featA.geometry().asPoint()),
                                                   trafo.transform(featB.geometry().asPoint()))
                            # self.plainTextEdit.insertPlainText("%s %s %s\n" % (featA.id(), featB.id(), tav))
                            if (tav / 1000.0) <= trh:
                                sor.append(featB.id())
                    lst.append(sor)
            else:
                while featsA.nextFeature(featA):
                    featB = QgsFeature()
                    featsB = self.lyr.getFeatures()
                    sor = []
                    while featsB.nextFeature(featB):
                        if featA.id() != featB.id():
                            tav = dist.measureLine(featA.geometry().asPoint(), featB.geometry().asPoint())
                            # self.plainTextEdit.insertPlainText("%s %s %s\n" % (featA.id(), featB.id(), tav))
                            if (tav / 1000.0) <= trh:
                                sor.append(featB.id())
                    lst.append(sor)
        else:
            while featsA.nextFeature(featA):
                featB = QgsFeature()
                featsB = self.lyr.getFeatures()
                sor = []
                while featsB.nextFeature(featB):
                    if featA.id() != featB.id():
                        tav = featA.geometry().asPoint().distance(featB.geometry().asPoint())
                        # self.plainTextEdit.insertPlainText("%s %s %s\n" % (featA.id(), featB.id(), tav))
                        if tav <= trh:
                            sor.append(featB.id())
                lst.append(sor)

        # self.plainTextEdit.insertPlainText("%s\n" % lst)
        return lst
Ejemplo n.º 42
0
    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}
Ejemplo n.º 43
0
class GuidanceDock(QtGui.QDockWidget, FORM_CLASS):
    '''
    classdocs
    '''

    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 setUtcClock(self):
        if self.showUtc:
            if not self.timer:
                self.timer = self.startTimer(1000)
            self.frameUtcClock.show()
        else:
            self.frameUtcClock.hide()
            self.killTimer(self.timer)
            self.timer = 0

    def setMobiles(self, mobiles):
        self.reset()
        self.mobiles = mobiles
        self.comboBoxSource.blockSignals(True)
        self.comboBoxTarget.blockSignals(True)
        self.comboBoxSource.clear()
        self.comboBoxSource.addItems(sorted(mobiles.keys()))
        self.comboBoxSource.setCurrentIndex(-1)
        self.comboBoxTarget.clear()
        self.comboBoxTarget.addItems(sorted(mobiles.keys()))
        self.comboBoxTarget.setCurrentIndex(-1)
        self.comboBoxSource.blockSignals(False)
        self.comboBoxTarget.blockSignals(False)
        s = QSettings()
        m = s.value('PosiView/Guidance/Source')
        if m in self.mobiles:
            self.comboBoxSource.setCurrentIndex(self.comboBoxSource.findText(m))
        m = s.value('PosiView/Guidance/Target')
        if m in self.mobiles:
            self.comboBoxTarget.setCurrentIndex(self.comboBoxTarget.findText(m))
        self.showUtc = s.value('PosiView/Misc/ShowUtcClock', defaultValue=False, type=bool)
        self.setUtcClock()

    @pyqtSlot(name='on_pushButtonFormat_clicked')
    def switchCoordinateFormat(self):
        self.format = (self.format + 1) % 3
        s = QSettings()
        s.setValue('PosiView/Guidance/Format', self.format)
        if self.trgPos[0]:
            lon, lat = self.posToStr(self.trgPos[0])
            self.labelTargetLat.setText(lat)
            self.labelTargetLon.setText(lon)
        if self.srcPos[0]:
            lon, lat = self.posToStr(self.srcPos[0])
            self.labelSourceLat.setText(lat)
            self.labelSourceLon.setText(lon)

    def posToStr(self, pos):
        if self.format == 0:
            return "{:.6f}".format(pos.x()), "{:.6f}".format(pos.y())
        if self.format == 1:
            return pos.toDegreesMinutes(4, True, True).split(',')
        if self.format == 2:
            return pos.toDegreesMinutesSeconds(2, True, True).split(',')

    @pyqtSlot(str, name='on_comboBoxSource_currentIndexChanged')
    def sourceChanged(self, mob):
        if self.source is not None:
            try:
                self.source.newPosition.disconnect(self.onNewSourcePosition)
                self.source.newAttitude.disconnect(self.onNewSourceAttitude)
            except TypeError:
                pass

        try:
            self.source = self.mobiles[mob]
            self.source.newPosition.connect(self.onNewSourcePosition)
            self.source.newAttitude.connect(self.onNewSourceAttitude)
            s = QSettings()
            s.setValue('PosiView/Guidance/Source', mob)
        except KeyError:
            self.source = None
        self.resetSource()

    @pyqtSlot(str, name='on_comboBoxTarget_currentIndexChanged')
    def targetChanged(self, mob):
        if self.target is not None:
            try:
                self.target.newPosition.disconnect(self.onNewTargetPosition)
                self.target.newAttitude.disconnect(self.onNewTargetAttitude)
            except TypeError:
                pass
        try:
            self.target = self.mobiles[mob]
            self.target.newPosition.connect(self.onNewTargetPosition)
            self.target.newAttitude.connect(self.onNewTargetAttitude)
            s = QSettings()
            s.setValue('PosiView/Guidance/Target', mob)
        except KeyError:
            self.target = None
        self.resetTarget()

    @pyqtSlot(float, QgsPoint, float, float)
    def onNewSourcePosition(self, fix, pos, depth, altitude):
        if [pos, depth] != self.srcPos:
            lon, lat = self.posToStr(pos)
            self.labelSourceLat.setText(lat)
            self.labelSourceLon.setText(lon)
            self.labelSourceDepth.setText(str(depth))
            if self.trgPos[0] is not None:
                self.labelVertDistance.setText(str(self.trgPos[1] - depth))
                dist = self.distArea.measureLine(self.trgPos[0], pos)
                self.labelDistance.setText('{:.1f}'.format(dist))
                if dist != 0:
                    bearing = self.distArea.bearing(pos, self.trgPos[0]) * 180 / pi
                    if bearing < 0:
                        bearing += 360
                else:
                    bearing = 0.0
                self.labelDirection.setText('{:.1f}'.format(bearing))
            self.srcPos = [pos, depth]

    @pyqtSlot(float, QgsPoint, float, float)
    def onNewTargetPosition(self, fix, pos, depth, altitude):
        if [pos, depth] != self.trgPos:
            lon, lat = self.posToStr(pos)
            self.labelTargetLat.setText(lat)
            self.labelTargetLon.setText(lon)
            self.labelTargetDepth.setText(str(depth))
            if self.srcPos[0] is not None:
                self.labelVertDistance.setText(str(depth - self.srcPos[1]))
                dist = self.distArea.measureLine(pos, self.srcPos[0])
                self.labelDistance.setText('{:.1f}'.format(dist))
                if dist != 0:
                    bearing = self.distArea.bearing(self.srcPos[0], pos) * 180 / pi
                    if bearing < 0:
                        bearing += 360
                else:
                    bearing = 0.0
                self.labelDirection.setText('{:.1f}'.format(bearing))
            self.trgPos = [pos, depth]

    @pyqtSlot(float, float, float)
    def onNewTargetAttitude(self, heading, pitch, roll):
        if self.trgHeading != heading:
            self.trgHeading = heading
            self.labelTargetHeading.setText(str(heading))
            self.compass.setAngle2(heading)

    @pyqtSlot(float, float, float)
    def onNewSourceAttitude(self, heading, pitch, roll):
        if self.srcHeading != heading:
            self.srcHeading = heading
            self.labelSourceHeading.setText(str(heading))
            self.compass.setAngle(heading)

    def reset(self):
        try:
            if self.source is not None:
                self.source.newPosition.disconnect(self.onNewSourcePosition)
                self.source.newAttitude.disconnect(self.onNewSourceAttitude)
            if self.target is not None:
                self.target.newPosition.disconnect(self.onNewTargetPosition)
                self.target.newAttitude.disconnect(self.onNewTargetAttitude)
        except TypeError:
            pass

        self.source = None
        self.target = None
        self.resetSource()
        self.resetTarget()
        self.resetDistBearing()

    def resetSource(self):
        self.srcPos = [None, 0.0]
        self.srcHeading = -720.0

        self.labelSourceLat.setText('---')
        self.labelSourceLon.setText('---')
        self.labelSourceHeading.setText('---')
        self.labelSourceDepth.setText('---')
        self.compass.reset(1)
        self.resetDistBearing()

    def resetTarget(self):
        self.trgPos = [None, 0.0]
        self.trgHeading = -720.0

        self.labelTargetLat.setText('---')
        self.labelTargetLon.setText('---')
        self.labelTargetHeading.setText('---')
        self.labelTargetDepth.setText('---')
        self.compass.reset(2)
        self.resetDistBearing()

    def resetDistBearing(self):
        self.labelDirection.setText('---')
        self.labelDistance.setText('---')
        self.labelVertDistance.setText('---')

    def resizeEvent(self, event):
        fsize = event.size().width() / 40
        if fsize != self.fontSize:
            self.fontSize = fsize
            self.dockWidgetContents.setStyleSheet("font-weight: bold; font-size: {}pt".format(self.fontSize))
        return QtGui.QDockWidget.resizeEvent(self, event)

    def timerEvent(self, event):
        dt = QDateTime.currentDateTimeUtc()
        self.labelTimeUtc.setText(dt.time().toString(u'hh:mm:ss'))
Ejemplo n.º 44
0
class GuidanceDock(QDockWidget, FORM_CLASS):
    '''
    classdocs
    '''

    def __init__(self, parent=None):
        '''
        Constructor
        '''
        super(GuidanceDock, self).__init__(parent)

        self.setupUi(self)
        self.setStyleSheet("QLabel { padding-left: 5px; padding-right: 5px; }")
        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.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:4326'), QgsProject.instance().transformContext())
        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()
        self.layer = None

    def setUtcClock(self):
        if self.showUtc:
            if not self.timer:
                self.timer = self.startTimer(1000)
            self.frameUtcClock.show()
        else:
            self.frameUtcClock.hide()
            self.killTimer(self.timer)
            self.timer = 0

    def setMobiles(self, mobiles):
        self.reset()
        self.mobiles = mobiles
        self.comboBoxSource.blockSignals(True)
        self.comboBoxTarget.blockSignals(True)
        mobs = sorted(mobiles.keys())
        self.comboBoxSource.clear()
        self.comboBoxSource.addItems(mobs)
        self.comboBoxSource.setCurrentIndex(-1)
        self.comboBoxTarget.clear()
        self.comboBoxTarget.addItems(mobs)
        self.comboBoxTarget.setCurrentIndex(-1)
        self.comboBoxSource.blockSignals(False)
        self.comboBoxTarget.blockSignals(False)
        s = QSettings()
        m = s.value('PosiView/Guidance/Source')
        if m in self.mobiles:
            self.comboBoxSource.setCurrentText(m)  # Index(self.comboBoxSource.findText(m))
        m = s.value('PosiView/Guidance/Target')
        if m in self.mobiles:
            self.comboBoxTarget.setCurrentText(m)  # Index(self.comboBoxTarget.findText(m))
        self.showUtc = s.value('PosiView/Misc/ShowUtcClock', defaultValue=False, type=bool)
        self.setUtcClock()

    @pyqtSlot(name='on_pushButtonFormat_clicked')
    def switchCoordinateFormat(self):
        self.format = (self.format + 1) % 3
        s = QSettings()
        s.setValue('PosiView/Guidance/Format', self.format)
        if self.trgPos[0]:
            lon, lat = self.posToStr(self.trgPos[0])
            self.labelTargetLat.setText(lat)
            self.labelTargetLon.setText(lon)
        if self.srcPos[0]:
            lon, lat = self.posToStr(self.srcPos[0])
            self.labelSourceLat.setText(lat)
            self.labelSourceLon.setText(lon)

    def posToStr(self, pos):
        if self.format == 0:
            return "{:.6f}".format(pos.x()), "{:.6f}".format(pos.y())
        if self.format == 1:
            return QgsCoordinateFormatter.format(pos, QgsCoordinateFormatter.FormatDegreesMinutes, 4).split(',')
        if self.format == 2:
            return QgsCoordinateFormatter.format(pos, QgsCoordinateFormatter.FormatDegreesMinutesSeconds, 2).split(',')

    @pyqtSlot(str, name='on_comboBoxSource_currentIndexChanged')
    def sourceChanged(self, mob):
        if self.source is not None:
            try:
                self.source.newPosition.disconnect(self.onNewSourcePosition)
                self.source.newAttitude.disconnect(self.onNewSourceAttitude)
            except TypeError:
                pass

        if mob in self.mobiles:
            try:
                self.source = self.mobiles[mob]
                self.source.newPosition.connect(self.onNewSourcePosition)
                self.source.newAttitude.connect(self.onNewSourceAttitude)
                s = QSettings()
                s.setValue('PosiView/Guidance/Source', mob)
            except KeyError:
                self.source = None
            self.resetSource()
        elif self.layer:
            for f in self.layer.getFeatures():
                if f['name'] == mob[:-2]:
                    pos = f.geometry().asPoint()
                    self.resetSource()
                    self.onNewSourcePosition(None, pos, -9999, -9999)

    @pyqtSlot(str, name='on_comboBoxTarget_currentIndexChanged')
    def targetChanged(self, mob):
        if self.target is not None:
            try:
                self.target.newPosition.disconnect(self.onNewTargetPosition)
                self.target.newAttitude.disconnect(self.onNewTargetAttitude)
            except TypeError:
                pass

        if mob in self.mobiles:
            try:
                self.target = self.mobiles[mob]
                self.target.newPosition.connect(self.onNewTargetPosition)
                self.target.newAttitude.connect(self.onNewTargetAttitude)
                s = QSettings()
                s.setValue('PosiView/Guidance/Target', mob)
            except KeyError:
                self.target = None
            self.resetTarget()
        elif self.layer:
            for f in self.layer.getFeatures():
                if f['name'] == mob[:-2]:
                    pos = f.geometry().asPoint()
                    self.resetTarget()
                    self.onNewTargetPosition(None, pos, -9999, -9999)

    @pyqtSlot(float, QgsPointXY, float, float)
    def onNewSourcePosition(self, fix, pos, depth, altitude):
        if [pos, depth] != self.srcPos:
            lon, lat = self.posToStr(pos)
            self.labelSourceLat.setText(lat)
            self.labelSourceLon.setText(lon)
            if depth > -9999:
                self.labelSourceDepth.setText('{:.1f}'.format(depth))
            if self.trgPos[0] is not None:
                if depth > -9999 and self.trgPos[1] > -9999:
                    self.labelVertDistance.setText('{:.1f}'.format(self.trgPos[1] - depth))
                dist = self.distArea.measureLine(self.trgPos[0], pos)
                self.labelDistance.setText('{:.1f}'.format(dist))
                if dist != 0:
                    bearing = self.distArea.bearing(pos, self.trgPos[0]) * 180 / pi
                    if bearing < 0:
                        bearing += 360
                else:
                    bearing = 0.0
                self.labelDirection.setText('{:.1f}'.format(bearing))
            self.srcPos = [pos, depth]

    @pyqtSlot(float, QgsPointXY, float, float)
    def onNewTargetPosition(self, fix, pos, depth, altitude):
        if [pos, depth] != self.trgPos:
            lon, lat = self.posToStr(pos)
            self.labelTargetLat.setText(lat)
            self.labelTargetLon.setText(lon)
            if depth > -9999:
                self.labelTargetDepth.setText('{:.1f}'.format(depth))
            if self.srcPos[0] is not None:
                if depth > -9999 and self.srcPos[1] > -9999:
                    self.labelVertDistance.setText('{:.1f}'.format(depth - self.srcPos[1]))
                dist = self.distArea.measureLine(pos, self.srcPos[0])
                self.labelDistance.setText('{:.1f}'.format(dist))
                if dist != 0:
                    bearing = self.distArea.bearing(self.srcPos[0], pos) * 180 / pi
                    if bearing < 0:
                        bearing += 360
                else:
                    bearing = 0.0
                self.labelDirection.setText('{:.1f}'.format(bearing))
            self.trgPos = [pos, depth]

    @pyqtSlot(float, float, float)
    def onNewTargetAttitude(self, heading, pitch, roll):
        if self.trgHeading != heading:
            self.trgHeading = heading
            self.labelTargetHeading.setText('{:.1f}'.format(heading))
            self.compass.setAngle2(heading)

    @pyqtSlot(float, float, float)
    def onNewSourceAttitude(self, heading, pitch, roll):
        if self.srcHeading != heading:
            self.srcHeading = heading
            self.labelSourceHeading.setText('{:.1f}'.format(heading))
            self.compass.setAngle(heading)

    @pyqtSlot(QgsMapLayer)
    def onActiveLayerChanged(self, layer):
        if self.cleanComboBox(self.comboBoxSource):
            self.resetSource()
        if self.cleanComboBox(self.comboBoxTarget):
            self.resetTarget()

        self.layer = None
        if not layer:
            return
        if layer.type() == QgsMapLayer.VectorLayer and layer.wkbType() == QgsWkbTypes.Point:
            if layer.fields().indexOf('name') != -1:
                self.layer = layer
                self.comboBoxSource.blockSignals(True)
                self.comboBoxTarget.blockSignals(True)
                items = sorted([f['name'] + '  ' for f in layer.getFeatures()])
                self.comboBoxSource.addItems(items)
                self.comboBoxTarget.addItems(items)
                self.comboBoxSource.blockSignals(False)
                self.comboBoxTarget.blockSignals(False)

    def reset(self):
        try:
            if self.source is not None:
                self.source.newPosition.disconnect(self.onNewSourcePosition)
                self.source.newAttitude.disconnect(self.onNewSourceAttitude)
            if self.target is not None:
                self.target.newPosition.disconnect(self.onNewTargetPosition)
                self.target.newAttitude.disconnect(self.onNewTargetAttitude)
        except TypeError:
            pass

        self.source = None
        self.target = None
        self.resetSource()
        self.resetTarget()
        self.resetDistBearing()

    def resetSource(self):
        self.srcPos = [None, 0.0]
        self.srcHeading = -9999.0

        self.labelSourceLat.setText('---')
        self.labelSourceLon.setText('---')
        self.labelSourceHeading.setText('---')
        self.labelSourceDepth.setText('---')
        self.compass.reset(1)
        self.resetDistBearing()

    def resetTarget(self):
        self.trgPos = [None, 0.0]
        self.trgHeading = -9999.0

        self.labelTargetLat.setText('---')
        self.labelTargetLon.setText('---')
        self.labelTargetHeading.setText('---')
        self.labelTargetDepth.setText('---')
        self.compass.reset(2)
        self.resetDistBearing()

    def cleanComboBox(self, comboBox):
        comboBox.blockSignals(True)
        ct = comboBox.currentText()
        for _ in range(comboBox.count() - len(self.mobiles)):
            comboBox.removeItem(len(self.mobiles))
        if ct not in self.mobiles:
            comboBox.setCurrentIndex(-1)
            res = True
        else:
            res = False
        comboBox.blockSignals(False)
        return res

    def resetDistBearing(self):
        self.labelDirection.setText('---')
        self.labelDistance.setText('---')
        self.labelVertDistance.setText('---')

    def resizeEvent(self, event):
        fsize = max(8, event.size().width() / 50)
        if fsize != self.fontSize:
            self.fontSize = fsize
            self.dockWidgetContents.setStyleSheet("font-weight: bold; font-size: {}pt;".format(self.fontSize))
        return QDockWidget.resizeEvent(self, event)

    def timerEvent(self, event):
        dt = QDateTime.currentDateTimeUtc()
        self.labelTimeUtc.setText(dt.time().toString(u'hh:mm:ss'))
Ejemplo n.º 45
0
class SizeCalculator():

    """Special object to handle size calculation with an output unit."""

    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 measure_distance(self, point_a, point_b):
        """Measure the distance between two points.

        This is added here since QgsDistanceArea object is already called here.

        :param point_a: First Point.
        :type point_a: QgsPoint

        :param point_b: Second Point.
        :type point_b: QgsPoint

        :return: The distance between input points.
        :rtype: float
        """
        return self.calculator.measureLine(point_a, point_b)

    def measure(self, geometry):
        """Measure the length or the area of a geometry.

        :param geometry: The geometry.
        :type geometry: QgsGeometry

        :return: The geometric size in the expected exposure unit.
        :rtype: float
        """
        message = 'Size with NaN value : geometry valid={valid}, WKT={wkt}'
        feature_size = 0
        if geometry.isMultipart():
            # Be careful, the size calculator is not working well on a
            # multipart.
            # So we compute the size part per part. See ticket #3812
            for single in geometry.asGeometryCollection():
                if self.geometry_type == QgsWkbTypes.LineGeometry:
                    geometry_size = self.calculator.measureLength(single)
                else:
                    geometry_size = self.calculator.measureArea(single)
                if not isnan(geometry_size):
                    feature_size += geometry_size
                else:
                    LOGGER.debug(message.format(
                        valid=single.isGeosValid(),
                        wkt=single.asWkt()))
        else:
            if self.geometry_type == QgsWkbTypes.LineGeometry:
                geometry_size = self.calculator.measureLength(geometry)
            else:
                geometry_size = self.calculator.measureArea(geometry)
            if not isnan(geometry_size):
                feature_size = geometry_size
            else:
                LOGGER.debug(message.format(
                    valid=geometry.isGeosValid(),
                    wkt=geometry.asWkt()))

        feature_size = round(feature_size)

        if self.output_unit:
            if self.output_unit != self.default_unit:
                feature_size = convert_unit(
                    feature_size, self.default_unit, self.output_unit)

        return feature_size
Ejemplo n.º 46
0
    def processAlgorithm(self, progress):
        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
                    progress.setPercentage(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
Ejemplo n.º 47
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, 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())

        points = dict()
        features = source.getFeatures(
            QgsFeatureRequest().setSubsetOfAttributes(
                [group_field_index, order_field_index]))
        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().geometry().clone()
            if group_field_index >= 0:
                group = f.attributes()[group_field_index]
            else:
                group = 1
            order = f.attributes()[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())
        da.setEllipsoid(context.project().ellipsoid())

        current = 0
        total = 100.0 / len(points) if points else 1
        for group, vertices in list(points.items()):
            if feedback.isCanceled():
                break

            vertices.sort()
            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 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}
Ejemplo n.º 48
0
    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)
        count = len(features)
        total = 100.0 / float(count)
        for count, 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(count * total))

        del writer
Ejemplo n.º 49
0
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()