def testFromUnitToUnitFactor(self): """Test calculation of conversion factor between units""" expected = {QgsUnitTypes.DistanceMeters: {QgsUnitTypes.DistanceMeters: 1.0, QgsUnitTypes.DistanceKilometers: 0.001, QgsUnitTypes.DistanceFeet: 3.28083989501, QgsUnitTypes.DistanceYards: 1.0936133, QgsUnitTypes.DistanceMiles: 0.00062136931818182, QgsUnitTypes.DistanceDegrees: 0.00000898315, QgsUnitTypes.DistanceNauticalMiles: 0.000539957}, QgsUnitTypes.DistanceKilometers: {QgsUnitTypes.DistanceMeters: 1000.0, QgsUnitTypes.DistanceKilometers: 1.0, QgsUnitTypes.DistanceFeet: 3280.8398950, QgsUnitTypes.DistanceYards: 1093.6132983, QgsUnitTypes.DistanceMiles: 0.62137121212119317271, QgsUnitTypes.DistanceDegrees: 0.0089832, QgsUnitTypes.DistanceNauticalMiles: 0.53995682073432482717}, QgsUnitTypes.DistanceFeet: {QgsUnitTypes.DistanceMeters: 0.3048, QgsUnitTypes.DistanceKilometers: 0.0003048, QgsUnitTypes.DistanceFeet: 1.0, QgsUnitTypes.DistanceYards: 0.3333333, QgsUnitTypes.DistanceMiles: 0.00018939375, QgsUnitTypes.DistanceDegrees: 2.73806498599629E-06, QgsUnitTypes.DistanceNauticalMiles: 0.000164579}, QgsUnitTypes.DistanceYards: {QgsUnitTypes.DistanceMeters: 0.9144, QgsUnitTypes.DistanceKilometers: 0.0009144, QgsUnitTypes.DistanceFeet: 3.0, QgsUnitTypes.DistanceYards: 1.0, QgsUnitTypes.DistanceMiles: 0.000568182, QgsUnitTypes.DistanceDegrees: 0.0000082, QgsUnitTypes.DistanceNauticalMiles: 0.0004937366590756}, QgsUnitTypes.DistanceDegrees: {QgsUnitTypes.DistanceMeters: 111319.49079327358, QgsUnitTypes.DistanceKilometers: 111.3194908, QgsUnitTypes.DistanceFeet: 365221.4264871, QgsUnitTypes.DistanceYards: 121740.4754957, QgsUnitTypes.DistanceMiles: 69.1707247, QgsUnitTypes.DistanceDegrees: 1.0, QgsUnitTypes.DistanceNauticalMiles: 60.1077164}, QgsUnitTypes.DistanceMiles: {QgsUnitTypes.DistanceMeters: 1609.3440000, QgsUnitTypes.DistanceKilometers: 1.6093440, QgsUnitTypes.DistanceFeet: 5280.0000000, QgsUnitTypes.DistanceYards: 1760.0000000, QgsUnitTypes.DistanceMiles: 1.0, QgsUnitTypes.DistanceDegrees: 0.0144570, QgsUnitTypes.DistanceNauticalMiles: 0.8689762}, QgsUnitTypes.DistanceNauticalMiles: {QgsUnitTypes.DistanceMeters: 1852.0, QgsUnitTypes.DistanceKilometers: 1.8520000, QgsUnitTypes.DistanceFeet: 6076.1154856, QgsUnitTypes.DistanceYards: 2025.3718285, QgsUnitTypes.DistanceMiles: 1.1507794, QgsUnitTypes.DistanceDegrees: 0.0166367990650, QgsUnitTypes.DistanceNauticalMiles: 1.0}, QgsUnitTypes.DistanceUnknownUnit: {QgsUnitTypes.DistanceMeters: 1.0, QgsUnitTypes.DistanceKilometers: 1.0, QgsUnitTypes.DistanceFeet: 1.0, QgsUnitTypes.DistanceYards: 1.0, QgsUnitTypes.DistanceMiles: 1.0, QgsUnitTypes.DistanceDegrees: 1.0, QgsUnitTypes.DistanceNauticalMiles: 1.0} } for from_unit in list(expected.keys()): for to_unit in list(expected[from_unit].keys()): expected_factor = expected[from_unit][to_unit] res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, to_unit) self.assertAlmostEqual(res, expected_factor, msg='got {:.7f}, expected {:.7f} when converting from {} to {}'.format(res, expected_factor, QgsUnitTypes.toString(from_unit), QgsUnitTypes.toString(to_unit))) #test conversion to unknown units res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, QgsUnitTypes.DistanceUnknownUnit) self.assertAlmostEqual(res, 1.0, msg='got {:.7f}, expected 1.0 when converting from {} to unknown units'.format(res, expected_factor, QgsUnitTypes.toString(from_unit)))
def testFromUnitToUnitFactor(self): """Test calculation of conversion factor between units""" expected = {QGis.Meters: {QGis.Meters: 1.0, QGis.Feet: 3.28083989501, QGis.Degrees: 0.00000898315, QGis.NauticalMiles: 0.000539957}, QGis.Feet: {QGis.Meters: 0.3048, QGis.Feet: 1.0, QGis.Degrees: 2.73806498599629E-06, QGis.NauticalMiles: 0.000164579}, QGis.Degrees: {QGis.Meters: 111319.49079327358, QGis.Feet: 365221.4264871, QGis.Degrees: 1.0, QGis.NauticalMiles: 60.1077164}, QGis.NauticalMiles: {QGis.Meters: 1852.0, QGis.Feet: 6076.1154856, QGis.Degrees: 0.0166367990650, QGis.NauticalMiles: 1.0}, QGis.UnknownUnit: {QGis.Meters: 1.0, QGis.Feet: 1.0, QGis.Degrees: 1.0, QGis.NauticalMiles: 1.0} } for from_unit in expected.keys(): for to_unit in expected[from_unit].keys(): expected_factor = expected[from_unit][to_unit] res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, to_unit) self.assertAlmostEqual(res, expected_factor, msg='got {:.7f}, expected {:.7f} when converting from {} to {}'.format(res, expected_factor, QgsUnitTypes.toString(from_unit), QgsUnitTypes.toString(to_unit))) #test conversion to unknown units res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, QGis.UnknownUnit) self.assertAlmostEqual(res, 1.0, msg='got {:.7f}, expected 1.0 when converting from {} to unknown units'.format(res, expected_factor, QgsUnitTypes.toString(from_unit)))
def testAreaFromUnitToUnitFactor(self): """Test calculation of conversion factor between areal units""" expected = {QgsUnitTypes.AreaSquareMeters: {QgsUnitTypes.AreaSquareMeters: 1.0, QgsUnitTypes.AreaSquareKilometers: 1e-6, QgsUnitTypes.AreaSquareFeet: 10.7639104, QgsUnitTypes.AreaSquareYards: 1.19599, QgsUnitTypes.AreaSquareMiles: 3.86102e-7, QgsUnitTypes.AreaHectares: 0.0001, QgsUnitTypes.AreaAcres: 0.000247105, QgsUnitTypes.AreaSquareNauticalMiles: 2.91553e-7, QgsUnitTypes.AreaSquareDegrees: 0.000000000080697, QgsUnitTypes.AreaUnknownUnit: 1.0}, QgsUnitTypes.AreaSquareKilometers: {QgsUnitTypes.AreaSquareMeters: 1e6, QgsUnitTypes.AreaSquareKilometers: 1, QgsUnitTypes.AreaSquareFeet: 10763910.4167097, QgsUnitTypes.AreaSquareYards: 1195990.04630108, QgsUnitTypes.AreaSquareMiles: 0.386102158, QgsUnitTypes.AreaHectares: 100, QgsUnitTypes.AreaAcres: 247.105381467, QgsUnitTypes.AreaSquareNauticalMiles: 0.291553349598, QgsUnitTypes.AreaSquareDegrees: 0.000080697034968, QgsUnitTypes.AreaUnknownUnit: 1.0}, QgsUnitTypes.AreaSquareFeet: {QgsUnitTypes.AreaSquareMeters: 0.092903, QgsUnitTypes.AreaSquareKilometers: 9.2903e-8, QgsUnitTypes.AreaSquareFeet: 1.0, QgsUnitTypes.AreaSquareYards: 0.11111111111, QgsUnitTypes.AreaSquareMiles: 3.58701e-8, QgsUnitTypes.AreaHectares: 9.2903e-6, QgsUnitTypes.AreaAcres: 2.29568e-5, QgsUnitTypes.AreaSquareNauticalMiles: 2.70862e-8, QgsUnitTypes.AreaSquareDegrees: 0.000000000007497, QgsUnitTypes.AreaUnknownUnit: 1.0}, QgsUnitTypes.AreaSquareYards: {QgsUnitTypes.AreaSquareMeters: 0.836127360, QgsUnitTypes.AreaSquareKilometers: 8.36127e-7, QgsUnitTypes.AreaSquareFeet: 9.0, QgsUnitTypes.AreaSquareYards: 1.0, QgsUnitTypes.AreaSquareMiles: 3.22831e-7, QgsUnitTypes.AreaHectares: 8.3612736E-5, QgsUnitTypes.AreaAcres: 0.00020661157, QgsUnitTypes.AreaSquareNauticalMiles: 2.43776e-7, QgsUnitTypes.AreaSquareDegrees: 0.000000000067473, QgsUnitTypes.AreaUnknownUnit: 1.0}, QgsUnitTypes.AreaSquareMiles: {QgsUnitTypes.AreaSquareMeters: 2589988.110336, QgsUnitTypes.AreaSquareKilometers: 2.589988110, QgsUnitTypes.AreaSquareFeet: 27878400, QgsUnitTypes.AreaSquareYards: 3097600, QgsUnitTypes.AreaSquareMiles: 1.0, QgsUnitTypes.AreaHectares: 258.998811, QgsUnitTypes.AreaAcres: 640, QgsUnitTypes.AreaSquareNauticalMiles: 0.75511970898, QgsUnitTypes.AreaSquareDegrees: 0.000209004361107, QgsUnitTypes.AreaUnknownUnit: 1.0}, QgsUnitTypes.AreaHectares: {QgsUnitTypes.AreaSquareMeters: 10000, QgsUnitTypes.AreaSquareKilometers: 0.01, QgsUnitTypes.AreaSquareFeet: 107639.1041670972, QgsUnitTypes.AreaSquareYards: 11959.9004630, QgsUnitTypes.AreaSquareMiles: 0.00386102, QgsUnitTypes.AreaHectares: 1.0, QgsUnitTypes.AreaAcres: 2.471053814, QgsUnitTypes.AreaSquareNauticalMiles: 0.00291553, QgsUnitTypes.AreaSquareDegrees: 0.000000806970350, QgsUnitTypes.AreaUnknownUnit: 1.0}, QgsUnitTypes.AreaAcres: {QgsUnitTypes.AreaSquareMeters: 4046.8564224, QgsUnitTypes.AreaSquareKilometers: 0.00404686, QgsUnitTypes.AreaSquareFeet: 43560, QgsUnitTypes.AreaSquareYards: 4840, QgsUnitTypes.AreaSquareMiles: 0.0015625, QgsUnitTypes.AreaHectares: 0.404685642, QgsUnitTypes.AreaAcres: 1.0, QgsUnitTypes.AreaSquareNauticalMiles: 0.00117987, QgsUnitTypes.AreaSquareDegrees: 0.000000326569314, QgsUnitTypes.AreaUnknownUnit: 1.0}, QgsUnitTypes.AreaSquareNauticalMiles: {QgsUnitTypes.AreaSquareMeters: 3429904, QgsUnitTypes.AreaSquareKilometers: 3.4299040, QgsUnitTypes.AreaSquareFeet: 36919179.39391434, QgsUnitTypes.AreaSquareYards: 4102131.04376826, QgsUnitTypes.AreaSquareMiles: 1.324293337, QgsUnitTypes.AreaHectares: 342.9904000000, QgsUnitTypes.AreaAcres: 847.54773631, QgsUnitTypes.AreaSquareNauticalMiles: 1.0, QgsUnitTypes.AreaSquareDegrees: 0.000276783083025, QgsUnitTypes.AreaUnknownUnit: 1.0}, QgsUnitTypes.AreaSquareDegrees: {QgsUnitTypes.AreaSquareMeters: 12392029030.5, QgsUnitTypes.AreaSquareKilometers: 12392.029030499, QgsUnitTypes.AreaSquareFeet: 133386690365.5682220, QgsUnitTypes.AreaSquareYards: 14820743373.9520263, QgsUnitTypes.AreaSquareMiles: 4784.5891573967, QgsUnitTypes.AreaHectares: 1239202.903050, QgsUnitTypes.AreaAcres: 3062137.060733889, QgsUnitTypes.AreaSquareNauticalMiles: 3612.93757215, QgsUnitTypes.AreaSquareDegrees: 1.0, QgsUnitTypes.AreaUnknownUnit: 1.0}} for from_unit in list(expected.keys()): for to_unit in list(expected[from_unit].keys()): expected_factor = expected[from_unit][to_unit] res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, to_unit) self.assertAlmostEqual(res, expected_factor, msg='got {:.15f}, expected {:.15f} when converting from {} to {}'.format(res, expected_factor, QgsUnitTypes.toString(from_unit), QgsUnitTypes.toString(to_unit))) #test conversion to unknown units res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, QgsUnitTypes.AreaUnknownUnit) self.assertAlmostEqual(res, 1.0, msg='got {:.7f}, expected 1.0 when converting from {} to unknown units'.format(res, expected_factor, QgsUnitTypes.toString(from_unit)))
def testAngleFromUnitToUnitFactor(self): """Test calculation of conversion factor between angular units""" expected = {QgsUnitTypes.AngleDegrees: {QgsUnitTypes.AngleDegrees: 1.0, QgsUnitTypes.AngleRadians: 0.0174533, QgsUnitTypes.AngleGon: 1.1111111, QgsUnitTypes.AngleMinutesOfArc: 60, QgsUnitTypes.AngleSecondsOfArc: 3600, QgsUnitTypes.AngleTurn: 0.00277777777778}, QgsUnitTypes.AngleRadians: {QgsUnitTypes.AngleDegrees: 57.2957795, QgsUnitTypes.AngleRadians: 1.0, QgsUnitTypes.AngleGon: 63.6619772, QgsUnitTypes.AngleMinutesOfArc: 3437.7467708, QgsUnitTypes.AngleSecondsOfArc: 206264.8062471, QgsUnitTypes.AngleTurn: 0.159154943092}, QgsUnitTypes.AngleGon: {QgsUnitTypes.AngleDegrees: 0.9000000, QgsUnitTypes.AngleRadians: 0.015707968623450838802, QgsUnitTypes.AngleGon: 1.0, QgsUnitTypes.AngleMinutesOfArc: 54.0000000, QgsUnitTypes.AngleSecondsOfArc: 3240.0000000, QgsUnitTypes.AngleTurn: 0.0025}, QgsUnitTypes.AngleMinutesOfArc: {QgsUnitTypes.AngleDegrees: 0.016666672633390722247, QgsUnitTypes.AngleRadians: 0.00029088831280398030638, QgsUnitTypes.AngleGon: 0.018518525464057963154, QgsUnitTypes.AngleMinutesOfArc: 1.0, QgsUnitTypes.AngleSecondsOfArc: 60.0, QgsUnitTypes.AngleTurn: 4.62962962962963e-05}, QgsUnitTypes.AngleSecondsOfArc: {QgsUnitTypes.AngleDegrees: 0.00027777787722304257169, QgsUnitTypes.AngleRadians: 4.848138546730629518e-6, QgsUnitTypes.AngleGon: 0.0003086420910674814405, QgsUnitTypes.AngleMinutesOfArc: 0.016666672633325253783, QgsUnitTypes.AngleSecondsOfArc: 1.0, QgsUnitTypes.AngleTurn: 7.71604938271605e-07}, QgsUnitTypes.AngleTurn: {QgsUnitTypes.AngleDegrees: 360.0, QgsUnitTypes.AngleRadians: 6.2831853071795, QgsUnitTypes.AngleGon: 400.0, QgsUnitTypes.AngleMinutesOfArc: 21600, QgsUnitTypes.AngleSecondsOfArc: 1296000, QgsUnitTypes.AngleTurn: 1} } for from_unit in list(expected.keys()): for to_unit in list(expected[from_unit].keys()): expected_factor = expected[from_unit][to_unit] res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, to_unit) self.assertAlmostEqual(res, expected_factor, msg='got {:.7f}, expected {:.7f} when converting from {} to {}'.format(res, expected_factor, QgsUnitTypes.toString(from_unit), QgsUnitTypes.toString(to_unit))) # test conversion to unknown units res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, QgsUnitTypes.AngleUnknownUnit) self.assertAlmostEqual(res, 1.0, msg='got {:.7f}, expected 1.0 when converting from {} to unknown units'.format(res, expected_factor, QgsUnitTypes.toString(from_unit)))
def getValue(self): val = super().getValue() if isinstance(val, float) and self.units_combo.isVisible(): display_unit = self.units_combo.currentData() return val * QgsUnitTypes.fromUnitToUnitFactor(display_unit, self.base_units) return val
def processAlgorithm(self, parameters, context, feedback): network = self.parameterAsSource(parameters, self.INPUT, context) startPoints = self.parameterAsSource(parameters, self.START_POINTS, context) endPoint = self.parameterAsPoint(parameters, self.END_POINT, context) strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) fields = QgsFields() fields.append(QgsField('start', QVariant.String, '', 254, 0)) fields.append(QgsField('end', QVariant.String, '', 254, 0)) fields.append(QgsField('cost', QVariant.Double, '', 20, 7)) feat = QgsFeature() feat.setFields(fields) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.LineString, network.sourceCrs()) directionField = -1 if directionFieldName: directionField = network.fields().lookupField(directionFieldName) speedField = -1 if speedFieldName: speedField = network.fields().lookupField(speedFieldName) director = QgsVectorLayerDirector(network, directionField, forwardValue, backwardValue, bothValue, defaultDirection) distUnit = context.project().crs().mapUnits() multiplier = QgsUnitTypes.fromUnitToUnitFactor( distUnit, QgsUnitTypes.DistanceMeters) if strategy == 0: strategy = QgsNetworkDistanceStrategy() else: strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed, multiplier * 1000.0 / 3600.0) multiplier = 3600 director.addStrategy(strategy) builder = QgsGraphBuilder(context.project().crs(), True, tolerance) feedback.pushInfo(self.tr('Loading start points...')) request = QgsFeatureRequest() request.setFlags(request.flags() ^ QgsFeatureRequest.SubsetOfAttributes) request.setDestinationCrs(network.sourceCrs()) features = startPoints.getFeatures(request) total = 100.0 / startPoints.featureCount() if startPoints.featureCount( ) else 0 points = [endPoint] for current, f in enumerate(features): if feedback.isCanceled(): break points.append(f.geometry().asPoint()) feedback.setProgress(int(current * total)) feedback.pushInfo(self.tr('Building graph...')) snappedPoints = director.makeGraph(builder, points, feedback) feedback.pushInfo(self.tr('Calculating shortest paths...')) graph = builder.graph() idxEnd = graph.findVertex(snappedPoints[0]) route = [] nPoints = len(snappedPoints) total = 100.0 / nPoints if nPoints else 1 for i in range(1, count + 1): if feedback.isCanceled(): break idxStart = graph.findVertex(snappedPoints[i]) tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) if tree[idxEnd] == -1: msg = self.tr( 'There is no route from start point ({}) to end point ({}).' .format(points[i].toString(), endPoint.toString())) feedback.setProgressText(msg) QgsMessageLog.logMessage(msg, self.tr('Processing'), QgsMessageLog.WARNING) continue cost = 0.0 current = idxEnd while current != idxStart: cost += graph.edge(tree[current]).cost(0) route.append( graph.vertex(graph.edge(tree[current]).inVertex()).point()) current = graph.edge(tree[current]).outVertex() route.append(snappedPoints[i]) route.reverse() geom = QgsGeometry.fromPolyline(route) feat.setGeometry(geom) feat['start'] = points[i].toString() feat['end'] = endPoint.toString() feat['cost'] = cost / multiplier sink.addFeature(feat, QgsFeatureSink.FastInsert) route[:] = [] feedback.setProgress(int(i * total)) return {self.OUTPUT: dest_id}
def saveScale(self): d = VoGISProfilToolScaleDialog(self) result = d.exec_() if result == QDialog.Rejected: return scale = d.ui.cmbScale.currentText() dpi = d.ui.cmbDpi.currentText() scaleFactor = float(scale.split(":")[1]) crsUnit = self.iface.mapCanvas().mapSettings().destinationCrs().mapUnits() toCm = QgsUnitTypes.fromUnitToUnitFactor(crsUnit, QgsUnitTypes.DistanceCentimeters) m2Cm = QgsUnitTypes.fromUnitToUnitFactor(QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceCentimeters) profile_length = 0 profile_height = 0 plt_extent = PlotExtent() for p in self.profiles: profile_length = max(p.getExtent().xmax, profile_length) profile_height = max(p.getExtent().ymax, profile_height) plt_extent.union(p.getExtent()) plt_extent.expand() s = self.subplot.figure.get_size_inches() maxLength = toCm * profile_length maxHeight = m2Cm * profile_height imgWidth = (maxLength / scaleFactor) * TO_INCH imgHeight = s[1] * imgWidth / s[0] fig = plt.figure(figsize=(imgWidth, imgHeight), dpi=10, linewidth=0.0, subplotpars=matplotlib.figure.SubplotParams(left=0, bottom=0, right=1, top=1, wspace=0, hspace=0 ) ) axes = fig.add_axes((LEFT_MARGIN, BOTTOM_MARGIN, RIGHT_MARGIN, TOP_MARGIN), adjustable="datalim", aspect=1 ) axes.set_xbound(plt_extent.xmin, plt_extent.xmax) axes.set_ybound(plt_extent.ymin, plt_extent.ymax) self.__setupAxes(axes) self.__drawProfiles(axes) exaggeration = floor(float(self.editExaggeration.text().replace(",", ".")) * 10) / 10 oldexa = axes.get_aspect() ratioexa = oldexa / exaggeration ylim = axes.get_ylim() deltaYold = ylim[1] - ylim[0] deltaYnew = deltaYold * ratioexa centerY = ylim[0] + (deltaYold / 2) axes.set_ylim(centerY - deltaYnew/2,centerY + deltaYnew/2) axes.set_aspect(exaggeration, "datalim", "C") axes.set_xlim(self.subplot.get_xlim()) axes.set_ylim(self.subplot.get_ylim()) axes.set_xbound(self.subplot.get_xbound()) axes.set_ybound(self.subplot.get_ybound()) u = Util(self.iface) caption = QApplication.translate("code", "PNG export") file_format = [["PNG files", "png"]] fileName, fileExt = u.getFileName(caption, file_format, self.filePath) if fileName == "": return fInfo = QFileInfo(fileName) self.filePath = fInfo.path() QgsSettings().setValue("vogisprofiltoolmain/savepath", self.filePath) fig.show() fig.savefig(fileName, dpi=int(dpi), format="png", bbox_inches='tight') plt.close(fig)
def processAlgorithm(self, parameters, context, feedback): network = self.parameterAsSource(parameters, self.INPUT, context) startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs()) endPoint = self.parameterAsPoint(parameters, self.END_POINT, context, network.sourceCrs()) strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) fields = QgsFields() fields.append(QgsField('start', QVariant.String, '', 254, 0)) fields.append(QgsField('end', QVariant.String, '', 254, 0)) fields.append(QgsField('cost', QVariant.Double, '', 20, 7)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.LineString, network.sourceCrs()) directionField = -1 if directionField: directionField = network.fields().lookupField(directionFieldName) speedField = -1 if speedFieldName: speedField = network.fields().lookupField(speedFieldName) director = QgsVectorLayerDirector(network, directionField, forwardValue, backwardValue, bothValue, defaultDirection) distUnit = context.project().crs().mapUnits() multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters) if strategy == 0: strategy = QgsNetworkDistanceStrategy() else: strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed, multiplier * 1000.0 / 3600.0) multiplier = 3600 director.addStrategy(strategy) builder = QgsGraphBuilder(network.sourceCrs(), True, tolerance) feedback.pushInfo(QCoreApplication.translate('ShortestPathPointToPoint', 'Building graph…')) snappedPoints = director.makeGraph(builder, [startPoint, endPoint], feedback) feedback.pushInfo(QCoreApplication.translate('ShortestPathPointToPoint', 'Calculating shortest path…')) graph = builder.graph() idxStart = graph.findVertex(snappedPoints[0]) idxEnd = graph.findVertex(snappedPoints[1]) tree, costs = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) if tree[idxEnd] == -1: raise QgsProcessingException( self.tr('There is no route from start point to end point.')) route = [graph.vertex(idxEnd).point()] cost = costs[idxEnd] current = idxEnd while current != idxStart: current = graph.edge(tree[current]).fromVertex() route.append(graph.vertex(current).point()) route.reverse() feedback.pushInfo(QCoreApplication.translate('ShortestPathPointToPoint', 'Writing results…')) geom = QgsGeometry.fromPolylineXY(route) feat = QgsFeature() feat.setFields(fields) feat['start'] = startPoint.toString() feat['end'] = endPoint.toString() feat['cost'] = cost / multiplier feat.setGeometry(geom) sink.addFeature(feat, QgsFeatureSink.FastInsert) results = {} results[self.TRAVEL_COST] = cost / multiplier results[self.OUTPUT] = dest_id return results
def testAngleFromUnitToUnitFactor(self): """Test calculation of conversion factor between angular units""" expected = { QgsUnitTypes.AngleDegrees: { QgsUnitTypes.AngleDegrees: 1.0, QgsUnitTypes.AngleRadians: 0.0174533, QgsUnitTypes.AngleGon: 1.1111111, QgsUnitTypes.AngleMinutesOfArc: 60, QgsUnitTypes.AngleSecondsOfArc: 3600, QgsUnitTypes.AngleTurn: 0.00277777777778, QgsUnitTypes.AngleMilliradiansSI: 17.453292519943297, QgsUnitTypes.AngleMilNATO: 17.77777777777778 }, QgsUnitTypes.AngleRadians: { QgsUnitTypes.AngleDegrees: 57.2957795, QgsUnitTypes.AngleRadians: 1.0, QgsUnitTypes.AngleGon: 63.6619772, QgsUnitTypes.AngleMinutesOfArc: 3437.7467708, QgsUnitTypes.AngleSecondsOfArc: 206264.8062471, QgsUnitTypes.AngleTurn: 0.159154943092, QgsUnitTypes.AngleMilliradiansSI: 1000.0, QgsUnitTypes.AngleMilNATO: 1018.5916357881301 }, QgsUnitTypes.AngleGon: { QgsUnitTypes.AngleDegrees: 0.9000000, QgsUnitTypes.AngleRadians: 0.015707968623450838802, QgsUnitTypes.AngleGon: 1.0, QgsUnitTypes.AngleMinutesOfArc: 54.0000000, QgsUnitTypes.AngleSecondsOfArc: 3240.0000000, QgsUnitTypes.AngleTurn: 0.0025, QgsUnitTypes.AngleMilliradiansSI: 15.707963267948967, QgsUnitTypes.AngleMilNATO: 16 }, QgsUnitTypes.AngleMinutesOfArc: { QgsUnitTypes.AngleDegrees: 0.016666672633390722247, QgsUnitTypes.AngleRadians: 0.00029088831280398030638, QgsUnitTypes.AngleGon: 0.018518525464057963154, QgsUnitTypes.AngleMinutesOfArc: 1.0, QgsUnitTypes.AngleSecondsOfArc: 60.0, QgsUnitTypes.AngleTurn: 4.62962962962963e-05, QgsUnitTypes.AngleMilliradiansSI: 0.29088820866572157, QgsUnitTypes.AngleMilNATO: 0.29629629629629634 }, QgsUnitTypes.AngleSecondsOfArc: { QgsUnitTypes.AngleDegrees: 0.00027777787722304257169, QgsUnitTypes.AngleRadians: 4.848138546730629518e-6, QgsUnitTypes.AngleGon: 0.0003086420910674814405, QgsUnitTypes.AngleMinutesOfArc: 0.016666672633325253783, QgsUnitTypes.AngleSecondsOfArc: 1.0, QgsUnitTypes.AngleTurn: 7.71604938271605e-07, QgsUnitTypes.AngleMilliradiansSI: 0.0048481482527009582897, QgsUnitTypes.AngleMilNATO: 0.0049382716049382715 }, QgsUnitTypes.AngleTurn: { QgsUnitTypes.AngleDegrees: 360.0, QgsUnitTypes.AngleRadians: 6.2831853071795, QgsUnitTypes.AngleGon: 400.0, QgsUnitTypes.AngleMinutesOfArc: 21600, QgsUnitTypes.AngleSecondsOfArc: 1296000, QgsUnitTypes.AngleTurn: 1, QgsUnitTypes.AngleMilliradiansSI: 6283.185307179586, QgsUnitTypes.AngleMilNATO: 6400 }, QgsUnitTypes.AngleMilliradiansSI: { QgsUnitTypes.AngleDegrees: 0.057295779513082325, QgsUnitTypes.AngleRadians: 0.001, QgsUnitTypes.AngleGon: 0.06366197723675814, QgsUnitTypes.AngleMinutesOfArc: 3.4377467707849396, QgsUnitTypes.AngleSecondsOfArc: 206.26480624709637, QgsUnitTypes.AngleTurn: 0.0015707963267948967, QgsUnitTypes.AngleMilliradiansSI: 1.0, QgsUnitTypes.AngleMilNATO: 1.0185916357881302 }, QgsUnitTypes.AngleMilNATO: { QgsUnitTypes.AngleDegrees: 0.05625, QgsUnitTypes.AngleRadians: 0.0009817477042468104, QgsUnitTypes.AngleGon: 0.0625, QgsUnitTypes.AngleMinutesOfArc: 3.375, QgsUnitTypes.AngleSecondsOfArc: 202.5, QgsUnitTypes.AngleTurn: 0.000015625, QgsUnitTypes.AngleMilliradiansSI: 0.9817477042468102, QgsUnitTypes.AngleMilNATO: 1.0 } } for from_unit in list(expected.keys()): for to_unit in list(expected[from_unit].keys()): expected_factor = expected[from_unit][to_unit] res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, to_unit) self.assertAlmostEqual( res, expected_factor, msg= 'got {:.7f}, expected {:.7f} when converting from {} to {}' .format(res, expected_factor, QgsUnitTypes.toString(from_unit), QgsUnitTypes.toString(to_unit))) # test conversion to unknown units res = QgsUnitTypes.fromUnitToUnitFactor( from_unit, QgsUnitTypes.AngleUnknownUnit) self.assertAlmostEqual( res, 1.0, msg= 'got {:.7f}, expected 1.0 when converting from {} to unknown units' .format(res, expected_factor, QgsUnitTypes.toString(from_unit)))
def processAlgorithm(self, parameters, context, feedback): network = self.parameterAsSource(parameters, self.INPUT, context) startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs()) strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) travelCost = self.parameterAsDouble(parameters, self.TRAVEL_COST, context) directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) directionField = -1 if directionFieldName: directionField = network.fields().lookupField(directionFieldName) speedField = -1 if speedFieldName: speedField = network.fields().lookupField(speedFieldName) director = QgsVectorLayerDirector(network, directionField, forwardValue, backwardValue, bothValue, defaultDirection) distUnit = context.project().crs().mapUnits() multiplier = QgsUnitTypes.fromUnitToUnitFactor( distUnit, QgsUnitTypes.DistanceMeters) if strategy == 0: strategy = QgsNetworkDistanceStrategy() else: strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed, multiplier * 1000.0 / 3600.0) director.addStrategy(strategy) builder = QgsGraphBuilder(network.sourceCrs(), True, tolerance) feedback.pushInfo(self.tr('Building graph...')) snappedPoints = director.makeGraph(builder, [startPoint], feedback) feedback.pushInfo(self.tr('Calculating service area...')) graph = builder.graph() idxStart = graph.findVertex(snappedPoints[0]) tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) vertices = [] for i, v in enumerate(cost): if v > travelCost and tree[i] != -1: vertexId = graph.edge(tree[i]).fromVertex() if cost[vertexId] <= travelCost: vertices.append(i) upperBoundary = [] lowerBoundary = [] for i in vertices: upperBoundary.append( graph.vertex(graph.edge(tree[i]).toVertex()).point()) lowerBoundary.append( graph.vertex(graph.edge(tree[i]).fromVertex()).point()) feedback.pushInfo(self.tr('Writing results...')) fields = QgsFields() fields.append(QgsField('type', QVariant.String, '', 254, 0)) fields.append(QgsField('start', QVariant.String, '', 254, 0)) feat = QgsFeature() feat.setFields(fields) geomUpper = QgsGeometry.fromMultiPointXY(upperBoundary) geomLower = QgsGeometry.fromMultiPointXY(lowerBoundary) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.MultiPoint, network.sourceCrs()) feat.setGeometry(geomUpper) feat['type'] = 'upper' feat['start'] = startPoint.toString() sink.addFeature(feat, QgsFeatureSink.FastInsert) feat.setGeometry(geomLower) feat['type'] = 'lower' feat['start'] = startPoint.toString() sink.addFeature(feat, QgsFeatureSink.FastInsert) upperBoundary.append(startPoint) lowerBoundary.append(startPoint) geomUpper = QgsGeometry.fromMultiPointXY(upperBoundary) geomLower = QgsGeometry.fromMultiPointXY(lowerBoundary) return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): network = self.parameterAsSource(parameters, self.INPUT, context) if network is None: raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs()) endPoint = self.parameterAsPoint(parameters, self.END_POINT, context, network.sourceCrs()) strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) fields = QgsFields() fields.append(QgsField('start', QVariant.String, '', 254, 0)) fields.append(QgsField('end', QVariant.String, '', 254, 0)) fields.append(QgsField('cost', QVariant.Double, '', 20, 7)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.LineString, network.sourceCrs()) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) directionField = -1 if directionField: directionField = network.fields().lookupField(directionFieldName) speedField = -1 if speedFieldName: speedField = network.fields().lookupField(speedFieldName) director = QgsVectorLayerDirector(network, directionField, forwardValue, backwardValue, bothValue, defaultDirection) distUnit = context.project().crs().mapUnits() multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters) if strategy == 0: strategy = QgsNetworkDistanceStrategy() else: strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed, multiplier * 1000.0 / 3600.0) multiplier = 3600 director.addStrategy(strategy) builder = QgsGraphBuilder(network.sourceCrs(), True, tolerance) feedback.pushInfo(QCoreApplication.translate('ShortestPathPointToPoint', 'Building graph…')) snappedPoints = director.makeGraph(builder, [startPoint, endPoint], feedback) feedback.pushInfo(QCoreApplication.translate('ShortestPathPointToPoint', 'Calculating shortest path…')) graph = builder.graph() idxStart = graph.findVertex(snappedPoints[0]) idxEnd = graph.findVertex(snappedPoints[1]) tree, costs = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) if tree[idxEnd] == -1: raise QgsProcessingException( self.tr('There is no route from start point to end point.')) route = [graph.vertex(idxEnd).point()] cost = costs[idxEnd] current = idxEnd while current != idxStart: current = graph.edge(tree[current]).fromVertex() route.append(graph.vertex(current).point()) route.reverse() feedback.pushInfo(QCoreApplication.translate('ShortestPathPointToPoint', 'Writing results…')) geom = QgsGeometry.fromPolylineXY(route) feat = QgsFeature() feat.setFields(fields) feat['start'] = startPoint.toString() feat['end'] = endPoint.toString() feat['cost'] = cost / multiplier feat.setGeometry(geom) sink.addFeature(feat, QgsFeatureSink.FastInsert) results = {} results[self.TRAVEL_COST] = cost / multiplier results[self.OUTPUT] = dest_id return results
def processAlgorithm(self, context, feedback): layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_VECTOR), context) startPoint = self.getParameterValue(self.START_POINT) strategy = self.getParameterValue(self.STRATEGY) travelCost = self.getParameterValue(self.TRAVEL_COST) directionFieldName = self.getParameterValue(self.DIRECTION_FIELD) forwardValue = self.getParameterValue(self.VALUE_FORWARD) backwardValue = self.getParameterValue(self.VALUE_BACKWARD) bothValue = self.getParameterValue(self.VALUE_BOTH) defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION) bothValue = self.getParameterValue(self.VALUE_BOTH) defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION) speedFieldName = self.getParameterValue(self.SPEED_FIELD) defaultSpeed = self.getParameterValue(self.DEFAULT_SPEED) tolerance = self.getParameterValue(self.TOLERANCE) tmp = startPoint.split(',') startPoint = QgsPoint(float(tmp[0]), float(tmp[1])) directionField = -1 if directionFieldName is not None: directionField = layer.fields().lookupField(directionFieldName) speedField = -1 if speedFieldName is not None: speedField = layer.fields().lookupField(speedFieldName) director = QgsVectorLayerDirector(layer, directionField, forwardValue, backwardValue, bothValue, defaultDirection) distUnit = iface.mapCanvas().mapSettings().destinationCrs().mapUnits() multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters) if strategy == 0: strategy = QgsNetworkDistanceStrategy() else: strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed, multiplier * 1000.0 / 3600.0) director.addStrategy(strategy) builder = QgsGraphBuilder(iface.mapCanvas().mapSettings().destinationCrs(), True, tolerance) feedback.pushInfo(self.tr('Building graph...')) snappedPoints = director.makeGraph(builder, [startPoint]) feedback.pushInfo(self.tr('Calculating service area...')) graph = builder.graph() idxStart = graph.findVertex(snappedPoints[0]) tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) vertices = [] for i, v in enumerate(cost): if v > travelCost and tree[i] != -1: vertexId = graph.edge(tree[i]).outVertex() if cost[vertexId] <= travelCost: vertices.append(i) upperBoundary = [] lowerBoundary = [] for i in vertices: upperBoundary.append(graph.vertex(graph.edge(tree[i]).inVertex()).point()) lowerBoundary.append(graph.vertex(graph.edge(tree[i]).outVertex()).point()) feedback.pushInfo(self.tr('Writing results...')) fields = QgsFields() fields.append(QgsField('type', QVariant.String, '', 254, 0)) fields.append(QgsField('start', QVariant.String, '', 254, 0)) feat = QgsFeature() feat.setFields(fields) geomUpper = QgsGeometry.fromMultiPoint(upperBoundary) geomLower = QgsGeometry.fromMultiPoint(lowerBoundary) writer = self.getOutputFromName( self.OUTPUT_POINTS).getVectorWriter(fields, QgsWkbTypes.MultiPoint, layer.crs(), context) feat.setGeometry(geomUpper) feat['type'] = 'upper' feat['start'] = startPoint.toString() writer.addFeature(feat) feat.setGeometry(geomLower) feat['type'] = 'lower' feat['start'] = startPoint.toString() writer.addFeature(feat) del writer upperBoundary.append(startPoint) lowerBoundary.append(startPoint) geomUpper = QgsGeometry.fromMultiPoint(upperBoundary) geomLower = QgsGeometry.fromMultiPoint(lowerBoundary) writer = self.getOutputFromName( self.OUTPUT_POLYGON).getVectorWriter(fields, QgsWkbTypes.Polygon, layer.crs(), context) geom = geomUpper.convexHull() feat.setGeometry(geom) feat['type'] = 'upper' feat['start'] = startPoint.toString() writer.addFeature(feat) geom = geomLower.convexHull() feat.setGeometry(geom) feat['type'] = 'lower' feat['start'] = startPoint.toString() writer.addFeature(feat) del writer
def processAlgorithm(self, parameters, context, feedback): network = self.parameterAsSource(parameters, self.INPUT, context) startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs()) strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) travelCost = self.parameterAsDouble(parameters, self.TRAVEL_COST, context) directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) directionField = -1 if directionFieldName: directionField = network.fields().lookupField(directionFieldName) speedField = -1 if speedFieldName: speedField = network.fields().lookupField(speedFieldName) director = QgsVectorLayerDirector(network, directionField, forwardValue, backwardValue, bothValue, defaultDirection) distUnit = context.project().crs().mapUnits() multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters) if strategy == 0: strategy = QgsNetworkDistanceStrategy() else: strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed, multiplier * 1000.0 / 3600.0) director.addStrategy(strategy) builder = QgsGraphBuilder(network.sourceCrs(), True, tolerance) feedback.pushInfo(self.tr('Building graph...')) snappedPoints = director.makeGraph(builder, [startPoint], feedback) feedback.pushInfo(self.tr('Calculating service area...')) graph = builder.graph() idxStart = graph.findVertex(snappedPoints[0]) tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) vertices = [] for i, v in enumerate(cost): if v > travelCost and tree[i] != -1: vertexId = graph.edge(tree[i]).fromVertex() if cost[vertexId] <= travelCost: vertices.append(i) upperBoundary = [] lowerBoundary = [] for i in vertices: upperBoundary.append(graph.vertex(graph.edge(tree[i]).toVertex()).point()) lowerBoundary.append(graph.vertex(graph.edge(tree[i]).fromVertex()).point()) feedback.pushInfo(self.tr('Writing results...')) fields = QgsFields() fields.append(QgsField('type', QVariant.String, '', 254, 0)) fields.append(QgsField('start', QVariant.String, '', 254, 0)) feat = QgsFeature() feat.setFields(fields) geomUpper = QgsGeometry.fromMultiPointXY(upperBoundary) geomLower = QgsGeometry.fromMultiPointXY(lowerBoundary) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.MultiPoint, network.sourceCrs()) feat.setGeometry(geomUpper) feat['type'] = 'upper' feat['start'] = startPoint.toString() sink.addFeature(feat, QgsFeatureSink.FastInsert) feat.setGeometry(geomLower) feat['type'] = 'lower' feat['start'] = startPoint.toString() sink.addFeature(feat, QgsFeatureSink.FastInsert) upperBoundary.append(startPoint) lowerBoundary.append(startPoint) geomUpper = QgsGeometry.fromMultiPointXY(upperBoundary) geomLower = QgsGeometry.fromMultiPointXY(lowerBoundary) return {self.OUTPUT: dest_id}
def compute(self): from AcATaMa.gui.acatama_dockwidget import AcATaMaDockWidget as AcATaMa AcATaMa.dockwidget.QPBtn_ComputeViewAccurasyAssessment.setText("Processing, please wait ...") QApplication.processEvents() # get labels from classification buttons labels = {} for button_config in self.classification.buttons_config.values(): labels[button_config["thematic_class"]] = button_config["name"] # get the classified and thematic map values thematic_map_values = [] classified_values = [] samples_outside_the_thematic = [] classification_points = [point for point in self.classification.points if point.is_classified] points_ordered = sorted(classification_points, key=lambda p: p.shape_id) for point in points_ordered: # classification from the pixel values in the thematic map thematic_map_value = self.ThematicR.get_pixel_value_from_pnt(point.QgsPnt) if not thematic_map_value: samples_outside_the_thematic.append(point) continue thematic_map_values.append(int(thematic_map_value)) # classified value made/checked by user with classification buttons classified_value = self.classification.buttons_config[point.classif_id]["thematic_class"] classified_values.append(int(classified_value)) # all unique and sorted values values = sorted(set(thematic_map_values + classified_values)) # Construct a value->index dictionary indices = dict((val, i) for (i, val) in enumerate(values)) # calculate the error/confusion matrix # https://github.com/nltk/nltk/blob/develop/nltk/metrics/confusionmatrix.py # # classified # t | | L1 | L2 | L3 | L4 | # h | L1 | | | | | # e | L2 | | | | | # m | L3 | | | | | # a | L4 | | | | | # error_matrix = [[0 for column in values] for row in values] for thematic, classified in zip(thematic_map_values, classified_values): error_matrix[indices[thematic]][indices[classified]] += 1 # calculate the total number of pixel in the thematic raster # by each thematic raster class used in the classification buttons for thematic_map_value in values: if thematic_map_value not in self.thematic_pixels_count: self.thematic_pixels_count[thematic_map_value] = self.ThematicR.get_total_pixels_by_value(thematic_map_value) # values necessary for results self.values = values self.labels = labels self.error_matrix = error_matrix self.samples_outside_the_thematic = samples_outside_the_thematic # set area by pixel self.pixel_area_base = self.ThematicR.qgs_layer.rasterUnitsPerPixelX() * self.ThematicR.qgs_layer.rasterUnitsPerPixelY() self.pixel_area_value = self.pixel_area_base * QgsUnitTypes.fromUnitToUnitFactor(self.base_area_unit, self.area_unit) self.pixel_area_unit = QgsUnitTypes.toAbbreviatedString(self.area_unit)
def processAlgorithm(self, parameters, context, feedback): network = self.parameterAsSource(parameters, self.INPUT, context) startPoints = self.parameterAsSource(parameters, self.START_POINTS, context) strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) travelCost = self.parameterAsDouble(parameters, self.TRAVEL_COST, context) directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) fields = startPoints.fields() fields.append(QgsField('type', QVariant.String, '', 254, 0)) fields.append(QgsField('start', QVariant.String, '', 254, 0)) feat = QgsFeature() feat.setFields(fields) directionField = -1 if directionFieldName: directionField = network.fields().lookupField(directionFieldName) speedField = -1 if speedFieldName: speedField = network.fields().lookupField(speedFieldName) director = QgsVectorLayerDirector(network, directionField, forwardValue, backwardValue, bothValue, defaultDirection) distUnit = context.project().crs().mapUnits() multiplier = QgsUnitTypes.fromUnitToUnitFactor( distUnit, QgsUnitTypes.DistanceMeters) if strategy == 0: strategy = QgsNetworkDistanceStrategy() else: strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed, multiplier * 1000.0 / 3600.0) director.addStrategy(strategy) builder = QgsGraphBuilder(network.sourceCrs(), True, tolerance) feedback.pushInfo(self.tr('Loading start points...')) request = QgsFeatureRequest() request.setDestinationCrs(network.sourceCrs(), context.transformContext()) features = startPoints.getFeatures(request) total = 100.0 / startPoints.featureCount() if startPoints.featureCount( ) else 0 points = [] source_attributes = {} i = 0 for current, f in enumerate(features): if feedback.isCanceled(): break if not f.hasGeometry(): continue for p in f.geometry().vertices(): points.append(QgsPointXY(p)) source_attributes[i] = f.attributes() i += 1 feedback.setProgress(int(current * total)) feedback.pushInfo(self.tr('Building graph...')) snappedPoints = director.makeGraph(builder, points, feedback) feedback.pushInfo(self.tr('Calculating service areas...')) graph = builder.graph() (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.MultiPoint, network.sourceCrs()) vertices = [] upperBoundary = [] lowerBoundary = [] total = 100.0 / len(snappedPoints) if snappedPoints else 1 for i, p in enumerate(snappedPoints): if feedback.isCanceled(): break idxStart = graph.findVertex(snappedPoints[i]) origPoint = points[i].toString() tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) for j, v in enumerate(cost): if v > travelCost and tree[j] != -1: vertexId = graph.edge(tree[j]).fromVertex() if cost[vertexId] <= travelCost: vertices.append(j) for j in vertices: upperBoundary.append( graph.vertex(graph.edge(tree[j]).toVertex()).point()) lowerBoundary.append( graph.vertex(graph.edge(tree[j]).fromVertex()).point()) geomUpper = QgsGeometry.fromMultiPointXY(upperBoundary) geomLower = QgsGeometry.fromMultiPointXY(lowerBoundary) feat.setGeometry(geomUpper) attrs = source_attributes[i] attrs.extend(['upper', origPoint]) feat.setAttributes(attrs) sink.addFeature(feat, QgsFeatureSink.FastInsert) feat.setGeometry(geomLower) attrs[-2] = 'lower' feat.setAttributes(attrs) sink.addFeature(feat, QgsFeatureSink.FastInsert) vertices[:] = [] upperBoundary[:] = [] lowerBoundary[:] = [] feedback.setProgress(int(i * total)) return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): layer = QgsProcessingUtils.mapLayerFromString( self.getParameterValue(self.INPUT_VECTOR), context) startPoints = QgsProcessingUtils.mapLayerFromString( self.getParameterValue(self.START_POINTS), context) endPoint = self.getParameterValue(self.END_POINT) strategy = self.getParameterValue(self.STRATEGY) directionFieldName = self.getParameterValue(self.DIRECTION_FIELD) forwardValue = self.getParameterValue(self.VALUE_FORWARD) backwardValue = self.getParameterValue(self.VALUE_BACKWARD) bothValue = self.getParameterValue(self.VALUE_BOTH) defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION) bothValue = self.getParameterValue(self.VALUE_BOTH) defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION) speedFieldName = self.getParameterValue(self.SPEED_FIELD) defaultSpeed = self.getParameterValue(self.DEFAULT_SPEED) tolerance = self.getParameterValue(self.TOLERANCE) fields = QgsFields() fields.append(QgsField('start', QVariant.String, '', 254, 0)) fields.append(QgsField('end', QVariant.String, '', 254, 0)) fields.append(QgsField('cost', QVariant.Double, '', 20, 7)) feat = QgsFeature() feat.setFields(fields) writer = self.getOutputFromName(self.OUTPUT_LAYER).getVectorWriter( fields, QgsWkbTypes.LineString, layer.crs(), context) tmp = endPoint.split(',') endPoint = QgsPointXY(float(tmp[0]), float(tmp[1])) directionField = -1 if directionFieldName is not None: directionField = layer.fields().lookupField(directionFieldName) speedField = -1 if speedFieldName is not None: speedField = layer.fields().lookupField(speedFieldName) director = QgsVectorLayerDirector(layer, directionField, forwardValue, backwardValue, bothValue, defaultDirection) distUnit = iface.mapCanvas().mapSettings().destinationCrs().mapUnits() multiplier = QgsUnitTypes.fromUnitToUnitFactor( distUnit, QgsUnitTypes.DistanceMeters) if strategy == 0: strategy = QgsNetworkDistanceStrategy() else: strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed, multiplier * 1000.0 / 3600.0) multiplier = 3600 director.addStrategy(strategy) builder = QgsGraphBuilder( iface.mapCanvas().mapSettings().destinationCrs(), True, tolerance) feedback.pushInfo(self.tr('Loading start points...')) request = QgsFeatureRequest() request.setFlags(request.flags() ^ QgsFeatureRequest.SubsetOfAttributes) features = QgsProcessingUtils.getFeatures(startPoints, context, request) count = QgsProcessingUtils.featureCount(startPoints, context) points = [endPoint] for f in features: points.append(f.geometry().asPoint()) feedback.pushInfo(self.tr('Building graph...')) snappedPoints = director.makeGraph(builder, points) feedback.pushInfo(self.tr('Calculating shortest paths...')) graph = builder.graph() idxEnd = graph.findVertex(snappedPoints[0]) route = [] total = 100.0 / count for i in range(1, count + 1): idxStart = graph.findVertex(snappedPoints[i]) tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) if tree[idxEnd] == -1: msg = self.tr( 'There is no route from start point ({}) to end point ({}).' .format(points[i].toString(), endPoint.toString())) feedback.setProgressText(msg) QgsMessageLog.logMessage(msg, self.tr('Processing'), QgsMessageLog.WARNING) continue cost = 0.0 current = idxEnd while current != idxStart: cost += graph.edge(tree[current]).cost(0) route.append( graph.vertex(graph.edge(tree[current]).inVertex()).point()) current = graph.edge(tree[current]).outVertex() route.append(snappedPoints[i]) route.reverse() geom = QgsGeometry.fromPolyline(route) feat.setGeometry(geom) feat['start'] = points[i].toString() feat['end'] = endPoint.toString() feat['cost'] = cost / multiplier writer.addFeature(feat) route[:] = [] feedback.setProgress(int(i * total)) del writer
def processAlgorithm(self, parameters, context, feedback): network = self.parameterAsSource(parameters, self.INPUT, context) startPoints = self.parameterAsSource(parameters, self.START_POINTS, context) endPoint = self.parameterAsPoint(parameters, self.END_POINT, context, network.sourceCrs()) strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) fields = startPoints.fields() fields.append(QgsField('start', QVariant.String, '', 254, 0)) fields.append(QgsField('end', QVariant.String, '', 254, 0)) fields.append(QgsField('cost', QVariant.Double, '', 20, 7)) feat = QgsFeature() feat.setFields(fields) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.LineString, network.sourceCrs()) directionField = -1 if directionFieldName: directionField = network.fields().lookupField(directionFieldName) speedField = -1 if speedFieldName: speedField = network.fields().lookupField(speedFieldName) director = QgsVectorLayerDirector(network, directionField, forwardValue, backwardValue, bothValue, defaultDirection) distUnit = context.project().crs().mapUnits() multiplier = QgsUnitTypes.fromUnitToUnitFactor( distUnit, QgsUnitTypes.DistanceMeters) if strategy == 0: strategy = QgsNetworkDistanceStrategy() else: strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed, multiplier * 1000.0 / 3600.0) multiplier = 3600 director.addStrategy(strategy) builder = QgsGraphBuilder(network.sourceCrs(), True, tolerance) feedback.pushInfo( QCoreApplication.translate('ShortestPathLayerToPoint', 'Loading start points…')) request = QgsFeatureRequest() request.setDestinationCrs(network.sourceCrs(), context.transformContext()) features = startPoints.getFeatures(request) total = 100.0 / startPoints.featureCount() if startPoints.featureCount( ) else 0 points = [endPoint] source_attributes = {} i = 1 for current, f in enumerate(features): if feedback.isCanceled(): break if not f.hasGeometry(): continue for p in f.geometry().vertices(): points.append(QgsPointXY(p)) source_attributes[i] = f.attributes() i += 1 feedback.setProgress(int(current * total)) feedback.pushInfo( QCoreApplication.translate('ShortestPathLayerToPoint', 'Building graph…')) snappedPoints = director.makeGraph(builder, points, feedback) feedback.pushInfo( QCoreApplication.translate('ShortestPathLayerToPoint', 'Calculating shortest paths…')) graph = builder.graph() idxEnd = graph.findVertex(snappedPoints[0]) nPoints = len(snappedPoints) total = 100.0 / nPoints if nPoints else 1 for i in range(1, nPoints): if feedback.isCanceled(): break idxStart = graph.findVertex(snappedPoints[i]) tree, costs = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) if tree[idxEnd] == -1: msg = self.tr( 'There is no route from start point ({}) to end point ({}).' .format(points[i].toString(), endPoint.toString())) feedback.reportError(msg) # add feature with no geometry feat.clearGeometry() attrs = source_attributes[i] attrs.append(points[i].toString()) feat.setAttributes(attrs) sink.addFeature(feat, QgsFeatureSink.FastInsert) continue route = [graph.vertex(idxEnd).point()] cost = costs[idxEnd] current = idxEnd while current != idxStart: current = graph.edge(tree[current]).fromVertex() route.append(graph.vertex(current).point()) route.reverse() geom = QgsGeometry.fromPolylineXY(route) feat.setGeometry(geom) attrs = source_attributes[i] attrs.extend( [points[i].toString(), endPoint.toString(), cost / multiplier]) feat.setAttributes(attrs) sink.addFeature(feat, QgsFeatureSink.FastInsert) feedback.setProgress(int(i * total)) return {self.OUTPUT: dest_id}
def __init__( self, input_network, #QgsProcessingParameterFeatureSource input_points, #[QgsPointXY] or QgsProcessingParameterFeatureSource or QgsVectorLayer --> Implement List of QgsFeatures [QgsFeatures] input_strategy, #int input_directionFieldName, #str, empty if field not given input_forwardValue, #str input_backwardValue, #str input_bothValue, #str input_defaultDirection, #int input_analysisCrs, #QgsCoordinateReferenceSystem input_speedField, #str input_defaultSpeed, #float input_tolerance, #float feedback #feedback object from processing (log window) ): """ Constructor for a Qneat3Network object. @type input_network: QgsProcessingParameterFeatureSource @param input_network: input network dataset from processing algorithm @type input_points: QgsProcessingParameterFeatureSource/QgsVectorLayer/[QgsPointXY] @param input_points: input point dataset from processing algorithm @type input_strategy: int @param input_strategy: Strategy parameter (0 for distance evaluation, 1 time evaluation) @type directionFieldName: string @param directionFieldName: Field name of field containing direction information @type input_forwardValue: string @param input_forwardValue: Value assigned to forward-directed edges @type input_backwardValue: string @param input_backwardValue: Value assigned to backward-directed edges @type input_bothValue: string @param input_bothValues: Value assigned to undirected edges (accessible from both directions) @type input_defaultDirection: QgsVectorLayerDirector.DirectionForward/DirectionBackward/DirectionBoth @param input_defaultDirection: QgsVectorLayerDirector Direction enum to determine default direction @type input_analysisCrs: QgsCoordinateReferenceSystem @param input_analysisCrs: Analysis coordinate system @type input_speedField: string @param input_speedField: Field name of field containing speed information @type input_tolerance: float @param input_tolerance: tolerance value when connecting graph edges @type feedback: QgsProcessingFeedback @param feedback: feedback object from processing algorithm """ #initialize feedback self.feedback = feedback self.feedback.pushInfo( "[QNEAT3Network][__init__] Setting up parameters") self.AnalysisCrs = input_analysisCrs #enable polygon calculation in geographic coordinate systems distUnit = self.AnalysisCrs.mapUnits() self.meter_to_unit_factor = QgsUnitTypes.fromUnitToUnitFactor( QgsUnitTypes.DistanceMeters, distUnit) #init direction fields self.feedback.pushInfo( "[QNEAT3Network][__init__] Setting up network direction parameters" ) self.directedAnalysis = self.setNetworkDirection( (input_directionFieldName, input_forwardValue, input_backwardValue, input_bothValue, input_defaultDirection)) self.director = QgsVectorLayerDirector( input_network, getFieldIndexFromQgsProcessingFeatureSource( input_network, input_directionFieldName), input_forwardValue, input_backwardValue, input_bothValue, input_defaultDirection) #init analysis points self.feedback.pushInfo( "[QNEAT3Network][__init__] Setting up analysis points") if isinstance(input_points, (list, )): self.list_input_points = input_points #[QgsPointXY] else: self.list_input_points = getListOfPoints( input_points) #[QgsPointXY] self.input_points = input_points #Setup cost-strategy pattern. self.feedback.pushInfo( "[QNEAT3Network][__init__] Setting analysis strategy: {}".format( input_strategy)) self.default_speed = input_defaultSpeed self.setNetworkStrategy(input_strategy, input_network, input_speedField, input_defaultSpeed) #add the strategy to the QgsGraphDirector self.director.addStrategy(self.strategy) self.builder = QgsGraphBuilder(self.AnalysisCrs) #tell the graph-director to make the graph using the builder object and tie the start point geometry to the graph self.feedback.pushInfo( "[QNEAT3Network][__init__] Start tying analysis points to the graph and building it." ) self.feedback.pushInfo( "[QNEAT3Network][__init__] This is a compute intensive task and may take some time depending on network size" ) start_local_time = time.localtime() start_time = time.time() self.feedback.pushInfo( "[QNEAT3Network][__init__] Start Time: {}".format( time.strftime(":%Y-%m-%d %H:%M:%S", start_local_time))) self.feedback.pushInfo("[QNEAT3Network][__init__] Building...") self.list_tiedPoints = self.director.makeGraph(self.builder, self.list_input_points, self.feedback) self.network = self.builder.graph() end_local_time = time.localtime() end_time = time.time() self.feedback.pushInfo("[QNEAT3Network][__init__] End Time: {}".format( time.strftime(":%Y-%m-%d %H:%M:%S", end_local_time))) self.feedback.pushInfo( "[QNEAT3Network][__init__] Total Build Time: {}".format( end_time - start_time)) self.feedback.pushInfo( "[QNEAT3Network][__init__] Analysis setup complete")
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT_VECTOR)) startPoint = self.getParameterValue(self.START_POINT) strategy = self.getParameterValue(self.STRATEGY) travelCost = self.getParameterValue(self.TRAVEL_COST) directionFieldName = self.getParameterValue(self.DIRECTION_FIELD) forwardValue = self.getParameterValue(self.VALUE_FORWARD) backwardValue = self.getParameterValue(self.VALUE_BACKWARD) bothValue = self.getParameterValue(self.VALUE_BOTH) defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION) bothValue = self.getParameterValue(self.VALUE_BOTH) defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION) speedFieldName = self.getParameterValue(self.SPEED_FIELD) defaultSpeed = self.getParameterValue(self.DEFAULT_SPEED) tolerance = self.getParameterValue(self.TOLERANCE) tmp = startPoint.split(',') startPoint = QgsPoint(float(tmp[0]), float(tmp[1])) directionField = -1 if directionFieldName is not None: directionField = layer.fields().lookupField(directionFieldName) speedField = -1 if speedFieldName is not None: speedField = layer.fields().lookupField(speedFieldName) director = QgsVectorLayerDirector(layer, directionField, forwardValue, backwardValue, bothValue, defaultDirection) distUnit = iface.mapCanvas().mapSettings().destinationCrs().mapUnits() multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters) if strategy == 0: strategy = QgsNetworkDistanceStrategy() else: strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed, multiplier * 1000.0 / 3600.0) director.addStrategy(strategy) builder = QgsGraphBuilder(iface.mapCanvas().mapSettings().destinationCrs(), iface.mapCanvas().hasCrsTransformEnabled(), tolerance) progress.setInfo(self.tr('Building graph...')) snappedPoints = director.makeGraph(builder, [startPoint]) progress.setInfo(self.tr('Calculating service area...')) graph = builder.graph() idxStart = graph.findVertex(snappedPoints[0]) tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) vertices = [] for i, v in enumerate(cost): if v > travelCost and tree[i] != -1: vertexId = graph.edge(tree [i]).outVertex() if cost[vertexId] <= travelCost: vertices.append(i) upperBoundary = [] lowerBoundary = [] for i in vertices: upperBoundary.append(graph.vertex(graph.edge(tree[i]).inVertex()).point()) lowerBoundary.append(graph.vertex(graph.edge(tree[i]).outVertex()).point()) progress.setInfo(self.tr('Writting results...')) fields = QgsFields() fields.append(QgsField('type', QVariant.String, '', 254, 0)) fields.append(QgsField('start', QVariant.String, '', 254, 0)) feat = QgsFeature() feat.setFields(fields) geomUpper = QgsGeometry.fromMultiPoint(upperBoundary) geomLower = QgsGeometry.fromMultiPoint(lowerBoundary) writer = self.getOutputFromName( self.OUTPUT_POINTS).getVectorWriter( fields, QgsWkbTypes.MultiPoint, layer.crs()) feat.setGeometry(geomUpper) feat['type'] = 'upper' feat['start'] = startPoint.toString() writer.addFeature(feat) feat.setGeometry(geomLower) feat['type'] = 'lower' feat['start'] = startPoint.toString() writer.addFeature(feat) del writer writer = self.getOutputFromName( self.OUTPUT_POLYGON).getVectorWriter( fields, QgsWkbTypes.Polygon, layer.crs()) geom = geomUpper.convexHull() feat.setGeometry(geom) feat['type'] = 'upper' feat['start'] = startPoint.toString() writer.addFeature(feat) geom = geomLower.convexHull() feat.setGeometry(geom) feat['type'] = 'lower' feat['start'] = startPoint.toString() writer.addFeature(feat) del writer
def testAreaFromUnitToUnitFactor(self): """Test calculation of conversion factor between areal units""" expected = { QgsUnitTypes.AreaSquareMeters: { QgsUnitTypes.AreaSquareMeters: 1.0, QgsUnitTypes.AreaSquareKilometers: 1e-6, QgsUnitTypes.AreaSquareFeet: 10.7639104, QgsUnitTypes.AreaSquareYards: 1.19599, QgsUnitTypes.AreaSquareMiles: 3.86102e-7, QgsUnitTypes.AreaHectares: 0.0001, QgsUnitTypes.AreaAcres: 0.000247105, QgsUnitTypes.AreaSquareNauticalMiles: 2.91553e-7, QgsUnitTypes.AreaSquareDegrees: 0.000000000080697, QgsUnitTypes.AreaSquareMillimeters: 1e6, QgsUnitTypes.AreaSquareCentimeters: 1e4, QgsUnitTypes.AreaUnknownUnit: 1.0 }, QgsUnitTypes.AreaSquareKilometers: { QgsUnitTypes.AreaSquareMeters: 1e6, QgsUnitTypes.AreaSquareKilometers: 1, QgsUnitTypes.AreaSquareFeet: 10763910.4167097, QgsUnitTypes.AreaSquareYards: 1195990.04630108, QgsUnitTypes.AreaSquareMiles: 0.386102158, QgsUnitTypes.AreaHectares: 100, QgsUnitTypes.AreaAcres: 247.105381467, QgsUnitTypes.AreaSquareNauticalMiles: 0.291553349598, QgsUnitTypes.AreaSquareDegrees: 0.000080697034968, QgsUnitTypes.AreaSquareMillimeters: 1e12, QgsUnitTypes.AreaSquareCentimeters: 1e10, QgsUnitTypes.AreaUnknownUnit: 1.0 }, QgsUnitTypes.AreaSquareFeet: { QgsUnitTypes.AreaSquareMeters: 0.092903, QgsUnitTypes.AreaSquareKilometers: 9.2903e-8, QgsUnitTypes.AreaSquareFeet: 1.0, QgsUnitTypes.AreaSquareYards: 0.11111111111, QgsUnitTypes.AreaSquareMiles: 3.58701e-8, QgsUnitTypes.AreaHectares: 9.2903e-6, QgsUnitTypes.AreaAcres: 2.29568e-5, QgsUnitTypes.AreaSquareNauticalMiles: 2.70862e-8, QgsUnitTypes.AreaSquareDegrees: 0.000000000007497, QgsUnitTypes.AreaSquareMillimeters: 92903.04, QgsUnitTypes.AreaSquareCentimeters: 929.0304, QgsUnitTypes.AreaUnknownUnit: 1.0 }, QgsUnitTypes.AreaSquareYards: { QgsUnitTypes.AreaSquareMeters: 0.836127360, QgsUnitTypes.AreaSquareKilometers: 8.36127e-7, QgsUnitTypes.AreaSquareFeet: 9.0, QgsUnitTypes.AreaSquareYards: 1.0, QgsUnitTypes.AreaSquareMiles: 3.22831e-7, QgsUnitTypes.AreaHectares: 8.3612736E-5, QgsUnitTypes.AreaAcres: 0.00020661157, QgsUnitTypes.AreaSquareNauticalMiles: 2.43776e-7, QgsUnitTypes.AreaSquareDegrees: 0.000000000067473, QgsUnitTypes.AreaSquareMillimeters: 836127.360, QgsUnitTypes.AreaSquareCentimeters: 8361.27360, QgsUnitTypes.AreaUnknownUnit: 1.0 }, QgsUnitTypes.AreaSquareMiles: { QgsUnitTypes.AreaSquareMeters: 2589988.110336, QgsUnitTypes.AreaSquareKilometers: 2.589988110, QgsUnitTypes.AreaSquareFeet: 27878400, QgsUnitTypes.AreaSquareYards: 3097600, QgsUnitTypes.AreaSquareMiles: 1.0, QgsUnitTypes.AreaHectares: 258.998811, QgsUnitTypes.AreaAcres: 640, QgsUnitTypes.AreaSquareNauticalMiles: 0.75511970898, QgsUnitTypes.AreaSquareDegrees: 0.000209004361107, QgsUnitTypes.AreaSquareMillimeters: 2589988110336.0, QgsUnitTypes.AreaSquareCentimeters: 25899881103.36, QgsUnitTypes.AreaUnknownUnit: 1.0 }, QgsUnitTypes.AreaHectares: { QgsUnitTypes.AreaSquareMeters: 10000, QgsUnitTypes.AreaSquareKilometers: 0.01, QgsUnitTypes.AreaSquareFeet: 107639.1041670972, QgsUnitTypes.AreaSquareYards: 11959.9004630, QgsUnitTypes.AreaSquareMiles: 0.00386102, QgsUnitTypes.AreaHectares: 1.0, QgsUnitTypes.AreaAcres: 2.471053814, QgsUnitTypes.AreaSquareNauticalMiles: 0.00291553, QgsUnitTypes.AreaSquareDegrees: 0.000000806970350, QgsUnitTypes.AreaSquareMillimeters: 10000000000.0, QgsUnitTypes.AreaSquareCentimeters: 100000000.0, QgsUnitTypes.AreaUnknownUnit: 1.0 }, QgsUnitTypes.AreaAcres: { QgsUnitTypes.AreaSquareMeters: 4046.8564224, QgsUnitTypes.AreaSquareKilometers: 0.00404686, QgsUnitTypes.AreaSquareFeet: 43560, QgsUnitTypes.AreaSquareYards: 4840, QgsUnitTypes.AreaSquareMiles: 0.0015625, QgsUnitTypes.AreaHectares: 0.404685642, QgsUnitTypes.AreaAcres: 1.0, QgsUnitTypes.AreaSquareNauticalMiles: 0.00117987, QgsUnitTypes.AreaSquareDegrees: 0.000000326569314, QgsUnitTypes.AreaSquareMillimeters: 4046856422.4000005, QgsUnitTypes.AreaSquareCentimeters: 40468564.224, QgsUnitTypes.AreaUnknownUnit: 1.0 }, QgsUnitTypes.AreaSquareNauticalMiles: { QgsUnitTypes.AreaSquareMeters: 3429904, QgsUnitTypes.AreaSquareKilometers: 3.4299040, QgsUnitTypes.AreaSquareFeet: 36919179.39391434, QgsUnitTypes.AreaSquareYards: 4102131.04376826, QgsUnitTypes.AreaSquareMiles: 1.324293337, QgsUnitTypes.AreaHectares: 342.9904000000, QgsUnitTypes.AreaAcres: 847.54773631, QgsUnitTypes.AreaSquareNauticalMiles: 1.0, QgsUnitTypes.AreaSquareDegrees: 0.000276783083025, QgsUnitTypes.AreaSquareMillimeters: 3429904000000.0, QgsUnitTypes.AreaSquareCentimeters: 34299040000.0, QgsUnitTypes.AreaUnknownUnit: 1.0 }, QgsUnitTypes.AreaSquareDegrees: { QgsUnitTypes.AreaSquareMeters: 12392029030.5, QgsUnitTypes.AreaSquareKilometers: 12392.029030499, QgsUnitTypes.AreaSquareFeet: 133386690365.5682220, QgsUnitTypes.AreaSquareYards: 14820743373.9520263, QgsUnitTypes.AreaSquareMiles: 4784.5891573967, QgsUnitTypes.AreaHectares: 1239202.903050, QgsUnitTypes.AreaAcres: 3062137.060733889, QgsUnitTypes.AreaSquareNauticalMiles: 3612.93757215, QgsUnitTypes.AreaSquareDegrees: 1.0, QgsUnitTypes.AreaSquareMillimeters: 12392029030500000.0, QgsUnitTypes.AreaSquareCentimeters: 123920290305000.0, QgsUnitTypes.AreaUnknownUnit: 1.0 }, QgsUnitTypes.AreaSquareMillimeters: { QgsUnitTypes.AreaSquareMeters: 1e-6, QgsUnitTypes.AreaSquareKilometers: 1e-12, QgsUnitTypes.AreaSquareFeet: 0.000010763910417, QgsUnitTypes.AreaSquareYards: 0.000001195990046, QgsUnitTypes.AreaSquareMiles: 3.861021585424458e-13, QgsUnitTypes.AreaHectares: 1e-10, QgsUnitTypes.AreaAcres: 2.471053814671653e-10, QgsUnitTypes.AreaSquareNauticalMiles: 2.9155334959812287e-13, QgsUnitTypes.AreaSquareDegrees: 8.069703496810251e-17, QgsUnitTypes.AreaSquareMillimeters: 1.0, QgsUnitTypes.AreaSquareCentimeters: 0.01, QgsUnitTypes.AreaUnknownUnit: 1.0 }, QgsUnitTypes.AreaSquareCentimeters: { QgsUnitTypes.AreaSquareMeters: 1e-4, QgsUnitTypes.AreaSquareKilometers: 1e-10, QgsUnitTypes.AreaSquareFeet: 0.0010763910417, QgsUnitTypes.AreaSquareYards: 0.0001195990046, QgsUnitTypes.AreaSquareMiles: 3.861021585424458e-11, QgsUnitTypes.AreaHectares: 1e-8, QgsUnitTypes.AreaAcres: 2.471053814671653e-8, QgsUnitTypes.AreaSquareNauticalMiles: 2.9155334959812287e-11, QgsUnitTypes.AreaSquareDegrees: 8.069703496810251e-15, QgsUnitTypes.AreaSquareMillimeters: 100, QgsUnitTypes.AreaSquareCentimeters: 1.0, QgsUnitTypes.AreaUnknownUnit: 1.0 } } for from_unit in list(expected.keys()): for to_unit in list(expected[from_unit].keys()): expected_factor = expected[from_unit][to_unit] res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, to_unit) self.assertAlmostEqual( res, expected_factor, msg= 'got {:.15f}, expected {:.15f} when converting from {} to {}' .format(res, expected_factor, QgsUnitTypes.toString(from_unit), QgsUnitTypes.toString(to_unit))) # test conversion to unknown units res = QgsUnitTypes.fromUnitToUnitFactor( from_unit, QgsUnitTypes.AreaUnknownUnit) self.assertAlmostEqual( res, 1.0, msg= 'got {:.7f}, expected 1.0 when converting from {} to unknown units' .format(res, expected_factor, QgsUnitTypes.toString(from_unit)))
def processAlgorithm(self, feedback): layer = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT_VECTOR)) startPoints = dataobjects.getObjectFromUri( self.getParameterValue(self.START_POINTS)) strategy = self.getParameterValue(self.STRATEGY) travelCost = self.getParameterValue(self.TRAVEL_COST) directionFieldName = self.getParameterValue(self.DIRECTION_FIELD) forwardValue = self.getParameterValue(self.VALUE_FORWARD) backwardValue = self.getParameterValue(self.VALUE_BACKWARD) bothValue = self.getParameterValue(self.VALUE_BOTH) defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION) bothValue = self.getParameterValue(self.VALUE_BOTH) defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION) speedFieldName = self.getParameterValue(self.SPEED_FIELD) defaultSpeed = self.getParameterValue(self.DEFAULT_SPEED) tolerance = self.getParameterValue(self.TOLERANCE) fields = QgsFields() fields.append(QgsField('type', QVariant.String, '', 254, 0)) fields.append(QgsField('start', QVariant.String, '', 254, 0)) feat = QgsFeature() feat.setFields(fields) writerPoints = self.getOutputFromName( self.OUTPUT_POINTS).getVectorWriter( fields, QgsWkbTypes.MultiPoint, layer.crs()) writerPolygons = self.getOutputFromName( self.OUTPUT_POLYGON).getVectorWriter( fields, QgsWkbTypes.Polygon, layer.crs()) directionField = -1 if directionFieldName is not None: directionField = layer.fields().lookupField(directionFieldName) speedField = -1 if speedFieldName is not None: speedField = layer.fields().lookupField(speedFieldName) director = QgsVectorLayerDirector(layer, directionField, forwardValue, backwardValue, bothValue, defaultDirection) distUnit = iface.mapCanvas().mapSettings().destinationCrs().mapUnits() multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters) if strategy == 0: strategy = QgsNetworkDistanceStrategy() else: strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed, multiplier * 1000.0 / 3600.0) director.addStrategy(strategy) builder = QgsGraphBuilder(iface.mapCanvas().mapSettings().destinationCrs(), iface.mapCanvas().hasCrsTransformEnabled(), tolerance) feedback.pushInfo(self.tr('Loading start points...')) request = QgsFeatureRequest() request.setFlags(request.flags() ^ QgsFeatureRequest.SubsetOfAttributes) features = vector.features(startPoints, request) points = [] for f in features: points.append(f.geometry().asPoint()) feedback.pushInfo(self.tr('Building graph...')) snappedPoints = director.makeGraph(builder, points) feedback.pushInfo(self.tr('Calculating service areas...')) graph = builder.graph() vertices = [] upperBoundary = [] lowerBoundary = [] total = 100.0 / len(snappedPoints) for i, p in enumerate(snappedPoints): idxStart = graph.findVertex(snappedPoints[i]) origPoint = points[i].toString() tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) for j, v in enumerate(cost): if v > travelCost and tree[j] != -1: vertexId = graph.edge(tree[j]).outVertex() if cost[vertexId] <= travelCost: vertices.append(j) for j in vertices: upperBoundary.append(graph.vertex(graph.edge(tree[j]).inVertex()).point()) lowerBoundary.append(graph.vertex(graph.edge(tree[j]).outVertex()).point()) geomUpper = QgsGeometry.fromMultiPoint(upperBoundary) geomLower = QgsGeometry.fromMultiPoint(lowerBoundary) feat.setGeometry(geomUpper) feat['type'] = 'upper' feat['start'] = origPoint writerPoints.addFeature(feat) feat.setGeometry(geomLower) feat['type'] = 'lower' feat['start'] = origPoint writerPoints.addFeature(feat) upperBoundary.append(startPoint) lowerBoundary.append(startPoint) geomUpper = QgsGeometry.fromMultiPoint(upperBoundary) geomLower = QgsGeometry.fromMultiPoint(lowerBoundary) geom = geomUpper.convexHull() feat.setGeometry(geom) feat['type'] = 'upper' feat['start'] = origPoint writerPolygons.addFeature(feat) geom = geomLower.convexHull() feat.setGeometry(geom) feat['type'] = 'lower' feat['start'] = origPoint writerPolygons.addFeature(feat) vertices[:] = [] upperBoundary[:] = [] lowerBoundary[:] = [] feedback.setProgress(int(i * total)) del writerPoints del writerPolygons
def processAlgorithm(self, parameters, context, feedback): network = self.parameterAsSource(parameters, self.INPUT, context) if network is None: raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) startPoints = self.parameterAsSource(parameters, self.START_POINTS, context) if startPoints is None: raise QgsProcessingException(self.invalidSourceError(parameters, self.START_POINTS)) endPoint = self.parameterAsPoint(parameters, self.END_POINT, context, network.sourceCrs()) strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) fields = startPoints.fields() fields.append(QgsField('start', QVariant.String, '', 254, 0)) fields.append(QgsField('end', QVariant.String, '', 254, 0)) fields.append(QgsField('cost', QVariant.Double, '', 20, 7)) feat = QgsFeature() feat.setFields(fields) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.LineString, network.sourceCrs()) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) directionField = -1 if directionFieldName: directionField = network.fields().lookupField(directionFieldName) speedField = -1 if speedFieldName: speedField = network.fields().lookupField(speedFieldName) director = QgsVectorLayerDirector(network, directionField, forwardValue, backwardValue, bothValue, defaultDirection) distUnit = context.project().crs().mapUnits() multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters) if strategy == 0: strategy = QgsNetworkDistanceStrategy() else: strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed, multiplier * 1000.0 / 3600.0) multiplier = 3600 director.addStrategy(strategy) builder = QgsGraphBuilder(network.sourceCrs(), True, tolerance) feedback.pushInfo(QCoreApplication.translate('ShortestPathLayerToPoint', 'Loading start points…')) request = QgsFeatureRequest() request.setDestinationCrs(network.sourceCrs(), context.transformContext()) features = startPoints.getFeatures(request) total = 100.0 / startPoints.featureCount() if startPoints.featureCount() else 0 points = [endPoint] source_attributes = {} i = 1 for current, f in enumerate(features): if feedback.isCanceled(): break if not f.hasGeometry(): continue for p in f.geometry().vertices(): points.append(QgsPointXY(p)) source_attributes[i] = f.attributes() i += 1 feedback.setProgress(int(current * total)) feedback.pushInfo(QCoreApplication.translate('ShortestPathLayerToPoint', 'Building graph…')) snappedPoints = director.makeGraph(builder, points, feedback) feedback.pushInfo(QCoreApplication.translate('ShortestPathLayerToPoint', 'Calculating shortest paths…')) graph = builder.graph() idxEnd = graph.findVertex(snappedPoints[0]) nPoints = len(snappedPoints) total = 100.0 / nPoints if nPoints else 1 for i in range(1, nPoints): if feedback.isCanceled(): break idxStart = graph.findVertex(snappedPoints[i]) tree, costs = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) if tree[idxEnd] == -1: msg = self.tr('There is no route from start point ({}) to end point ({}).'.format(points[i].toString(), endPoint.toString())) feedback.reportError(msg) # add feature with no geometry feat.clearGeometry() attrs = source_attributes[i] attrs.append(points[i].toString()) feat.setAttributes(attrs) sink.addFeature(feat, QgsFeatureSink.FastInsert) continue route = [graph.vertex(idxEnd).point()] cost = costs[idxEnd] current = idxEnd while current != idxStart: current = graph.edge(tree[current]).fromVertex() route.append(graph.vertex(current).point()) route.reverse() geom = QgsGeometry.fromPolylineXY(route) feat.setGeometry(geom) attrs = source_attributes[i] attrs.extend([points[i].toString(), endPoint.toString(), cost / multiplier]) feat.setAttributes(attrs) sink.addFeature(feat, QgsFeatureSink.FastInsert) feedback.setProgress(int(i * total)) return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): network = self.parameterAsSource(parameters, self.INPUT, context) startPoints = self.parameterAsSource(parameters, self.START_POINTS, context) strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) travelCost = self.parameterAsDouble(parameters, self.TRAVEL_COST, context) directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) fields = startPoints.fields() fields.append(QgsField('type', QVariant.String, '', 254, 0)) fields.append(QgsField('start', QVariant.String, '', 254, 0)) feat = QgsFeature() feat.setFields(fields) directionField = -1 if directionFieldName: directionField = network.fields().lookupField(directionFieldName) speedField = -1 if speedFieldName: speedField = network.fields().lookupField(speedFieldName) director = QgsVectorLayerDirector(network, directionField, forwardValue, backwardValue, bothValue, defaultDirection) distUnit = context.project().crs().mapUnits() multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters) if strategy == 0: strategy = QgsNetworkDistanceStrategy() else: strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed, multiplier * 1000.0 / 3600.0) director.addStrategy(strategy) builder = QgsGraphBuilder(network.sourceCrs(), True, tolerance) feedback.pushInfo(self.tr('Loading start points...')) request = QgsFeatureRequest() request.setDestinationCrs(network.sourceCrs()) features = startPoints.getFeatures(request) total = 100.0 / startPoints.featureCount() if startPoints.featureCount() else 0 points = [] source_attributes = {} i = 0 for current, f in enumerate(features): if feedback.isCanceled(): break if not f.hasGeometry(): continue for p in f.geometry().vertices(): points.append(QgsPointXY(p)) source_attributes[i] = f.attributes() i += 1 feedback.setProgress(int(current * total)) feedback.pushInfo(self.tr('Building graph...')) snappedPoints = director.makeGraph(builder, points, feedback) feedback.pushInfo(self.tr('Calculating service areas...')) graph = builder.graph() (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.MultiPoint, network.sourceCrs()) vertices = [] upperBoundary = [] lowerBoundary = [] total = 100.0 / len(snappedPoints) if snappedPoints else 1 for i, p in enumerate(snappedPoints): if feedback.isCanceled(): break idxStart = graph.findVertex(snappedPoints[i]) origPoint = points[i].toString() tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) for j, v in enumerate(cost): if v > travelCost and tree[j] != -1: vertexId = graph.edge(tree[j]).fromVertex() if cost[vertexId] <= travelCost: vertices.append(j) for j in vertices: upperBoundary.append(graph.vertex(graph.edge(tree[j]).toVertex()).point()) lowerBoundary.append(graph.vertex(graph.edge(tree[j]).fromVertex()).point()) geomUpper = QgsGeometry.fromMultiPointXY(upperBoundary) geomLower = QgsGeometry.fromMultiPointXY(lowerBoundary) feat.setGeometry(geomUpper) attrs = source_attributes[i] attrs.extend(['upper', origPoint]) feat.setAttributes(attrs) sink.addFeature(feat, QgsFeatureSink.FastInsert) feat.setGeometry(geomLower) attrs[-2] = 'lower' feat.setAttributes(attrs) sink.addFeature(feat, QgsFeatureSink.FastInsert) vertices[:] = [] upperBoundary[:] = [] lowerBoundary[:] = [] feedback.setProgress(int(i * total)) return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): network = self.parameterAsSource(parameters, self.INPUT, context) startPoints = self.parameterAsSource(parameters, self.START_POINTS, context) endPoint = self.parameterAsPoint(parameters, self.END_POINT, context) strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) fields = QgsFields() fields.append(QgsField('start', QVariant.String, '', 254, 0)) fields.append(QgsField('end', QVariant.String, '', 254, 0)) fields.append(QgsField('cost', QVariant.Double, '', 20, 7)) feat = QgsFeature() feat.setFields(fields) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.LineString, network.sourceCrs()) directionField = -1 if directionFieldName: directionField = network.fields().lookupField(directionFieldName) speedField = -1 if speedFieldName: speedField = network.fields().lookupField(speedFieldName) director = QgsVectorLayerDirector(network, directionField, forwardValue, backwardValue, bothValue, defaultDirection) distUnit = context.project().crs().mapUnits() multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters) if strategy == 0: strategy = QgsNetworkDistanceStrategy() else: strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed, multiplier * 1000.0 / 3600.0) multiplier = 3600 director.addStrategy(strategy) builder = QgsGraphBuilder(context.project().crs(), True, tolerance) feedback.pushInfo(self.tr('Loading start points...')) request = QgsFeatureRequest() request.setFlags(request.flags() ^ QgsFeatureRequest.SubsetOfAttributes) request.setDestinationCrs(network.sourceCrs()) features = startPoints.getFeatures(request) total = 100.0 / startPoints.featureCount() if startPoints.featureCount() else 0 points = [endPoint] for current, f in enumerate(features): if feedback.isCanceled(): break points.append(f.geometry().asPoint()) feedback.setProgress(int(current * total)) feedback.pushInfo(self.tr('Building graph...')) snappedPoints = director.makeGraph(builder, points, feedback) feedback.pushInfo(self.tr('Calculating shortest paths...')) graph = builder.graph() idxEnd = graph.findVertex(snappedPoints[0]) route = [] nPoints = len(snappedPoints) total = 100.0 / nPoints if nPoints else 1 for i in range(1, count + 1): if feedback.isCanceled(): break idxStart = graph.findVertex(snappedPoints[i]) tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) if tree[idxEnd] == -1: msg = self.tr('There is no route from start point ({}) to end point ({}).'.format(points[i].toString(), endPoint.toString())) feedback.setProgressText(msg) QgsMessageLog.logMessage(msg, self.tr('Processing'), QgsMessageLog.WARNING) continue cost = 0.0 current = idxEnd while current != idxStart: cost += graph.edge(tree[current]).cost(0) route.append(graph.vertex(graph.edge(tree[current]).inVertex()).point()) current = graph.edge(tree[current]).outVertex() route.append(snappedPoints[i]) route.reverse() geom = QgsGeometry.fromPolyline(route) feat.setGeometry(geom) feat['start'] = points[i].toString() feat['end'] = endPoint.toString() feat['cost'] = cost / multiplier sink.addFeature(feat, QgsFeatureSink.FastInsert) route[:] = [] feedback.setProgress(int(i * total)) return {self.OUTPUT: dest_id}
QgsUnitTypes.DistanceYards, QgsUnitTypes.DistanceMeters) elif units == 5: # Feet measureFactor = QgsUnitTypes.fromUnitToUnitFactor( QgsUnitTypes.DistanceFeet, QgsUnitTypes.DistanceMeters) elif units == 6: # Inches measureFactor = QgsUnitTypes.fromUnitToUnitFactor( QgsUnitTypes.DistanceFeet, QgsUnitTypes.DistanceMeters) / 12.0 elif units == 7: # Nautical Miles measureFactor = QgsUnitTypes.fromUnitToUnitFactor( QgsUnitTypes.DistanceNauticalMiles, QgsUnitTypes.DistanceMeters) return measureFactor epsg4326 = QgsCoordinateReferenceSystem("EPSG:4326") nmToMeters = QgsUnitTypes.fromUnitToUnitFactor( QgsUnitTypes.DistanceNauticalMiles, QgsUnitTypes.DistanceMeters) metersToFeet = QgsUnitTypes.fromUnitToUnitFactor(QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceFeet) degToMeters = nmToMeters * 60 metersToDeg = 1 / degToMeters # vector addition of two XY points def addPoints(a, b): return QgsPointXY(a.x() + b.x(), a.y() + b.y()) # vector difference of two XY points def diffPoints(a, b): return QgsPointXY(a.x() - b.x(), a.y() - b.y())
def processAlgorithm(self, feedback): layer = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT_VECTOR)) startPoint = self.getParameterValue(self.START_POINT) endPoint = self.getParameterValue(self.END_POINT) strategy = self.getParameterValue(self.STRATEGY) directionFieldName = self.getParameterValue(self.DIRECTION_FIELD) forwardValue = self.getParameterValue(self.VALUE_FORWARD) backwardValue = self.getParameterValue(self.VALUE_BACKWARD) bothValue = self.getParameterValue(self.VALUE_BOTH) defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION) bothValue = self.getParameterValue(self.VALUE_BOTH) defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION) speedFieldName = self.getParameterValue(self.SPEED_FIELD) defaultSpeed = self.getParameterValue(self.DEFAULT_SPEED) tolerance = self.getParameterValue(self.TOLERANCE) fields = QgsFields() fields.append(QgsField('start', QVariant.String, '', 254, 0)) fields.append(QgsField('end', QVariant.String, '', 254, 0)) fields.append(QgsField('cost', QVariant.Double, '', 20, 7)) writer = self.getOutputFromName( self.OUTPUT_LAYER).getVectorWriter( fields.toList(), QgsWkbTypes.LineString, layer.crs()) tmp = startPoint.split(',') startPoint = QgsPoint(float(tmp[0]), float(tmp[1])) tmp = endPoint.split(',') endPoint = QgsPoint(float(tmp[0]), float(tmp[1])) directionField = -1 if directionFieldName is not None: directionField = layer.fields().lookupField(directionFieldName) speedField = -1 if speedFieldName is not None: speedField = layer.fields().lookupField(speedFieldName) director = QgsVectorLayerDirector(layer, directionField, forwardValue, backwardValue, bothValue, defaultDirection) distUnit = iface.mapCanvas().mapSettings().destinationCrs().mapUnits() multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters) if strategy == 0: strategy = QgsNetworkDistanceStrategy() else: strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed, multiplier * 1000.0 / 3600.0) multiplier = 3600 director.addStrategy(strategy) builder = QgsGraphBuilder(iface.mapCanvas().mapSettings().destinationCrs(), iface.mapCanvas().hasCrsTransformEnabled(), tolerance) feedback.pushInfo(self.tr('Building graph...')) snappedPoints = director.makeGraph(builder, [startPoint, endPoint]) feedback.pushInfo(self.tr('Calculating shortest path...')) graph = builder.graph() idxStart = graph.findVertex(snappedPoints[0]) idxEnd = graph.findVertex(snappedPoints[1]) tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) if tree[idxEnd] == -1: raise GeoAlgorithmExecutionException( self.tr('There is no route from start point to end point.')) route = [] cost = 0.0 current = idxEnd while current != idxStart: cost += graph.edge(tree[current]).cost(0) route.append(graph.vertex(graph.edge(tree[current]).inVertex()).point()) current = graph.edge(tree[current]).outVertex() route.append(snappedPoints[0]) route.reverse() self.setOutputValue(self.TRAVEL_COST, cost / multiplier) feedback.pushInfo(self.tr('Writing results...')) geom = QgsGeometry.fromPolyline(route) feat = QgsFeature() feat.setFields(fields) feat['start'] = startPoint.toString() feat['end'] = endPoint.toString() feat['cost'] = cost / multiplier feat.setGeometry(geom) writer.addFeature(feat) del writer
def testAngleFromUnitToUnitFactor(self): """Test calculation of conversion factor between angular units""" expected = { QgsUnitTypes.AngleDegrees: { QgsUnitTypes.AngleDegrees: 1.0, QgsUnitTypes.AngleRadians: 0.0174533, QgsUnitTypes.AngleGon: 1.1111111, QgsUnitTypes.AngleMinutesOfArc: 60, QgsUnitTypes.AngleSecondsOfArc: 3600, QgsUnitTypes.AngleTurn: 0.00277777777778 }, QgsUnitTypes.AngleRadians: { QgsUnitTypes.AngleDegrees: 57.2957795, QgsUnitTypes.AngleRadians: 1.0, QgsUnitTypes.AngleGon: 63.6619772, QgsUnitTypes.AngleMinutesOfArc: 3437.7467708, QgsUnitTypes.AngleSecondsOfArc: 206264.8062471, QgsUnitTypes.AngleTurn: 0.159154943092 }, QgsUnitTypes.AngleGon: { QgsUnitTypes.AngleDegrees: 0.9000000, QgsUnitTypes.AngleRadians: 0.015707968623450838802, QgsUnitTypes.AngleGon: 1.0, QgsUnitTypes.AngleMinutesOfArc: 54.0000000, QgsUnitTypes.AngleSecondsOfArc: 3240.0000000, QgsUnitTypes.AngleTurn: 0.0025 }, QgsUnitTypes.AngleMinutesOfArc: { QgsUnitTypes.AngleDegrees: 0.016666672633390722247, QgsUnitTypes.AngleRadians: 0.00029088831280398030638, QgsUnitTypes.AngleGon: 0.018518525464057963154, QgsUnitTypes.AngleMinutesOfArc: 1.0, QgsUnitTypes.AngleSecondsOfArc: 60.0, QgsUnitTypes.AngleTurn: 4.62962962962963e-05 }, QgsUnitTypes.AngleSecondsOfArc: { QgsUnitTypes.AngleDegrees: 0.00027777787722304257169, QgsUnitTypes.AngleRadians: 4.848138546730629518e-6, QgsUnitTypes.AngleGon: 0.0003086420910674814405, QgsUnitTypes.AngleMinutesOfArc: 0.016666672633325253783, QgsUnitTypes.AngleSecondsOfArc: 1.0, QgsUnitTypes.AngleTurn: 7.71604938271605e-07 }, QgsUnitTypes.AngleTurn: { QgsUnitTypes.AngleDegrees: 360.0, QgsUnitTypes.AngleRadians: 6.2831853071795, QgsUnitTypes.AngleGon: 400.0, QgsUnitTypes.AngleMinutesOfArc: 21600, QgsUnitTypes.AngleSecondsOfArc: 1296000, QgsUnitTypes.AngleTurn: 1 } } for from_unit in list(expected.keys()): for to_unit in list(expected[from_unit].keys()): expected_factor = expected[from_unit][to_unit] res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, to_unit) self.assertAlmostEqual( res, expected_factor, msg= 'got {:.7f}, expected {:.7f} when converting from {} to {}' .format(res, expected_factor, QgsUnitTypes.toString(from_unit), QgsUnitTypes.toString(to_unit))) # test conversion to unknown units res = QgsUnitTypes.fromUnitToUnitFactor( from_unit, QgsUnitTypes.AngleUnknownUnit) self.assertAlmostEqual( res, 1.0, msg= 'got {:.7f}, expected 1.0 when converting from {} to unknown units' .format(res, expected_factor, QgsUnitTypes.toString(from_unit)))
def processAlgorithm(self, feedback): layer = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT_VECTOR)) startPoints = dataobjects.getObjectFromUri( self.getParameterValue(self.START_POINTS)) strategy = self.getParameterValue(self.STRATEGY) travelCost = self.getParameterValue(self.TRAVEL_COST) directionFieldName = self.getParameterValue(self.DIRECTION_FIELD) forwardValue = self.getParameterValue(self.VALUE_FORWARD) backwardValue = self.getParameterValue(self.VALUE_BACKWARD) bothValue = self.getParameterValue(self.VALUE_BOTH) defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION) bothValue = self.getParameterValue(self.VALUE_BOTH) defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION) speedFieldName = self.getParameterValue(self.SPEED_FIELD) defaultSpeed = self.getParameterValue(self.DEFAULT_SPEED) tolerance = self.getParameterValue(self.TOLERANCE) fields = QgsFields() fields.append(QgsField('type', QVariant.String, '', 254, 0)) fields.append(QgsField('start', QVariant.String, '', 254, 0)) feat = QgsFeature() feat.setFields(fields) writerPoints = self.getOutputFromName( self.OUTPUT_POINTS).getVectorWriter(fields, QgsWkbTypes.MultiPoint, layer.crs()) writerPolygons = self.getOutputFromName( self.OUTPUT_POLYGON).getVectorWriter(fields, QgsWkbTypes.Polygon, layer.crs()) directionField = -1 if directionFieldName is not None: directionField = layer.fields().lookupField(directionFieldName) speedField = -1 if speedFieldName is not None: speedField = layer.fields().lookupField(speedFieldName) director = QgsVectorLayerDirector(layer, directionField, forwardValue, backwardValue, bothValue, defaultDirection) distUnit = iface.mapCanvas().mapSettings().destinationCrs().mapUnits() multiplier = QgsUnitTypes.fromUnitToUnitFactor( distUnit, QgsUnitTypes.DistanceMeters) if strategy == 0: strategy = QgsNetworkDistanceStrategy() else: strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed, multiplier * 1000.0 / 3600.0) director.addStrategy(strategy) builder = QgsGraphBuilder( iface.mapCanvas().mapSettings().destinationCrs(), iface.mapCanvas().hasCrsTransformEnabled(), tolerance) feedback.pushInfo(self.tr('Loading start points...')) request = QgsFeatureRequest() request.setFlags(request.flags() ^ QgsFeatureRequest.SubsetOfAttributes) features = vector.features(startPoints, request) points = [] for f in features: points.append(f.geometry().asPoint()) feedback.pushInfo(self.tr('Building graph...')) snappedPoints = director.makeGraph(builder, points) feedback.pushInfo(self.tr('Calculating service areas...')) graph = builder.graph() vertices = [] upperBoundary = [] lowerBoundary = [] total = 100.0 / len(snappedPoints) for i, p in enumerate(snappedPoints): idxStart = graph.findVertex(snappedPoints[i]) origPoint = points[i].toString() tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) for j, v in enumerate(cost): if v > travelCost and tree[j] != -1: vertexId = graph.edge(tree[j]).outVertex() if cost[vertexId] <= travelCost: vertices.append(j) for j in vertices: upperBoundary.append( graph.vertex(graph.edge(tree[j]).inVertex()).point()) lowerBoundary.append( graph.vertex(graph.edge(tree[j]).outVertex()).point()) geomUpper = QgsGeometry.fromMultiPoint(upperBoundary) geomLower = QgsGeometry.fromMultiPoint(lowerBoundary) feat.setGeometry(geomUpper) feat['type'] = 'upper' feat['start'] = origPoint writerPoints.addFeature(feat) feat.setGeometry(geomLower) feat['type'] = 'lower' feat['start'] = origPoint writerPoints.addFeature(feat) upperBoundary.append(startPoint) lowerBoundary.append(startPoint) geomUpper = QgsGeometry.fromMultiPoint(upperBoundary) geomLower = QgsGeometry.fromMultiPoint(lowerBoundary) geom = geomUpper.convexHull() feat.setGeometry(geom) feat['type'] = 'upper' feat['start'] = origPoint writerPolygons.addFeature(feat) geom = geomLower.convexHull() feat.setGeometry(geom) feat['type'] = 'lower' feat['start'] = origPoint writerPolygons.addFeature(feat) vertices[:] = [] upperBoundary[:] = [] lowerBoundary[:] = [] feedback.setProgress(int(i * total)) del writerPoints del writerPolygons
def processAlgorithm(self, feedback): layer = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT_VECTOR)) startPoint = self.getParameterValue(self.START_POINT) endPoint = self.getParameterValue(self.END_POINT) strategy = self.getParameterValue(self.STRATEGY) directionFieldName = self.getParameterValue(self.DIRECTION_FIELD) forwardValue = self.getParameterValue(self.VALUE_FORWARD) backwardValue = self.getParameterValue(self.VALUE_BACKWARD) bothValue = self.getParameterValue(self.VALUE_BOTH) defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION) bothValue = self.getParameterValue(self.VALUE_BOTH) defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION) speedFieldName = self.getParameterValue(self.SPEED_FIELD) defaultSpeed = self.getParameterValue(self.DEFAULT_SPEED) tolerance = self.getParameterValue(self.TOLERANCE) fields = QgsFields() fields.append(QgsField('start', QVariant.String, '', 254, 0)) fields.append(QgsField('end', QVariant.String, '', 254, 0)) fields.append(QgsField('cost', QVariant.Double, '', 20, 7)) writer = self.getOutputFromName(self.OUTPUT_LAYER).getVectorWriter( fields.toList(), QgsWkbTypes.LineString, layer.crs()) tmp = startPoint.split(',') startPoint = QgsPoint(float(tmp[0]), float(tmp[1])) tmp = endPoint.split(',') endPoint = QgsPoint(float(tmp[0]), float(tmp[1])) directionField = -1 if directionFieldName is not None: directionField = layer.fields().lookupField(directionFieldName) speedField = -1 if speedFieldName is not None: speedField = layer.fields().lookupField(speedFieldName) director = QgsVectorLayerDirector(layer, directionField, forwardValue, backwardValue, bothValue, defaultDirection) distUnit = iface.mapCanvas().mapSettings().destinationCrs().mapUnits() multiplier = QgsUnitTypes.fromUnitToUnitFactor( distUnit, QgsUnitTypes.DistanceMeters) if strategy == 0: strategy = QgsNetworkDistanceStrategy() else: strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed, multiplier * 1000.0 / 3600.0) multiplier = 3600 director.addStrategy(strategy) builder = QgsGraphBuilder( iface.mapCanvas().mapSettings().destinationCrs(), True, tolerance) feedback.pushInfo(self.tr('Building graph...')) snappedPoints = director.makeGraph(builder, [startPoint, endPoint]) feedback.pushInfo(self.tr('Calculating shortest path...')) graph = builder.graph() idxStart = graph.findVertex(snappedPoints[0]) idxEnd = graph.findVertex(snappedPoints[1]) tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) if tree[idxEnd] == -1: raise GeoAlgorithmExecutionException( self.tr('There is no route from start point to end point.')) route = [] cost = 0.0 current = idxEnd while current != idxStart: cost += graph.edge(tree[current]).cost(0) route.append( graph.vertex(graph.edge(tree[current]).inVertex()).point()) current = graph.edge(tree[current]).outVertex() route.append(snappedPoints[0]) route.reverse() self.setOutputValue(self.TRAVEL_COST, cost / multiplier) feedback.pushInfo(self.tr('Writing results...')) geom = QgsGeometry.fromPolyline(route) feat = QgsFeature() feat.setFields(fields) feat['start'] = startPoint.toString() feat['end'] = endPoint.toString() feat['cost'] = cost / multiplier feat.setGeometry(geom) writer.addFeature(feat) del writer
def processAlgorithm(self, parameters, context, feedback): network = self.parameterAsSource(parameters, self.INPUT, context) if network is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT)) startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs()) strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) travelCost = self.parameterAsDouble(parameters, self.TRAVEL_COST, context) directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) include_bounds = True # default to true to maintain 3.0 API if self.INCLUDE_BOUNDS in parameters: include_bounds = self.parameterAsBool(parameters, self.INCLUDE_BOUNDS, context) directionField = -1 if directionFieldName: directionField = network.fields().lookupField(directionFieldName) speedField = -1 if speedFieldName: speedField = network.fields().lookupField(speedFieldName) director = QgsVectorLayerDirector(network, directionField, forwardValue, backwardValue, bothValue, defaultDirection) distUnit = context.project().crs().mapUnits() multiplier = QgsUnitTypes.fromUnitToUnitFactor( distUnit, QgsUnitTypes.DistanceMeters) if strategy == 0: strategy = QgsNetworkDistanceStrategy() else: strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed, multiplier * 1000.0 / 3600.0) director.addStrategy(strategy) builder = QgsGraphBuilder(network.sourceCrs(), True, tolerance) feedback.pushInfo( QCoreApplication.translate('ServiceAreaFromPoint', 'Building graph…')) snappedPoints = director.makeGraph(builder, [startPoint], feedback) feedback.pushInfo( QCoreApplication.translate('ServiceAreaFromPoint', 'Calculating service area…')) graph = builder.graph() idxStart = graph.findVertex(snappedPoints[0]) tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) vertices = set() points = [] lines = [] for vertex, start_vertex_cost in enumerate(cost): inbound_edge_index = tree[vertex] if inbound_edge_index == -1 and vertex != idxStart: # unreachable vertex continue if start_vertex_cost > travelCost: # vertex is too expensive, discard continue vertices.add(vertex) start_point = graph.vertex(vertex).point() # find all edges coming from this vertex for edge_id in graph.vertex(vertex).outgoingEdges(): edge = graph.edge(edge_id) end_vertex_cost = start_vertex_cost + edge.cost(0) end_point = graph.vertex(edge.toVertex()).point() if end_vertex_cost <= travelCost: # end vertex is cheap enough to include vertices.add(edge.toVertex()) lines.append([start_point, end_point]) else: # travelCost sits somewhere on this edge, interpolate position interpolated_end_point = QgsGeometryUtils.interpolatePointOnLineByValue( start_point.x(), start_point.y(), start_vertex_cost, end_point.x(), end_point.y(), end_vertex_cost, travelCost) points.append(interpolated_end_point) lines.append([start_point, interpolated_end_point]) for i in vertices: points.append(graph.vertex(i).point()) feedback.pushInfo( QCoreApplication.translate('ServiceAreaFromPoint', 'Writing results…')) fields = QgsFields() fields.append(QgsField('type', QVariant.String, '', 254, 0)) fields.append(QgsField('start', QVariant.String, '', 254, 0)) feat = QgsFeature() feat.setFields(fields) (point_sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.MultiPoint, network.sourceCrs()) results = {} if point_sink is not None: results[self.OUTPUT] = dest_id geomPoints = QgsGeometry.fromMultiPointXY(points) feat.setGeometry(geomPoints) feat['type'] = 'within' feat['start'] = startPoint.toString() point_sink.addFeature(feat, QgsFeatureSink.FastInsert) if include_bounds: upperBoundary = [] lowerBoundary = [] vertices = [] for i, v in enumerate(cost): if v > travelCost and tree[i] != -1: vertexId = graph.edge(tree[i]).fromVertex() if cost[vertexId] <= travelCost: vertices.append(i) for i in vertices: upperBoundary.append( graph.vertex(graph.edge(tree[i]).toVertex()).point()) lowerBoundary.append( graph.vertex(graph.edge(tree[i]).fromVertex()).point()) geomUpper = QgsGeometry.fromMultiPointXY(upperBoundary) geomLower = QgsGeometry.fromMultiPointXY(lowerBoundary) feat.setGeometry(geomUpper) feat['type'] = 'upper' feat['start'] = startPoint.toString() point_sink.addFeature(feat, QgsFeatureSink.FastInsert) feat.setGeometry(geomLower) feat['type'] = 'lower' feat['start'] = startPoint.toString() point_sink.addFeature(feat, QgsFeatureSink.FastInsert) (line_sink, line_dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LINES, context, fields, QgsWkbTypes.MultiLineString, network.sourceCrs()) if line_sink is not None: results[self.OUTPUT_LINES] = line_dest_id geom_lines = QgsGeometry.fromMultiPolylineXY(lines) feat.setGeometry(geom_lines) feat['type'] = 'lines' feat['start'] = startPoint.toString() line_sink.addFeature(feat, QgsFeatureSink.FastInsert) return results
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT_VECTOR)) startPoint = self.getParameterValue(self.START_POINT) endPoints = dataobjects.getObjectFromUri( self.getParameterValue(self.END_POINTS)) strategy = self.getParameterValue(self.STRATEGY) directionFieldName = self.getParameterValue(self.DIRECTION_FIELD) forwardValue = self.getParameterValue(self.VALUE_FORWARD) backwardValue = self.getParameterValue(self.VALUE_BACKWARD) bothValue = self.getParameterValue(self.VALUE_BOTH) defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION) bothValue = self.getParameterValue(self.VALUE_BOTH) defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION) speedFieldName = self.getParameterValue(self.SPEED_FIELD) defaultSpeed = self.getParameterValue(self.DEFAULT_SPEED) tolerance = self.getParameterValue(self.TOLERANCE) fields = QgsFields() fields.append(QgsField('start', QVariant.String, '', 254, 0)) fields.append(QgsField('end', QVariant.String, '', 254, 0)) fields.append(QgsField('cost', QVariant.Double, '', 20, 7)) feat = QgsFeature() feat.setFields(fields) writer = self.getOutputFromName( self.OUTPUT_LAYER).getVectorWriter( fields.toList(), QgsWkbTypes.LineString, layer.crs()) tmp = startPoint.split(',') startPoint = QgsPoint(float(tmp[0]), float(tmp[1])) directionField = -1 if directionFieldName is not None: directionField = layer.fields().lookupField(directionFieldName) speedField = -1 if speedFieldName is not None: speedField = layer.fields().lookupField(speedFieldName) director = QgsVectorLayerDirector(layer, directionField, forwardValue, backwardValue, bothValue, defaultDirection) distUnit = iface.mapCanvas().mapSettings().destinationCrs().mapUnits() multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters) if strategy == 0: strategy = QgsNetworkDistanceStrategy() else: strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed, multiplier * 1000.0 / 3600.0) multiplier = 3600 director.addStrategy(strategy) builder = QgsGraphBuilder(iface.mapCanvas().mapSettings().destinationCrs(), iface.mapCanvas().hasCrsTransformEnabled(), tolerance) progress.setInfo(self.tr('Loading end points...')) request = QgsFeatureRequest() request.setFlags(request.flags() ^ QgsFeatureRequest.SubsetOfAttributes) features = vector.features(endPoints, request) count = len(features) points = [startPoint] for f in features: points.append(f.geometry().asPoint()) progress.setInfo(self.tr('Building graph...')) snappedPoints = director.makeGraph(builder, points) progress.setInfo(self.tr('Calculating shortest paths...')) graph = builder.graph() idxStart = graph.findVertex(snappedPoints[0]) tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) route = [] total = 100.0 / count for i in range(1, count + 1): idxEnd = graph.findVertex(snappedPoints[i]) if tree[idxEnd] == -1: msg = self.tr('There is no route from start point ({}) to end point ({}).'.format(startPoint.toString(), points[i].toString())) progress.setText(msg) ProcessingLog.addToLog(ProcessingLog.LOG_WARNING, msg) continue cost = 0.0 current = idxEnd while current != idxStart: cost += graph.edge(tree[current]).cost(0) route.append(graph.vertex(graph.edge(tree[current]).inVertex()).point()) current = graph.edge(tree[current]).outVertex() route.append(snappedPoints[0]) route.reverse() geom = QgsGeometry.fromPolyline(route) feat.setGeometry(geom) feat['start'] = startPoint.toString() feat['end'] = points[i].toString() feat['cost'] = cost / multiplier writer.addFeature(feat) route[:] = [] progress.setPercentage(int(i * total)) del writer
def testFromUnitToUnitFactor(self): """Test calculation of conversion factor between units""" expected = { QgsUnitTypes.DistanceMeters: { QgsUnitTypes.DistanceMeters: 1.0, QgsUnitTypes.DistanceKilometers: 0.001, QgsUnitTypes.DistanceFeet: 3.28083989501, QgsUnitTypes.DistanceYards: 1.0936133, QgsUnitTypes.DistanceMiles: 0.00062136931818182, QgsUnitTypes.DistanceDegrees: 0.00000898315, QgsUnitTypes.DistanceNauticalMiles: 0.000539957, QgsUnitTypes.DistanceMillimeters: 1000.0, QgsUnitTypes.DistanceCentimeters: 100.0 }, QgsUnitTypes.DistanceKilometers: { QgsUnitTypes.DistanceMeters: 1000.0, QgsUnitTypes.DistanceKilometers: 1.0, QgsUnitTypes.DistanceFeet: 3280.8398950, QgsUnitTypes.DistanceYards: 1093.6132983, QgsUnitTypes.DistanceMiles: 0.62137121212119317271, QgsUnitTypes.DistanceDegrees: 0.0089832, QgsUnitTypes.DistanceNauticalMiles: 0.53995682073432482717, QgsUnitTypes.DistanceMillimeters: 1000000.0, QgsUnitTypes.DistanceCentimeters: 100000.0 }, QgsUnitTypes.DistanceFeet: { QgsUnitTypes.DistanceMeters: 0.3048, QgsUnitTypes.DistanceKilometers: 0.0003048, QgsUnitTypes.DistanceFeet: 1.0, QgsUnitTypes.DistanceYards: 0.3333333, QgsUnitTypes.DistanceMiles: 0.00018939375, QgsUnitTypes.DistanceDegrees: 2.73806498599629E-06, QgsUnitTypes.DistanceNauticalMiles: 0.000164579, QgsUnitTypes.DistanceMillimeters: 304.8, QgsUnitTypes.DistanceCentimeters: 30.48 }, QgsUnitTypes.DistanceYards: { QgsUnitTypes.DistanceMeters: 0.9144, QgsUnitTypes.DistanceKilometers: 0.0009144, QgsUnitTypes.DistanceFeet: 3.0, QgsUnitTypes.DistanceYards: 1.0, QgsUnitTypes.DistanceMiles: 0.000568182, QgsUnitTypes.DistanceDegrees: 0.0000082, QgsUnitTypes.DistanceNauticalMiles: 0.0004937366590756, QgsUnitTypes.DistanceMillimeters: 914.4, QgsUnitTypes.DistanceCentimeters: 91.44 }, QgsUnitTypes.DistanceDegrees: { QgsUnitTypes.DistanceMeters: 111319.49079327358, QgsUnitTypes.DistanceKilometers: 111.3194908, QgsUnitTypes.DistanceFeet: 365221.4264871, QgsUnitTypes.DistanceYards: 121740.4754957, QgsUnitTypes.DistanceMiles: 69.1707247, QgsUnitTypes.DistanceDegrees: 1.0, QgsUnitTypes.DistanceNauticalMiles: 60.1077164, QgsUnitTypes.DistanceMillimeters: 111319490.79327358, QgsUnitTypes.DistanceCentimeters: 11131949.079327358 }, QgsUnitTypes.DistanceMiles: { QgsUnitTypes.DistanceMeters: 1609.3440000, QgsUnitTypes.DistanceKilometers: 1.6093440, QgsUnitTypes.DistanceFeet: 5280.0000000, QgsUnitTypes.DistanceYards: 1760.0000000, QgsUnitTypes.DistanceMiles: 1.0, QgsUnitTypes.DistanceDegrees: 0.0144570, QgsUnitTypes.DistanceNauticalMiles: 0.8689762, QgsUnitTypes.DistanceMillimeters: 1609344.0, QgsUnitTypes.DistanceCentimeters: 160934.4 }, QgsUnitTypes.DistanceNauticalMiles: { QgsUnitTypes.DistanceMeters: 1852.0, QgsUnitTypes.DistanceKilometers: 1.8520000, QgsUnitTypes.DistanceFeet: 6076.1154856, QgsUnitTypes.DistanceYards: 2025.3718285, QgsUnitTypes.DistanceMiles: 1.1507794, QgsUnitTypes.DistanceDegrees: 0.0166367990650, QgsUnitTypes.DistanceNauticalMiles: 1.0, QgsUnitTypes.DistanceMillimeters: 1852000.0, QgsUnitTypes.DistanceCentimeters: 185200.0 }, QgsUnitTypes.DistanceMillimeters: { QgsUnitTypes.DistanceMeters: 0.001, QgsUnitTypes.DistanceKilometers: 0.000001, QgsUnitTypes.DistanceFeet: 0.00328083989501, QgsUnitTypes.DistanceYards: 0.0010936133, QgsUnitTypes.DistanceMiles: 0.00000062136931818182, QgsUnitTypes.DistanceDegrees: 0.00000000898315, QgsUnitTypes.DistanceNauticalMiles: 0.000000539957, QgsUnitTypes.DistanceMillimeters: 1.0, QgsUnitTypes.DistanceCentimeters: 0.1 }, QgsUnitTypes.DistanceCentimeters: { QgsUnitTypes.DistanceMeters: 0.01, QgsUnitTypes.DistanceKilometers: 0.00001, QgsUnitTypes.DistanceFeet: 0.0328083989501, QgsUnitTypes.DistanceYards: 0.010936133, QgsUnitTypes.DistanceMiles: 0.0000062136931818182, QgsUnitTypes.DistanceDegrees: 0.0000000898315, QgsUnitTypes.DistanceNauticalMiles: 0.00000539957, QgsUnitTypes.DistanceMillimeters: 10.0, QgsUnitTypes.DistanceCentimeters: 1.0 }, QgsUnitTypes.DistanceUnknownUnit: { QgsUnitTypes.DistanceMeters: 1.0, QgsUnitTypes.DistanceKilometers: 1.0, QgsUnitTypes.DistanceFeet: 1.0, QgsUnitTypes.DistanceYards: 1.0, QgsUnitTypes.DistanceMiles: 1.0, QgsUnitTypes.DistanceDegrees: 1.0, QgsUnitTypes.DistanceNauticalMiles: 1.0, QgsUnitTypes.DistanceMillimeters: 1.0, QgsUnitTypes.DistanceCentimeters: 1.0 }, } for from_unit in list(expected.keys()): for to_unit in list(expected[from_unit].keys()): expected_factor = expected[from_unit][to_unit] res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, to_unit) self.assertAlmostEqual( res, expected_factor, msg= 'got {:.7f}, expected {:.7f} when converting from {} to {}' .format(res, expected_factor, QgsUnitTypes.toString(from_unit), QgsUnitTypes.toString(to_unit))) # test conversion to unknown units res = QgsUnitTypes.fromUnitToUnitFactor( from_unit, QgsUnitTypes.DistanceUnknownUnit) self.assertAlmostEqual( res, 1.0, msg= 'got {:.7f}, expected 1.0 when converting from {} to unknown units' .format(res, expected_factor, QgsUnitTypes.toString(from_unit)))
def processAlgorithm(self, parameters, context, feedback): network = self.parameterAsSource(parameters, self.INPUT, context) if network is None: raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs()) strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) travelCost = self.parameterAsDouble(parameters, self.TRAVEL_COST, context) directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) include_bounds = True # default to true to maintain 3.0 API if self.INCLUDE_BOUNDS in parameters: include_bounds = self.parameterAsBool(parameters, self.INCLUDE_BOUNDS, context) directionField = -1 if directionFieldName: directionField = network.fields().lookupField(directionFieldName) speedField = -1 if speedFieldName: speedField = network.fields().lookupField(speedFieldName) director = QgsVectorLayerDirector(network, directionField, forwardValue, backwardValue, bothValue, defaultDirection) distUnit = context.project().crs().mapUnits() multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters) if strategy == 0: strategy = QgsNetworkDistanceStrategy() else: strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed, multiplier * 1000.0 / 3600.0) director.addStrategy(strategy) builder = QgsGraphBuilder(network.sourceCrs(), True, tolerance) feedback.pushInfo(QCoreApplication.translate('ServiceAreaFromPoint', 'Building graph…')) snappedPoints = director.makeGraph(builder, [startPoint], feedback) feedback.pushInfo(QCoreApplication.translate('ServiceAreaFromPoint', 'Calculating service area…')) graph = builder.graph() idxStart = graph.findVertex(snappedPoints[0]) tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) vertices = set() points = [] lines = [] for vertex, start_vertex_cost in enumerate(cost): inbound_edge_index = tree[vertex] if inbound_edge_index == -1 and vertex != idxStart: # unreachable vertex continue if start_vertex_cost > travelCost: # vertex is too expensive, discard continue vertices.add(vertex) start_point = graph.vertex(vertex).point() # find all edges coming from this vertex for edge_id in graph.vertex(vertex).outgoingEdges(): edge = graph.edge(edge_id) end_vertex_cost = start_vertex_cost + edge.cost(0) end_point = graph.vertex(edge.toVertex()).point() if end_vertex_cost <= travelCost: # end vertex is cheap enough to include vertices.add(edge.toVertex()) lines.append([start_point, end_point]) else: # travelCost sits somewhere on this edge, interpolate position interpolated_end_point = QgsGeometryUtils.interpolatePointOnLineByValue(start_point.x(), start_point.y(), start_vertex_cost, end_point.x(), end_point.y(), end_vertex_cost, travelCost) points.append(interpolated_end_point) lines.append([start_point, interpolated_end_point]) for i in vertices: points.append(graph.vertex(i).point()) feedback.pushInfo(QCoreApplication.translate('ServiceAreaFromPoint', 'Writing results…')) fields = QgsFields() fields.append(QgsField('type', QVariant.String, '', 254, 0)) fields.append(QgsField('start', QVariant.String, '', 254, 0)) feat = QgsFeature() feat.setFields(fields) (point_sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.MultiPoint, network.sourceCrs()) results = {} if point_sink is not None: results[self.OUTPUT] = dest_id geomPoints = QgsGeometry.fromMultiPointXY(points) feat.setGeometry(geomPoints) feat['type'] = 'within' feat['start'] = startPoint.toString() point_sink.addFeature(feat, QgsFeatureSink.FastInsert) if include_bounds: upperBoundary = [] lowerBoundary = [] vertices = [] for i, v in enumerate(cost): if v > travelCost and tree[i] != -1: vertexId = graph.edge(tree[i]).fromVertex() if cost[vertexId] <= travelCost: vertices.append(i) for i in vertices: upperBoundary.append(graph.vertex(graph.edge(tree[i]).toVertex()).point()) lowerBoundary.append(graph.vertex(graph.edge(tree[i]).fromVertex()).point()) geomUpper = QgsGeometry.fromMultiPointXY(upperBoundary) geomLower = QgsGeometry.fromMultiPointXY(lowerBoundary) feat.setGeometry(geomUpper) feat['type'] = 'upper' feat['start'] = startPoint.toString() point_sink.addFeature(feat, QgsFeatureSink.FastInsert) feat.setGeometry(geomLower) feat['type'] = 'lower' feat['start'] = startPoint.toString() point_sink.addFeature(feat, QgsFeatureSink.FastInsert) (line_sink, line_dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LINES, context, fields, QgsWkbTypes.MultiLineString, network.sourceCrs()) if line_sink is not None: results[self.OUTPUT_LINES] = line_dest_id geom_lines = QgsGeometry.fromMultiPolylineXY(lines) feat.setGeometry(geom_lines) feat['type'] = 'lines' feat['start'] = startPoint.toString() line_sink.addFeature(feat, QgsFeatureSink.FastInsert) return results
def processEllipse(self, layer, outname, semimajorcol, semiminorcol, orientcol, unitOfMeasure, defSemiMajor, defSemiMinor, defOrientation): measureFactor = 1.0 # The ellipse calculation is done in Nautical Miles. This converts # the semi-major and minor axis to nautical miles if unitOfMeasure == 2: # Nautical Miles measureFactor = 1.0 elif unitOfMeasure == 0: # Kilometers measureFactor = QgsUnitTypes.fromUnitToUnitFactor( QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceNauticalMiles) * 1000.0 elif unitOfMeasure == 1: # Meters measureFactor = QgsUnitTypes.fromUnitToUnitFactor( QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceNauticalMiles) elif unitOfMeasure == 3: # Miles measureFactor = QgsUnitTypes.fromUnitToUnitFactor( QgsUnitTypes.DistanceFeet, QgsUnitTypes.DistanceNauticalMiles) * 5280.0 elif unitOfMeasure == 4: # Feet measureFactor = QgsUnitTypes.fromUnitToUnitFactor( QgsUnitTypes.DistanceFeet, QgsUnitTypes.DistanceNauticalMiles) fields = layer.fields() self.polygonLayer = QgsVectorLayer( "Polygon?crs={}".format(self.outputCRS.authid()), outname, "memory") ppolygon = self.polygonLayer.dataProvider() ppolygon.addAttributes(fields) self.polygonLayer.updateFields() iter = layer.getFeatures() num_features = 0 num_good = 0 for feature in iter: num_features += 1 try: if semimajorcol != -1: semi_major = float(feature[semimajorcol]) else: semi_major = defSemiMajor if semiminorcol != -1: semi_minor = float(feature[semiminorcol]) else: semi_minor = defSemiMinor if orientcol != -1: orient = float(feature[orientcol]) else: orient = defOrientation pt = feature.geometry().asPoint() # make sure the coordinates are in EPSG:4326 pt = self.transform.transform(pt.x(), pt.y()) pts = LatLon.getEllipseCoords(pt.y(), pt.x(), semi_major * measureFactor, semi_minor * measureFactor, orient) # If the Output crs is not 4326 transform the points to the proper crs if self.outputCRS != epsg4326: for x, ptout in enumerate(pts): pts[x] = self.transformOut.transform(ptout) featureout = QgsFeature() featureout.setGeometry(QgsGeometry.fromPolygonXY([pts])) featureout.setAttributes(feature.attributes()) ppolygon.addFeatures([featureout]) num_good += 1 except: # Just skip any lines that are badly formed #traceback.print_exc() pass self.polygonLayer.updateExtents() QgsProject.instance().addMapLayer(self.polygonLayer) self.iface.messageBar().pushMessage( "", "{} Ellipses created from {} records".format( num_good, num_features), level=Qgis.Info, duration=3)