def simpleMeasure(geom, method=0, ellips=None, crs=None): # Method defines calculation type: # 0 - layer CRS # 1 - project CRS # 2 - ellipsoidal if geom.type() == QgsWkbTypes.PointGeometry: if not geom.isMultipart(): pt = geom.geometry() attr1 = pt.x() attr2 = pt.y() else: pt = geom.asMultiPoint() attr1 = pt[0].x() attr2 = pt[0].y() else: measure = QgsDistanceArea() if method == 2: measure.setSourceCrs(crs) measure.setEllipsoid(ellips) measure.setEllipsoidalMode(True) if geom.type() == QgsWkbTypes.PolygonGeometry: attr1 = measure.measureArea(geom) attr2 = measure.measurePerimeter(geom) else: attr1 = measure.measureLength(geom) attr2 = None return (attr1, attr2)
def simpleMeasure(geom, method=0, ellips=None, crs=None): # Method defines calculation type: # 0 - layer CRS # 1 - project CRS # 2 - ellipsoidal if geom.type() == QgsWkbTypes.PointGeometry: if not geom.isMultipart(): pt = geom.geometry() attr1 = pt.x() attr2 = pt.y() else: pt = geom.asMultiPoint() attr1 = pt[0].x() attr2 = pt[0].y() else: measure = QgsDistanceArea() if method == 2: measure.setSourceCrs(crs) measure.setEllipsoid(ellips) measure.setEllipsoidalMode(True) if geom.type() == QgsWkbTypes.PolygonGeometry: attr1 = measure.measureArea(geom) attr2 = measure.measurePerimeter(geom) else: attr1 = measure.measureLength(geom) attr2 = None return (attr1, attr2)
def simpleMeasure(geom, method=0, ellips=None, crs=None): # Method defines calculation type: # 0 - layer CRS # 1 - project CRS # 2 - ellipsoidal if geom.wkbType() in [QGis.WKBPoint, QGis.WKBPoint25D]: pt = geom.asPoint() attr1 = pt.x() attr2 = pt.y() elif geom.wkbType() in [QGis.WKBMultiPoint, QGis.WKBMultiPoint25D]: pt = geom.asMultiPoint() attr1 = pt[0].x() attr2 = pt[0].y() else: measure = QgsDistanceArea() if method == 2: measure.setSourceCrs(crs) measure.setEllipsoid(ellips) measure.setEllipsoidalMode(True) attr1 = measure.measure(geom) if geom.type() == QGis.Polygon: attr2 = measure.measurePerimeter(geom) else: attr2 = None return (attr1, attr2)
def simpleMeasure(geom, method=0, ellips=None, crs=None): # Method defines calculation type: # 0 - layer CRS # 1 - project CRS # 2 - ellipsoidal if geom.wkbType() in [QGis.WKBPoint, QGis.WKBPoint25D]: pt = geom.asPoint() attr1 = pt.x() attr2 = pt.y() elif geom.wkbType() in [QGis.WKBMultiPoint, QGis.WKBMultiPoint25D]: pt = geom.asMultiPoint() attr1 = pt[0].x() attr2 = pt[0].y() else: measure = QgsDistanceArea() if method == 2: measure.setSourceCrs(crs) measure.setEllipsoid(ellips) measure.setEllipsoidalMode(True) attr1 = measure.measure(geom) if geom.type() == QGis.Polygon: attr2 = measure.measurePerimeter(geom) else: attr2 = None return (attr1, attr2)
def _calc_north(self): extent = self.canvas.extent() if self.canvas.layerCount() == 0 or extent.isEmpty(): print "No layers or extent" return 0 outcrs = self.canvas.mapSettings().destinationCrs() if outcrs.isValid() and not outcrs.geographicFlag(): crs = QgsCoordinateReferenceSystem() crs.createFromOgcWmsCrs("EPSG:4326") transform = QgsCoordinateTransform(outcrs, crs) p1 = QgsPoint(extent.center()) p2 = QgsPoint(p1.x(), p1.y() + extent.height() * 0.25) try: pp1 = transform.transform(p1) pp2 = transform.transform(p2) except QgsCsException: roam.utils.warning("North arrow. Error transforming.") return None area = QgsDistanceArea() area.setEllipsoid(crs.ellipsoidAcronym()) area.setEllipsoidalMode(True) area.setSourceCrs(crs) distance, angle, _ = area.computeDistanceBearing(pp1, pp2) angle = math.degrees(angle) return angle else: return 0
def _calc_north(self): extent = self.canvas.extent() if self.canvas.layerCount() == 0 or extent.isEmpty(): return 0 outcrs = self.canvas.mapSettings().destinationCrs() if outcrs.isValid() and not outcrs.geographicFlag(): crs = QgsCoordinateReferenceSystem() crs.createFromOgcWmsCrs("EPSG:4326") transform = QgsCoordinateTransform(outcrs, crs) p1 = QgsPoint(extent.center()) p2 = QgsPoint(p1.x(), p1.y() + extent.height() * 0.25) try: pp1 = transform.transform(p1) pp2 = transform.transform(p2) except QgsCsException: roam.utils.warning("North arrow. Error transforming.") return None area = QgsDistanceArea() area.setEllipsoid(crs.ellipsoidAcronym()) area.setEllipsoidalMode(True) area.setSourceCrs(crs) distance, angle, _ = area.computeDistanceBearing(pp1, pp2) angle = math.degrees(angle) return angle else: return 0
def calculateDistance(self, p1, p2): distance = QgsDistanceArea() distance.setSourceCrs(self.iface.activeLayer().crs()) distance.setEllipsoidalMode(True) # Sirgas 2000 distance.setEllipsoid('GRS1980') m = distance.measureLine(p1, p2) return m
def calculateDistance(self, p1, p2): distance = QgsDistanceArea() distance.setSourceCrs(self.iface.activeLayer().crs()) distance.setEllipsoidalMode(True) # Sirgas 2000 distance.setEllipsoid('GRS1980') m = distance.measureLine(p1, p2) return m
def get_distance_area(self, layer): destination = layer.crs() distance_area = QgsDistanceArea() distance_area.setSourceCrs(layer.crs()) distance_area.setEllipsoid(destination.ellipsoidAcronym()) # sets whether coordinates must be projected to ellipsoid before measuring distance_area.setEllipsoidalMode(True) return distance_area
def get_distance_area(self, layer): destination = layer.crs() distance_area = QgsDistanceArea() distance_area.setSourceCrs(layer.crs()) distance_area.setEllipsoid(destination.ellipsoidAcronym()) # sets whether coordinates must be projected to ellipsoid before measuring distance_area.setEllipsoidalMode(True) return distance_area
def calculate( self, layer, fieldName, expression ): if ( layer.featureCount() == 0 ): self.msg.show( "[Info] * No existing features on layer " + layer.name() + " to calculate expression.", 'info', True ) return expression = QgsExpression( expression ) if expression.hasParserError(): self.msg.show( QApplication.translate( "AutoFields-FieldCalculator", "[Error] (Parsing) " ) + \ expression.parserErrorString(), 'critical' ) return context = QgsExpressionContext() context.appendScope( QgsExpressionContextUtils.globalScope() ) context.appendScope( QgsExpressionContextUtils.projectScope() ) context.appendScope( QgsExpressionContextUtils.layerScope( layer ) ) context.setFields( layer.fields() ) if expression.needsGeometry(): if self.iface: # This block was borrowed from QGIS/python/plugins/processing/algs/qgis/FieldsCalculator.py da = QgsDistanceArea() da.setSourceCrs( layer.crs().srsid() ) da.setEllipsoidalMode( self.iface.mapCanvas().mapSettings().hasCrsTransformEnabled() ) da.setEllipsoid( QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE )[0] ) expression.setGeomCalculator( da ) if QGis.QGIS_VERSION_INT >= 21400: # Methods added in QGIS 2.14 expression.setDistanceUnits( QgsProject.instance().distanceUnits() ) expression.setAreaUnits( QgsProject.instance().areaUnits() ) expression.prepare( context ) fieldIndex = layer.fieldNameIndex( fieldName ) if fieldIndex == -1: return field = layer.fields()[fieldIndex] dictResults = {} for feature in layer.getFeatures(): context.setFeature( feature ) result = expression.evaluate( context ) if expression.hasEvalError(): self.msg.show( QApplication.translate( "AutoFields-FieldCalculator", "[Error] (Evaluating) " ) + \ expression.evalErrorString(), 'critical' ) return dictResults[feature.id()] = { fieldIndex: field.convertCompatible( result ) } layer.dataProvider().changeAttributeValues( dictResults ) self.msg.show( "[Info] * An expression was calculated on existing features of layer " + layer.name() + ", field " + fieldName + ".", 'info', True )
def size_calculator(crs): """Helper function to create a size calculator according to a CRS. :param crs: The coordinate reference system to use. :type crs: QgsCoordinateReferenceSystem :return: The QgsDistanceArea object. :rtype: QgsDistanceArea """ calculator = QgsDistanceArea() calculator.setSourceCrs(crs) calculator.setEllipsoid('WGS84') calculator.setEllipsoidalMode(True) return calculator
def setCustomExpression(self): """ Initialize and show the expression builder dialog """ layer = None if len(self.tblLayers.selectedItems() ) / 3 == 1: # Single layer selected? for item in self.tblLayers.selectedItems(): if item.column() == 1: # It's the layer name item layer = QgsMapLayerRegistry.instance().mapLayer( item.data(Qt.UserRole)) if not self.expressionDlg: self.expressionDlg = ExpressionBuilderDialog( self.iface.mainWindow()) context = QgsExpressionContext() context.appendScope(QgsExpressionContextUtils.globalScope()) context.appendScope(QgsExpressionContextUtils.projectScope()) # Initialize dialog with layer-based names and variables if single layer selected if len(self.tblLayers.selectedItems()) / 3 == 1: context.appendScope( QgsExpressionContextUtils.layerScope(layer)) self.expressionDlg.expressionBuilderWidget.setLayer(layer) self.expressionDlg.expressionBuilderWidget.loadFieldNames() # This block was borrowed from QGIS/python/plugins/processing/algs/qgis/FieldsCalculator.py da = QgsDistanceArea() da.setSourceCrs(layer.crs().srsid()) da.setEllipsoidalMode(self.iface.mapCanvas().mapSettings(). hasCrsTransformEnabled()) da.setEllipsoid(QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE)[0]) self.expressionDlg.expressionBuilderWidget.setGeomCalculator( da) # If this layer-field is an AutoField, get its expression if self.optExistingField.isChecked(): fieldName = self.cboField.currentText() expression = self.autoFieldManager.getFieldExpression( layer, fieldName) self.expressionDlg.expressionBuilderWidget.setExpressionText( expression) self.expressionDlg.expression = expression # To remember it when closing/opening self.expressionDlg.expressionBuilderWidget.setExpressionContext( context) self.expressionDlg.show()
def testLengthMeasureAndUnits(self): """Test a variety of length measurements in different CRS and ellipsoid modes, to check that the calculated lengths and units are always consistent """ da = QgsDistanceArea() da.setSourceCrs(3452) da.setEllipsoidalMode(False) da.setEllipsoid("NONE") daCRS = QgsCoordinateReferenceSystem() daCRS.createFromSrsId(da.sourceCrs()) # We check both the measured length AND the units, in case the logic regarding # ellipsoids and units changes in future distance = da.measureLine(QgsPoint(1, 1), QgsPoint(2, 3)) units = da.lengthUnits() print "measured {} in {}".format(distance, QgsUnitTypes.toString(units)) assert ((abs(distance - 2.23606797) < 0.00000001 and units == QGis.Degrees) or (abs(distance - 248.52) < 0.01 and units == QGis.Meters)) da.setEllipsoid("WGS84") distance = da.measureLine(QgsPoint(1, 1), QgsPoint(2, 3)) units = da.lengthUnits() print "measured {} in {}".format(distance, QgsUnitTypes.toString(units)) assert ((abs(distance - 2.23606797) < 0.00000001 and units == QGis.Degrees) or (abs(distance - 248.52) < 0.01 and units == QGis.Meters)) da.setEllipsoidalMode(True) distance = da.measureLine(QgsPoint(1, 1), QgsPoint(2, 3)) units = da.lengthUnits() print "measured {} in {}".format(distance, QgsUnitTypes.toString(units)) # should always be in Meters self.assertAlmostEqual(distance, 247555.57, delta=0.01) self.assertEqual(units, QGis.Meters) # now try with a source CRS which is in feet da.setSourceCrs(27469) da.setEllipsoidalMode(False) # measurement should be in feet distance = da.measureLine(QgsPoint(1, 1), QgsPoint(2, 3)) units = da.lengthUnits() print "measured {} in {}".format(distance, QgsUnitTypes.toString(units)) self.assertAlmostEqual(distance, 2.23606797, delta=0.000001) self.assertEqual(units, QGis.Feet) da.setEllipsoidalMode(True) # now should be in Meters again distance = da.measureLine(QgsPoint(1, 1), QgsPoint(2, 3)) units = da.lengthUnits() print "measured {} in {}".format(distance, QgsUnitTypes.toString(units)) self.assertAlmostEqual(distance, 0.67953772, delta=0.000001) self.assertEqual(units, QGis.Meters)
def _newDialog(self, cloneFeature): feature = QgsFeature() if (cloneFeature): feature = QgsFeature(self._feature) else: feature = self._feature context = QgsAttributeEditorContext() myDa = QgsDistanceArea() myDa.setSourceCrs(self._layer.crs()) myDa.setEllipsoidalMode( self._iface.mapCanvas().mapSettings().hasCrsTransformEnabled()) myDa.setEllipsoid(QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE)[0]) context.setDistanceArea(myDa) context.setVectorLayerTools(self._iface.vectorLayerTools()) dialog = QgsAttributeDialog(self._layer, feature, cloneFeature, None, True, context) if (self._layer.actions().size() > 0): dialog.setContextMenuPolicy(Qt.ActionsContextMenu) a = QAction(self.tr('Run actions'), dialog) a.setEnabled(False) dialog.addAction(a) i = 0 for action in self._layer.actions(): if (action.runable()): a = FeatureAction(action.name(), feature, self._layer, i, -1, self._iface, dialog) dialog.addAction(a) a.triggered.connect(a.execute) pb = dialog.findChild(action.name()) if (pb): pb.clicked.connect(a.execute) i += 1 return dialog
def impact_table(self): """Return data as dictionary""" # prepare area calculator object area_calc = QgsDistanceArea() area_calc.setSourceCrs(self.impact_layer.crs()) area_calc.setEllipsoid('WGS84') area_calc.setEllipsoidalMode(True) impacted_table = FlatTable('landcover', 'hazard', 'zone') for f in self.impact_layer.getFeatures(): area = area_calc.measure(f.geometry()) / 1e4 zone = f[self.zone_field] if self.zone_field is not None else None impacted_table.add_value(area, landcover=f[self.land_cover_field], hazard=f[self.target_field], zone=zone) return impacted_table.to_dict()
def impact_table(self): """Return data as dictionary""" # prepare area calculator object area_calc = QgsDistanceArea() area_calc.setSourceCrs(self.impact_layer.crs()) area_calc.setEllipsoid('WGS84') area_calc.setEllipsoidalMode(True) impacted_table = FlatTable('landcover', 'hazard', 'zone') for f in self.impact_layer.getFeatures(): area = area_calc.measure(f.geometry()) / 1e4 zone = f[self.zone_field] if self.zone_field is not None else None impacted_table.add_value( area, landcover=f[self.land_cover_field], hazard=f[self.target_field], zone=zone) return impacted_table.to_dict()
def evaluation(self=None, parameters={},feature=None): from PyQt4.QtCore import QVariant from qgis.core import QgsDistanceArea, QgsCoordinateReferenceSystem ar = NULL per = NULL id = NULL flr = NULL usage = NULL kind = NULL da_engine=QgsDistanceArea() da_engine.setSourceCrs(QgsCoordinateReferenceSystem(int(config.project_crs.split(':')[-1]), QgsCoordinateReferenceSystem.EpsgCrsId)) da_engine.setEllipsoid(config.project_ellipsoid) da_engine.setEllipsoidalMode(True) if feature: geometry = feature.geometry() #print geometry ar = da_engine.measureArea(geometry) per =da_engine.measurePerimeter(geometry) id = feature[config.building_id_key] #necessary to safe dependency check flr = feature[u'FLRS_ALK'] # necessary to safe dependency check usage = feature[u'FUNC_ALK'] # necessary to safe dependency check kind = feature[u'KIND_ALK'] # necessary to safe dependency check #print ar #print per #print id return {config.building_id_key: {'type': QVariant.String, 'value': id}, 'AREA_ALK': {'type': QVariant.Double, 'value': ar}, 'PERI_ALK': {'type': QVariant.Double, 'value': per}, 'FLRS_ALK': {'type': QVariant.Double, 'value': flr}, 'FUNC_ALK': {'type': QVariant.Double, 'value': usage}, 'KIND_ALK': {'type': QVariant.Double, 'value': kind}, }
def _newDialog(self, cloneFeature): feature = QgsFeature() if (cloneFeature): feature = QgsFeature(self._feature) else: feature = self._feature context = QgsAttributeEditorContext() myDa = QgsDistanceArea() myDa.setSourceCrs(self._layer.crs()) myDa.setEllipsoidalMode(self._iface.mapCanvas().mapSettings().hasCrsTransformEnabled()) myDa.setEllipsoid(QgsProject.instance().readEntry('Measure', '/Ellipsoid', GEO_NONE)[0]) context.setDistanceArea(myDa) context.setVectorLayerTools(self._iface.vectorLayerTools()) dialog = QgsAttributeDialog(self._layer, feature, cloneFeature, None, True, context) if (self._layer.actions().size() > 0): dialog.setContextMenuPolicy(Qt.ActionsContextMenu) a = QAction(self.tr('Run actions'), dialog) a.setEnabled(False) dialog.addAction(a) i = 0 for action in self._layer.actions(): if (action.runable()): a = FeatureAction(action.name(), feature, self._layer, i, -1, self._iface, dialog) dialog.addAction(a) a.triggered.connect(a.execute) pb = dialog.findChild(action.name()) if (pb): pb.clicked.connect(a.execute) i += 1 return dialog
def simpleMeasure(self, inGeom, calcType, ellips, crs): if inGeom.wkbType() in (QGis.WKBPoint, QGis.WKBPoint25D): pt = inGeom.asPoint() attr1 = pt.x() attr2 = pt.y() elif inGeom.wkbType() in (QGis.WKBMultiPoint, QGis.WKBMultiPoint25D): pt = inGeom.asMultiPoint() attr1 = pt[0].x() attr2 = pt[0].y() else: measure = QgsDistanceArea() if calcType == 2: measure.setSourceCrs(crs) measure.setEllipsoid(ellips) measure.setEllipsoidalMode(True) attr1 = measure.measure(inGeom) if inGeom.type() == QGis.Polygon: attr2 = self.perimMeasure(inGeom, measure) else: attr2 = attr1 return (attr1, attr2)
def simpleMeasure( self, inGeom, calcType, ellips, crs ): if inGeom.wkbType() in ( QGis.WKBPoint, QGis.WKBPoint25D ): pt = inGeom.asPoint() attr1 = pt.x() attr2 = pt.y() elif inGeom.wkbType() in ( QGis.WKBMultiPoint, QGis.WKBMultiPoint25D ): pt = inGeom.asMultiPoint() attr1 = pt[ 0 ].x() attr2 = pt[ 0 ].y() else: measure = QgsDistanceArea() if calcType == 2: measure.setSourceCrs( crs ) measure.setEllipsoid( ellips ) measure.setEllipsoidalMode( True ) attr1 = measure.measure( inGeom ) if inGeom.type() == QGis.Polygon: attr2 = self.perimMeasure( inGeom, measure ) else: attr2 = attr1 return ( attr1, attr2 )
def setCustomExpression( self ): """ Initialize and show the expression builder dialog """ layer = None if len( self.tblLayers.selectedItems() ) / 3 == 1: # Single layer selected? for item in self.tblLayers.selectedItems(): if item.column() == 1: # It's the layer name item layer = QgsMapLayerRegistry.instance().mapLayer( item.data( Qt.UserRole ) ) if not self.expressionDlg: self.expressionDlg = ExpressionBuilderDialog( self.iface.mainWindow() ) context = QgsExpressionContext() context.appendScope( QgsExpressionContextUtils.globalScope() ) context.appendScope( QgsExpressionContextUtils.projectScope() ) # Initialize dialog with layer-based names and variables if single layer selected if len( self.tblLayers.selectedItems() ) / 3 == 1: context.appendScope( QgsExpressionContextUtils.layerScope( layer ) ) self.expressionDlg.expressionBuilderWidget.setLayer( layer ) self.expressionDlg.expressionBuilderWidget.loadFieldNames() # This block was borrowed from QGIS/python/plugins/processing/algs/qgis/FieldsCalculator.py da = QgsDistanceArea() da.setSourceCrs( layer.crs().srsid() ) da.setEllipsoidalMode( self.iface.mapCanvas().mapSettings().hasCrsTransformEnabled() ) da.setEllipsoid( QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE )[0] ) self.expressionDlg.expressionBuilderWidget.setGeomCalculator( da ) # If this layer-field is an AutoField, get its expression if self.optExistingField.isChecked(): fieldName = self.cboField.currentText() expression = self.autoFieldManager.getFieldExpression( layer, fieldName ) self.expressionDlg.expressionBuilderWidget.setExpressionText( expression ) self.expressionDlg.expression = expression # To remember it when closing/opening self.expressionDlg.expressionBuilderWidget.setExpressionContext( context ) self.expressionDlg.show()
def testWillUseEllipsoid(self): """test QgsDistanceArea::willUseEllipsoid """ da = QgsDistanceArea() da.setEllipsoidalMode(False) da.setEllipsoid("NONE") self.assertFalse(da.willUseEllipsoid()) da.setEllipsoidalMode(True) self.assertFalse(da.willUseEllipsoid()) da.setEllipsoid("WGS84") assert da.willUseEllipsoid() da.setEllipsoidalMode(False) self.assertFalse(da.willUseEllipsoid())
def testWillUseEllipsoid(self): """test QgsDistanceArea::willUseEllipsoid """ da = QgsDistanceArea() da.setEllipsoidalMode(False) da.setEllipsoid("NONE") self.assertFalse(da.willUseEllipsoid()) da.setEllipsoidalMode(True) self.assertFalse(da.willUseEllipsoid()) da.setEllipsoid("WGS84") assert da.willUseEllipsoid() da.setEllipsoidalMode(False) self.assertFalse(da.willUseEllipsoid())
class SizeCalculator(object): """Special object to handle size calculation with an output unit.""" def __init__( self, coordinate_reference_system, geometry_type, exposure_key): """Constructor for the size calculator. :param coordinate_reference_system: The Coordinate Reference System of the layer. :type coordinate_reference_system: QgsCoordinateReferenceSystem :param exposure_key: The geometry type of the layer. :type exposure_key: qgis.core.QgsWkbTypes.GeometryType """ self.calculator = QgsDistanceArea() self.calculator.setSourceCrs(coordinate_reference_system) self.calculator.setEllipsoid('WGS84') self.calculator.setEllipsoidalMode(True) if geometry_type == QgsWKBTypes.LineGeometry: self.default_unit = unit_metres LOGGER.info('The size calculator is set to use {unit}'.format( unit=distance_unit[self.calculator.lengthUnits()])) else: self.default_unit = unit_square_metres LOGGER.info('The size calculator is set to use {unit}'.format( unit=distance_unit[self.calculator.areaUnits()])) self.geometry_type = geometry_type self.output_unit = None if exposure_key: exposure_definition = definition(exposure_key) self.output_unit = exposure_definition['size_unit'] def measure(self, geometry): """Measure the length or the area of a geometry. :param geometry: The geometry. :type geometry: QgsGeometry :return: The geometric size in the expected exposure unit. :rtype: float """ message = 'Size with NaN value : geometry valid={valid}, WKT={wkt}' feature_size = 0 if geometry.isMultipart(): # Be careful, the size calculator is not working well on a # multipart. # So we compute the size part per part. See ticket #3812 for single in geometry.asGeometryCollection(): if self.geometry_type == QgsWKBTypes.LineGeometry: geometry_size = self.calculator.measureLength(single) else: geometry_size = self.calculator.measureArea(single) if not isnan(geometry_size): feature_size += geometry_size else: LOGGER.debug(message.format( valid=single.isGeosValid(), wkt=single.exportToWkt())) else: if self.geometry_type == QgsWKBTypes.LineGeometry: geometry_size = self.calculator.measureLength(geometry) else: geometry_size = self.calculator.measureArea(geometry) if not isnan(geometry_size): feature_size = geometry_size else: LOGGER.debug(message.format( valid=geometry.isGeosValid(), wkt=geometry.exportToWkt())) feature_size = round(feature_size) if self.output_unit: if self.output_unit != self.default_unit: feature_size = convert_unit( feature_size, self.default_unit, self.output_unit) return feature_size
def by_seconds(self, seconds): """move by variable distance""" def iterations(distance, h): FIe1 = 0 LAMe1 = 0 FI = 100 LAM = 100 # iterations while fabs(FI - FIe1) > 0.0000000001 and fabs( LAM - LAMe1) > 0.0000000001: FI = FIe1 LAM = LAMe1 for i in range(0, int(ceil(distance / h))): kfi = [] klam = [] kazi = [] kfi.append( cos(azi[i]) / (a * (1 - (e2)) / (pow( (sqrt(1 - (e2) * pow(sin(fi[i]), 2))), 3)))) klam.append( sin(azi[i]) / ((a / (sqrt(1 - (e2) * pow(sin(fi[i]), 2)))) * cos(fi[i]))) kazi.append( sin(azi[i]) * tan(fi[i]) / (a / (sqrt(1 - (e2) * pow(sin(fi[i]), 2))))) for j in range(1, 3): kfi.append( cos(azi[i] + kazi[j - 1] * h / 2) / (a * (1 - (e2)) / (pow( sqrt(1 - (e2) * pow(sin(fi[i] + kfi[j - 1] * h / 2), 2)), 3)))) klam.append( sin(azi[i] + kazi[j - 1] * h / 2) / ((a / (sqrt(1 - (e2) * pow(sin(fi[i] + kfi[j - 1] * h / 2), 2)))) * cos(fi[i] + kfi[j - 1] * h / 2))) kazi.append( sin(azi[i] + kazi[j - 1] * h / 2) * tan(fi[i] + kfi[j - 1] * h / 2) / (a / (sqrt(1 - (e2) * pow(sin(fi[i] + kfi[j - 1] * h / 2), 2))))) kfi.append( cos(azi[i] + kazi[2] * h) / (a * (1 - (e2)) / (pow( sqrt(1 - (e2) * pow(sin(fi[i] + kfi[2] * h), 2)), 3)))) klam.append( sin(azi[i] + kazi[2] * h) / ((a / (sqrt(1 - (e2) * pow(sin(fi[i] + kfi[2] * h), 2)))) * cos(fi[i] + kfi[2] * h))) kazi.append( sin(azi[i] + kazi[2] * h) * tan(fi[i] + kfi[2] * h) / (a / (sqrt(1 - (e2) * pow(sin(fi[i] + kfi[2] * h), 2))))) fi.append(fi[i] + (h / 6.0) * (kfi[0] + 2 * kfi[1] + 2 * kfi[2] + kfi[3])) lam.append(lam[i] + (h / 6.0) * (klam[0] + 2 * klam[1] + 2 * klam[2] + klam[3])) azi.append(azi[i] + (h / 6.0) * (kazi[0] + 2 * kazi[1] + 2 * kazi[2] + kazi[3])) FIe1 = fi[i + 1] LAMe1 = lam[i + 1] h = h / 2 fi[1:] = [] lam[1:] = [] azi[1:] = [] return FIe1, LAMe1 self._check() header = self.inputfile.readline() beforeLat = header.split('Lat_deg') numberOfLatColumn = beforeLat[0].split(',') beforeLong = header.split('Lon_deg') numberOfLonColumn = beforeLong[0].split(',') beforeSec = header.split('Gtm_sec') numberOfSecColumn = beforeSec[0].split(',') self.outputfile.write(header) d = QgsDistanceArea() d.setEllipsoid('WGS84') d.setEllipsoidalMode(True) d.ellipsoid() a = 6378137.0 # WGS84 ellipsoid parametres e2 = 0.081819190842622 line1 = self.inputfile.readline() if seconds > 0: linePos = self.inputfile.tell() line1 = line1.split(',') while line1: self.inputfile.seek(linePos) line2 = self.inputfile.readline() linePos = self.inputfile.tell() moveTime = 1 * seconds outline = 1 * line1 inline = line2.split(',') while moveTime > 0: # for case of more than 1 second if line2: line2 = line2.split(',') p1 = QgsPoint(float(line1[len(numberOfLonColumn) - 1]), float(line1[len(numberOfLatColumn) - 1])) p2 = QgsPoint(float(line2[len(numberOfLonColumn) - 1]), float(line2[len(numberOfLatColumn) - 1])) if p1 != p2: aziA = d.bearing(p1, p2) l = d.computeDistanceBearing(p1, p2)[0] if moveTime > ( float(line2[len(numberOfSecColumn) - 1]) - float(line1[len(numberOfSecColumn) - 1])): moveTime = moveTime - ( float(line2[len(numberOfSecColumn) - 1]) - float(line1[len(numberOfSecColumn) - 1])) elif moveTime != 0 and moveTime != ( float(line2[len(numberOfSecColumn) - 1]) - float(line1[len(numberOfSecColumn) - 1])): #first geodetic problem distance = l / ( float(line2[len(numberOfSecColumn) - 1]) - float(line1[len(numberOfSecColumn) - 1])) * moveTime h = distance / 2.0 fi = [ float(line1[len(numberOfLatColumn) - 1]) * pi / 180 ] lam = [ float(line1[len(numberOfLonColumn) - 1]) * pi / 180 ] azi = [aziA] FIe1, LAMe1 = iterations(distance, h) moveTime = 0 else: FIe1 = float(line2[len(numberOfLatColumn) - 1]) * pi / 180 LAMe1 = float(line2[len(numberOfLonColumn) - 1]) * pi / 180 moveTime = 0 break else: if moveTime > ( float(line2[len(numberOfSecColumn) - 1]) - float(line1[len(numberOfSecColumn) - 1])): moveTime = moveTime - ( float(line2[len(numberOfSecColumn) - 1]) - float(line1[len(numberOfSecColumn) - 1])) else: FIe1 = float(line2[len(numberOfLatColumn) - 1]) * pi / 180 LAMe1 = float(line2[len(numberOfLonColumn) - 1]) * pi / 180 moveTime = 0 break else: break line1 = 1 * line2 line2 = self.inputfile.readline() line1 = 1 * inline if moveTime == 0: outline[len(numberOfLatColumn) - 1] = str( FIe1 * 180 / pi) # changing latitude and longitude of new point outline[len(numberOfLonColumn) - 1] = str(LAMe1 * 180 / pi) outline = ','.join(outline) self.outputfile.write(outline) else: break elif seconds < 0: line = [] line.append(line1) line[0] = line[0].split(',') line.append(self.inputfile.readline()) line[1] = line[1].split(',') allSecs = (float(line[1][len(numberOfSecColumn) - 1]) - float(line[0][len(numberOfSecColumn) - 1])) i = 1 moveTime = 1 * seconds while fabs(moveTime) > allSecs: line.append(self.inputfile.readline().split(',')) i = i + 1 if line[len(line) - 1] == ['']: break allSecs = allSecs + ( float(line[i][len(numberOfSecColumn) - 1]) - float(line[i - 1][len(numberOfSecColumn) - 1])) while line[len(line) - 1] != ['']: allSecs = 0 for i in reversed(range(1, len(line))): allSecs = allSecs + ( float(line[i][len(numberOfSecColumn) - 1]) - float(line[i - 1][len(numberOfSecColumn) - 1])) if fabs(moveTime) <= allSecs: for x in range(i - 1): del line[0] break for i in reversed(range(len(line))): p1 = QgsPoint( float(line[i - 1][len(numberOfLonColumn) - 1]), float(line[i - 1][len(numberOfLatColumn) - 1])) p2 = QgsPoint(float(line[i][len(numberOfLonColumn) - 1]), float(line[i][len(numberOfLatColumn) - 1])) if p1 != p2: aziA = d.bearing(p2, p1) l = d.computeDistanceBearing(p1, p2)[0] if moveTime < -(float( line[i][len(numberOfSecColumn) - 1]) - float( line[i - 1][len(numberOfSecColumn) - 1])): moveTime = moveTime + ( float(line[i][len(numberOfSecColumn) - 1]) - float(line[i - 1][len(numberOfSecColumn) - 1])) elif moveTime != 0 and moveTime != -( float(line[i][len(numberOfSecColumn) - 1]) - float(line[i - 1][len(numberOfSecColumn) - 1]) ): #first geodetic problem distance = l / ( float(line[i][len(numberOfSecColumn) - 1]) - float(line[i - 1][len(numberOfSecColumn) - 1])) * fabs(moveTime) h = distance / 2.0 fi = [ float(line[i][len(numberOfLatColumn) - 1]) * pi / 180 ] lam = [ float(line[i][len(numberOfLonColumn) - 1]) * pi / 180 ] azi = [aziA] FIe1, LAMe1 = iterations(distance, h) break else: FIe1 = float(line[i - 1][len(numberOfLatColumn) - 1]) * pi / 180 LAMe1 = float(line[i - 1][len(numberOfLonColumn) - 1]) * pi / 180 break else: if moveTime < -(float( line[i][len(numberOfSecColumn) - 1]) - float( line[i - 1][len(numberOfSecColumn) - 1])): moveTime = moveTime + ( float(line[i][len(numberOfSecColumn) - 1]) - float(line[i - 1][len(numberOfSecColumn) - 1])) else: FIe1 = float(line[i - 1][len(numberOfLatColumn) - 1]) * pi / 180 LAMe1 = float(line[i - 1][len(numberOfLonColumn) - 1]) * pi / 180 break outline = 1 * line[len(line) - 1] outline[len(numberOfLatColumn) - 1] = str( FIe1 * 180 / pi) # changing latitude and longitude of new point outline[len(numberOfLonColumn) - 1] = str(LAMe1 * 180 / pi) outline = ','.join(outline) self.outputfile.write(outline) line.append(self.inputfile.readline()) line[len(line) - 1] = line[len(line) - 1].split(',') moveTime = 1 * seconds else: while line1: self.outputfile.write(line1) line1 = self.inputfile.readline() self._close()
def by_seconds(self, seconds): """ shift by variable distance :param seconds: number of seconds used to calculate velocity """ self._check() header = self.inputfile.readline() beforeLat = header.split('Lat_deg') numberOfLatColumn = beforeLat[0].split(',') beforeLong = header.split('Lon_deg') numberOfLonColumn = beforeLong[0].split(',') beforeSec = header.split('Gtm_sec') numberOfSecColumn = beforeSec[0].split(',') self.outputfile.write(header) d = QgsDistanceArea() d.setEllipsoid('WGS84') d.setEllipsoidalMode(True) d.ellipsoid() a = 6378137.0 # WGS84 ellipsoid parametres e2 = 0.081819190842622 line1 = self.inputfile.readline() if seconds > 0: linePos = self.inputfile.tell() line1 = line1.split(',') while line1: self.inputfile.seek(linePos) line2 = self.inputfile.readline() linePos = self.inputfile.tell() moveTime = 1*seconds outline = 1*line1 inline = line2.split(',') while moveTime > 0: # for case of more than 1 second if line2: line2 = line2.split(',') p1 = QgsPoint(float(line1[len(numberOfLonColumn)-1]), float(line1[len(numberOfLatColumn)-1])) p2 = QgsPoint(float(line2[len(numberOfLonColumn)-1]), float(line2[len(numberOfLatColumn)-1])) if p1 != p2: aziA = d.bearing(p1, p2) l = d.computeDistanceBearing(p1, p2)[0] if moveTime > (float(line2[len(numberOfSecColumn)-1])-float(line1[len(numberOfSecColumn)-1])): moveTime = moveTime-(float(line2[len(numberOfSecColumn)-1])-float(line1[len(numberOfSecColumn)-1])) elif moveTime != 0 and moveTime != (float(line2[len(numberOfSecColumn)-1])-float(line1[len(numberOfSecColumn)-1])): # first geodetic problem distance = l/(float(line2[len(numberOfSecColumn)-1])-float(line1[len(numberOfSecColumn)-1]))*moveTime h = distance/2.0 fi = [float( line1[len(numberOfLatColumn)-1])*pi/180] lam = [float( line1[len(numberOfLonColumn)-1])*pi/180] azi = [aziA] FIe1, LAMe1 = self.iterations( distance, a, e2, h, azi, fi, lam) moveTime = 0 else: FIe1 = float( line2[len(numberOfLatColumn)-1])*pi/180 LAMe1 = float( line2[len(numberOfLonColumn)-1])*pi/180 moveTime = 0 break else: if moveTime > (float(line2[len(numberOfSecColumn)-1])-float(line1[len(numberOfSecColumn)-1])): moveTime = moveTime-(float(line2[len(numberOfSecColumn)-1])-float(line1[len(numberOfSecColumn)-1])) else: FIe1 = float( line2[len(numberOfLatColumn)-1])*pi/180 LAMe1 = float( line2[len(numberOfLonColumn)-1])*pi/180 moveTime = 0 break else: break line1 = 1*line2 line2 = self.inputfile.readline() line1 = 1*inline if moveTime == 0: # changing latitude and longitude of new point outline[len(numberOfLatColumn)-1] = str(FIe1*180/pi) outline[len(numberOfLonColumn)-1] = str(LAMe1*180/pi) outline = ','.join(outline) self.outputfile.write(outline) else: break elif seconds < 0: line = [] line.append(line1) line[0] = line[0].split(',') line.append(self.inputfile.readline()) line[1] = line[1].split(',') allSecs = (float(line[1][len(numberOfSecColumn)-1])-float(line[0][len(numberOfSecColumn)-1])) i = 1 moveTime = 1*seconds while fabs(moveTime) > allSecs: line.append(self.inputfile.readline().split(',')) i = i+1 if line[len(line)-1] == ['']: break allSecs = allSecs+(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])) while line[len(line)-1] != ['']: allSecs = 0 for i in reversed(range(1, len(line))): allSecs = allSecs+(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])) if fabs(moveTime) <= allSecs: for x in range(i-1): del line[0] break for i in reversed(range(len(line))): p1 = QgsPoint(float(line[i-1][len(numberOfLonColumn)-1]), float(line[i-1][len(numberOfLatColumn)-1])) p2 = QgsPoint(float(line[i][len(numberOfLonColumn)-1]), float(line[i][len(numberOfLatColumn)-1])) if p1 != p2: aziA = d.bearing(p2, p1) l = d.computeDistanceBearing(p1, p2)[0] if moveTime < -(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])): moveTime = moveTime+(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])) elif moveTime != 0 and moveTime != -(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])): # first geodetic problem distance = l/(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1]))*fabs(moveTime) h = distance/2.0 fi = [float( line[i][len(numberOfLatColumn)-1])*pi/180] lam = [float( line[i][len(numberOfLonColumn)-1])*pi/180] azi = [aziA] FIe1, LAMe1 = self.iterations( distance, a, e2, h, azi, fi, lam) break else: FIe1 = float( line[i-1][len(numberOfLatColumn)-1])*pi/180 LAMe1 = float( line[i-1][len(numberOfLonColumn)-1])*pi/180 break else: if moveTime < -(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])): moveTime = moveTime+(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])) else: FIe1 = float( line[i-1][len(numberOfLatColumn)-1])*pi/180 LAMe1 = float( line[i-1][len(numberOfLonColumn)-1])*pi/180 break outline = 1*line[len(line)-1] # changing latitude and longitude of new point outline[len(numberOfLatColumn)-1] = str(FIe1*180/pi) outline[len(numberOfLonColumn)-1] = str(LAMe1*180/pi) outline = ','.join(outline) self.outputfile.write(outline) line.append(self.inputfile.readline()) line[len(line)-1] = line[len(line)-1].split(',') moveTime = 1*seconds else: while line1: self.outputfile.write(line1) line1 = self.inputfile.readline() self._close()
def draw_scalebar(self, composer_map, top_offset): """Add a numeric scale to the bottom left of the map. We draw the scale bar manually because QGIS does not yet support rendering a scale bar for a geographic map in km. .. seealso:: :meth:`drawNativeScaleBar` :param composer_map: Composer map on which to draw the scalebar. :type composer_map: QgsComposerMap :param top_offset: Vertical offset at which the logo should be drawn. :type top_offset: int """ LOGGER.debug('InaSAFE Map drawScaleBar called') canvas = self.iface.mapCanvas() renderer = canvas.mapRenderer() # # Add a linear map scale # distance_area = QgsDistanceArea() distance_area.setSourceCrs(renderer.destinationCrs().srsid()) distance_area.setEllipsoidalMode(True) # Determine how wide our map is in km/m # Starting point at BL corner composer_extent = composer_map.extent() start_point = QgsPoint( composer_extent.xMinimum(), composer_extent.yMinimum()) # Ending point at BR corner end_point = QgsPoint( composer_extent.xMaximum(), composer_extent.yMinimum()) ground_distance = distance_area.measureLine(start_point, end_point) # Get the equivalent map distance per page mm map_width = self.mapWidth # How far is 1mm on map on the ground in meters? mm_to_ground = ground_distance / map_width #print 'MM:', myMMDistance # How long we want the scale bar to be in relation to the map scalebar_to_map_ratio = 0.5 # How many divisions the scale bar should have tick_count = 5 scale_bar_width_mm = map_width * scalebar_to_map_ratio print_segment_width_mm = scale_bar_width_mm / tick_count # Segment width in real world (m) # We apply some logic here so that segments are displayed in meters # if each segment is less that 1000m otherwise km. Also the segment # lengths are rounded down to human looking numbers e.g. 1km not 1.1km units = '' ground_segment_width = print_segment_width_mm * mm_to_ground if ground_segment_width < 1000: units = 'm' ground_segment_width = round(ground_segment_width) # adjust the segment width now to account for rounding print_segment_width_mm = ground_segment_width / mm_to_ground else: units = 'km' # Segment with in real world (km) ground_segment_width = round(ground_segment_width / 1000) print_segment_width_mm = ( (ground_segment_width * 1000) / mm_to_ground) # Now adjust the scalebar width to account for rounding scale_bar_width_mm = tick_count * print_segment_width_mm #print "SBWMM:", scale_bar_width_mm #print "SWMM:", print_segment_width_mm #print "SWM:", myGroundSegmentWidthM #print "SWKM:", myGroundSegmentWidthKM # start drawing in line segments scalebar_height = 5 # mm line_width = 0.3 # mm inset_distance = 7 # how much to inset the scalebar into the map by scalebar_x = self.page_margin + inset_distance scalebar_y = ( top_offset + self.map_height - inset_distance - scalebar_height) # mm # Draw an outer background box - shamelessly hardcoded buffer rectangle = QgsComposerShape( scalebar_x - 4, # left edge scalebar_y - 3, # top edge scale_bar_width_mm + 13, # right edge scalebar_height + 6, # bottom edge self.composition) rectangle.setShapeType(QgsComposerShape.Rectangle) pen = QtGui.QPen() pen.setColor(QtGui.QColor(255, 255, 255)) pen.setWidthF(line_width) rectangle.setPen(pen) #rectangle.setLineWidth(line_width) rectangle.setFrameEnabled(False) brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) # workaround for missing setTransparentFill missing from python api rectangle.setBrush(brush) self.composition.addItem(rectangle) # Set up the tick label font font_weight = QtGui.QFont.Normal font_size = 6 italics_flag = False font = QtGui.QFont( 'verdana', font_size, font_weight, italics_flag) # Draw the bottom line up_shift = 0.3 # shift the bottom line up for better rendering rectangle = QgsComposerShape( scalebar_x, scalebar_y + scalebar_height - up_shift, scale_bar_width_mm, 0.1, self.composition) rectangle.setShapeType(QgsComposerShape.Rectangle) pen = QtGui.QPen() pen.setColor(QtGui.QColor(255, 255, 255)) pen.setWidthF(line_width) rectangle.setPen(pen) #rectangle.setLineWidth(line_width) rectangle.setFrameEnabled(False) self.composition.addItem(rectangle) # Now draw the scalebar ticks for tick_counter in range(0, tick_count + 1): distance_suffix = '' if tick_counter == tick_count: distance_suffix = ' ' + units real_world_distance = ( '%.0f%s' % (tick_counter * ground_segment_width, distance_suffix)) #print 'RW:', myRealWorldDistance mm_offset = scalebar_x + ( tick_counter * print_segment_width_mm) #print 'MM:', mm_offset tick_height = scalebar_height / 2 # Lines are not exposed by the api yet so we # bodge drawing lines using rectangles with 1px height or width tick_width = 0.1 # width or rectangle to be drawn uptick_line = QgsComposerShape( mm_offset, scalebar_y + scalebar_height - tick_height, tick_width, tick_height, self.composition) uptick_line.setShapeType(QgsComposerShape.Rectangle) pen = QtGui.QPen() pen.setWidthF(line_width) uptick_line.setPen(pen) #uptick_line.setLineWidth(line_width) uptick_line.setFrameEnabled(False) self.composition.addItem(uptick_line) # # Add a tick label # label = QgsComposerLabel(self.composition) label.setFont(font) label.setText(real_world_distance) label.adjustSizeToText() label.setItemPosition( mm_offset - 3, scalebar_y - tick_height) label.setFrameEnabled(self.show_frames) self.composition.addItem(label)
def processAlgorithm(self, progress): layerPoints = dataobjects.getObjectFromUri( self.getParameterValue(self.POINTS)) layerHubs = dataobjects.getObjectFromUri( self.getParameterValue(self.HUBS)) fieldName = self.getParameterValue(self.FIELD) addLines = self.getParameterValue(self.GEOMETRY) units = self.UNITS[self.getParameterValue(self.UNIT)] if layerPoints.source() == layerHubs.source(): raise GeoAlgorithmExecutionException( self.tr('Same layer given for both hubs and spokes')) fields = layerPoints.fields() fields.append(QgsField('HubName', QVariant.String)) fields.append(QgsField('HubDist', QVariant.Double)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, QgsWkbTypes.LineString, layerPoints.crs()) index = vector.spatialindex(layerHubs) distance = QgsDistanceArea() distance.setSourceCrs(layerPoints.crs().srsid()) distance.setEllipsoidalMode(True) # Scan source points, find nearest hub, and write to output file features = vector.features(layerPoints) total = 100.0 / len(features) for current, f in enumerate(features): src = f.geometry().boundingBox().center() neighbors = index.nearestNeighbor(src, 1) ft = layerHubs.getFeatures(QgsFeatureRequest().setFilterFid( neighbors[0])).next() closest = ft.geometry().boundingBox().center() hubDist = distance.measureLine(src, closest) attributes = f.attributes() attributes.append(ft[fieldName]) if units == 'Feet': attributes.append(hubDist * 3.2808399) elif units == 'Miles': attributes.append(hubDist * 0.000621371192) elif units == 'Kilometers': attributes.append(hubDist / 1000.0) elif units != 'Meters': attributes.append( sqrt( pow(src.x() - closest.x(), 2.0) + pow(src.y() - closest.y(), 2.0))) else: attributes.append(hubDist) feat = QgsFeature() feat.setAttributes(attributes) feat.setGeometry(QgsGeometry.fromPolyline([src, closest])) writer.addFeature(feat) progress.setPercentage(int(current * total)) del writer
def processAlgorithm(self, progress): layer = self.getParameterValue(self.INPUT_LAYER) mapping = self.getParameterValue(self.FIELDS_MAPPING) output = self.getOutputFromName(self.OUTPUT_LAYER) layer = dataobjects.getObjectFromUri(layer) fields = [] expressions = [] da = QgsDistanceArea() da.setSourceCrs(layer.crs().srsid()) da.setEllipsoidalMode( iface.mapCanvas().mapSettings().hasCrsTransformEnabled()) da.setEllipsoid(QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE)[0]) exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope(QgsExpressionContextUtils.projectScope()) exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer)) for field_def in mapping: fields.append( QgsField(name=field_def['name'], type=field_def['type'], len=field_def['length'], prec=field_def['precision'])) expression = QgsExpression(field_def['expression']) expression.setGeomCalculator(da) expression.setDistanceUnits(QgsProject.instance().distanceUnits()) expression.setAreaUnits(QgsProject.instance().areaUnits()) if expression.hasParserError(): raise GeoAlgorithmExecutionException( self.tr(u'Parser error in expression "{}": {}').format( str(field_def['expression']), str(expression.parserErrorString()))) expression.prepare(exp_context) if expression.hasEvalError(): raise GeoAlgorithmExecutionException( self.tr(u'Evaluation error in expression "{}": {}').format( str(field_def['expression']), str(expression.evalErrorString()))) expressions.append(expression) writer = output.getVectorWriter(fields, layer.wkbType(), layer.crs()) # Create output vector layer with new attributes error = '' calculationSuccess = True inFeat = QgsFeature() outFeat = QgsFeature() features = vector.features(layer) total = 100.0 / len(features) for current, inFeat in enumerate(features): rownum = current + 1 geometry = inFeat.geometry() outFeat.setGeometry(geometry) attrs = [] for i in range(0, len(mapping)): field_def = mapping[i] expression = expressions[i] exp_context.setFeature(inFeat) exp_context.lastScope().setVariable("row_number", rownum) value = expression.evaluate(exp_context) if expression.hasEvalError(): calculationSuccess = False error = expression.evalErrorString() break attrs.append(value) outFeat.setAttributes(attrs) writer.addFeature(outFeat) progress.setPercentage(int(current * total)) del writer if not calculationSuccess: raise GeoAlgorithmExecutionException( self.tr('An error occurred while evaluating the calculation' ' string:\n') + error)
def testAreaMeasureAndUnits(self): """Test a variety of area measurements in different CRS and ellipsoid modes, to check that the calculated areas and units are always consistent """ da = QgsDistanceArea() da.setSourceCrs(3452) da.setEllipsoidalMode(False) da.setEllipsoid("NONE") daCRS = QgsCoordinateReferenceSystem() daCRS = da.sourceCrs() polygon = QgsGeometry.fromPolygon( [[ QgsPoint(0, 0), QgsPoint(1, 0), QgsPoint(1, 1), QgsPoint(2, 1), QgsPoint(2, 2), QgsPoint(0, 2), QgsPoint(0, 0), ]] ) # We check both the measured area AND the units, in case the logic regarding # ellipsoids and units changes in future area = da.measureArea(polygon) units = da.areaUnits() print(("measured {} in {}".format(area, QgsUnitTypes.toString(units)))) assert ((abs(area - 3.0) < 0.00000001 and units == QgsUnitTypes.AreaSquareDegrees) or (abs(area - 37176087091.5) < 0.1 and units == QgsUnitTypes.AreaSquareMeters)) da.setEllipsoid("WGS84") area = da.measureArea(polygon) units = da.areaUnits() print(("measured {} in {}".format(area, QgsUnitTypes.toString(units)))) assert ((abs(area - 3.0) < 0.00000001 and units == QgsUnitTypes.AreaSquareDegrees) or (abs(area - 37176087091.5) < 0.1 and units == QgsUnitTypes.AreaSquareMeters)) da.setEllipsoidalMode(True) area = da.measureArea(polygon) units = da.areaUnits() print(("measured {} in {}".format(area, QgsUnitTypes.toString(units)))) # should always be in Meters Squared self.assertAlmostEqual(area, 37416879192.9, delta=0.1) self.assertEqual(units, QgsUnitTypes.AreaSquareMeters) # test converting the resultant area area = da.convertAreaMeasurement(area, QgsUnitTypes.AreaSquareMiles) self.assertAlmostEqual(area, 14446.7378, delta=0.001) # now try with a source CRS which is in feet polygon = QgsGeometry.fromPolygon( [[ QgsPoint(1850000, 4423000), QgsPoint(1851000, 4423000), QgsPoint(1851000, 4424000), QgsPoint(1852000, 4424000), QgsPoint(1852000, 4425000), QgsPoint(1851000, 4425000), QgsPoint(1850000, 4423000) ]] ) da.setSourceCrs(27469) da.setEllipsoidalMode(False) # measurement should be in square feet area = da.measureArea(polygon) units = da.areaUnits() print(("measured {} in {}".format(area, QgsUnitTypes.toString(units)))) self.assertAlmostEqual(area, 2000000, delta=0.001) self.assertEqual(units, QgsUnitTypes.AreaSquareFeet) # test converting the resultant area area = da.convertAreaMeasurement(area, QgsUnitTypes.AreaSquareYards) self.assertAlmostEqual(area, 222222.2222, delta=0.001) da.setEllipsoidalMode(True) # now should be in Square Meters again area = da.measureArea(polygon) units = da.areaUnits() print(("measured {} in {}".format(area, QgsUnitTypes.toString(units)))) self.assertAlmostEqual(area, 184149.37, delta=1.0) self.assertEqual(units, QgsUnitTypes.AreaSquareMeters) # test converting the resultant area area = da.convertAreaMeasurement(area, QgsUnitTypes.AreaSquareYards) self.assertAlmostEqual(area, 220240.8172549, delta=1.0)
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT_LAYER)) fieldName = self.getParameterValue(self.FIELD_NAME) fieldType = self.TYPES[self.getParameterValue(self.FIELD_TYPE)] width = self.getParameterValue(self.FIELD_LENGTH) precision = self.getParameterValue(self.FIELD_PRECISION) newField = self.getParameterValue(self.NEW_FIELD) formula = self.getParameterValue(self.FORMULA) output = self.getOutputFromName(self.OUTPUT_LAYER) fields = layer.fields() if newField: fields.append(QgsField(fieldName, fieldType, '', width, precision)) writer = output.getVectorWriter(fields, layer.wkbType(), layer.crs()) exp = QgsExpression(formula) da = QgsDistanceArea() da.setSourceCrs(layer.crs().srsid()) da.setEllipsoidalMode( iface.mapCanvas().mapSettings().hasCrsTransformEnabled()) da.setEllipsoid(QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE)[0]) exp.setGeomCalculator(da) exp.setDistanceUnits(QgsProject.instance().distanceUnits()) exp.setAreaUnits(QgsProject.instance().areaUnits()) exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope(QgsExpressionContextUtils.projectScope()) exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer)) if not exp.prepare(exp_context): raise GeoAlgorithmExecutionException( self.tr('Evaluation error: %s' % exp.evalErrorString())) outFeature = QgsFeature() outFeature.initAttributes(len(fields)) outFeature.setFields(fields) error = '' calculationSuccess = True features = vector.features(layer) total = 100.0 / len(features) rownum = 1 for current, f in enumerate(features): rownum = current + 1 exp_context.setFeature(f) exp_context.lastScope().setVariable("row_number", rownum) value = exp.evaluate(exp_context) if exp.hasEvalError(): calculationSuccess = False error = exp.evalErrorString() break else: outFeature.setGeometry(f.geometry()) for fld in f.fields(): outFeature[fld.name()] = f[fld.name()] outFeature[fieldName] = value writer.addFeature(outFeature) progress.setPercentage(int(current * total)) del writer if not calculationSuccess: raise GeoAlgorithmExecutionException( self.tr('An error occurred while evaluating the calculation ' 'string:\n%s' % error))
def processAlgorithm(self, progress): layerPoints = dataobjects.getObjectFromUri(self.getParameterValue(self.POINTS)) layerHubs = dataobjects.getObjectFromUri(self.getParameterValue(self.HUBS)) fieldName = self.getParameterValue(self.FIELD) addLines = self.getParameterValue(self.GEOMETRY) units = self.UNITS[self.getParameterValue(self.UNIT)] if layerPoints.source() == layerHubs.source(): raise GeoAlgorithmExecutionException(self.tr("Same layer given for both hubs and spokes")) geomType = QGis.WKBPoint if addLines: geomType = QGis.WKBLineString fields = layerPoints.pendingFields() fields.append(QgsField("HubName", QVariant.String)) fields.append(QgsField("HubDist", QVariant.Double)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, geomType, layerPoints.crs()) # Create array of hubs in memory hubs = [] features = vector.features(layerHubs) for f in features: hubs.append(Hub(f.geometry().boundingBox().center(), unicode(f[fieldName]))) distance = QgsDistanceArea() distance.setSourceCrs(layerPoints.crs().srsid()) distance.setEllipsoidalMode(True) # Scan source points, find nearest hub, and write to output file features = vector.features(layerPoints) count = len(features) total = 100.0 / float(count) for count, f in enumerate(features): src = f.geometry().boundingBox().center() closest = hubs[0] hubDist = distance.measureLine(src, closest.point) for hub in hubs: dist = distance.measureLine(src, hub.point) if dist < hubDist: closest = hub hubDist = dist attributes = f.attributes() attributes.append(closest.name) if units == "Feet": attributes.append(hubDist * 3.2808399) elif units == "Miles": attributes.append(hubDist * 0.000621371192) elif units == "Kilometers": attributes.append(hubDist / 1000.0) elif units != "Meters": attributes.append(sqrt(pow(src.x() - closest.point.x(), 2.0) + pow(src.y() - closest.point.y(), 2.0))) else: attributes.append(hubDist) feat = QgsFeature() feat.setAttributes(attributes) if geomType == QGis.WKBPoint: feat.setGeometry(QgsGeometry.fromPoint(src)) else: feat.setGeometry(QgsGeometry.fromPolyline([src, closest.point])) writer.addFeature(feat) progress.setPercentage(int(count * total)) del writer
def processAlgorithm(self, feedback): layer = self.getParameterValue(self.INPUT_LAYER) mapping = self.getParameterValue(self.FIELDS_MAPPING) output = self.getOutputFromName(self.OUTPUT_LAYER) layer = dataobjects.getObjectFromUri(layer) fields = [] expressions = [] da = QgsDistanceArea() da.setSourceCrs(layer.crs()) da.setEllipsoidalMode(True) da.setEllipsoid(QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE)[0]) exp_context = layer.createExpressionContext() for field_def in mapping: fields.append(QgsField(name=field_def['name'], type=field_def['type'], len=field_def['length'], prec=field_def['precision'])) expression = QgsExpression(field_def['expression']) expression.setGeomCalculator(da) expression.setDistanceUnits(QgsProject.instance().distanceUnits()) expression.setAreaUnits(QgsProject.instance().areaUnits()) expression.prepare(exp_context) if expression.hasParserError(): raise GeoAlgorithmExecutionException( self.tr(u'Parser error in expression "{}": {}') .format(str(expression.expression()), str(expression.parserErrorString()))) expressions.append(expression) writer = output.getVectorWriter(fields, layer.wkbType(), layer.crs()) # Create output vector layer with new attributes error_exp = None inFeat = QgsFeature() outFeat = QgsFeature() features = vector.features(layer) total = 100.0 / len(features) for current, inFeat in enumerate(features): rownum = current + 1 geometry = inFeat.geometry() outFeat.setGeometry(geometry) attrs = [] for i in range(0, len(mapping)): field_def = mapping[i] expression = expressions[i] exp_context.setFeature(inFeat) exp_context.lastScope().setVariable("row_number", rownum) value = expression.evaluate(exp_context) if expression.hasEvalError(): error_exp = expression break attrs.append(value) outFeat.setAttributes(attrs) writer.addFeature(outFeat) feedback.setProgress(int(current * total)) del writer if error_exp is not None: raise GeoAlgorithmExecutionException( self.tr(u'Evaluation error in expression "{}": {}') .format(str(error_exp.expression()), str(error_exp.parserErrorString())))
def expressionBasedUpdate( self, layer, dictProperties, featureId, index=None, value=None ): """ Defines the logic of the expression-based update to be applied. This SLOT listens to featureAdded, geometryChanged, and attributeValueChanged SIGNALS. """ # Check if AutoField is there, otherwise return fieldIndex = layer.fieldNameIndex( dictProperties['field'] ) if fieldIndex == -1: self.msg.show( QApplication.translate( "EventManager", "[Error] Updating AutoField " ) + \ dictProperties['field'] + \ QApplication.translate( "EventManager", " in layer " ) + \ layer.name() + QApplication.translate( "EventManager", " was NOT possible." ) + \ QApplication.translate( "EventManager", " Perhaps you just removed it but haven't saved the changes yet?" ), 'warning' ) return event = "" result = None expression = QgsExpression( dictProperties['expression'] ) if expression.hasParserError(): self.msg.show( QApplication.translate( "EventManager", "[Error] (Parsing) " ) + \ expression.parserErrorString(), 'critical' ) result = NULL # Avoid infinite recursion (changing the same attribute value infinitely). if not index is None: # Filters out the featureAdded SIGNAL if type( index ) == int: # Filters out the geometryChanged SIGNAL if index == fieldIndex: # This call comes from the same AutoField, so return return if self.afm.isFieldAnAutoField( layer, layer.fields()[index].name() ): # Call from AutoField, don't listen # This is to prevent corrupting the layerEditBuffer and being bitten by: # Fatal: ASSERT: "mChangedAttributeValues.isEmpty()" in file /tmp/buildd/qgis-2.14.2+20trusty/src/core/qgsvectorlayereditbuffer.cpp, line 585 return #if type(value)==QPyNullVariant: # Vector layers with numeric field whose value for 1st feature is NULL # trigger an attributeValueChanged SIGNAL when start editing from the # attribute table window. We use this conditional to avoid such SIGNAL. # The ideal case is that such NULL valued SIGNAL shouldn't be emitted by QGIS. # return # While the previous block reduces the number of times attributeValueChanged # is called from the attribute table, it leads to a QGIS bug: # Fatal: ASSERT: "mChangedAttributeValues.isEmpty()" in file /tmp/buildd/qgis-2.14.2+20trusty/src/core/qgsvectorlayereditbuffer.cpp, line 585 # I prefer the attributeValueChanged to be called multiple # times (inefficient) than to open the possibility to a bug. # As soon as QGIS bug #15272 is solved, the number of calls will be reduced! event = "attributeValueChanged" else: event = "geometryChanged" else: event = "featureAdded" feature = layer.getFeatures( QgsFeatureRequest( featureId ) ).next() if result is None: context = QgsExpressionContext() context.appendScope( QgsExpressionContextUtils.globalScope() ) context.appendScope( QgsExpressionContextUtils.projectScope() ) context.appendScope( QgsExpressionContextUtils.layerScope( layer ) ) context.setFields( feature.fields() ) context.setFeature( feature ) if expression.needsGeometry(): if self.iface: # This block was borrowed from QGIS/python/plugins/processing/algs/qgis/FieldsCalculator.py da = QgsDistanceArea() da.setSourceCrs( layer.crs().srsid() ) da.setEllipsoidalMode( self.iface.mapCanvas().mapSettings().hasCrsTransformEnabled() ) da.setEllipsoid( QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE )[0] ) expression.setGeomCalculator( da ) if QGis.QGIS_VERSION_INT >= 21400: # Methods added in QGIS 2.14 expression.setDistanceUnits( QgsProject.instance().distanceUnits() ) expression.setAreaUnits( QgsProject.instance().areaUnits() ) expression.prepare( context ) result = expression.evaluate( context ) if expression.hasEvalError(): self.msg.show( QApplication.translate( "EventManager", "[Error] (Evaluating) " ) + \ expression.evalErrorString(), 'critical' ) result = NULL field = layer.fields()[fieldIndex] res = field.convertCompatible( result ) # If result is None, res will be None, but even in that case, QGIS knows # what to do with it while saving, it seems it's treated as NULL. # TODO when bug #15311 is fixed, this block should work better #if dictProperties['expression'] in self.listProviderExpressions: # # Save directly to provider # layer.dataProvider().changeAttributeValues( { featureId : { fieldIndex : res } } ) #else: # Save to layer # layer.changeAttributeValue( featureId, fieldIndex, res ) # Workaround if event == 'featureAdded': # Save directly to the provider layer.dataProvider().changeAttributeValues( { featureId : { fieldIndex : res } } ) else: # Save to layer layer.changeAttributeValue( featureId, fieldIndex, res ) self.msg.show( "[Info] * AutoField's value updated to " + unicode(res) + \ ", (" + layer.name() + "." + dictProperties['field'] + ") by " + event +".", 'info', True )
def by_seconds(self, seconds): """move by variable distance""" def iterations(distance,h): FIe1=0 LAMe1=0 FI=100 LAM=100 # iterations while fabs(FI-FIe1)>0.0000000001 and fabs(LAM -LAMe1)>0.0000000001: FI=FIe1 LAM=LAMe1 for i in range(0,int(ceil(distance/h))): kfi=[] klam=[] kazi=[] kfi.append(cos(azi[i])/(a*(1-(e2))/(pow((sqrt(1-(e2)*pow(sin(fi[i]),2))),3)))) klam.append(sin(azi[i])/((a/(sqrt(1-(e2)*pow(sin(fi[i]),2))))*cos(fi[i]))) kazi.append(sin(azi[i])*tan(fi[i])/(a/(sqrt(1-(e2)*pow(sin(fi[i]),2))))) for j in range(1,3): kfi.append(cos(azi[i]+kazi[j-1]*h/2)/(a*(1-(e2))/(pow(sqrt(1-(e2)*pow(sin(fi[i]+kfi[j-1]*h/2),2)),3)))) klam.append(sin(azi[i]+kazi[j-1]*h/2)/((a/(sqrt(1-(e2)*pow(sin(fi[i]+kfi[j-1]*h/2),2))))*cos(fi[i]+kfi[j-1]*h/2))) kazi.append(sin(azi[i]+kazi[j-1]*h/2)*tan(fi[i]+kfi[j-1]*h/2)/(a/(sqrt(1-(e2)*pow(sin(fi[i]+kfi[j-1]*h/2),2))))) kfi.append(cos(azi[i]+kazi[2]*h)/(a*(1-(e2))/(pow(sqrt(1-(e2)*pow(sin(fi[i]+kfi[2]*h),2)),3)))) klam.append(sin(azi[i]+kazi[2]*h)/((a/(sqrt(1-(e2)*pow(sin(fi[i]+kfi[2]*h),2))))*cos(fi[i]+kfi[2]*h))) kazi.append(sin(azi[i]+kazi[2]*h)*tan(fi[i]+kfi[2]*h)/(a/(sqrt(1-(e2)*pow(sin(fi[i]+kfi[2]*h),2))))) fi.append(fi[i]+(h/6.0)*(kfi[0]+2*kfi[1]+2*kfi[2]+kfi[3])) lam.append(lam[i]+(h/6.0)*(klam[0]+2*klam[1]+2*klam[2]+klam[3])) azi.append(azi[i]+(h/6.0)*(kazi[0]+2*kazi[1]+2*kazi[2]+kazi[3])) FIe1=fi[i+1] LAMe1=lam[i+1] h=h/2 fi[1:]=[] lam[1:]=[] azi[1:]=[] return FIe1,LAMe1 self._check() header=self.inputfile.readline() beforeLat=header.split('Lat_deg') numberOfLatColumn=beforeLat[0].split(',') beforeLong=header.split('Lon_deg') numberOfLonColumn=beforeLong[0].split(',') beforeSec=header.split('Gtm_sec') numberOfSecColumn=beforeSec[0].split(',') self.outputfile.write(header) d = QgsDistanceArea() d.setEllipsoid('WGS84') d.setEllipsoidalMode(True) d.ellipsoid() a = 6378137.0 # WGS84 ellipsoid parametres e2 = 0.081819190842622 line1=self.inputfile.readline() if seconds>0: linePos=self.inputfile.tell() line1=line1.split(',') while line1: self.inputfile.seek(linePos) line2=self.inputfile.readline() linePos=self.inputfile.tell() moveTime=1*seconds outline=1*line1 inline=line2.split(',') while moveTime>0: # for case of more than 1 second if line2: line2=line2.split(',') p1=QgsPoint(float(line1[len(numberOfLonColumn)-1]),float(line1[len(numberOfLatColumn)-1])) p2=QgsPoint(float(line2[len(numberOfLonColumn)-1]),float(line2[len(numberOfLatColumn)-1])) if p1!=p2: aziA = d.bearing(p1,p2) l = d.computeDistanceBearing(p1,p2)[0] if moveTime>(float(line2[len(numberOfSecColumn)-1])-float(line1[len(numberOfSecColumn)-1])): moveTime=moveTime-(float(line2[len(numberOfSecColumn)-1])-float(line1[len(numberOfSecColumn)-1])) elif moveTime!=0 and moveTime!=(float(line2[len(numberOfSecColumn)-1])-float(line1[len(numberOfSecColumn)-1])): #first geodetic problem distance=l/(float(line2[len(numberOfSecColumn)-1])-float(line1[len(numberOfSecColumn)-1]))*moveTime h=distance/2.0 fi=[float(line1[len(numberOfLatColumn)-1])*pi/180] lam=[float(line1[len(numberOfLonColumn)-1])*pi/180] azi=[aziA] FIe1,LAMe1 = iterations(distance,h) moveTime=0 else: FIe1=float(line2[len(numberOfLatColumn)-1])*pi/180 LAMe1=float(line2[len(numberOfLonColumn)-1])*pi/180 moveTime=0 break else: if moveTime>(float(line2[len(numberOfSecColumn)-1])-float(line1[len(numberOfSecColumn)-1])): moveTime=moveTime-(float(line2[len(numberOfSecColumn)-1])-float(line1[len(numberOfSecColumn)-1])) else: FIe1=float(line2[len(numberOfLatColumn)-1])*pi/180 LAMe1=float(line2[len(numberOfLonColumn)-1])*pi/180 moveTime=0 break else:break line1=1*line2 line2=self.inputfile.readline() line1=1*inline if moveTime==0: outline[len(numberOfLatColumn)-1]=str(FIe1*180/pi) # changing latitude and longitude of new point outline[len(numberOfLonColumn)-1]=str(LAMe1*180/pi) outline=','.join(outline) self.outputfile.write(outline) else:break elif seconds<0: line=[] line.append(line1) line[0]=line[0].split(',') line.append(self.inputfile.readline()) line[1]=line[1].split(',') allSecs=(float(line[1][len(numberOfSecColumn)-1])-float(line[0][len(numberOfSecColumn)-1])) i=1 moveTime=1*seconds while fabs(moveTime)>allSecs: line.append(self.inputfile.readline().split(',')) i=i+1 if line[len(line)-1]==['']: break allSecs=allSecs+(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])) while line[len(line)-1]!=['']: allSecs=0 for i in reversed(range(1,len(line))): allSecs=allSecs+(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])) if fabs(moveTime)<=allSecs: for x in range(i-1): del line[0] break for i in reversed(range(len(line))): p1=QgsPoint(float(line[i-1][len(numberOfLonColumn)-1]),float(line[i-1][len(numberOfLatColumn)-1])) p2=QgsPoint(float(line[i][len(numberOfLonColumn)-1]),float(line[i][len(numberOfLatColumn)-1])) if p1!=p2: aziA = d.bearing(p2,p1) l = d.computeDistanceBearing(p1,p2)[0] if moveTime<-(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])): moveTime=moveTime+(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])) elif moveTime!=0 and moveTime!=-(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])): #first geodetic problem distance=l/(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1]))*fabs(moveTime) h=distance/2.0 fi=[float(line[i][len(numberOfLatColumn)-1])*pi/180] lam=[float(line[i][len(numberOfLonColumn)-1])*pi/180] azi=[aziA] FIe1,LAMe1 = iterations(distance,h) break else: FIe1=float(line[i-1][len(numberOfLatColumn)-1])*pi/180 LAMe1=float(line[i-1][len(numberOfLonColumn)-1])*pi/180 break else: if moveTime<-(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])): moveTime=moveTime+(float(line[i][len(numberOfSecColumn)-1])-float(line[i-1][len(numberOfSecColumn)-1])) else: FIe1=float(line[i-1][len(numberOfLatColumn)-1])*pi/180 LAMe1=float(line[i-1][len(numberOfLonColumn)-1])*pi/180 break outline=1*line[len(line)-1] outline[len(numberOfLatColumn)-1]=str(FIe1*180/pi) # changing latitude and longitude of new point outline[len(numberOfLonColumn)-1]=str(LAMe1*180/pi) outline=','.join(outline) self.outputfile.write(outline) line.append(self.inputfile.readline()) line[len(line)-1]=line[len(line)-1].split(',') moveTime=1*seconds else: while line1: self.outputfile.write(line1) line1=self.inputfile.readline() self._close()
class PositionMarker(QgsMapCanvasItem): ''' classdocs ''' def __init__(self, canvas, params={}): ''' Constructor :param iface: An interface instance that will be passed to this class which provides the hook by which you can manipulate the QGIS application at run time. :type iface: QgsInterface :param params: A dictionary defining all the properties of the position marker :type params: dictionary ''' self.canvas = canvas self.type = params.get('type', 'BOX').upper() self.size = int(params.get('size', 16)) self.bounding = 1.414213562 * self.size self.length = float(params.get('length', 98.0)) self.width = float(params.get('width', 17.0)) self.shape = params.get('shape', ((0.0, -0.5), (0.5, -0.3), (0.5, 0.5), (-0.5, 0.50), (-0.5, -0.3))) s = (self.size - 1) / 2 self.paintShape = QPolygonF([QPointF(-s, -s), QPointF(s, -s), QPointF(s, s), QPointF(-s, s)]) self.color = self.getColor(params.get('color', 'black')) self.fillColor = self.getColor(params.get('fillColor', 'lime')) self.penWidth = int(params.get('penWidth', 1)) if self.type in ('CROSS', 'X'): self.penWidth = 5 self.trackLen = int(params.get('trackLength', 100)) self.trackColor = self.getColor(params.get('trackColor', self.fillColor)) self.track = deque() self.pos = None self.heading = 0 super(PositionMarker, self).__init__(canvas) self.setZValue(int(params.get('zValue', 100))) self.distArea = QgsDistanceArea() self.distArea.setEllipsoid(u'WGS84') self.distArea.setEllipsoidalMode(True) self.updateSize() def properties(self): return {'type': self.type, 'size': self.size, 'length': self.length, 'width': self.width, 'shape': self.shape, 'color': self.color.rgba(), 'fillColor': self.fillColor.rgba(), 'penWidth': self.penWidth, 'trackLength': self.trackLen, 'trackColor' : self.trackColor.rgba(), 'zValue': self.zValue()} def setMapPosition(self, pos): if self.pos != pos: self.updateTrack() self.pos = pos self.setPos(self.toCanvasCoordinates(self.pos)) self.update() def newHeading(self, heading): if self.heading != heading: self.heading = heading self.setRotation(self.canvas.rotation() + self.heading) self.update() def resetPosition(self): self.pos = None def updatePosition(self): if self.pos: self.prepareGeometryChange() self.updateSize() self.setPos(self.toCanvasCoordinates(self.pos)) self.setRotation(self.canvas.rotation() + self.heading) self.update() def updateSize(self): if self.type != 'SHAPE': return s = self.canvas.mapSettings() self.distArea.setSourceCrs(s.destinationCrs()) try: p1 = self.toMapCoordinates(QPoint(0, 0)) p2 = self.toMapCoordinates(QPoint(0, 100)) l = self.distArea.measureLine(p1, p2) f = 100 / l except: f = s.outputDpi() / 0.0254 / s.scale() paintLength = max(self.length * f, 50) paintWidth = paintLength * self.width / self.length self.paintShape.clear() for v in self.shape: self.paintShape << QPointF(v[0] * paintWidth, v[1] * paintLength) self.size = max(paintLength, paintWidth) self.bounding = sqrt(pow(paintLength, 2) + pow(paintLength, 2)) def updateTrack(self): if self.pos and self.trackLen: if len(self.track) >= self.trackLen: tpr = self.track.popleft() self.canvas.scene().removeItem(tpr) del(tpr) tp = QgsVertexMarker(self.canvas) tp.setCenter(self.pos) tp.setIconType(QgsVertexMarker.ICON_CROSS) tp.setColor(self.trackColor) tp.setZValue(self.zValue() - 0.1) tp.setIconSize(3) tp.setPenWidth(3) self.track.append(tp) def setVisible(self, visible): for tp in self.track: tp.setVisible(visible) QgsMapCanvasItem.setVisible(self, visible) def deleteTrack(self): for tp in self.track: self.canvas.scene().removeItem(tp) self.track.clear() def paint(self, painter, xxx, xxx2): if not self.pos: return s = (self.size - 1) / 2 pen = QPen(self.color) pen.setWidth(self.penWidth) painter.setPen(pen) if self.type == 'CROSS': painter.drawLine(QLineF(-s, 0, s, 0)) painter.drawLine(QLineF(0, -s, 0, s)) elif self.type == 'X': painter.drawLine(QLineF(-s, -s, s, s)) painter.drawLine(QLineF(-s, s, s, -s)) elif self.type == 'BOX': brush = QBrush(self.fillColor) painter.setBrush(brush) painter.drawConvexPolygon(self.paintShape) elif self.type == 'SHAPE': painter.setRenderHint(QPainter.Antialiasing, True) brush = QBrush(self.fillColor) painter.setBrush(brush) painter.drawConvexPolygon(self.paintShape) def boundingRect(self): s = self.bounding / 2 return QRectF(QPointF(-s, -s), QPointF(s, s)) def getColor(self, value): try: return QColor.fromRgba(int(value)) except ValueError: return QColor(value) def removeFromCanvas(self): self.deleteTrack() self.canvas.scene().removeItem(self)
def processAlgorithm(self, progress): layer = self.getParameterValue(self.INPUT_LAYER) mapping = self.getParameterValue(self.FIELDS_MAPPING) output = self.getOutputFromName(self.OUTPUT_LAYER) layer = dataobjects.getObjectFromUri(layer) fields = [] expressions = [] da = QgsDistanceArea() da.setSourceCrs(layer.crs().srsid()) da.setEllipsoidalMode( iface.mapCanvas().mapSettings().hasCrsTransformEnabled()) da.setEllipsoid(QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE)[0]) exp_context = layer.createExpressionContext() for field_def in mapping: fields.append(QgsField(name=field_def['name'], type=field_def['type'], len=field_def['length'], prec=field_def['precision'])) expression = QgsExpression(field_def['expression']) expression.setGeomCalculator(da) expression.setDistanceUnits(QgsProject.instance().distanceUnits()) expression.setAreaUnits(QgsProject.instance().areaUnits()) expression.prepare(exp_context) if expression.hasParserError(): raise GeoAlgorithmExecutionException( self.tr(u'Parser error in expression "{}": {}') .format(unicode(expression.expression()), unicode(expression.parserErrorString()))) expressions.append(expression) writer = output.getVectorWriter(fields, layer.wkbType(), layer.crs()) # Create output vector layer with new attributes error_exp = None inFeat = QgsFeature() outFeat = QgsFeature() features = vector.features(layer) total = 100.0 / len(features) for current, inFeat in enumerate(features): rownum = current + 1 geometry = inFeat.geometry() outFeat.setGeometry(geometry) attrs = [] for i in range(0, len(mapping)): field_def = mapping[i] expression = expressions[i] exp_context.setFeature(inFeat) exp_context.lastScope().setVariable("row_number", rownum) value = expression.evaluate(exp_context) if expression.hasEvalError(): error_exp = expression break attrs.append(value) outFeat.setAttributes(attrs) writer.addFeature(outFeat) progress.setPercentage(int(current * total)) del writer if error_exp is not None: raise GeoAlgorithmExecutionException( self.tr(u'Evaluation error in expression "{}": {}') .format(unicode(error_exp.expression()), unicode(error_exp.parserErrorString())))
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT_LAYER)) fieldName = self.getParameterValue(self.FIELD_NAME) fieldType = self.TYPES[self.getParameterValue(self.FIELD_TYPE)] width = self.getParameterValue(self.FIELD_LENGTH) precision = self.getParameterValue(self.FIELD_PRECISION) newField = self.getParameterValue(self.NEW_FIELD) formula = self.getParameterValue(self.FORMULA) output = self.getOutputFromName(self.OUTPUT_LAYER) if output.value == '': ext = output.getDefaultFileExtension(self) output.value = system.getTempFilenameInTempFolder(output.name + '.' + ext) fields = layer.fields() if newField: fields.append(QgsField(fieldName, fieldType, '', width, precision)) writer = output.getVectorWriter(fields, layer.wkbType(), layer.crs()) exp = QgsExpression(formula) da = QgsDistanceArea() da.setSourceCrs(layer.crs().srsid()) da.setEllipsoidalMode( iface.mapCanvas().mapSettings().hasCrsTransformEnabled()) da.setEllipsoid(QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE)[0]) exp.setGeomCalculator(da) exp.setDistanceUnits(QgsProject.instance().distanceUnits()) exp.setAreaUnits(QgsProject.instance().areaUnits()) exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope(QgsExpressionContextUtils.projectScope()) exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer)) if not exp.prepare(exp_context): raise GeoAlgorithmExecutionException( self.tr('Evaluation error: %s' % exp.evalErrorString())) # add layer to registry to fix https://issues.qgis.org/issues/17300 # it is necessary only for aggregate expressions that verify that layer # is registered removeRegistryAfterEvaluation = False if not QgsMapLayerRegistry.instance().mapLayer(layer.id()): removeRegistryAfterEvaluation = True QgsMapLayerRegistry.instance().addMapLayer(layer, addToLegend=False) outFeature = QgsFeature() outFeature.initAttributes(len(fields)) outFeature.setFields(fields) error = '' calculationSuccess = True features = vector.features(layer) total = 100.0 / len(features) if len(features) > 0 else 1 rownum = 1 for current, f in enumerate(features): rownum = current + 1 exp_context.setFeature(f) exp_context.lastScope().setVariable("row_number", rownum) value = exp.evaluate(exp_context) if exp.hasEvalError(): calculationSuccess = False error = exp.evalErrorString() break else: outFeature.setGeometry(f.geometry()) for fld in f.fields(): outFeature[fld.name()] = f[fld.name()] outFeature[fieldName] = value writer.addFeature(outFeature) progress.setPercentage(int(current * total)) del writer # remove from registry if added for expression requirement # see above comment about fix #17300 if removeRegistryAfterEvaluation: QgsMapLayerRegistry.instance().removeMapLayer(layer) if not calculationSuccess: raise GeoAlgorithmExecutionException( self.tr('An error occurred while evaluating the calculation ' 'string:\n%s' % error))
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT_LAYER)) fieldName = self.getParameterValue(self.FIELD_NAME) fieldType = self.TYPES[self.getParameterValue(self.FIELD_TYPE)] width = self.getParameterValue(self.FIELD_LENGTH) precision = self.getParameterValue(self.FIELD_PRECISION) newField = self.getParameterValue(self.NEW_FIELD) formula = self.getParameterValue(self.FORMULA) output = self.getOutputFromName(self.OUTPUT_LAYER) if output.value == '': ext = output.getDefaultFileExtension(self) output.value = system.getTempFilenameInTempFolder( output.name + '.' + ext) fields = layer.fields() if newField: fields.append(QgsField(fieldName, fieldType, '', width, precision)) writer = output.getVectorWriter(fields, layer.wkbType(), layer.crs()) exp = QgsExpression(formula) da = QgsDistanceArea() da.setSourceCrs(layer.crs().srsid()) da.setEllipsoidalMode( iface.mapCanvas().mapSettings().hasCrsTransformEnabled()) da.setEllipsoid(QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE)[0]) exp.setGeomCalculator(da) exp.setDistanceUnits(QgsProject.instance().distanceUnits()) exp.setAreaUnits(QgsProject.instance().areaUnits()) exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope(QgsExpressionContextUtils.projectScope()) exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer)) if not exp.prepare(exp_context): raise GeoAlgorithmExecutionException( self.tr('Evaluation error: %s' % exp.evalErrorString())) # add layer to registry to fix https://issues.qgis.org/issues/17300 # it is necessary only for aggregate expressions that verify that layer # is registered removeRegistryAfterEvaluation = False if not QgsMapLayerRegistry.instance().mapLayer(layer.id()): removeRegistryAfterEvaluation = True QgsMapLayerRegistry.instance().addMapLayer(layer, addToLegend=False) outFeature = QgsFeature() outFeature.initAttributes(len(fields)) outFeature.setFields(fields) error = '' calculationSuccess = True features = vector.features(layer) total = 100.0 / len(features) if len(features) > 0 else 1 rownum = 1 for current, f in enumerate(features): rownum = current + 1 exp_context.setFeature(f) exp_context.lastScope().setVariable("row_number", rownum) value = exp.evaluate(exp_context) if exp.hasEvalError(): calculationSuccess = False error = exp.evalErrorString() break else: outFeature.setGeometry(f.geometry()) for fld in f.fields(): outFeature[fld.name()] = f[fld.name()] outFeature[fieldName] = value writer.addFeature(outFeature) progress.setPercentage(int(current * total)) del writer # remove from registry if added for expression requirement # see above comment about fix #17300 if removeRegistryAfterEvaluation: QgsMapLayerRegistry.instance().removeMapLayer(layer) if not calculationSuccess: raise GeoAlgorithmExecutionException( self.tr('An error occurred while evaluating the calculation ' 'string:\n%s' % error))
def testAreaMeasureAndUnits(self): """Test a variety of area measurements in different CRS and ellipsoid modes, to check that the calculated areas and units are always consistent """ da = QgsDistanceArea() da.setSourceCrs(3452) da.setEllipsoidalMode(False) da.setEllipsoid("NONE") daCRS = QgsCoordinateReferenceSystem() daCRS.createFromSrsId(da.sourceCrs()) polygon = QgsGeometry.fromPolygon([[ QgsPoint(0, 0), QgsPoint(1, 0), QgsPoint(1, 1), QgsPoint(2, 1), QgsPoint(2, 2), QgsPoint(0, 2), QgsPoint(0, 0), ]]) # We check both the measured area AND the units, in case the logic regarding # ellipsoids and units changes in future area = da.measureArea(polygon) units = da.areaUnits() print("measured {} in {}".format(area, QgsUnitTypes.toString(units))) assert ((abs(area - 3.0) < 0.00000001 and units == QgsUnitTypes.SquareDegrees) or (abs(area - 37176087091.5) < 0.1 and units == QgsUnitTypes.SquareMeters)) da.setEllipsoid("WGS84") area = da.measureArea(polygon) units = da.areaUnits() print("measured {} in {}".format(area, QgsUnitTypes.toString(units))) assert ((abs(area - 3.0) < 0.00000001 and units == QgsUnitTypes.SquareDegrees) or (abs(area - 37176087091.5) < 0.1 and units == QgsUnitTypes.SquareMeters)) da.setEllipsoidalMode(True) area = da.measureArea(polygon) units = da.areaUnits() print("measured {} in {}".format(area, QgsUnitTypes.toString(units))) # should always be in Meters Squared self.assertAlmostEqual(area, 37416879192.9, delta=0.1) self.assertEqual(units, QgsUnitTypes.SquareMeters) # test converting the resultant area area = da.convertAreaMeasurement(area, QgsUnitTypes.SquareMiles) self.assertAlmostEqual(area, 14446.7378, delta=0.001) # now try with a source CRS which is in feet polygon = QgsGeometry.fromPolygon([[ QgsPoint(1850000, 4423000), QgsPoint(1851000, 4423000), QgsPoint(1851000, 4424000), QgsPoint(1852000, 4424000), QgsPoint(1852000, 4425000), QgsPoint(1851000, 4425000), QgsPoint(1850000, 4423000) ]]) da.setSourceCrs(27469) da.setEllipsoidalMode(False) # measurement should be in square feet area = da.measureArea(polygon) units = da.areaUnits() print("measured {} in {}".format(area, QgsUnitTypes.toString(units))) self.assertAlmostEqual(area, 2000000, delta=0.001) self.assertEqual(units, QgsUnitTypes.SquareFeet) # test converting the resultant area area = da.convertAreaMeasurement(area, QgsUnitTypes.SquareYards) self.assertAlmostEqual(area, 222222.2222, delta=0.001) da.setEllipsoidalMode(True) # now should be in Square Meters again area = da.measureArea(polygon) units = da.areaUnits() print("measured {} in {}".format(area, QgsUnitTypes.toString(units))) self.assertAlmostEqual(area, 184149.37, delta=1.0) self.assertEqual(units, QgsUnitTypes.SquareMeters) # test converting the resultant area area = da.convertAreaMeasurement(area, QgsUnitTypes.SquareYards) self.assertAlmostEqual(area, 220240.8172549, delta=1.0)
# initialize QGIS application providers qgs = QgsApplication([], True) qgs.setPrefixPath(r'A:\OSGeo4W64\apps\qgis', True) qgs.initQgis() # import QGIS processing toolbox from processing.core.Processing import Processing Processing.initialize() from processing.tools import general # create a QGIS measure object distance_area = QgsDistanceArea() crs = QgsCoordinateReferenceSystem() crs.createFromSrsId(3452) # EPSG:4326 distance_area.setSourceCrs(crs) distance_area.setEllipsoidalMode(True) distance_area.setEllipsoid('WGS84') # define number of iterations of rebalancing phase (more iterations makes more islands) num_iterations = 1 # define school levels school_levels = ['elem', 'midd', 'high'] # define output directory output_dir = r"B:\Workspaces\GIS\GEOG653\final_project\output" # define filenames attendance_areas_filename = r"B:\Workspaces\GIS\GEOG653\final_project\data\MPIA\FS17_COMpolys.shp" school_capacities_filenames = { 'elem': r"B:\Workspaces\GIS\GEOG653\final_project\data\capacities_elem.csv",
class SizeCalculator(object): """Special object to handle size calculation with an output unit.""" def __init__(self, coordinate_reference_system, geometry_type, exposure_key): """Constructor for the size calculator. :param coordinate_reference_system: The Coordinate Reference System of the layer. :type coordinate_reference_system: QgsCoordinateReferenceSystem :param exposure_key: The geometry type of the layer. :type exposure_key: qgis.core.QgsWkbTypes.GeometryType """ self.calculator = QgsDistanceArea() self.calculator.setSourceCrs(coordinate_reference_system) self.calculator.setEllipsoid('WGS84') self.calculator.setEllipsoidalMode(True) if geometry_type == QgsWKBTypes.LineGeometry: self.default_unit = unit_metres LOGGER.info('The size calculator is set to use {unit}'.format( unit=distance_unit[self.calculator.lengthUnits()])) else: self.default_unit = unit_square_metres LOGGER.info('The size calculator is set to use {unit}'.format( unit=distance_unit[self.calculator.areaUnits()])) self.geometry_type = geometry_type self.output_unit = None if exposure_key: exposure_definition = definition(exposure_key) self.output_unit = exposure_definition['size_unit'] def measure(self, geometry): """Measure the length or the area of a geometry. :param geometry: The geometry. :type geometry: QgsGeometry :return: The geometric size in the expected exposure unit. :rtype: float """ message = 'Size with NaN value : geometry valid={valid}, WKT={wkt}' feature_size = 0 if geometry.isMultipart(): # Be careful, the size calculator is not working well on a # multipart. # So we compute the size part per part. See ticket #3812 for single in geometry.asGeometryCollection(): if self.geometry_type == QgsWKBTypes.LineGeometry: geometry_size = self.calculator.measureLength(single) else: geometry_size = self.calculator.measureArea(single) if not isnan(geometry_size): feature_size += geometry_size else: LOGGER.debug( message.format(valid=single.isGeosValid(), wkt=single.exportToWkt())) else: if self.geometry_type == QgsWKBTypes.LineGeometry: geometry_size = self.calculator.measureLength(geometry) else: geometry_size = self.calculator.measureArea(geometry) if not isnan(geometry_size): feature_size = geometry_size else: LOGGER.debug( message.format(valid=geometry.isGeosValid(), wkt=geometry.exportToWkt())) feature_size = round(feature_size) if self.output_unit: if self.output_unit != self.default_unit: feature_size = convert_unit(feature_size, self.default_unit, self.output_unit) return feature_size
def draw_scalebar(self, composer_map, top_offset): """Add a numeric scale to the bottom left of the map. We draw the scale bar manually because QGIS does not yet support rendering a scale bar for a geographic map in km. .. seealso:: :meth:`drawNativeScaleBar` :param composer_map: Composer map on which to draw the scalebar. :type composer_map: QgsComposerMap :param top_offset: Vertical offset at which the logo should be drawn. :type top_offset: int """ LOGGER.debug('InaSAFE Map drawScaleBar called') canvas = self.iface.mapCanvas() renderer = canvas.mapRenderer() # # Add a linear map scale # distance_area = QgsDistanceArea() distance_area.setSourceCrs(renderer.destinationCrs().srsid()) distance_area.setEllipsoidalMode(True) # Determine how wide our map is in km/m # Starting point at BL corner composer_extent = composer_map.extent() start_point = QgsPoint(composer_extent.xMinimum(), composer_extent.yMinimum()) # Ending point at BR corner end_point = QgsPoint(composer_extent.xMaximum(), composer_extent.yMinimum()) ground_distance = distance_area.measureLine(start_point, end_point) # Get the equivalent map distance per page mm map_width = self.mapWidth # How far is 1mm on map on the ground in meters? mm_to_ground = ground_distance / map_width #print 'MM:', myMMDistance # How long we want the scale bar to be in relation to the map scalebar_to_map_ratio = 0.5 # How many divisions the scale bar should have tick_count = 5 scale_bar_width_mm = map_width * scalebar_to_map_ratio print_segment_width_mm = scale_bar_width_mm / tick_count # Segment width in real world (m) # We apply some logic here so that segments are displayed in meters # if each segment is less that 1000m otherwise km. Also the segment # lengths are rounded down to human looking numbers e.g. 1km not 1.1km units = '' ground_segment_width = print_segment_width_mm * mm_to_ground if ground_segment_width < 1000: units = 'm' ground_segment_width = round(ground_segment_width) # adjust the segment width now to account for rounding print_segment_width_mm = ground_segment_width / mm_to_ground else: units = 'km' # Segment with in real world (km) ground_segment_width = round(ground_segment_width / 1000) print_segment_width_mm = ((ground_segment_width * 1000) / mm_to_ground) # Now adjust the scalebar width to account for rounding scale_bar_width_mm = tick_count * print_segment_width_mm #print "SBWMM:", scale_bar_width_mm #print "SWMM:", print_segment_width_mm #print "SWM:", myGroundSegmentWidthM #print "SWKM:", myGroundSegmentWidthKM # start drawing in line segments scalebar_height = 5 # mm line_width = 0.3 # mm inset_distance = 7 # how much to inset the scalebar into the map by scalebar_x = self.page_margin + inset_distance scalebar_y = (top_offset + self.map_height - inset_distance - scalebar_height) # mm # Draw an outer background box - shamelessly hardcoded buffer rectangle = QgsComposerShape( scalebar_x - 4, # left edge scalebar_y - 3, # top edge scale_bar_width_mm + 13, # right edge scalebar_height + 6, # bottom edge self.composition) rectangle.setShapeType(QgsComposerShape.Rectangle) pen = QtGui.QPen() pen.setColor(QtGui.QColor(255, 255, 255)) pen.setWidthF(line_width) rectangle.setPen(pen) #rectangle.setLineWidth(line_width) rectangle.setFrameEnabled(False) brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) # workaround for missing setTransparentFill missing from python api rectangle.setBrush(brush) self.composition.addItem(rectangle) # Set up the tick label font font_weight = QtGui.QFont.Normal font_size = 6 italics_flag = False font = QtGui.QFont('verdana', font_size, font_weight, italics_flag) # Draw the bottom line up_shift = 0.3 # shift the bottom line up for better rendering rectangle = QgsComposerShape(scalebar_x, scalebar_y + scalebar_height - up_shift, scale_bar_width_mm, 0.1, self.composition) rectangle.setShapeType(QgsComposerShape.Rectangle) pen = QtGui.QPen() pen.setColor(QtGui.QColor(255, 255, 255)) pen.setWidthF(line_width) rectangle.setPen(pen) #rectangle.setLineWidth(line_width) rectangle.setFrameEnabled(False) self.composition.addItem(rectangle) # Now draw the scalebar ticks for tick_counter in range(0, tick_count + 1): distance_suffix = '' if tick_counter == tick_count: distance_suffix = ' ' + units real_world_distance = ( '%.0f%s' % (tick_counter * ground_segment_width, distance_suffix)) #print 'RW:', myRealWorldDistance mm_offset = scalebar_x + (tick_counter * print_segment_width_mm) #print 'MM:', mm_offset tick_height = scalebar_height / 2 # Lines are not exposed by the api yet so we # bodge drawing lines using rectangles with 1px height or width tick_width = 0.1 # width or rectangle to be drawn uptick_line = QgsComposerShape( mm_offset, scalebar_y + scalebar_height - tick_height, tick_width, tick_height, self.composition) uptick_line.setShapeType(QgsComposerShape.Rectangle) pen = QtGui.QPen() pen.setWidthF(line_width) uptick_line.setPen(pen) #uptick_line.setLineWidth(line_width) uptick_line.setFrameEnabled(False) self.composition.addItem(uptick_line) # # Add a tick label # label = QgsComposerLabel(self.composition) label.setFont(font) label.setText(real_world_distance) label.adjustSizeToText() label.setItemPosition(mm_offset - 3, scalebar_y - tick_height) label.setFrameEnabled(self.show_frames) self.composition.addItem(label)
def processAlgorithm(self, progress): Points = self.getParameterValue(self.Points) SelectedFeaturesOnly = self.getParameterValue(self.SelectedFeaturesOnly) Cluster_Type = self.getParameterValue(self.Cluster_Type) RandomSeed = self.getParameterValue(self.RandomSeed) Linkage = self.getParameterValue(self.Linkage) Distance_Type = self.getParameterValue(self.Distance_Type) NumberOfClusters = self.getParameterValue(self.NumberOfClusters) vlayer = getObject(Points) provider = vlayer.dataProvider() if provider.featureCount()<NumberOfClusters: raise GeoAlgorithmExecutionException("Error initializing cluster analysis:\nToo little features available") sRs = provider.crs() d = QgsDistanceArea() d.setSourceCrs(sRs) d.setEllipsoid(sRs.ellipsoidAcronym()) d.setEllipsoidalMode(sRs.geographicFlag()) # retrieve input features infeat = QgsFeature() if SelectedFeaturesOnly: fit = vlayer.selectedFeaturesIterator() else: fit = provider.getFeatures() # initialize points for clustering points = {} key = 0 while fit.nextFeature(infeat): points[key] = infeat.geometry().asPoint() key += 1 if NumberOfClusters>key: raise GeoAlgorithmExecutionException("Too little points available for %i clusters") % (NumberOfClusters) # do the clustering if Cluster_Type==0: if Linkage<>0: progress.setInfo("Linkage not used for K-Means") # K-means clustering clusters = self.kmeans(progress,points,NumberOfClusters,d,10*float_info.epsilon,Distance_Type==1) del points cluster_id = {} for idx,cluster in enumerate(clusters): for key in cluster.ids: cluster_id[key] = idx else: # Hierarchical clustering if Linkage==0: clusters = self.hcluster_wards(progress,points,NumberOfClusters,d,Distance_Type==1) elif Linkage==1: clusters = self.hcluster_single(progress,points,NumberOfClusters,d,Distance_Type==1) elif Linkage==2: clusters = self.hcluster_complete(progress,points,NumberOfClusters,d,Distance_Type==1) elif Linkage==3: clusters = self.hcluster_average(progress,points,NumberOfClusters,d,Distance_Type==1) else: raise GeoAlgorithmExecutionException("Linkage must be Ward's, Single, Complete or Average") del points cluster_id = {} for idx,cluster in enumerate(clusters): for key in cluster: cluster_id[key] = idx # write results to input file progress.setInfo("Writing output field Cluster_ID") if not vlayer.isEditable(): vlayer.startEditing() fieldList = provider.fields() if 'Cluster_ID' in [field.name() for field in fieldList]: icl = fieldList.indexFromName('Cluster_ID') provider.deleteAttributes([icl]) provider.addAttributes([QgsField('Cluster_ID',QVariant.Int)]) vlayer.updateFields() # assign the output points to the clusters if SelectedFeaturesOnly: fit = vlayer.selectedFeaturesIterator() else: fit = provider.getFeatures() key = 0 while fit.nextFeature(infeat): atMap = infeat.attributes() atMap[-1] = cluster_id[key] infeat.setAttributes(atMap) vlayer.updateFeature(infeat) key += 1 vlayer.commitChanges() progress.setPercentage(100)
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT_LAYER)) fieldName = self.getParameterValue(self.FIELD_NAME) fieldType = self.TYPES[self.getParameterValue(self.FIELD_TYPE)] width = self.getParameterValue(self.FIELD_LENGTH) precision = self.getParameterValue(self.FIELD_PRECISION) newField = self.getParameterValue(self.NEW_FIELD) formula = self.getParameterValue(self.FORMULA) output = self.getOutputFromName(self.OUTPUT_LAYER) fields = layer.fields() if newField: fields.append(QgsField(fieldName, fieldType, '', width, precision)) writer = output.getVectorWriter(fields, layer.wkbType(), layer.crs()) exp = QgsExpression(formula) da = QgsDistanceArea() da.setSourceCrs(layer.crs().srsid()) da.setEllipsoidalMode( iface.mapCanvas().mapSettings().hasCrsTransformEnabled()) da.setEllipsoid(QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE)[0]) exp.setGeomCalculator(da) exp.setDistanceUnits(QgsProject.instance().distanceUnits()) exp.setAreaUnits(QgsProject.instance().areaUnits()) exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope(QgsExpressionContextUtils.projectScope()) exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer)) if not exp.prepare(exp_context): raise GeoAlgorithmExecutionException( self.tr('Evaluation error: %s' % exp.evalErrorString())) outFeature = QgsFeature() outFeature.initAttributes(len(fields)) outFeature.setFields(fields) error = '' calculationSuccess = True features = vector.features(layer) total = 100.0 / len(features) rownum = 1 for current, f in enumerate(features): rownum = current + 1 exp_context.setFeature(f) exp_context.lastScope().setVariable("row_number", rownum) value = exp.evaluate(exp_context) if exp.hasEvalError(): calculationSuccess = False error = exp.evalErrorString() break else: outFeature.setGeometry(f.geometry()) for fld in f.fields(): outFeature[fld.name()] = f[fld.name()] outFeature[fieldName] = value writer.addFeature(outFeature) progress.setPercentage(int(current * total)) del writer if not calculationSuccess: raise GeoAlgorithmExecutionException( self.tr('An error occurred while evaluating the calculation ' 'string:\n%s' % error))
def expressionBasedUpdate(self, layer, dictProperties, featureId, index=None, value=None): """ Defines the logic of the expression-based update to be applied. This SLOT listens to featureAdded, geometryChanged, and attributeValueChanged SIGNALS. """ # Check if AutoField is there, otherwise return fieldIndex = layer.fieldNameIndex(dictProperties['field']) if fieldIndex == -1: self.msg.show( QApplication.translate( "EventManager", "[Error] Updating AutoField " ) + \ dictProperties['field'] + \ QApplication.translate( "EventManager", " in layer " ) + \ layer.name() + QApplication.translate( "EventManager", " was NOT possible." ) + \ QApplication.translate( "EventManager", " Perhaps you just removed it but haven't saved the changes yet?" ), 'warning' ) return event = "" result = None expression = QgsExpression(dictProperties['expression']) if expression.hasParserError(): self.msg.show( QApplication.translate( "EventManager", "[Error] (Parsing) " ) + \ expression.parserErrorString(), 'critical' ) result = NULL # Avoid infinite recursion (changing the same attribute value infinitely). if not index is None: # Filters out the featureAdded SIGNAL if type(index) == int: # Filters out the geometryChanged SIGNAL if index == fieldIndex: # This call comes from the same AutoField, so return return if self.afm.isFieldAnAutoField( layer, layer.fields() [index].name()): # Call from AutoField, don't listen # This is to prevent corrupting the layerEditBuffer and being bitten by: # Fatal: ASSERT: "mChangedAttributeValues.isEmpty()" in file /tmp/buildd/qgis-2.14.2+20trusty/src/core/qgsvectorlayereditbuffer.cpp, line 585 return #if type(value)==QPyNullVariant: # Vector layers with numeric field whose value for 1st feature is NULL # trigger an attributeValueChanged SIGNAL when start editing from the # attribute table window. We use this conditional to avoid such SIGNAL. # The ideal case is that such NULL valued SIGNAL shouldn't be emitted by QGIS. # return # While the previous block reduces the number of times attributeValueChanged # is called from the attribute table, it leads to a QGIS bug: # Fatal: ASSERT: "mChangedAttributeValues.isEmpty()" in file /tmp/buildd/qgis-2.14.2+20trusty/src/core/qgsvectorlayereditbuffer.cpp, line 585 # I prefer the attributeValueChanged to be called multiple # times (inefficient) than to open the possibility to a bug. # As soon as QGIS bug #15272 is solved, the number of calls will be reduced! event = "attributeValueChanged" else: event = "geometryChanged" else: event = "featureAdded" feature = layer.getFeatures(QgsFeatureRequest(featureId)).next() if result is None: context = QgsExpressionContext() context.appendScope(QgsExpressionContextUtils.globalScope()) context.appendScope(QgsExpressionContextUtils.projectScope()) context.appendScope(QgsExpressionContextUtils.layerScope(layer)) context.setFields(feature.fields()) context.setFeature(feature) if expression.needsGeometry(): if self.iface: # This block was borrowed from QGIS/python/plugins/processing/algs/qgis/FieldsCalculator.py da = QgsDistanceArea() da.setSourceCrs(layer.crs().srsid()) da.setEllipsoidalMode(self.iface.mapCanvas().mapSettings(). hasCrsTransformEnabled()) da.setEllipsoid(QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE)[0]) expression.setGeomCalculator(da) if QGis.QGIS_VERSION_INT >= 21400: # Methods added in QGIS 2.14 expression.setDistanceUnits( QgsProject.instance().distanceUnits()) expression.setAreaUnits( QgsProject.instance().areaUnits()) expression.prepare(context) result = expression.evaluate(context) if expression.hasEvalError(): self.msg.show( QApplication.translate( "EventManager", "[Error] (Evaluating) " ) + \ expression.evalErrorString(), 'critical' ) result = NULL field = layer.fields()[fieldIndex] res = field.convertCompatible(result) # If result is None, res will be None, but even in that case, QGIS knows # what to do with it while saving, it seems it's treated as NULL. # TODO when bug #15311 is fixed, this block should work better #if dictProperties['expression'] in self.listProviderExpressions: # # Save directly to provider # layer.dataProvider().changeAttributeValues( { featureId : { fieldIndex : res } } ) #else: # Save to layer # layer.changeAttributeValue( featureId, fieldIndex, res ) # Workaround if event == 'featureAdded': # Save directly to the provider layer.dataProvider().changeAttributeValues( {featureId: { fieldIndex: res }}) else: # Save to layer layer.changeAttributeValue(featureId, fieldIndex, res) self.msg.show( "[Info] * AutoField's value updated to " + unicode(res) + \ ", (" + layer.name() + "." + dictProperties['field'] + ") by " + event +".", 'info', True )
def processAlgorithm(self, progress): layerPoints = dataobjects.getObjectFromUri( self.getParameterValue(self.POINTS)) layerHubs = dataobjects.getObjectFromUri( self.getParameterValue(self.HUBS)) fieldName = self.getParameterValue(self.FIELD) addLines = self.getParameterValue(self.GEOMETRY) units = self.UNITS[self.getParameterValue(self.UNIT)] if layerPoints.source() == layerHubs.source(): raise GeoAlgorithmExecutionException( self.tr('Same layer given for both hubs and spokes')) geomType = QGis.WKBPoint if addLines: geomType = QGis.WKBLineString fields = layerPoints.pendingFields() fields.append(QgsField('HubName', QVariant.String)) fields.append(QgsField('HubDist', QVariant.Double)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, geomType, layerPoints.crs()) # Create array of hubs in memory hubs = [] features = vector.features(layerHubs) for f in features: hubs.append( Hub(f.geometry().boundingBox().center(), unicode(f[fieldName]))) distance = QgsDistanceArea() distance.setSourceCrs(layerPoints.crs().srsid()) distance.setEllipsoidalMode(True) # Scan source points, find nearest hub, and write to output file features = vector.features(layerPoints) count = len(features) total = 100.0 / float(count) for count, f in enumerate(features): src = f.geometry().boundingBox().center() closest = hubs[0] hubDist = distance.measureLine(src, closest.point) for hub in hubs: dist = distance.measureLine(src, hub.point) if dist < hubDist: closest = hub hubDist = dist attributes = f.attributes() attributes.append(closest.name) if units == 'Feet': attributes.append(hubDist * 3.2808399) elif units == 'Miles': attributes.append(hubDist * 0.000621371192) elif units == 'Kilometers': attributes.append(hubDist / 1000.0) elif units != 'Meters': attributes.append( sqrt( pow(src.x() - closest.point.x(), 2.0) + pow(src.y() - closest.point.y(), 2.0))) else: attributes.append(hubDist) feat = QgsFeature() feat.setAttributes(attributes) if geomType == QGis.WKBPoint: feat.setGeometry(QgsGeometry.fromPoint(src)) else: feat.setGeometry(QgsGeometry.fromPolyline([src, closest.point])) writer.addFeature(feat) progress.setPercentage(int(count * total)) del writer
def by_distance(self, distance): """ shift by constant distance :param distance: distance used to shift in meters """ self._check() header = self.inputfile.readline() beforeLat = header.split('Lat_deg') numberOfLatColumn = beforeLat[0].split(',') beforeLong = header.split('Lon_deg') numberOfLonColumn = beforeLong[0].split(',') self.outputfile.write(header) d = QgsDistanceArea() d.setEllipsoid('WGS84') d.setEllipsoidalMode(True) d.ellipsoid() a = 6378137.0 # WGS84 ellipsoid parametres e2 = 0.081819190842622 line1 = self.inputfile.readline() if distance > 0: linePos = self.inputfile.tell() line1 = line1.split(',') while line1: self.inputfile.seek(linePos) line2 = self.inputfile.readline() linePos = self.inputfile.tell() moveDistance = 1*distance outline = 1*line1 inline = line2.split(',') if line2: line2 = line2.split(',') p1 = QgsPoint(float(line1[len(numberOfLonColumn)-1]), float(line1[len(numberOfLatColumn)-1])) p2 = QgsPoint(float(line2[len(numberOfLonColumn)-1]), float(line2[len(numberOfLatColumn)-1])) l = d.computeDistanceBearing(p1, p2)[0] while moveDistance > l: if line2: moveDistance = moveDistance-l line1 = 1*line2 line2 = self.inputfile.readline() if line2: line2 = line2.split(',') p1 = QgsPoint( float(line1[len(numberOfLonColumn)-1]), float(line1[len(numberOfLatColumn)-1])) p2 = QgsPoint( float(line2[len(numberOfLonColumn)-1]), float(line2[len(numberOfLatColumn)-1])) l = d.computeDistanceBearing(p1, p2)[0] else: break if line2: if moveDistance != l: if p1 != p2: aziA = d.bearing(p1, p2) h = moveDistance/2.0 fi = [float( line1[len(numberOfLatColumn)-1])*pi/180] lam = [float( line1[len(numberOfLonColumn)-1])*pi/180] azi = [aziA] FIe1, LAMe1 = self.iterations( moveDistance, a, e2, h, azi, fi, lam) else: FIe1 = float( line2[len(numberOfLatColumn)-1])*pi/180 LAMe1 = float( line2[len(numberOfLonColumn)-1])*pi/180 else: FIe1 = float( line2[len(numberOfLatColumn)-1])*pi/180 LAMe1 = float( line2[len(numberOfLonColumn)-1])*pi/180 # changing latitude and longitude of new point outline[len(numberOfLatColumn)-1] = str(FIe1*180/pi) outline[len(numberOfLonColumn)-1] = str(LAMe1*180/pi) outline = ','.join(outline) self.outputfile.write(outline) line1 = inline else: break else: break elif distance < 0: line = [] line.append(line1) line[0] = line[0].split(',') line.append(self.inputfile.readline()) line[1] = line[1].split(',') i = 1 distance = fabs(distance) moveDistance = fabs(distance) p1 = QgsPoint(float(line[0][len(numberOfLonColumn)-1]), float(line[0][len(numberOfLatColumn)-1])) p2 = QgsPoint(float(line[1][len(numberOfLonColumn)-1]), float(line[1][len(numberOfLatColumn)-1])) allDist = d.computeDistanceBearing(p1, p2)[0] while moveDistance > allDist: line.append(self.inputfile.readline().split(',')) i = i+1 if line[len(line)-1] == ['']: break p1 = QgsPoint(float(line[i-1][len(numberOfLonColumn)-1]), float(line[i-1][len(numberOfLatColumn)-1])) p2 = QgsPoint(float(line[i][len(numberOfLonColumn)-1]), float(line[i][len(numberOfLatColumn)-1])) allDist = allDist+d.computeDistanceBearing(p1, p2)[0] while line[len(line)-1] != ['']: allDist = 0 for i in reversed(range(1, len(line))): p1 = QgsPoint(float(line[i-1][len(numberOfLonColumn)-1]), float(line[i-1][len(numberOfLatColumn)-1])) p2 = QgsPoint(float(line[i][len(numberOfLonColumn)-1]), float(line[i][len(numberOfLatColumn)-1])) allDist = allDist+d.computeDistanceBearing(p1, p2)[0] if fabs(moveDistance) <= allDist: for x in range(i-1): del line[0] break for i in reversed(range(len(line))): p1 = QgsPoint(float(line[i-1][len(numberOfLonColumn)-1]), float(line[i-1][len(numberOfLatColumn)-1])) p2 = QgsPoint(float(line[i][len(numberOfLonColumn)-1]), float(line[i][len(numberOfLatColumn)-1])) if p1 != p2: aziA = d.bearing(p2, p1) l = d.computeDistanceBearing(p1, p2)[0] if moveDistance > l: moveDistance = moveDistance-l elif moveDistance != 0 and moveDistance != l: # first geodetic problem h = moveDistance/2.0 fi = [float( line[i][len(numberOfLatColumn)-1])*pi/180] lam = [float( line[i][len(numberOfLonColumn)-1])*pi/180] azi = [aziA] FIe1, LAMe1 = self.iterations( moveDistance, a, e2, h, azi, fi, lam) break else: FIe1 = float( line[i-1][len(numberOfLatColumn)-1])*pi/180 LAMe1 = float( line[i-1][len(numberOfLonColumn)-1])*pi/180 break else: if moveDistance > l: moveDistance = moveDistance-l else: FIe1 = float( line[i-1][len(numberOfLatColumn)-1])*pi/180 LAMe1 = float( line[i-1][len(numberOfLonColumn)-1])*pi/180 break outline = 1*line[len(line)-1] # changing latitude and longitude of new point outline[len(numberOfLatColumn)-1] = str(FIe1*180/pi) outline[len(numberOfLonColumn)-1] = str(LAMe1*180/pi) outline = ','.join(outline) self.outputfile.write(outline) line.append(self.inputfile.readline()) line[len(line)-1] = line[len(line)-1].split(',') moveDistance = fabs(distance) else: while line1: self.outputfile.write(line1) line1 = self.inputfile.readline() self._close()
def draw_scalebar(self, composer_map, top_offset): """Add a numeric scale to the bottom left of the map. We draw the scale bar manually because QGIS does not yet support rendering a scale bar for a geographic map in km. .. seealso:: :meth:`drawNativeScaleBar` :param composer_map: Composer map on which to draw the scalebar. :type composer_map: QgsComposerMap :param top_offset: Vertical offset at which the logo should be drawn. :type top_offset: int """ LOGGER.debug('InaSAFE Map drawScaleBar called') myCanvas = self.iface.mapCanvas() myRenderer = myCanvas.mapRenderer() # # Add a linear map scale # myDistanceArea = QgsDistanceArea() myDistanceArea.setSourceCrs(myRenderer.destinationCrs().srsid()) myDistanceArea.setEllipsoidalMode(True) # Determine how wide our map is in km/m # Starting point at BL corner myComposerExtent = composer_map.extent() myStartPoint = QgsPoint(myComposerExtent.xMinimum(), myComposerExtent.yMinimum()) # Ending point at BR corner myEndPoint = QgsPoint(myComposerExtent.xMaximum(), myComposerExtent.yMinimum()) myGroundDistance = myDistanceArea.measureLine(myStartPoint, myEndPoint) # Get the equivalent map distance per page mm myMapWidth = self.mapWidth # How far is 1mm on map on the ground in meters? myMMToGroundDistance = myGroundDistance / myMapWidth #print 'MM:', myMMDistance # How long we want the scale bar to be in relation to the map myScaleBarToMapRatio = 0.5 # How many divisions the scale bar should have myTickCount = 5 myScaleBarWidthMM = myMapWidth * myScaleBarToMapRatio myPrintSegmentWidthMM = myScaleBarWidthMM / myTickCount # Segment width in real world (m) # We apply some logic here so that segments are displayed in meters # if each segment is less that 1000m otherwise km. Also the segment # lengths are rounded down to human looking numbers e.g. 1km not 1.1km myUnits = '' myGroundSegmentWidth = myPrintSegmentWidthMM * myMMToGroundDistance if myGroundSegmentWidth < 1000: myUnits = 'm' myGroundSegmentWidth = round(myGroundSegmentWidth) # adjust the segment width now to account for rounding myPrintSegmentWidthMM = myGroundSegmentWidth / myMMToGroundDistance else: myUnits = 'km' # Segment with in real world (km) myGroundSegmentWidth = round(myGroundSegmentWidth / 1000) myPrintSegmentWidthMM = ((myGroundSegmentWidth * 1000) / myMMToGroundDistance) # Now adjust the scalebar width to account for rounding myScaleBarWidthMM = myTickCount * myPrintSegmentWidthMM #print "SBWMM:", myScaleBarWidthMM #print "SWMM:", myPrintSegmentWidthMM #print "SWM:", myGroundSegmentWidthM #print "SWKM:", myGroundSegmentWidthKM # start drawing in line segments myScaleBarHeight = 5 # mm myLineWidth = 0.3 # mm myInsetDistance = 7 # how much to inset the scalebar into the map by myScaleBarX = self.pageMargin + myInsetDistance myScaleBarY = ( top_offset + self.mapHeight - myInsetDistance - myScaleBarHeight) # mm # Draw an outer background box - shamelessly hardcoded buffer myRect = QgsComposerShape(myScaleBarX - 4, # left edge myScaleBarY - 3, # top edge myScaleBarWidthMM + 13, # right edge myScaleBarHeight + 6, # bottom edge self.composition) myRect.setShapeType(QgsComposerShape.Rectangle) myPen = QtGui.QPen() myPen.setColor(QtGui.QColor(255, 255, 255)) myPen.setWidthF(myLineWidth) myRect.setPen(myPen) #myRect.setLineWidth(myLineWidth) myRect.setFrameEnabled(False) myBrush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) # workaround for missing setTransparentFill missing from python api myRect.setBrush(myBrush) self.composition.addItem(myRect) # Set up the tick label font myFontWeight = QtGui.QFont.Normal myFontSize = 6 myItalicsFlag = False myFont = QtGui.QFont('verdana', myFontSize, myFontWeight, myItalicsFlag) # Draw the bottom line myUpshift = 0.3 # shift the bottom line up for better rendering myRect = QgsComposerShape(myScaleBarX, myScaleBarY + myScaleBarHeight - myUpshift, myScaleBarWidthMM, 0.1, self.composition) myRect.setShapeType(QgsComposerShape.Rectangle) myPen = QtGui.QPen() myPen.setColor(QtGui.QColor(255, 255, 255)) myPen.setWidthF(myLineWidth) myRect.setPen(myPen) #myRect.setLineWidth(myLineWidth) myRect.setFrameEnabled(False) self.composition.addItem(myRect) # Now draw the scalebar ticks for myTickCountIterator in range(0, myTickCount + 1): myDistanceSuffix = '' if myTickCountIterator == myTickCount: myDistanceSuffix = ' ' + myUnits myRealWorldDistance = ('%.0f%s' % (myTickCountIterator * myGroundSegmentWidth, myDistanceSuffix)) #print 'RW:', myRealWorldDistance myMMOffset = myScaleBarX + (myTickCountIterator * myPrintSegmentWidthMM) #print 'MM:', myMMOffset myTickHeight = myScaleBarHeight / 2 # Lines are not exposed by the api yet so we # bodge drawing lines using rectangles with 1px height or width myTickWidth = 0.1 # width or rectangle to be drawn myUpTickLine = QgsComposerShape( myMMOffset, myScaleBarY + myScaleBarHeight - myTickHeight, myTickWidth, myTickHeight, self.composition) myUpTickLine.setShapeType(QgsComposerShape.Rectangle) myPen = QtGui.QPen() myPen.setWidthF(myLineWidth) myUpTickLine.setPen(myPen) #myUpTickLine.setLineWidth(myLineWidth) myUpTickLine.setFrameEnabled(False) self.composition.addItem(myUpTickLine) # # Add a tick label # myLabel = QgsComposerLabel(self.composition) myLabel.setFont(myFont) myLabel.setText(myRealWorldDistance) myLabel.adjustSizeToText() myLabel.setItemPosition( myMMOffset - 3, myScaleBarY - myTickHeight) myLabel.setFrameEnabled(self.showFramesFlag) self.composition.addItem(myLabel)
def point2nb(self): lst = [] # geoms = [geom.geometry() for geom in self.lyr.getFeatures() # feats = self.lyr.getFeatures() # for f1, f2 in itertools.product(feats, repeat=2): # if f1!=f2: # d = f1.geometry().asPoint().distance(f2.geometry().asPoint()) # self.plainTextEdit.insertPlainText("%s %s: %s\n" % (f1.id(), f2.id(), d)) featA = QgsFeature() featsA = self.lyr.getFeatures() trh = float(self.lineEdit.text()) if self.comboBox_6.currentText() == 'km': # psrid = self.iface.mapCanvas().mapRenderer().destinationCrs().srsid() prv = self.lyr.dataProvider() psrid = prv.crs().srsid() dist = QgsDistanceArea() dist.setEllipsoid('WGS84') dist.setEllipsoidalMode(True) # self.plainTextEdit.insertPlainText("%s\n" % psrid) if psrid != 3452: trafo = QgsCoordinateTransform(psrid, 3452) while featsA.nextFeature(featA): featB = QgsFeature() featsB = self.lyr.getFeatures() sor = [] while featsB.nextFeature(featB): if featA.id() != featB.id(): tav = dist.measureLine(trafo.transform(featA.geometry().asPoint()), trafo.transform(featB.geometry().asPoint())) # self.plainTextEdit.insertPlainText("%s %s %s\n" % (featA.id(), featB.id(), tav)) if (tav / 1000.0) <= trh: sor.append(featB.id()) lst.append(sor) else: while featsA.nextFeature(featA): featB = QgsFeature() featsB = self.lyr.getFeatures() sor = [] while featsB.nextFeature(featB): if featA.id() != featB.id(): tav = dist.measureLine(featA.geometry().asPoint(), featB.geometry().asPoint()) # self.plainTextEdit.insertPlainText("%s %s %s\n" % (featA.id(), featB.id(), tav)) if (tav / 1000.0) <= trh: sor.append(featB.id()) lst.append(sor) else: while featsA.nextFeature(featA): featB = QgsFeature() featsB = self.lyr.getFeatures() sor = [] while featsB.nextFeature(featB): if featA.id() != featB.id(): tav = featA.geometry().asPoint().distance(featB.geometry().asPoint()) # self.plainTextEdit.insertPlainText("%s %s %s\n" % (featA.id(), featB.id(), tav)) if tav <= trh: sor.append(featB.id()) lst.append(sor) # self.plainTextEdit.insertPlainText("%s\n" % lst) return lst
def processAlgorithm(self, feedback): layerPoints = dataobjects.getObjectFromUri( self.getParameterValue(self.POINTS)) layerHubs = dataobjects.getObjectFromUri( self.getParameterValue(self.HUBS)) fieldName = self.getParameterValue(self.FIELD) addLines = self.getParameterValue(self.GEOMETRY) units = self.UNITS[self.getParameterValue(self.UNIT)] if layerPoints.source() == layerHubs.source(): raise GeoAlgorithmExecutionException( self.tr('Same layer given for both hubs and spokes')) fields = layerPoints.fields() fields.append(QgsField('HubName', QVariant.String)) fields.append(QgsField('HubDist', QVariant.Double)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, QgsWkbTypes.LineString, layerPoints.crs()) index = vector.spatialindex(layerHubs) distance = QgsDistanceArea() distance.setSourceCrs(layerPoints.crs().srsid()) distance.setEllipsoidalMode(True) # Scan source points, find nearest hub, and write to output file features = vector.features(layerPoints) total = 100.0 / len(features) for current, f in enumerate(features): src = f.geometry().boundingBox().center() neighbors = index.nearestNeighbor(src, 1) ft = next(layerHubs.getFeatures(QgsFeatureRequest().setFilterFid(neighbors[0]).setSubsetOfAttributes([fieldName], layerHubs.fields()))) closest = ft.geometry().boundingBox().center() hubDist = distance.measureLine(src, closest) attributes = f.attributes() attributes.append(ft[fieldName]) if units == 'Feet': attributes.append(hubDist * 3.2808399) elif units == 'Miles': attributes.append(hubDist * 0.000621371192) elif units == 'Kilometers': attributes.append(hubDist / 1000.0) elif units != 'Meters': attributes.append(sqrt( pow(src.x() - closest.x(), 2.0) + pow(src.y() - closest.y(), 2.0))) else: attributes.append(hubDist) feat = QgsFeature() feat.setAttributes(attributes) feat.setGeometry(QgsGeometry.fromPolyline([src, closest])) writer.addFeature(feat) feedback.setProgress(int(current * total)) del writer
class GuidanceDock(QtGui.QDockWidget, FORM_CLASS): ''' classdocs ''' def __init__(self, parent=None): ''' Constructor ''' super(GuidanceDock, self).__init__(parent) self.setupUi(self) self.compass = CompassWidget() self.compass.setMinimumHeight(80) self.verticalLayout.addWidget(self.compass) self.verticalLayout.setStretch(5, 8) self.distArea = QgsDistanceArea() self.distArea.setEllipsoid(u'WGS84') self.distArea.setEllipsoidalMode(True) self.distArea.setSourceCrs(3452L) self.fontSize = 11 self.source = None self.target = None self.srcPos = [None, 0.0] self.trgPos = [None, 0.0] self.srcHeading = 0.0 self.trgHeading = 0.0 s = QSettings() self.format = s.value('PosiView/Guidance/Format', defaultValue=1, type=int) self.showUtc = s.value('PosiView/Misc/ShowUtcClock', defaultValue=False, type=bool) self.timer = 0 self.setUtcClock() def setUtcClock(self): if self.showUtc: if not self.timer: self.timer = self.startTimer(1000) self.frameUtcClock.show() else: self.frameUtcClock.hide() self.killTimer(self.timer) self.timer = 0 def setMobiles(self, mobiles): self.reset() self.mobiles = mobiles self.comboBoxSource.blockSignals(True) self.comboBoxTarget.blockSignals(True) self.comboBoxSource.clear() self.comboBoxSource.addItems(sorted(mobiles.keys())) self.comboBoxSource.setCurrentIndex(-1) self.comboBoxTarget.clear() self.comboBoxTarget.addItems(sorted(mobiles.keys())) self.comboBoxTarget.setCurrentIndex(-1) self.comboBoxSource.blockSignals(False) self.comboBoxTarget.blockSignals(False) s = QSettings() m = s.value('PosiView/Guidance/Source') if m in self.mobiles: self.comboBoxSource.setCurrentIndex(self.comboBoxSource.findText(m)) m = s.value('PosiView/Guidance/Target') if m in self.mobiles: self.comboBoxTarget.setCurrentIndex(self.comboBoxTarget.findText(m)) self.showUtc = s.value('PosiView/Misc/ShowUtcClock', defaultValue=False, type=bool) self.setUtcClock() @pyqtSlot(name='on_pushButtonFormat_clicked') def switchCoordinateFormat(self): self.format = (self.format + 1) % 3 s = QSettings() s.setValue('PosiView/Guidance/Format', self.format) if self.trgPos[0]: lon, lat = self.posToStr(self.trgPos[0]) self.labelTargetLat.setText(lat) self.labelTargetLon.setText(lon) if self.srcPos[0]: lon, lat = self.posToStr(self.srcPos[0]) self.labelSourceLat.setText(lat) self.labelSourceLon.setText(lon) def posToStr(self, pos): if self.format == 0: return "{:.6f}".format(pos.x()), "{:.6f}".format(pos.y()) if self.format == 1: return pos.toDegreesMinutes(4, True, True).split(',') if self.format == 2: return pos.toDegreesMinutesSeconds(2, True, True).split(',') @pyqtSlot(str, name='on_comboBoxSource_currentIndexChanged') def sourceChanged(self, mob): if self.source is not None: try: self.source.newPosition.disconnect(self.onNewSourcePosition) self.source.newAttitude.disconnect(self.onNewSourceAttitude) except TypeError: pass try: self.source = self.mobiles[mob] self.source.newPosition.connect(self.onNewSourcePosition) self.source.newAttitude.connect(self.onNewSourceAttitude) s = QSettings() s.setValue('PosiView/Guidance/Source', mob) except KeyError: self.source = None self.resetSource() @pyqtSlot(str, name='on_comboBoxTarget_currentIndexChanged') def targetChanged(self, mob): if self.target is not None: try: self.target.newPosition.disconnect(self.onNewTargetPosition) self.target.newAttitude.disconnect(self.onNewTargetAttitude) except TypeError: pass try: self.target = self.mobiles[mob] self.target.newPosition.connect(self.onNewTargetPosition) self.target.newAttitude.connect(self.onNewTargetAttitude) s = QSettings() s.setValue('PosiView/Guidance/Target', mob) except KeyError: self.target = None self.resetTarget() @pyqtSlot(float, QgsPoint, float, float) def onNewSourcePosition(self, fix, pos, depth, altitude): if [pos, depth] != self.srcPos: lon, lat = self.posToStr(pos) self.labelSourceLat.setText(lat) self.labelSourceLon.setText(lon) self.labelSourceDepth.setText(str(depth)) if self.trgPos[0] is not None: self.labelVertDistance.setText(str(self.trgPos[1] - depth)) dist = self.distArea.measureLine(self.trgPos[0], pos) self.labelDistance.setText('{:.1f}'.format(dist)) if dist != 0: bearing = self.distArea.bearing(pos, self.trgPos[0]) * 180 / pi if bearing < 0: bearing += 360 else: bearing = 0.0 self.labelDirection.setText('{:.1f}'.format(bearing)) self.srcPos = [pos, depth] @pyqtSlot(float, QgsPoint, float, float) def onNewTargetPosition(self, fix, pos, depth, altitude): if [pos, depth] != self.trgPos: lon, lat = self.posToStr(pos) self.labelTargetLat.setText(lat) self.labelTargetLon.setText(lon) self.labelTargetDepth.setText(str(depth)) if self.srcPos[0] is not None: self.labelVertDistance.setText(str(depth - self.srcPos[1])) dist = self.distArea.measureLine(pos, self.srcPos[0]) self.labelDistance.setText('{:.1f}'.format(dist)) if dist != 0: bearing = self.distArea.bearing(self.srcPos[0], pos) * 180 / pi if bearing < 0: bearing += 360 else: bearing = 0.0 self.labelDirection.setText('{:.1f}'.format(bearing)) self.trgPos = [pos, depth] @pyqtSlot(float, float, float) def onNewTargetAttitude(self, heading, pitch, roll): if self.trgHeading != heading: self.trgHeading = heading self.labelTargetHeading.setText(str(heading)) self.compass.setAngle2(heading) @pyqtSlot(float, float, float) def onNewSourceAttitude(self, heading, pitch, roll): if self.srcHeading != heading: self.srcHeading = heading self.labelSourceHeading.setText(str(heading)) self.compass.setAngle(heading) def reset(self): try: if self.source is not None: self.source.newPosition.disconnect(self.onNewSourcePosition) self.source.newAttitude.disconnect(self.onNewSourceAttitude) if self.target is not None: self.target.newPosition.disconnect(self.onNewTargetPosition) self.target.newAttitude.disconnect(self.onNewTargetAttitude) except TypeError: pass self.source = None self.target = None self.resetSource() self.resetTarget() self.resetDistBearing() def resetSource(self): self.srcPos = [None, 0.0] self.srcHeading = -720.0 self.labelSourceLat.setText('---') self.labelSourceLon.setText('---') self.labelSourceHeading.setText('---') self.labelSourceDepth.setText('---') self.compass.reset(1) self.resetDistBearing() def resetTarget(self): self.trgPos = [None, 0.0] self.trgHeading = -720.0 self.labelTargetLat.setText('---') self.labelTargetLon.setText('---') self.labelTargetHeading.setText('---') self.labelTargetDepth.setText('---') self.compass.reset(2) self.resetDistBearing() def resetDistBearing(self): self.labelDirection.setText('---') self.labelDistance.setText('---') self.labelVertDistance.setText('---') def resizeEvent(self, event): fsize = event.size().width() / 40 if fsize != self.fontSize: self.fontSize = fsize self.dockWidgetContents.setStyleSheet("font-weight: bold; font-size: {}pt".format(self.fontSize)) return QtGui.QDockWidget.resizeEvent(self, event) def timerEvent(self, event): dt = QDateTime.currentDateTimeUtc() self.labelTimeUtc.setText(dt.time().toString(u'hh:mm:ss'))