def testLengthMeasureAndUnits(self): """Test a variety of length measurements in different CRS and ellipsoid modes, to check that the calculated lengths and units are always consistent """ da = QgsDistanceArea() da.setSourceCrs(QgsCoordinateReferenceSystem.fromSrsId(3452), QgsProject.instance().transformContext()) da.setEllipsoid("NONE") # We check both the measured length AND the units, in case the logic regarding # ellipsoids and units changes in future distance = da.measureLine(QgsPointXY(1, 1), QgsPointXY(2, 3)) units = da.lengthUnits() print(("measured {} in {}".format(distance, QgsUnitTypes.toString(units)))) assert ((abs(distance - 2.23606797) < 0.00000001 and units == QgsUnitTypes.DistanceDegrees) or (abs(distance - 248.52) < 0.01 and units == QgsUnitTypes.DistanceMeters)) da.setEllipsoid("WGS84") distance = da.measureLine(QgsPointXY(1, 1), QgsPointXY(2, 3)) units = da.lengthUnits() print(("measured {} in {}".format(distance, QgsUnitTypes.toString(units)))) # should always be in Meters self.assertAlmostEqual(distance, 247555.57, delta=0.01) self.assertEqual(units, QgsUnitTypes.DistanceMeters) # test converting the resultant length distance = da.convertLengthMeasurement(distance, QgsUnitTypes.DistanceNauticalMiles) self.assertAlmostEqual(distance, 133.669, delta=0.01) # now try with a source CRS which is in feet da.setSourceCrs(QgsCoordinateReferenceSystem.fromSrsId(27469), QgsProject.instance().transformContext()) da.setEllipsoid("NONE") # measurement should be in feet distance = da.measureLine(QgsPointXY(1, 1), QgsPointXY(2, 3)) units = da.lengthUnits() print(("measured {} in {}".format(distance, QgsUnitTypes.toString(units)))) self.assertAlmostEqual(distance, 2.23606797, delta=0.000001) self.assertEqual(units, QgsUnitTypes.DistanceFeet) # test converting the resultant length distance = da.convertLengthMeasurement(distance, QgsUnitTypes.DistanceMeters) self.assertAlmostEqual(distance, 0.6815, delta=0.001) da.setEllipsoid("WGS84") # now should be in Meters again distance = da.measureLine(QgsPointXY(1, 1), QgsPointXY(2, 3)) units = da.lengthUnits() print(("measured {} in {}".format(distance, QgsUnitTypes.toString(units)))) self.assertAlmostEqual(distance, 0.67953772, delta=0.000001) self.assertEqual(units, QgsUnitTypes.DistanceMeters) # test converting the resultant length distance = da.convertLengthMeasurement(distance, QgsUnitTypes.DistanceFeet) self.assertAlmostEqual(distance, 2.2294, delta=0.001)
def processAlgorithm(self, parameters, context, feedback): if parameters[self.INPUT] == parameters[self.HUBS]: raise QgsProcessingException( self.tr('Same layer given for both hubs and spokes')) point_source = self.parameterAsSource(parameters, self.INPUT, context) hub_source = self.parameterAsSource(parameters, self.HUBS, context) fieldName = self.parameterAsString(parameters, self.FIELD, context) units = self.UNITS[self.parameterAsEnum(parameters, self.UNIT, context)] fields = point_source.fields() fields.append(QgsField('HubName', QVariant.String)) fields.append(QgsField('HubDist', QVariant.Double)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Point, point_source.sourceCrs()) index = QgsSpatialIndex(hub_source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(point_source.sourceCrs(), context.transformContext()))) distance = QgsDistanceArea() distance.setSourceCrs(point_source.sourceCrs(), context.transformContext()) distance.setEllipsoid(context.project().ellipsoid()) # Scan source points, find nearest hub, and write to output file features = point_source.getFeatures() total = 100.0 / point_source.featureCount() if point_source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break if not f.hasGeometry(): sink.addFeature(f, QgsFeatureSink.FastInsert) continue src = f.geometry().boundingBox().center() neighbors = index.nearestNeighbor(src, 1) ft = next(hub_source.getFeatures(QgsFeatureRequest().setFilterFid(neighbors[0]).setSubsetOfAttributes([fieldName], hub_source.fields()).setDestinationCrs(point_source.sourceCrs(), context.transformContext()))) closest = ft.geometry().boundingBox().center() hubDist = distance.measureLine(src, closest) if units != self.LAYER_UNITS: hub_dist_in_desired_units = distance.convertLengthMeasurement(hubDist, units) else: hub_dist_in_desired_units = hubDist attributes = f.attributes() attributes.append(ft[fieldName]) attributes.append(hub_dist_in_desired_units) feat = QgsFeature() feat.setAttributes(attributes) feat.setGeometry(QgsGeometry.fromPointXY(src)) sink.addFeature(feat, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): if parameters[self.INPUT] == parameters[self.HUBS]: raise QgsProcessingException( self.tr('Same layer given for both hubs and spokes')) point_source = self.parameterAsSource(parameters, self.INPUT, context) if point_source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT)) hub_source = self.parameterAsSource(parameters, self.HUBS, context) if hub_source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.HUBS)) fieldName = self.parameterAsString(parameters, self.FIELD, context) units = self.UNITS[self.parameterAsEnum(parameters, self.UNIT, context)] fields = point_source.fields() fields.append(QgsField('HubName', QVariant.String)) fields.append(QgsField('HubDist', QVariant.Double)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Point, point_source.sourceCrs()) if sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT)) index = QgsSpatialIndex( hub_source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes( []).setDestinationCrs(point_source.sourceCrs(), context.transformContext()))) distance = QgsDistanceArea() distance.setSourceCrs(point_source.sourceCrs(), context.transformContext()) distance.setEllipsoid(context.project().ellipsoid()) # Scan source points, find nearest hub, and write to output file features = point_source.getFeatures() total = 100.0 / point_source.featureCount( ) if point_source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break if not f.hasGeometry(): sink.addFeature(f, QgsFeatureSink.FastInsert) continue src = f.geometry().boundingBox().center() neighbors = index.nearestNeighbor(src, 1) ft = next( hub_source.getFeatures(QgsFeatureRequest().setFilterFid( neighbors[0]).setSubsetOfAttributes( [fieldName], hub_source.fields()).setDestinationCrs( point_source.sourceCrs(), context.transformContext()))) closest = ft.geometry().boundingBox().center() hubDist = distance.measureLine(src, closest) if units != self.LAYER_UNITS: hub_dist_in_desired_units = distance.convertLengthMeasurement( hubDist, units) else: hub_dist_in_desired_units = hubDist attributes = f.attributes() attributes.append(ft[fieldName]) attributes.append(hub_dist_in_desired_units) feat = QgsFeature() feat.setAttributes(attributes) feat.setGeometry(QgsGeometry.fromPointXY(src)) sink.addFeature(feat, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def testLengthMeasureAndUnits(self): """Test a variety of length measurements in different CRS and ellipsoid modes, to check that the calculated lengths and units are always consistent """ da = QgsDistanceArea() da.setSourceCrs(3452) da.setEllipsoidalMode(False) da.setEllipsoid("NONE") daCRS = QgsCoordinateReferenceSystem() daCRS = da.sourceCrs() # We check both the measured length AND the units, in case the logic regarding # ellipsoids and units changes in future distance = da.measureLine(QgsPoint(1, 1), QgsPoint(2, 3)) units = da.lengthUnits() print(("measured {} in {}".format(distance, QgsUnitTypes.toString(units)))) assert ((abs(distance - 2.23606797) < 0.00000001 and units == QgsUnitTypes.DistanceDegrees) or (abs(distance - 248.52) < 0.01 and units == QgsUnitTypes.DistanceMeters)) da.setEllipsoid("WGS84") distance = da.measureLine(QgsPoint(1, 1), QgsPoint(2, 3)) units = da.lengthUnits() print(("measured {} in {}".format(distance, QgsUnitTypes.toString(units)))) assert ((abs(distance - 2.23606797) < 0.00000001 and units == QgsUnitTypes.DistanceDegrees) or (abs(distance - 248.52) < 0.01 and units == QgsUnitTypes.DistanceMeters)) da.setEllipsoidalMode(True) distance = da.measureLine(QgsPoint(1, 1), QgsPoint(2, 3)) units = da.lengthUnits() print(("measured {} in {}".format(distance, QgsUnitTypes.toString(units)))) # should always be in Meters self.assertAlmostEqual(distance, 247555.57, delta=0.01) self.assertEqual(units, QgsUnitTypes.DistanceMeters) # test converting the resultant length distance = da.convertLengthMeasurement( distance, QgsUnitTypes.DistanceNauticalMiles) self.assertAlmostEqual(distance, 133.669, delta=0.01) # now try with a source CRS which is in feet da.setSourceCrs(27469) da.setEllipsoidalMode(False) # measurement should be in feet distance = da.measureLine(QgsPoint(1, 1), QgsPoint(2, 3)) units = da.lengthUnits() print(("measured {} in {}".format(distance, QgsUnitTypes.toString(units)))) self.assertAlmostEqual(distance, 2.23606797, delta=0.000001) self.assertEqual(units, QgsUnitTypes.DistanceFeet) # test converting the resultant length distance = da.convertLengthMeasurement(distance, QgsUnitTypes.DistanceMeters) self.assertAlmostEqual(distance, 0.6815, delta=0.001) da.setEllipsoidalMode(True) # now should be in Meters again distance = da.measureLine(QgsPoint(1, 1), QgsPoint(2, 3)) units = da.lengthUnits() print(("measured {} in {}".format(distance, QgsUnitTypes.toString(units)))) self.assertAlmostEqual(distance, 0.67953772, delta=0.000001) self.assertEqual(units, QgsUnitTypes.DistanceMeters) # test converting the resultant length distance = da.convertLengthMeasurement(distance, QgsUnitTypes.DistanceFeet) self.assertAlmostEqual(distance, 2.2294, delta=0.001)
def write_line_length(self, layer, ellipsoid, transform_context, m=False, km=False, nm=False): '''Write length attribute [m/km/nm] to layer Parameters ---------- layer : QgsVectorLayer input line vector layer ellipsoid : str QgsCoordinateReferenceSystem.ellipsoidAcronym() transform_context : QgsCoordinateTransformContext transform context for coordinate transformation m : boolean write meters (Default value = False) km : boolean write kilometers (Default value = False) nm : boolean write nautical miles (Default value = False) Returns ------- error : boolean 0/1 - no error/error result : str or None output or error msg if error == 1 ''' # if no lengths shall be written, return if m == km == nm == False: return 1, 'No length units selected, no attributes created!\n' # set some field names prefix = 'length_' m_field = f'{prefix}m' km_field = f'{prefix}km' nm_field = f'{prefix}nm' # get CRS of input layer crs_layer = layer.crs() # Initialize Distance calculator class with ellipsoid da = QgsDistanceArea() da.setSourceCrs(crs_layer, transform_context) da.setEllipsoid(ellipsoid) with edit(layer): # delete fields previously created by Cruise Tools self.delete_fields_by_prefix(layer, prefix) # create fields for length_m and/or length_nm if m: layer.addAttribute( QgsField(m_field, QVariant.Double, len=15, prec=2)) if km: layer.addAttribute( QgsField(km_field, QVariant.Double, len=15, prec=3)) if nm: layer.addAttribute( QgsField(nm_field, QVariant.Double, len=15, prec=3)) # update attribute table fields layer.updateFields() # get all features features = self.get_features(layer, selected=False) for feature in features: # get geometry of feature geom = feature.geometry() # measure feature length in meters len = da.measureLength(geom) # set field values according to the calculated length if m: len_m = da.convertLengthMeasurement( len, QgsUnitTypes.DistanceMeters) len_m = round(len_m, 2) feature.setAttribute(layer.fields().indexFromName(m_field), len_m) if km: len_km = da.convertLengthMeasurement( len, QgsUnitTypes.DistanceKilometers) len_km = round(len_km, 5) feature.setAttribute( layer.fields().indexFromName(km_field), len_km) if nm: len_nm = da.convertLengthMeasurement( len, QgsUnitTypes.DistanceNauticalMiles) len_nm = round(len_nm, 5) feature.setAttribute( layer.fields().indexFromName(nm_field), len_nm) # check if speed_kn exists f_idx_speed = layer.fields().indexFromName('speed_kn') f_idx_time = layer.fields().indexFromName('time_h') if (f_idx_speed != -1) and (f_idx_time != -1): # if yes, get value speed_kn = feature.attributes()[f_idx_speed] if speed_kn != None: # if value not NULL, calculate time and write it to time_h field len_nm = da.convertLengthMeasurement( len, QgsUnitTypes.DistanceNauticalMiles) time_h = round(len_nm / speed_kn, 2) feature.setAttribute(f_idx_time, time_h) # update attribute table layer.updateFeature(feature) return 0, None
class QChainageDialog(QDialog, Ui_QChainageDialog): """ Setting up User Interface """ def __init__(self, iface): self.iface = iface QDialog.__init__(self) self.setupUi(self) self.setWindowTitle('QChainage') self.currentUnits = None self.qgisSettings = QSettings() self.okbutton = self.buttonBox.button(QDialogButtonBox.Ok) self.okbutton.setEnabled(False) self.da = QgsDistanceArea() self.UnitsComboBox.clear() for u in [ QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceKilometers, QgsUnitTypes.DistanceFeet, QgsUnitTypes.DistanceNauticalMiles, QgsUnitTypes.DistanceYards, QgsUnitTypes.DistanceMiles, QgsUnitTypes.DistanceDegrees, QgsUnitTypes.DistanceCentimeters, QgsUnitTypes.DistanceMillimeters, QgsUnitTypes.DistanceUnknownUnit, ]: self.UnitsComboBox.addItem(QgsUnitTypes.toString(u), u) selectedLayerIndex = -1 counter = -1 for layer in self.iface.mapCanvas().layers(): if layer.type() == QgsMapLayer.VectorLayer and \ layer.geometryType() == QgsWkbTypes.LineGeometry: self.loadLayer(layer) counter += 1 if layer == self.iface.mapCanvas().currentLayer(): selectedLayerIndex = counter if selectedLayerIndex >= 0: self.selectLayerComboBox.setCurrentIndex(selectedLayerIndex) def setCurrentLayer(self): index = self.selectLayerComboBox.findData(self) self.selectLayerComboBox.setCurrentIndex(index) def loadLayer(self, layer): self.selectLayerComboBox.addItem(layer.name(), layer) def get_current_layer(self): index = self.selectLayerComboBox.currentIndex() return self.selectLayerComboBox.itemData(index) def on_selectLayerComboBox_currentIndexChanged(self): layer = self.get_current_layer() if not layer: return units = layer.crs().mapUnits() self.da.setSourceCrs(layer.crs()) self.da.setEllipsoid(QgsProject.instance().ellipsoid()) self.currentUnits = self.UnitsComboBox.findData(units) self.UnitsComboBox.setCurrentIndex(self.currentUnits) self.layerNameLine.setText("chain_" + layer.name()) if layer.selectedFeatureCount() == 0: self.selectAllRadioBtn.setChecked(True) self.selectOnlyRadioBtn.setEnabled(False) else: self.selectOnlyRadioBtn.setChecked(True) self.selectOnlyRadioBtn.setEnabled(True) self.okbutton.setEnabled(True) def on_UnitsComboBox_currentIndexChanged(self): if self.currentUnits is None: return calc2 = self.da.convertLengthMeasurement( 1.0, self.UnitsComboBox.currentData()) calc = self.da.convertLengthMeasurement(1.0, self.currentUnits) self.distanceSpinBox.setValue(self.distanceSpinBox.value() / calc * calc2) self.currentUnits = self.UnitsComboBox.currentData() def accept(self): layer = self.get_current_layer() label = self.autoLabelCheckBox.isChecked() layerout = self.layerNameLine.text() self.UnitsComboBox.setCurrentIndex( self.UnitsComboBox.findData(layer.crs().mapUnits())) distance = self.distanceSpinBox.value() startpoint = self.startSpinBox.value() endpoint = self.endSpinBox.value() selectedOnly = self.selectOnlyRadioBtn.isChecked() force = self.forceLastCheckBox.isChecked() fo_fila = self.force_fl_CB.isChecked() divide = self.divideSpinBox.value() decimal = self.decimalSpinBox.value() projectionSettingKey = "Projections/defaultBehaviour" oldProjectionSetting = self.qgisSettings.value(projectionSettingKey) self.qgisSettings.setValue(projectionSettingKey, "useGlobal") self.qgisSettings.sync() points_along_line(layerout, startpoint, endpoint, distance, label, layer, selectedOnly, force, fo_fila, divide, decimal) self.qgisSettings.setValue(projectionSettingKey, oldProjectionSetting) QDialog.accept(self)
class QChainageDialog(QDialog, Ui_QChainageDialog): """ Setting up User Interface """ def __init__(self, iface): self.iface = iface QDialog.__init__(self) self.setupUi(self) self.setWindowTitle('QChainage') self.currentUnits = None self.qgisSettings = QSettings() self.okbutton = self.buttonBox.button(QDialogButtonBox.Ok) self.okbutton.setEnabled(False) self.da = QgsDistanceArea() self.UnitsComboBox.clear() for u in [ QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceKilometers, QgsUnitTypes.DistanceFeet, QgsUnitTypes.DistanceNauticalMiles, QgsUnitTypes.DistanceYards, QgsUnitTypes.DistanceMiles, QgsUnitTypes.DistanceDegrees, QgsUnitTypes.DistanceCentimeters, QgsUnitTypes.DistanceMillimeters, QgsUnitTypes.DistanceUnknownUnit, ]: self.UnitsComboBox.addItem(QgsUnitTypes.toString(u), u) selected_layer_index = -1 counter = -1 for layer in self.iface.mapCanvas().layers(): if layer.type() == QgsMapLayer.VectorLayer and \ layer.geometryType() == QgsWkbTypes.LineGeometry: self.loadLayer(layer) counter += 1 if layer == self.iface.mapCanvas().currentLayer(): selected_layer_index = counter if selected_layer_index >= 0: self.selectLayerComboBox.setCurrentIndex(selected_layer_index) def set_current_layer(self): index = self.selectLayerComboBox.findData(self) self.selectLayerComboBox.setCurrentIndex(index) def loadLayer(self, layer): self.selectLayerComboBox.addItem(layer.name(), layer) def get_current_layer(self): index = self.selectLayerComboBox.currentIndex() return self.selectLayerComboBox.itemData(index) def on_selectLayerComboBox_currentIndexChanged(self): layer = self.get_current_layer() if not layer: return units = layer.crs().mapUnits() self.da.setSourceCrs(layer.crs(), QgsProject.instance().transformContext()) self.da.setEllipsoid( QgsProject.instance().ellipsoid()) self.currentUnits = self.UnitsComboBox.findData(units) self.UnitsComboBox.setCurrentIndex(self.currentUnits) self.layerNameLine.setText("chain_" + layer.name()) if layer.selectedFeatureCount() == 0: self.selectAllRadioBtn.setChecked(True) self.selectOnlyRadioBtn.setEnabled(False) else: self.selectOnlyRadioBtn.setChecked(True) self.selectOnlyRadioBtn.setEnabled(True) self.okbutton.setEnabled(True) def on_UnitsComboBox_currentIndexChanged(self): if self.currentUnits is None: return calc2 = self.da.convertLengthMeasurement(1.0, self.UnitsComboBox.currentData()) calc = self.da.convertLengthMeasurement(1.0, self.currentUnits) self.distanceSpinBox.setValue(self.distanceSpinBox.value() / calc * calc2) self.currentUnits = self.UnitsComboBox.currentData() def accept(self): layer = self.get_current_layer() label = self.autoLabelCheckBox.isChecked() layerout = self.layerNameLine.text() self.UnitsComboBox.setCurrentIndex(self.UnitsComboBox.findData(layer.crs().mapUnits())) distance = self.distanceSpinBox.value() startpoint = self.startSpinBox.value() endpoint = self.endSpinBox.value() selected_only = self.selectOnlyRadioBtn.isChecked() force = self.forceLastCheckBox.isChecked() fo_fila = self.force_fl_CB.isChecked() divide = self.divideSpinBox.value() decimal = self.decimalSpinBox.value() projection_setting_key = "Projections/defaultBehaviour" old_projection_setting = self.qgisSettings.value(projection_setting_key) self.qgisSettings.setValue(projection_setting_key, "useGlobal") self.qgisSettings.sync() points_along_line( layerout, startpoint, endpoint, distance, label, layer, selected_only, force, fo_fila, divide, decimal) self.qgisSettings.setValue(projection_setting_key, old_projection_setting) QDialog.accept(self)
class MeasureSelectedFeatures: def __init__(self, iface): self.iface = iface self.window = self.iface.mainWindow() self.proj_close_action = [ a for a in self.iface.projectMenu().actions() if a.objectName() == 'mActionCloseProject' ][0] self.dlg = MeasureSelectedFeaturesDialog() self.toolbar = self.iface.pluginToolBar() self.folder_name = os.path.dirname(os.path.abspath(__file__)) self.icon_path = os.path.join(self.folder_name, 'msf_icon.png') self.action = QAction(QIcon(self.icon_path), 'Sum selected feature size', self.window) self.action.setToolTip('Display total dimensions of selected features') self.da = QgsDistanceArea() # self.da.setEllipsoid('WGS84') self.Distance_Units = { 0: 'm', 1: 'km', 2: 'Feet', 3: 'NM', 4: 'Yards', 5: 'Miles', 6: 'Degrees', 7: 'cm', 8: 'mm', 9: 'Unknown units' } self.Area_Units = { 0: 'm2', 1: 'km2', 2: 'Square feet', 3: 'Square yards', 4: 'Square miles', 5: 'Hectares', 6: 'Acres', 7: 'NM2', 8: 'Square degrees', 9: 'cm2', 10: 'mm2', 11: 'Unknown units' } self.cb_linear_items = [ 'meters', 'kilometers', 'feet', 'nautical miles', 'yards', 'miles', 'degrees', 'centimeters', 'millimeters' ] self.cb_area_items = [ 'square meters', 'square kilometers', 'square feet', 'square yards', 'square miles', 'hectares', 'acres', 'square nautical miles', 'square degrees', 'square centimeters', 'square millimeters' ] self.project = None self.layer = None def initGui(self): """This method is where we add the plugin action to the plugin toolbar.""" self.action.setObjectName('btnMSF') self.toolbar.addAction(self.action) if self.iface.activeLayer(): self.layer = self.iface.activeLayer() else: self.action.setEnabled(False) self.action.triggered.connect(self.action_triggered) self.iface.projectRead.connect(self.project_opened) self.iface.newProjectCreated.connect(self.project_opened) self.dlg.was_closed.connect(self.dockwidget_closed) self.dlg.topLevelChanged.connect(self.widget_moved) self.iface.projectMenu().aboutToShow.connect(self.project_menu_shown) self.proj_close_action.triggered.connect( self.project_closed_via_menu_action) self.dlg.rad_1.setChecked(True) # 03-06-21 #####31-05-21 self.dlg.rad_1.toggled.connect( self.radios_toggled) #############25-06-21 self.dlg.cb_units.currentIndexChanged.connect(self.total_length) def project_menu_shown(self): if self.dlg.isVisible(): self.dlg.close() def project_opened(self): if self.project is not None: self.project.layerWasAdded.disconnect(self.layer_added) self.project.layersRemoved.disconnect(self.layers_removed) self.project = QgsProject.instance() a = [a for a in self.toolbar.actions() if a.objectName() == 'btnMSF'][0] if self.iface.activeLayer(): self.layer = self.iface.activeLayer() if not a.isEnabled(): a.setEnabled(True) self.set_title() else: if a.isEnabled(): a.setEnabled(False) self.project.layerWasAdded.connect(self.layer_added) self.project.layersRemoved.connect(self.layers_removed) def layer_added(self, l): if self.layer is None: if isinstance(l, QgsVectorLayer): self.layer = l if len(self.project.mapLayers()) == 1: a = [ a for a in self.toolbar.actions() if a.objectName() == 'btnMSF' ][0] if not a.isEnabled(): a.setEnabled(True) def layers_removed(self, lyr_ids): if len(self.project.mapLayers()) == 0: self.layer = None if self.dlg.isVisible(): self.dlg.close() a = [ a for a in self.toolbar.actions() if a.objectName() == 'btnMSF' ][0] if a.isEnabled(): a.setEnabled(False) def project_closed_via_menu_action(self): a = [a for a in self.toolbar.actions() if a.objectName() == 'btnMSF'][0] a.setEnabled(False) QgsProject.instance().layerWasAdded.disconnect(self.layer_added) def widget_moved(self, top_level): if top_level is True: self.set_gui_geometry() def set_gui_geometry(self): self.dlg.setGeometry(750, 300, 750, 50) def action_triggered(self): self.window.addDockWidget(Qt.TopDockWidgetArea, self.dlg) self.dlg.setAllowedAreas(Qt.TopDockWidgetArea) self.dlg.show() if self.layer is not None: if isinstance(self.iface.activeLayer(), QgsVectorLayer): self.layer = self.iface.activeLayer() if isinstance(self.layer, QgsVectorLayer): self.layer.selectionChanged.connect(self.total_length) self.iface.currentLayerChanged.connect(self.active_changed) self.set_title() # V2 change self.total_length() # V2 change #####25-05-21 self.action.setEnabled(False) ##### def active_changed(self, new_layer): self.tool_reset(self.layer) self.set_title() # V3 change if isinstance(new_layer, QgsVectorLayer): if self.layer is not None: # print(self.layer.name()) if len(QgsProject.instance().mapLayers()) > 1: self.layer.selectionChanged.disconnect(self.total_length) self.layer = new_layer self.layer.selectionChanged.connect(self.total_length) self.total_length() # V2 change def tool_reset(self, layer): if layer is not None: if isinstance( layer, QgsVectorLayer) and layer.geometryType() == 0: # V2 change layer.selectByIds([]) for le in self.dlg.findChildren(QLineEdit): le.clear() for cb in self.dlg.findChildren(QComboBox): cb.clear() cb.setEnabled(False) def set_title(self): self.dlg.lbl_1.setText('Total') for le in self.dlg.findChildren(QLineEdit): le.setEnabled(False) active_layer = self.iface.activeLayer() if isinstance(active_layer, QgsVectorLayer): if active_layer.isSpatial(): #####25-05-21 if active_layer.geometryType() == 0: # points self.dlg.setWindowTitle('Point layer selected') for le in self.dlg.findChildren(QLineEdit): le.setEnabled(False) for rb in self.dlg.findChildren(QRadioButton): rb.setEnabled(False) for cb in self.dlg.findChildren(QComboBox): cb.clear() cb.setEnabled(False) elif active_layer.geometryType() in [1, 2]: # self.dlg.setWindowTitle('Measuring {} selected features from layer: {}'.format(active_layer.selectedFeatureCount(), active_layer.name())) # V2 change for le in self.dlg.findChildren(QLineEdit): le.setEnabled(True) self.dlg.cb_units.setEnabled(True) if active_layer.crs().isGeographic(): self.dlg.rad_1.setChecked(True) self.dlg.rad_1.setEnabled(True) self.dlg.rad_2.setEnabled(False) ###25-06-21 self.dlg.cb_units.clear() if active_layer.geometryType() == 1: # lines self.dlg.cb_units.addItems(self.cb_linear_items) elif active_layer.geometryType() == 2: # polygons self.dlg.cb_units.addItems(self.cb_area_items) else: # projected CRS for rb in self.dlg.findChildren(QRadioButton): rb.setEnabled(True) ###25-06-21 if active_layer.geometryType() == 1: # lines self.dlg.cb_units.clear() self.dlg.cb_units.addItems(self.cb_linear_items) if self.dlg.rad_2.isChecked(): self.dlg.cb_units.removeItem( self.cb_linear_items.index('degrees')) elif active_layer.geometryType() == 2: # polygons self.dlg.cb_units.clear() self.dlg.cb_units.addItems(self.cb_area_items) if self.dlg.rad_2.isChecked(): self.dlg.cb_units.removeItem( self.cb_area_items.index('square degrees')) ##### elif not active_layer.isSpatial(): self.dlg.setWindowTitle( 'Raster or non-spatial vector layer selected') for le in self.dlg.findChildren(QLineEdit): le.setEnabled(False) for rb in self.dlg.findChildren(QRadioButton): rb.setEnabled(False) for cb in self.dlg.findChildren(QComboBox): cb.clear() cb.setEnabled(False) elif isinstance(active_layer, QgsRasterLayer): self.dlg.setWindowTitle( 'Raster or non-spatial vector layer selected') for le in self.dlg.findChildren(QLineEdit): le.setEnabled(False) for rb in self.dlg.findChildren(QRadioButton): rb.setEnabled(False) for cb in self.dlg.findChildren(QComboBox): cb.clear() cb.setEnabled(False) elif active_layer is None: self.dlg.setWindowTitle('No layer selected') def radios_toggled(self): if self.iface.activeLayer().geometryType() == 1: # lines if self.dlg.rad_2.isChecked(): # planimetric if self.dlg.cb_units.currentText() == 'degrees': # reload combobox items without degree option self.dlg.cb_units.clear() self.dlg.cb_units.addItems(self.cb_linear_items) self.dlg.cb_units.removeItem( self.cb_linear_items.index('degrees')) else: # just remove the degree option self.dlg.cb_units.removeItem( self.cb_linear_items.index('degrees')) elif self.dlg.rad_1.isChecked(): # ellipsoidal if self.dlg.cb_units.count() == 0: self.dlg.cb_units.addItems(self.cb_linear_items) if not self.dlg.cb_units.isEnabled(): self.dlg.cb_units.setEnabled(True) if self.layer.crs().mapUnits( ) != QgsUnitTypes.DistanceUnknownUnit: self.dlg.cb_units.setCurrentText( QgsUnitTypes.encodeUnit( self.layer.crs().mapUnits())) else: self.dlg.cb_units.insertItem(6, 'degrees') elif self.iface.activeLayer().geometryType() == 2: # polygons if self.dlg.rad_2.isChecked(): if self.dlg.cb_units.currentText() == 'square degrees': self.dlg.cb_units.clear() self.dlg.cb_units.addItems(self.cb_area_items) self.dlg.cb_units.removeItem( self.cb_area_items.index('square degrees')) else: self.dlg.cb_units.removeItem( self.cb_area_items.index('square degrees')) elif self.dlg.rad_1.isChecked(): if self.dlg.cb_units.count() == 0: self.dlg.cb_units.addItems(self.cb_area_items) if not self.dlg.cb_units.isEnabled(): self.dlg.cb_units.setEnabled(True) if self.layer.crs().mapUnits( ) != QgsUnitTypes.DistanceUnknownUnit: self.dlg.cb_units.setCurrentText('square {}'.format( QgsUnitTypes.encodeUnit( self.layer.crs().mapUnits()))) else: self.dlg.cb_units.insertItem(8, 'square degrees') self.total_length() def geodetic_length(self, feat): geo_m = self.da.measureLength(feat.geometry()) return geo_m def geodetic_area(self, feat): geo_m2 = self.da.measureArea(feat.geometry()) return geo_m2 def planar_length(self, feat): proj_m = feat.geometry().length() return proj_m def planar_area(self, feat): proj_m2 = feat.geometry().area() return proj_m2 def total_length(self): # print('func called') layer = self.layer # self.set_title() if isinstance(layer, QgsVectorLayer) and layer.isSpatial(): #####04-06-21 self.da.setSourceCrs(layer.crs(), QgsProject.instance().transformContext()) self.da.setEllipsoid(layer.crs().ellipsoidAcronym()) #####04-06-21 select_fts = [f for f in layer.selectedFeatures()] epsg_code = layer.crs().authid() if layer.crs().isGeographic(): crs_type = 'Geographic' else: crs_type = 'Projected' l_units = layer.crs().mapUnits() if layer.geometryType() == 1: # Lines self.dlg.setWindowTitle( 'Measuring {} selected features from layer: {} - {} ({})'. format(layer.selectedFeatureCount(), layer.name(), epsg_code, crs_type)) self.dlg.lbl_1.setText('Total length of selected features: ') if layer.crs().isGeographic() or ( not layer.crs().isGeographic() and self.dlg.rad_1.isChecked()): total_geo_m = sum( [self.geodetic_length(f) for f in select_fts]) if self.dlg.cb_units.currentText() == 'meters': self.dlg.le_total.setText( str('{:.3f}m'.format(total_geo_m))) elif self.dlg.cb_units.currentText() == 'kilometers': total_geo_km = self.da.convertLengthMeasurement( total_geo_m, QgsUnitTypes.DistanceKilometers) self.dlg.le_total.setText( str('{:.3f}km'.format(total_geo_km))) elif self.dlg.cb_units.currentText() == 'feet': total_geo_ft = self.da.convertLengthMeasurement( total_geo_m, QgsUnitTypes.DistanceFeet) self.dlg.le_total.setText( str('{:.3f}ft'.format(total_geo_ft))) elif self.dlg.cb_units.currentText() == 'nautical miles': total_geo_nm = self.da.convertLengthMeasurement( total_geo_m, QgsUnitTypes.DistanceNauticalMiles) self.dlg.le_total.setText( str('{:.3f}NM'.format(total_geo_nm))) elif self.dlg.cb_units.currentText() == 'yards': total_geo_yds = self.da.convertLengthMeasurement( total_geo_m, QgsUnitTypes.DistanceYards) self.dlg.le_total.setText( str('{:.3f}yds'.format(total_geo_yds))) elif self.dlg.cb_units.currentText() == 'miles': total_geo_mi = self.da.convertLengthMeasurement( total_geo_m, QgsUnitTypes.DistanceMiles) self.dlg.le_total.setText( str('{:.3f}mi'.format(total_geo_mi))) elif self.dlg.cb_units.currentText() == 'degrees': total_geo_deg = self.da.convertLengthMeasurement( total_geo_m, QgsUnitTypes.DistanceDegrees) self.dlg.le_total.setText( str('{:.3f}deg'.format(total_geo_deg))) elif self.dlg.cb_units.currentText() == 'centimeters': total_geo_cm = self.da.convertLengthMeasurement( total_geo_m, QgsUnitTypes.DistanceCentimeters) self.dlg.le_total.setText( str('{:.3f}cm'.format(total_geo_cm))) elif self.dlg.cb_units.currentText() == 'millimeters': total_geo_mm = self.da.convertLengthMeasurement( total_geo_m, QgsUnitTypes.DistanceMillimeters) self.dlg.le_total.setText( str('{:.3f}mm'.format(total_geo_mm))) else: # projected CRS total_length_proj = sum( [self.planar_length(f) for f in select_fts]) if l_units != 6: # Units are NOT degrees if self.dlg.cb_units.currentText() == 'meters': self.dlg.le_total.setText( str('{:.3f}m'.format( self.convert_planar_length( total_length_proj, l_units, 0)))) elif self.dlg.cb_units.currentText() == 'kilometers': self.dlg.le_total.setText( str('{:.3f}km'.format( self.convert_planar_length( total_length_proj, l_units, 1)))) elif self.dlg.cb_units.currentText() == 'feet': self.dlg.le_total.setText( str('{:.3f}ft'.format( self.convert_planar_length( total_length_proj, l_units, 2)))) elif self.dlg.cb_units.currentText( ) == 'nautical miles': self.dlg.le_total.setText( str('{:.3f}NM'.format( self.convert_planar_length( total_length_proj, l_units, 3)))) elif self.dlg.cb_units.currentText() == 'yards': self.dlg.le_total.setText( str('{:.3f}yd'.format( self.convert_planar_length( total_length_proj, l_units, 4)))) elif self.dlg.cb_units.currentText() == 'miles': self.dlg.le_total.setText( str('{:.3f}mi'.format( self.convert_planar_length( total_length_proj, l_units, 5)))) elif self.dlg.cb_units.currentText() == 'centimeters': self.dlg.le_total.setText( str('{:.3f}cm'.format( self.convert_planar_length( total_length_proj, l_units, 7)))) elif self.dlg.cb_units.currentText() == 'millimeters': self.dlg.le_total.setText( str('{:.3f}mm'.format( self.convert_planar_length( total_length_proj, l_units, 8)))) else: # degree units self.dlg.cb_units.clear() self.dlg.cb_units.setEnabled(False) self.dlg.le_total.setText( str('{:.3f}{}'.format( total_length_proj, self.Distance_Units[l_units]))) elif layer.geometryType() == 2: # Polygons self.dlg.setWindowTitle( 'Measuring {} selected features from layer: {} - {} ({})'. format(layer.selectedFeatureCount(), layer.name(), epsg_code, crs_type)) self.dlg.lbl_1.setText('Total area of selected features: ') if layer.crs().isGeographic() or ( not layer.crs().isGeographic() and self.dlg.rad_1.isChecked()): total_geo_m = sum( [self.geodetic_area(f) for f in select_fts]) if self.dlg.cb_units.currentText() == 'square meters': self.dlg.le_total.setText( str('{:.3f}m2'.format(total_geo_m))) elif self.dlg.cb_units.currentText( ) == 'square kilometers': total_geo_km = self.da.convertAreaMeasurement( total_geo_m, QgsUnitTypes.AreaSquareKilometers) self.dlg.le_total.setText( str('{:.3f}km2'.format(total_geo_km))) elif self.dlg.cb_units.currentText() == 'square feet': total_geo_ft = self.da.convertAreaMeasurement( total_geo_m, QgsUnitTypes.AreaSquareFeet) self.dlg.le_total.setText( str('{:.3f}ft2'.format(total_geo_ft))) elif self.dlg.cb_units.currentText() == 'square yards': total_geo_yds = self.da.convertAreaMeasurement( total_geo_m, QgsUnitTypes.AreaSquareYards) self.dlg.le_total.setText( str('{:.3f}yd2'.format(total_geo_yds))) elif self.dlg.cb_units.currentText() == 'square miles': total_geo_mi = self.da.convertAreaMeasurement( total_geo_m, QgsUnitTypes.AreaSquareMiles) self.dlg.le_total.setText( str('{:.3f}mi2'.format(total_geo_mi))) elif self.dlg.cb_units.currentText() == 'hectares': total_geo_ha = self.da.convertAreaMeasurement( total_geo_m, QgsUnitTypes.AreaHectares) self.dlg.le_total.setText( str('{:.3f}ha'.format(total_geo_ha))) elif self.dlg.cb_units.currentText() == 'acres': total_geo_ac = self.da.convertAreaMeasurement( total_geo_m, QgsUnitTypes.AreaAcres) self.dlg.le_total.setText( str('{:.3f}ac'.format(total_geo_ac))) elif self.dlg.cb_units.currentText( ) == 'square nautical miles': total_geo_nm = self.da.convertAreaMeasurement( total_geo_m, QgsUnitTypes.AreaSquareNauticalMiles) self.dlg.le_total.setText( str('{:.3f}NM2'.format(total_geo_nm))) elif self.dlg.cb_units.currentText() == 'square degrees': total_geo_deg = self.da.convertAreaMeasurement( total_geo_m, QgsUnitTypes.AreaSquareDegrees) self.dlg.le_total.setText( str('{:.3f}deg2'.format(total_geo_deg))) elif self.dlg.cb_units.currentText( ) == 'square centimeters': total_geo_cm = self.da.convertAreaMeasurement( total_geo_m, QgsUnitTypes.AreaSquareCentimeters) self.dlg.le_total.setText( str('{:.3f}cm2'.format(total_geo_cm))) elif self.dlg.cb_units.currentText( ) == 'square millimeters': total_geo_mm = self.da.convertAreaMeasurement( total_geo_m, QgsUnitTypes.AreaSquareMillimeters) self.dlg.le_total.setText( str('{:.3f}mm2'.format(total_geo_mm))) else: # projected CRS total_area_proj = sum( [self.planar_area(f) for f in select_fts]) if l_units != 6: # Units are NOT degrees if self.dlg.cb_units.currentText() == 'square meters': self.dlg.le_total.setText( str('{:.3f}m2'.format( self.convert_planar_area( total_area_proj, l_units, 'square meters')))) elif self.dlg.cb_units.currentText( ) == 'square kilometers': self.dlg.le_total.setText( str('{:.3f}km2'.format( self.convert_planar_area( total_area_proj, l_units, 'square kilometers')))) elif self.dlg.cb_units.currentText() == 'square feet': self.dlg.le_total.setText( str('{:.3f}ft2'.format( self.convert_planar_area( total_area_proj, l_units, 'square feet')))) elif self.dlg.cb_units.currentText() == 'square yards': self.dlg.le_total.setText( str('{:.3f}yd2'.format( self.convert_planar_area( total_area_proj, l_units, 'square yards')))) elif self.dlg.cb_units.currentText() == 'square miles': self.dlg.le_total.setText( str('{:.3f}mi2'.format( self.convert_planar_area( total_area_proj, l_units, 'square miles')))) elif self.dlg.cb_units.currentText() == 'hectares': self.dlg.le_total.setText( str('{:.3f}ha'.format( self.convert_planar_area( total_area_proj, l_units, 'hectares')))) elif self.dlg.cb_units.currentText() == 'acres': self.dlg.le_total.setText( str('{:.3f}ac'.format( self.convert_planar_area( total_area_proj, l_units, 'acres')))) elif self.dlg.cb_units.currentText( ) == 'square nautical miles': self.dlg.le_total.setText( str('{:.3f}NM2'.format( self.convert_planar_area( total_area_proj, l_units, 'square nautical miles')))) elif self.dlg.cb_units.currentText( ) == 'square centimeters': self.dlg.le_total.setText( str('{:.3f}cm2'.format( self.convert_planar_area( total_area_proj, l_units, 'square centimeters')))) elif self.dlg.cb_units.currentText( ) == 'square millimeters': self.dlg.le_total.setText( str('{:.3f}mm2'.format( self.convert_planar_area( total_area_proj, l_units, 'square millimeters')))) else: # Degree units self.dlg.cb_units.clear() if self.dlg.cb_units.isEnabled(): self.dlg.cb_units.setEnabled(False) self.dlg.le_total.setText( str('{:.3f}{}2'.format( total_area_proj, self.Distance_Units[l_units]))) if layer.geometryType() in [3, 4]: self.iface.messageBar().pushMessage( 'Layer has unknown or Null geometry type', duration=2) ###########################UNIT CONVERSIONS FOR PROJECTED CRS'S##################################### def convert_planar_length(self, length, input_units, output_units): if input_units == 0: # Meters if output_units == 0: # Meters result = length elif output_units == 1: # Kilometers result = length / 1000 elif output_units == 2: # Imperial feet result = length * 3.28084 elif output_units == 3: # Nautical miles result = length / 1852 elif output_units == 4: # Imperial yards result = length * 1.09361 elif output_units == 5: # Terrestrial miles result = length / 1609.344 elif output_units == 7: # Centimeters result = length * 100 elif output_units == 8: # Millimeters result = length * 1000 elif input_units == 1: # Kilometers if output_units == 0: # Meters result = length * 1000 elif output_units == 1: # Kilometers result = length elif output_units == 2: # Imperial feet result = length * 3280.84 elif output_units == 3: # Nautical miles result = length / 1.852 elif output_units == 4: # Imperial yards result = length * 1093.61 elif output_units == 5: # Terrestrial miles result = length / 1.609 elif output_units == 7: # Centimeters result = length * 100000 elif output_units == 8: # Millimeters result = length * 1000000 elif input_units == 2: # Imperial feet if output_units == 0: # Meters result = length / 3.281 elif output_units == 1: # Kilometers result = length / 3281 elif output_units == 2: # Imperial feet result = length elif output_units == 3: # Nautical Miles result = length / 6076 elif output_units == 4: # Imperial yards result = length / 3 elif output_units == 5: # Terrestrial miles result = length / 5280 elif output_units == 7: # Centimeters result = length * 30.48 elif output_units == 8: # Millimeters result = length * 304.8 elif input_units == 3: # Nautical miles if output_units == 0: # Meters result = length * 1852 if output_units == 1: # Kilometers result = length * 1.852 elif output_units == 2: # Imperial feet result = length * 6076 elif output_units == 3: # Nautical miles result = length elif output_units == 4: # Imperial yards result = length * 2025.37 elif output_units == 5: # Terrestrial miles result = length * 1.15078 elif output_units == 7: # Centimeters result = length * 185200 elif output_units == 8: # Millimeters result = length * 1852000 elif input_units == 4: # Imperial yards if output_units == 0: # Meters result = length / 1.094 elif output_units == 1: # Kilometers result = length / 1094 elif output_units == 2: # Imperial feet result = length * 3 elif output_units == 3: # Nautical miles result = length / 2025 elif output_units == 4: # Imperial yards result = length elif output_units == 5: # Terrestrial miles result = length / 1760 elif output_units == 7: # Centimeters result = length * 91.44 elif output_units == 8: # Millimeters result = length * 914.4 elif input_units == 5: # Terrestrial miles if output_units == 0: # Meters result = length * 1609.34 elif output_units == 1: # Kilometers result = length * 1.609 elif output_units == 2: # Imperial feet result = length * 5280 elif output_units == 3: # Nautical miles result = length / 1.151 elif output_units == 4: # Imperial yards result = length * 1760 elif output_units == 5: # Terrestrial miles result = length elif output_units == 7: # Centimeters result = length * 160934 elif output_units == 8: # Millimeters result = length * 1609340 elif input_units == 7: # Centimeters if output_units == 0: # Meters result = length / 100 elif output_units == 1: # Kilometers result = length / 100000 elif output_units == 2: # Imperial feet result = length / 30.48 elif output_units == 3: # Nautical miles result = length / 185200 elif output_units == 4: # Imperial yards result = length / 91.44 elif output_units == 5: # Terrestrial miles result = length / 160934 elif output_units == 7: # Centimeters result = length elif output_units == 8: # Millimeters result = length * 10 elif input_units == 8: # Millimeters if output_units == 0: # Meters result = length / 1000 elif output_units == 1: # Kilometers result = length / 1000000 elif output_units == 2: # Imperial feet result = length / 305 elif output_units == 3: # Nautical miles result = length / 1852000 elif output_units == 4: # Imperial yards result = length / 914 elif output_units == 5: # Terrestrial miles result = length / 1609000 elif output_units == 7: # Centimeters result = length / 10 elif output_units == 8: # Millimeters result = length return result #####################################AREA UNITS##################################################### def convert_planar_area(self, area, input_units, output_units): if input_units == 0: # Meters if output_units == 'square meters': # Square meters result = area elif output_units == 'square kilometers': # Square kilometers result = area / 1000000 elif output_units == 'square feet': # Square feet result = area * 10.764 elif output_units == 'square yards': # Square yards result = area * 1.196 elif output_units == 'square miles': # Square miles result = area / 2589988.1 elif output_units == 'hectares': # Hectares result = area / 10000 elif output_units == 'acres': # Acres result = area / 4047 elif output_units == 'square nautical miles': # Square Nautical miles result = area / 3429904 elif output_units == 'square centimeters': # Square centimeters result = area * 10000 elif output_units == 'square millimeters': # Square millimeters result = area * 1000000 #-------------------------------------------------------------------- elif input_units == 1: # Kilometers if output_units == 'square meters': # Square meters result = area * 10000 elif output_units == 'square kilometers': # Square kilometers result = area elif output_units == 'square feet': # Square feet result = area * 10763910.417 elif output_units == 'square yards': # Square yards result = area * 1195990.05 elif output_units == 'square miles': # Square miles result = area / 2.59 elif output_units == 'hectares': # Hectares result = area * 100 elif output_units == 'acres': # Acres result = area * 247.105 elif output_units == 'square nautical miles': # Square Nautical miles result = area / 3.43 elif output_units == 'square centimeters': # Square centimeters result = area * 10000000000 elif output_units == 'square millimeters': # Square millimeters result = area * 1000000000000 #-------------------------------------------------------------------- elif input_units == 2: # Imperial feet if output_units == 'square meters': # Square meters result = area / 10.764 elif output_units == 'square kilometers': # Square kilometers result = area / 10763910.417 elif output_units == 'square feet': # Square feet result = area elif output_units == 'square yards': # Square yards result = area / 9 elif output_units == 'square miles': # Square miles result = area / 27878400 elif output_units == 'hectares': # Hectares result = area / 107639 elif output_units == 'acres': # Acres result = area / 43560 elif output_units == 'square nautical miles': # Square Nautical miles result = area / 36920000 elif output_units == 'square centimeters': # Square centimeters result = area * 929 elif output_units == 'square millimeters': # Square millimeters result = area * 92903 #-------------------------------------------------------------------- elif input_units == 3: # Nautical miles if output_units == 'square meters': # Square meters result = area * 3430000 elif output_units == 'square kilometers': # Square kilometers result = area * 3.43 elif output_units == 'square feet': # Square feet result = area * 36920000 elif output_units == 'square yards': # Square yards result = area * 4102000 elif output_units == 'square miles': # Square miles result = area * 1.324 elif output_units == 'hectares': # Hectares result = area * 343 elif output_units == 'acres': # Acres result = area * 847.548 elif output_units == 'square nautical miles': # Square Nautical miles result = area elif output_units == 'square centimeters': # Square centimeters result = area * 34300000000 elif output_units == 'square millimeters': # Square millimeters result = area * 3430000000000 #-------------------------------------------------------------------- elif input_units == 4: # Imperial yards if output_units == 'square meters': # Square meters result = area / 1.196 elif output_units == 'square kilometers': # Square kilometers result = area / 1196000 elif output_units == 'square feet': # Square feet result = area * 9 elif output_units == 'square yards': # Square yards result = area elif output_units == 'square miles': # Square miles result = area / 3098000 elif output_units == 'hectares': # Hectares result = area / 11960 elif output_units == 'acres': # Acres result = area / 4840 elif output_units == 'square nautical miles': # Square Nautical miles result = area / 4102000 elif output_units == 'square centimeters': # Square centimeters result = area * 8361 elif output_units == 'square millimeters': # Square millimeters result = area * 836127 #-------------------------------------------------------------------- elif input_units == 5: # Terrestrial miles if output_units == 'square meters': # Square meters result = area * 2590000 elif output_units == 'square kilometers': # Square kilometers result = area * 2.59 elif output_units == 'square feet': # Square feet result = area * 27880000 elif output_units == 'square yards': # Square yards result = area * 3098000 elif output_units == 'square miles': # Square miles result = area elif output_units == 'hectares': # Hectares result = area * 259 elif output_units == 'acres': # Acres result = length * 640 elif output_units == 'square nautical miles': # Square Nautical miles result = area / 1.324 elif output_units == 'square centimeters': # Square centimeters result = area * 25900000000 elif output_units == 'square millimeters': # Square millimeters result = area * 2590000000000 #-------------------------------------------------------------------- elif input_units == 7: # Centimeters if output_units == 'square meters': # Square meters result = area / 10000 elif output_units == 'square kilometers': # Square kilometers result = area / 10000000000 elif output_units == 'square feet': # Square feet result = area / 929.03 elif output_units == 'square yards': # Square yards result = area / 8361.27 elif output_units == 'square miles': # Square miles result = area / 25899881103.36 elif output_units == 'hectares': # Hectares result = area / 100000000 elif output_units == 'acres': # Acres result = area / 40468564.224 elif output_units == 'square nautical miles': # Square Nautical miles result = area / 34299040000 elif output_units == 'square centimeters': # Square centimeters result = area elif output_units == 'square millimeters': # Square millimeters result = area * 100 #-------------------------------------------------------------------- elif input_units == 8: # Millimeters if output_units == 'square meters': # Square meters result = area / 1000000 elif output_units == 'square kilometers': # Square kilometers result = area / 1000000000000 elif output_units == 'square feet': # Square feet result = area / 92903 elif output_units == 'square yards': # Square yards result = area / 836127 elif output_units == 'square miles': # Square miles result = area / 2589988110336 elif output_units == 'hectares': # Hectares result = area / 10000000000 elif output_units == 'acres': # Acres result = area / 4046856422 elif output_units == 'square nautical miles': # Square Nautical miles result = area / 3429904000000 elif output_units == 'square centimeters': # Square centimeters result = area / 100 elif output_units == 'square millimeters': # Square millimeters result = area return result #################################################################################################### def dockwidget_closed(self): # print('dockwidget closed!!') self.dlg.setFloating(False) if self.layer is not None: self.tool_reset(self.layer) if isinstance(self.layer, QgsVectorLayer): self.layer.selectionChanged.disconnect(self.total_length) self.iface.currentLayerChanged.disconnect(self.active_changed) #####25-05-21 self.action.setEnabled(True) def unload(self): self.toolbar.removeAction(self.action) del self.action
def maneuverForPoint(self, pt, speed): min_dist = MAX_DISTANCE_FOR_NAVIGATION closest_leg = None closest_segment = None qgsdistance = QgsDistanceArea() qgsdistance.setSourceCrs(QgsCoordinateReferenceSystem(4326), QgsProject.instance().transformContext()) qgsdistance.setEllipsoid(qgsdistance.sourceCrs().ellipsoidAcronym()) legs = list(self.maneuvers.keys()) for i, line in enumerate(legs): _, _pt, segment, _ = line.closestSegmentWithContext(pt) dist = qgsdistance.convertLengthMeasurement( qgsdistance.measureLine(pt, _pt), QgsUnitTypes.DistanceMeters) if dist < min_dist: closest_leg = line closest_segment = segment closest_point = _pt min_dist = dist if closest_leg is not None: leg_points = closest_leg.asPolyline() maneuvers = self.maneuvers[closest_leg] for i, maneuver in enumerate(maneuvers[:-1]): if (maneuver["begin_shape_index"] < closest_segment and maneuver["end_shape_index"] >= closest_segment): points = [closest_point] points.extend( leg_points[closest_segment:maneuver["end_shape_index"]] ) distance_to_next = qgsdistance.convertLengthMeasurement( qgsdistance.measureLine(points), QgsUnitTypes.DistanceMeters) message = maneuvers[i + 1]['instruction'] if i == len(maneuvers) - 2: distance_to_next2 = None message2 = "" icon2 = _icon_path("transparentpixel") else: next_maneuver = maneuvers[i + 2] distance_to_next2 = maneuvers[i + 1]['length'] * 1000 message2 = next_maneuver['instruction'] icon2 = icon_path_for_maneuver(maneuvers[i + 2]["type"]) icon = icon_path_for_maneuver(maneuvers[i + 1]["type"]) time_to_next = distance_to_next / 1000 / speed * 3600 try: maneuvers_ahead = maneuvers[i + 1:] except IndexError: maneuvers_ahead = [] timeleft = time_to_next + sum( [m["time"] for m in maneuvers_ahead]) distanceleft = distance_to_next + sum( [m["length"] for m in maneuvers_ahead]) * 1000 delta = datetime.timedelta(seconds=timeleft) timeleft_string = ":".join(str(delta).split(":")[:-1]) eta = datetime.datetime.now() + delta eta_string = eta.strftime("%H:%M") maneuver = dict(dist=formatdist(distance_to_next), message=message, icon=icon, dist2=formatdist(distance_to_next2), message2=message2, icon2=icon2, speed=speed, timeleft=timeleft_string, distleft=formatdist(distanceleft), raw_distleft=distanceleft, eta=eta_string, x=closest_point.x(), y=closest_point.y()) return maneuver raise NotInRouteException()
from qgis.core import QgsDistanceArea san_francisco = (37.7749, -122.4194) new_york = (40.661, -73.944) las_vegas = (36.1699, -115.1398) d = QgsDistanceArea() d.setEllipsoid('WGS84') lat1, lon1 = san_francisco lat2, lon2 = las_vegas lat3, lon3 = new_york # Remember the order is X,Y point1 = QgsPointXY(lon1, lat1) point2 = QgsPointXY(lon2, lat2) point3 = QgsPointXY(lon3, lat3) distance = d.measureLine([point1, point2, point3]) print(distance / 1000) distance_mi = d.convertLengthMeasurement(distance, QgsUnitTypes.DistanceMiles) print(distance_mi)