def testContextSingle(self): """ Various tests to ensure that datum transforms are correctly set respecting context """ context = QgsCoordinateTransformContext() context.addSourceDatumTransform(QgsCoordinateReferenceSystem('EPSG:28356'), 1) context.addDestinationDatumTransform(QgsCoordinateReferenceSystem('EPSG:4283'), 2) context.addSourceDestinationDatumTransform(QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem('EPSG:4283'), 3, 4) transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:28354'), QgsCoordinateReferenceSystem('EPSG:28353'), context) # should be no datum transforms self.assertEqual(transform.sourceDatumTransformId(), -1) self.assertEqual(transform.destinationDatumTransformId(), -1) # matching source transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem('EPSG:28353'), context) self.assertEqual(transform.sourceDatumTransformId(), 1) self.assertEqual(transform.destinationDatumTransformId(), -1) # matching dest transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:28354'), QgsCoordinateReferenceSystem('EPSG:4283'), context) self.assertEqual(transform.sourceDatumTransformId(), -1) self.assertEqual(transform.destinationDatumTransformId(), 2) # matching src/dest pair transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem('EPSG:4283'), context) self.assertEqual(transform.sourceDatumTransformId(), 3) self.assertEqual(transform.destinationDatumTransformId(), 4) # test manual overwriting transform.setSourceDatumTransform(11) transform.setDestinationDatumTransform(13) self.assertEqual(transform.sourceDatumTransformId(), 11) self.assertEqual(transform.destinationDatumTransformId(), 13) # test that auto datum setting occurs when updating src/dest crs transform.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:28356')) self.assertEqual(transform.sourceDatumTransformId(), 3) self.assertEqual(transform.destinationDatumTransformId(), 4) transform.setSourceDatumTransform(11) transform.setDestinationDatumTransform(13) transform.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4283')) self.assertEqual(transform.sourceDatumTransformId(), 3) self.assertEqual(transform.destinationDatumTransformId(), 4) transform.setSourceDatumTransform(11) transform.setDestinationDatumTransform(13) # delayed context set transform = QgsCoordinateTransform() self.assertEqual(transform.sourceDatumTransformId(), -1) self.assertEqual(transform.destinationDatumTransformId(), -1) transform.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:28356')) transform.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4283')) self.assertEqual(transform.sourceDatumTransformId(), -1) self.assertEqual(transform.destinationDatumTransformId(), -1) transform.setContext(context) self.assertEqual(transform.sourceDatumTransformId(), 3) self.assertEqual(transform.destinationDatumTransformId(), 4)
def testContextProj6(self): """ Various tests to ensure that datum transforms are correctly set respecting context """ context = QgsCoordinateTransformContext() context.addCoordinateOperation(QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem('EPSG:4283'), 'proj') transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:28354'), QgsCoordinateReferenceSystem('EPSG:28353'), context) self.assertEqual(list(transform.context().coordinateOperations().keys()), [('EPSG:28356', 'EPSG:4283')]) # should be no coordinate operation self.assertEqual(transform.coordinateOperation(), '') # matching source transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem('EPSG:28353'), context) self.assertEqual(transform.coordinateOperation(), '') # matching dest transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:28354'), QgsCoordinateReferenceSystem('EPSG:4283'), context) self.assertEqual(transform.coordinateOperation(), '') # matching src/dest pair transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem('EPSG:4283'), context) self.assertEqual(transform.coordinateOperation(), 'proj') # test manual overwriting transform.setCoordinateOperation('proj2') self.assertEqual(transform.coordinateOperation(), 'proj2') # test that auto operation setting occurs when updating src/dest crs transform.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:28356')) self.assertEqual(transform.coordinateOperation(), 'proj') transform.setCoordinateOperation('proj2') transform.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4283')) self.assertEqual(transform.coordinateOperation(), 'proj') transform.setCoordinateOperation('proj2') # delayed context set transform = QgsCoordinateTransform() self.assertEqual(transform.coordinateOperation(), '') transform.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:28356')) transform.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4283')) self.assertEqual(transform.coordinateOperation(), '') transform.setContext(context) self.assertEqual(transform.coordinateOperation(), 'proj') self.assertEqual(list(transform.context().coordinateOperations().keys()), [('EPSG:28356', 'EPSG:4283')])
def testContextSingle(self): """ Various tests to ensure that datum transforms are correctly set respecting context """ context = QgsCoordinateTransformContext() context.addSourceDatumTransform( QgsCoordinateReferenceSystem('EPSG:28356'), 1) context.addDestinationDatumTransform( QgsCoordinateReferenceSystem('EPSG:4283'), 2) context.addSourceDestinationDatumTransform( QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem('EPSG:4283'), 3, 4) transform = QgsCoordinateTransform( QgsCoordinateReferenceSystem('EPSG:28354'), QgsCoordinateReferenceSystem('EPSG:28353'), context) # should be no datum transforms self.assertEqual(transform.sourceDatumTransformId(), -1) self.assertEqual(transform.destinationDatumTransformId(), -1) # matching source transform = QgsCoordinateTransform( QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem('EPSG:28353'), context) self.assertEqual(transform.sourceDatumTransformId(), 1) self.assertEqual(transform.destinationDatumTransformId(), -1) # matching dest transform = QgsCoordinateTransform( QgsCoordinateReferenceSystem('EPSG:28354'), QgsCoordinateReferenceSystem('EPSG:4283'), context) self.assertEqual(transform.sourceDatumTransformId(), -1) self.assertEqual(transform.destinationDatumTransformId(), 2) # matching src/dest pair transform = QgsCoordinateTransform( QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem('EPSG:4283'), context) self.assertEqual(transform.sourceDatumTransformId(), 3) self.assertEqual(transform.destinationDatumTransformId(), 4) # test manual overwriting transform.setSourceDatumTransform(11) transform.setDestinationDatumTransform(13) self.assertEqual(transform.sourceDatumTransformId(), 11) self.assertEqual(transform.destinationDatumTransformId(), 13) # test that auto datum setting occurs when updating src/dest crs transform.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:28356')) self.assertEqual(transform.sourceDatumTransformId(), 3) self.assertEqual(transform.destinationDatumTransformId(), 4) transform.setSourceDatumTransform(11) transform.setDestinationDatumTransform(13) transform.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4283')) self.assertEqual(transform.sourceDatumTransformId(), 3) self.assertEqual(transform.destinationDatumTransformId(), 4) transform.setSourceDatumTransform(11) transform.setDestinationDatumTransform(13) # delayed context set transform = QgsCoordinateTransform() self.assertEqual(transform.sourceDatumTransformId(), -1) self.assertEqual(transform.destinationDatumTransformId(), -1) transform.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:28356')) transform.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4283')) self.assertEqual(transform.sourceDatumTransformId(), -1) self.assertEqual(transform.destinationDatumTransformId(), -1) transform.setContext(context) self.assertEqual(transform.sourceDatumTransformId(), 3) self.assertEqual(transform.destinationDatumTransformId(), 4)
class Coordinator(): """YACUP plugin""" def __init__(self, iface, mainWindow=None): """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 """ # store references to important stuff from QGIS self.iface = iface self.canvas = iface.mapCanvas() self._project = QgsProject.instance() self._observingLayer = None self._uiHook = mainWindow if isinstance(mainWindow, QMainWindow) else iface # region: LOCALE - UNUSED # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # #initialize locale localeString = QSettings().value('locale/userLocale') if (localeString): locale = localeString[0:2] else: locale = QLocale().language() locale_path = os.path.join(self.plugin_dir, 'i18n', 'coordinator_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) QCoreApplication.installTranslator(self.translator) # endregion # plugin housekeeping: self.openPanelAction = None self.pluginIsActive = False self.dockwidget = None # Init CRS Transformation: self._inputCrs = None self._outputCrs = None # self._transform : input -> output transformation # self._canvasTransform: input -> canvas transformation self.__initTransformers() # initialize canvas marker icon: self.marker = QgsVertexMarker(self.canvas) self.marker.hide() self.marker.setColor(QColor(255, 0, 0)) self.marker.setIconSize(14) self.marker.setIconType( QgsVertexMarker.ICON_CIRCLE ) # See the enum IconType from http://www.qgis.org/api/classQgsVertexMarker.html self.marker.setPenWidth(3) # init point picker: self.mapTool = QgsMapToolEmitPoint(self.canvas) # LIFECYCLE : def initGui(self): """Create the menu entry inside the QGIS GUI.""" icon = QIcon(':/plugins/coordinator/icons/marker.svg') menuTitle = CT.tr("Open Coordinator") self.openPanelAction = QAction(icon, menuTitle) self.openPanelAction.triggered.connect(self.run) self.iface.pluginMenu().addAction(self.openPanelAction) #-------------------------------------------------------------------------- def onClosePlugin(self): """Cleanup necessary items here when plugin dockwidget is closed""" # remove the marker from the canvas: self.marker.hide() self.dockwidget.closingPlugin.disconnect(self.onClosePlugin) # disconnect from the GUI-signals self._disconnectExternalSignals() self.pluginIsActive = False def unload(self): """Removes the plugin menu item from QGIS GUI.""" self.iface.pluginMenu().removeAction(self.openPanelAction) self.marker.hide() self._disconnectExternalSignals() #-------------------------------------------------------------------------- # PRIVATE HELPERS: def __initTransformers(self): """Initializes both coordinate transform object needed: the transformation from the input CRS to the output CRS (self._transform) and a tranformer from the input CRS to the current canvas CRS.""" inputCrs = self._inputCrs if self._inputCrs != None else QgsCoordinateReferenceSystem( "EPSG:4326") outputCrs = self._outputCrs if self._outputCrs != None else QgsCoordinateReferenceSystem( "EPSG:4326") self._transform = QgsCoordinateTransform(inputCrs, outputCrs, self._project) canvasCrs = self.canvas.mapSettings().destinationCrs() # coordinatorLog("init canvas transform with %s -> %s" # % (inputCrs.authid(), canvasCrs.authid() if canvasCrs else "NONE!!") # ) self._canvasTransform = QgsCoordinateTransform(inputCrs, canvasCrs, self._project) def __checkEnableAddFeatureButton(self): shouldEnable = bool(self.dockwidget.hasInput() and self.__compatibleMapTool()) return shouldEnable def __compatibleMapTool(self): newTool = self.canvas.mapTool() if (newTool != None and (newTool.flags() & QgsMapTool.EditTool)): newTool = sip.cast(newTool, QgsMapToolCapture) # pre-check probably fixing issue #3 regarding Enums with Qt >= 5.11: # --> https://www.riverbankcomputing.com/static/Docs/PyQt5/gotchas.html#enums try: validModes = (QgsMapToolCapture.CaptureMode.CapturePoint, QgsMapToolCapture.CaptureMode.CapturePolygon, QgsMapToolCapture.CaptureMode.CaptureLine) except AttributeError: validModes = (QgsMapToolCapture.CapturePoint, QgsMapToolCapture.CapturePolygon, QgsMapToolCapture.CaptureLine) if newTool.mode() in validModes: return newTool return False def _disconnectExternalSignals(self): try: self.iface.mapCanvas().destinationCrsChanged.disconnect( self.mapCanvasCrsChanged) except TypeError: pass try: self.canvas.mapToolSet.disconnect(self.mapToolChanged) except TypeError: pass try: self.iface.currentLayerChanged.disconnect(self.currentLayerChanged) except TypeError: pass try: self.iface.projectRead.disconnect(self.projectRead) except TypeError: pass if (self._observingLayer != None) and sip.isdeleted( self._observingLayer): self._observingLayer = None if self._observingLayer: try: self._observingLayer.crsChanged.disconnect( self.layerChangedCrs) except TypeError: pass def _currentEffectiveCrsInMap(self): activeLayer = self.iface.activeLayer() if (activeLayer): if type(activeLayer) == QgsVectorLayer: return activeLayer.sourceCrs() elif type(activeLayer) == QgsRasterLayer: return activeLayer.crs() else: return self.canvas.mapSettings().destinationCrs() def _warnIfPointOutsideCanvas(self): if (self.dockwidget.hasInput() and not self.canvas.extent().contains( self.inputCoordinatesInCanvasCrs())): self.setWarningMessage(CT.tr("outside of map extent")) else: self.setWarningMessage(None) #-------------------------------------------------------------------------- # GETTERS/SETTERS def setInputCrs(self, crs): oldCrs = self._inputCrs if (oldCrs == None) or (crs.authid() != oldCrs.authid()): #coordinatorLog("setting input CRS to %s" % crs.authid()) currentCoordinates = self.dockwidget.inputCoordinates() self._inputCrs = crs self.dockwidget.setSectionCrs(CoordinatorDockWidget.SectionInput, crs) self._transform.setSourceCrs(crs) self._canvasTransform.setSourceCrs(crs) if (oldCrs != None and self.dockwidget.hasInput()): # make sure we transform the currently set coordinate # to the new Coordinate System : t = QgsCoordinateTransform(oldCrs, crs, QgsProject.instance()) transformedPoint = t.transform( QgsPointXY(currentCoordinates[0], currentCoordinates[1])) self.dockwidget.setInputPoint(transformedPoint) else: self.dockwidget.clearSection(CoordinatorDockWidget.SectionBoth) def inputCrs(self): return self._inputCrs def setOutputCrs(self, crs): #coordinatorLog("changing output CRS %s -> %s" % (self._outputCrs.authid() if self._outputCrs else "NONE!", crs.authid()) ) oldCrs = self._outputCrs if (oldCrs == None) or (oldCrs.authid() != crs.authid()): self._outputCrs = crs self.dockwidget.setSectionCrs(CoordinatorDockWidget.SectionOutput, crs) self._transform.setDestinationCrs(crs) self.process() def outputCrs(self): return self._outputCrs def setWarningMessage(self, message): self.dockwidget.setWarningMessage(message) # ACTIONS : def openCrsSelectionDialogForSection(self, section): projSelector = QgsProjectionSelectionDialog() if (projSelector.exec()): selectedCrs = projSelector.crs() # workaround for checking if there was no CRS selected # but user clicked 'OK': check if authid-string is empty: if not selectedCrs.authid(): return if section == CoordinatorDockWidget.SectionInput: self.setInputCrs(selectedCrs) elif section == CoordinatorDockWidget.SectionOutput: self.setOutputCrs(selectedCrs) def setOutputCrsToCanvasCrs(self): crs = self.canvas.mapSettings().destinationCrs() self.setOutputCrs(crs) def connectCrsToCanvas(self, section, connect): #coordinatorLog("%s %s" % (section, connect)) if section == CoordinatorDockWidget.SectionOutput: if (connect): # connect to map # disable dialog for selecting output CRS: self.dockwidget.outputCrs.clicked.disconnect() # set CRS to be canvas' CRS and follow it self.setOutputCrsToCanvasCrs() else: # enable dialog selection self.dockwidget.outputCrs.clicked.connect( partial(self.openCrsSelectionDialogForSection, CoordinatorDockWidget.SectionOutput)) def addCurrentCoordinatesToDigitizeSession(self): editTool = self.__compatibleMapTool() if (not editTool): return False result = False point = self.inputCoordinatesInCanvasCrs() if (editTool.mode() == QgsMapToolCapture.CaptureMode.CapturePoint): #coordinatorLog("Point Capture!") layer = self.iface.activeLayer() # if canvas CRS is not layer CRS we need to transform first: transform = QgsCoordinateTransform( self.canvas.mapSettings().destinationCrs(), layer.sourceCrs(), self._project) point = transform.transform( point, QgsCoordinateTransform.ForwardTransform) geometry = QgsGeometry.fromPointXY(point) feature = QgsVectorLayerUtils.createFeature( layer, geometry, {}, layer.createExpressionContext()) if ((len(layer.fields()) < 1) or self.iface.openFeatureForm(layer, feature)): result = layer.addFeature(feature) if (result): #coordinatorLog("Point successfully written to layer") pass layer.triggerRepaint() elif ((editTool.mode() == QgsMapToolCapture.CaptureMode.CapturePolygon) or (editTool.mode() == QgsMapToolCapture.CaptureMode.CaptureLine)): #coordinatorLog("Rubberband Capture!") result = (editTool.addVertex(point) == 0) else: return False if (result): self.dockwidget.showInfoMessage(CT.tr("coordinate added"), 1500) else: self.setWarningMessage(CT.tr("adding coordinate failed")) return result def switchInputOutputCrs(self): inputCrs = self._inputCrs self.setInputCrs(self._outputCrs) self.setOutputCrs(inputCrs) if self.dockwidget.outputCrsConn.isChecked() and ( self._outputCrs.authid() != self._inputCrs.authid()): self.dockwidget.outputCrsConn.setChecked(False) def _showMarker(self, show): if show and self.dockwidget.hasInput(): self.marker.show() else: self.marker.hide() # API : def enableMarker(self, show): self._showMarker(show) self.dockwidget.showMarker.setChecked(show) # PIPELINE : def ensureValidInputGui(self): self.dockwidget.addFeatureButton.setEnabled( self.__checkEnableAddFeatureButton()) self._warnIfPointOutsideCanvas() # make sure we show the marker now: if self.dockwidget.hasInput(): if self.dockwidget.showMarker.isChecked(): self.marker.show() else: self.marker.hide() self.dockwidget.setInputToDMS(self.dockwidget.inputAsDMS.isChecked() & self._inputCrs.isGeographic()) def process(self): #coordinatorLog("about to process input") if (self.dockwidget.hasInput()): (x, y) = self.dockwidget.inputCoordinates() # coordinatorLog("Input: %f %f " % (x, y) ) transformedPoint = self._transform.transform(QgsPointXY(x, y)) # coordinatorLog("Transformed point: %f %f " % (transformedPoint.x(), transformedPoint.y()) ) self.dockwidget.setResultPoint(transformedPoint) self.marker.setCenter(self.inputCoordinatesInCanvasCrs()) else: self.dockwidget.clearFieldsInSection( CoordinatorDockWidget.SectionOutput) def reset(self): self.__initTransformers() self.dockwidget.resetInterface() self.dockwidget.setEastingInverted(False) self.dockwidget.setNorthingInverted(False) def inputCoordinatesInCanvasCrs(self): (x, y) = self.dockwidget.inputCoordinates() result = self._canvasTransform.transform(QgsPointXY(x, y)) #coordinatorLog("transformation: (%s,%s) are (%s,%s)" % (x,y, result.x(), result.y())) #coordinatorLog(" %s -> %s" % (self._canvasTransform.sourceCrs().authid(), self._canvasTransform.destinationCrs().authid()) ) return result # SLOTS : def mapCanvasCrsChanged(self): self._canvasTransform.setDestinationCrs( self.canvas.mapSettings().destinationCrs()) #if(self.dockwidget.outputCrsConn.isChecked()): # self.setOutputCrs(self.canvas.mapSettings().destinationCrs()) def inputCoordinatesChanged(self): #Coordinator.log("Input changed") self.process() self.ensureValidInputGui() def inputFormatChanged(self): self.ensureValidInputGui() def outputFormatChanged(self): self.process() def moveCanvasButtonClicked(self): self.canvas.setCenter(self.inputCoordinatesInCanvasCrs()) def mapCrsConnectionButtonToggled(self, forSection, enabled): self.connectCrsToCanvas(forSection, enabled) def showMarkerButtonToggled(self, show): self._showMarker(show) def captureCoordsButtonToggled(self, enabled): #coordinatorLog( "enable Capture Coords: %s" % enabled) if (enabled): self.canvas.setMapTool(self.mapTool) self.mapTool.canvasClicked.connect(self.canvasClickedWithPicker) else: try: self.mapTool.canvasClicked.disconnect( self.canvasClickedWithPicker) except TypeError: pass self.canvas.unsetMapTool(self.mapTool) def canvasClickedWithPicker(self, point, button): # button is the MouseButton #coordinatorLog(type(button).__name__) if QApplication.keyboardModifiers() and Qt.ControlModifier: self.setInputCrs(self.canvas.mapSettings().destinationCrs()) # coordinatorLog("Current Canvas Transform is %s -> %s (we do the reverse to get input)" # % (self._canvasTransform.sourceCrs().authid(), self._canvasTransform.destinationCrs().authid()) # ) point = self._canvasTransform.transform( point, QgsCoordinateTransform.ReverseTransform) self.dockwidget.setInputPoint(point) def canvasMoved(self): self._warnIfPointOutsideCanvas() def mapToolChanged(self): #coordinatorLog("map tools changed") #coordinatorLog( type( self.canvas.mapTool() ).__name__ ) currentMapTool = self.canvas.mapTool() if (currentMapTool == self.mapTool): # user selected our coordinate capture tool -> do nothing pass elif (self.__checkEnableAddFeatureButton()): # user selected a tool to modify features -> enable our add feature button self.dockwidget.addFeatureButton.setEnabled(True) self.dockwidget.captureCoordButton.setChecked(False) else: # user selected a totally unrelated tool -> make sure our coordinate capture tool is disabled self.dockwidget.captureCoordButton.setChecked(False) self.dockwidget.addFeatureButton.setEnabled(False) def addFeatureClicked(self): self.addCurrentCoordinatesToDigitizeSession() def projectRead(self): #coordinatorLog("new project") self._project = QgsProject.instance() self.reset() def currentLayerChanged(self, layer): if self._observingLayer: self._observingLayer.crsChanged.disconnect(self.layerChangedCrs) if layer: self._observingLayer = layer self._observingLayer.crsChanged.connect(self.layerChangedCrs) #coordinatorLog("%s" % type(layer).__name__) if self.dockwidget.outputCrsConn.isChecked(): self.setOutputCrs(self._currentEffectiveCrsInMap()) def layerChangedCrs(self): #coordinatorLog("%s" % type(layer).__name__) if self.dockwidget.outputCrsConn.isChecked(): self.setOutputCrs(self._currentEffectiveCrsInMap()) def run(self): """Run method that loads and starts the plugin""" #coordinatorLog("run", "Coordinator") if not self.pluginIsActive: self.pluginIsActive = True #QgsMessageLog.logMessage("Starting", "Coordinator") # dockwidget may not exist if: # first run of plugin # removed on close (see self.onClosePlugin method) if self.dockwidget == None: # Create the dockwidget (after translation) and keep reference self.dockwidget = CoordinatorDockWidget() #for child in self.dockwidget.children(): # self.log("Child: %s" % child.objectName()) # MA LOGIC: # EXTERNAL connections self.canvas.destinationCrsChanged.connect(self.mapCanvasCrsChanged) self.canvas.mapToolSet.connect(self.mapToolChanged) self.canvas.extentsChanged.connect(self.canvasMoved) self.iface.projectRead.connect(self.projectRead) self.iface.currentLayerChanged.connect(self.currentLayerChanged) # CONNECT the initially active buttons from the GUI: self.dockwidget.selectCrsButton.clicked.connect( partial(self.openCrsSelectionDialogForSection, CoordinatorDockWidget.SectionInput)) self.dockwidget.mapConnectionChanged.connect( self.mapCrsConnectionButtonToggled) # set the inital CRS: self.setInputCrs(QgsCoordinateReferenceSystem("EPSG:4326")) self.setOutputCrs(self.canvas.mapSettings().destinationCrs()) # connect the marker button : self.dockwidget.showMarker.clicked.connect( self.showMarkerButtonToggled) self.dockwidget.moveCanvas.clicked.connect( self.moveCanvasButtonClicked) self.dockwidget.captureCoordButton.clicked.connect( self.captureCoordsButtonToggled) self.dockwidget.addFeatureButton.clicked.connect( self.addFeatureClicked) self.dockwidget.inputFormatButtonGroup.buttonClicked.connect( self.inputFormatChanged) self.dockwidget.resultFormatButtonGroup.buttonClicked.connect( self.outputFormatChanged) self.dockwidget.inputChanged.connect(self.inputCoordinatesChanged) # connect to provide cleanup on closing of dockwidget self.dockwidget.closingPlugin.connect(self.onClosePlugin) # SETUP: self.enableMarker(True) self._canvasTransform.setDestinationCrs( self.canvas.mapSettings().destinationCrs()) # show the dockwidget # TODO: fix to allow choice of dock location self._uiHook.addDockWidget(Qt.LeftDockWidgetArea, self.dockwidget) self.dockwidget.show()
def testContextProj6(self): """ Various tests to ensure that datum transforms are correctly set respecting context """ context = QgsCoordinateTransformContext() context.addCoordinateOperation( QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem('EPSG:4283'), 'proj') transform = QgsCoordinateTransform( QgsCoordinateReferenceSystem('EPSG:28354'), QgsCoordinateReferenceSystem('EPSG:28353'), context) self.assertEqual( list(transform.context().coordinateOperations().keys()), [('EPSG:28356', 'EPSG:4283')]) # should be no coordinate operation self.assertEqual(transform.coordinateOperation(), '') # should default to allowing fallback transforms self.assertTrue(transform.allowFallbackTransforms()) transform = QgsCoordinateTransform( QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem('EPSG:4283'), context) self.assertTrue(transform.allowFallbackTransforms()) context.addCoordinateOperation( QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem('EPSG:4283'), 'proj', False) transform = QgsCoordinateTransform( QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem('EPSG:4283'), context) self.assertFalse(transform.allowFallbackTransforms()) # matching source transform = QgsCoordinateTransform( QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem('EPSG:28353'), context) self.assertEqual(transform.coordinateOperation(), '') # matching dest transform = QgsCoordinateTransform( QgsCoordinateReferenceSystem('EPSG:28354'), QgsCoordinateReferenceSystem('EPSG:4283'), context) self.assertEqual(transform.coordinateOperation(), '') # matching src/dest pair transform = QgsCoordinateTransform( QgsCoordinateReferenceSystem('EPSG:28356'), QgsCoordinateReferenceSystem('EPSG:4283'), context) self.assertEqual(transform.coordinateOperation(), 'proj') # test manual overwriting transform.setCoordinateOperation('proj2') self.assertEqual(transform.coordinateOperation(), 'proj2') transform.setAllowFallbackTransforms(False) self.assertFalse(transform.allowFallbackTransforms()) transform.setAllowFallbackTransforms(True) self.assertTrue(transform.allowFallbackTransforms()) # test that auto operation setting occurs when updating src/dest crs transform.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:28356')) self.assertEqual(transform.coordinateOperation(), 'proj') transform.setCoordinateOperation('proj2') transform.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4283')) self.assertEqual(transform.coordinateOperation(), 'proj') transform.setCoordinateOperation('proj2') # delayed context set transform = QgsCoordinateTransform() self.assertEqual(transform.coordinateOperation(), '') transform.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:28356')) transform.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4283')) self.assertEqual(transform.coordinateOperation(), '') transform.setContext(context) self.assertEqual(transform.coordinateOperation(), 'proj') self.assertEqual( list(transform.context().coordinateOperations().keys()), [('EPSG:28356', 'EPSG:4283')])
class MobileItem(QObject): ''' A Mobile Item that reveives its position from a dataprovider and is displayed on the canvas Could be everything liek vehicles or simple beacons ''' mobileItemCount = 0 newPosition = pyqtSignal(float, QgsPointXY, float, float) newAttitude = pyqtSignal(float, float, float) # heading, pitch, roll timeout = pyqtSignal() def __init__(self, iface, params={}, parent=None): ''' 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 item :type params: dictionary :param parent: Parent object for the new item. Defaults None. :type parent: QObject ''' super(MobileItem, self).__init__(parent) self.iface = iface self.canvas = iface.mapCanvas() MobileItem.mobileItemCount += 1 self.name = params.setdefault( 'Name', 'MobileItem_' + str(MobileItem.mobileItemCount)) self.marker = PositionMarker(self.canvas, params) self.marker.setToolTip(self.name) self.dataProvider = params.get('provider', dict()) self.messageFilter = dict() self.extData = dict() self.coordinates = None self.position = None self.heading = 0.0 self.depth = 0.0 self.altitude = 0.0 self.lastFix = 0.0 self.crsXform = QgsCoordinateTransform() self.crsXform.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:4326')) self.onCrsChange() self.canvas.destinationCrsChanged.connect(self.onCrsChange) if hasattr(self.canvas, 'magnificationChanged'): self.canvas.magnificationChanged.connect( self.onMagnificationChanged) self.timer = QTimer(self) self.timer.timeout.connect(self.timeout) self.notifyCount = int(params.get('nofixNotify', 0)) self.fadeOut = bool(params.get('fadeOut', False)) if self.notifyCount or self.fadeOut: self.timer.timeout.connect(self.notifyTimeout) self.timeoutCount = 0 self.timeoutTime = int(params.get('timeout', 3000)) self.notifyDuration = int(params.get('NotifyDuration', 0)) self.timedOut = False self.enabled = True def removeFromCanvas(self): ''' Remove the item and its track from the canvas ''' self.marker.removeFromCanvas() def properties(self): ''' Return the items properties as dictionary :returns: Items properties :rtype: dict ''' d = { 'Name': self.name, 'timeout': self.timeoutTime, 'nofixNotify': self.notifyCount, 'fadeOut': self.fadeOut, 'enabled': self.enabled, 'provider': self.dataProvider } d.update(self.marker.properties()) return d def subscribePositionProvider(self, provider, filterId=None): ''' Subscribe the provider for this item by connecting to the providers signals :param provider: Provider to connect to :type provider: DataProvider :param filterId: Filter Id for this item :type filterId: ''' provider.newDataReceived.connect(self.processNewData) try: if filterId['id'] not in (None, 'None') or filterId['flags']: self.messageFilter[provider.name] = filterId elif provider.name in self.messageFilter: self.messageFilter.pop(provider.name, None) except (KeyError, TypeError): self.messageFilter.pop(provider.name, None) def unsubscribePositionProvider(self, provider): ''' Unsubscribe provider by disconnecting the providers signals :param provider: Provider to diconnect from :type provider: DataProvider ''' try: provider.newDataReceived.disconnect(self.processData) self.messageFilter.pop(provider.name, None) except KeyError: pass @pyqtSlot(dict) def processNewData(self, data): ''' Process incoming data from the data provider :param data: Positon or attitude data :type data: dict ''' if not self.enabled: return flags = list() try: pname = data['name'] flags = self.messageFilter[pname]['flags'] if not self.messageFilter[pname]['id'] in (None, 'None'): if not data['id'] in (self.messageFilter[pname]['id'], str(self.messageFilter[pname]['id'])): return except Exception: pass self.extData.update(data) if '-pos' not in flags: if 'lat' in data and 'lon' in data: if self.fadeOut and self.timedOut: self.marker.setVisible(True) self.timedOut = False self.position = QgsPointXY(data['lon'], data['lat']) self.heading = data.get('heading', -9999.9) self.depth = data.get('depth', -9999.9) self.altitude = data.get('altitude', -9999.9) try: self.coordinates = self.crsXform.transform(self.position) self.marker.setMapPosition(self.coordinates) if 'time' in data: self.lastFix = data['time'] self.newPosition.emit( self.lastFix, self.position, self.extData.get('depth', -9999.9), self.extData.get('altitude', -9999.9)) self.timer.start(self.timeoutTime) self.timeoutCount = 0 except QgsCsException: pass elif self.position is not None: if 'depth' in data or 'altitude' in data: self.newPosition.emit( self.lastFix, self.position, self.extData.get('depth', -9999.9), self.extData.get('altitude', -9999.9)) if 'heading' in data and '-head' not in flags: self.newAttitude.emit(data['heading'], data.get('pitch', 0.0), data.get('roll', 0.0)) self.marker.newHeading(data['heading']) self.heading = data['heading'] elif 'course' in data and '+course' in flags: self.newAttitude.emit(data['course'], data.get('pitch', 0.0), data.get('roll', 0.0)) self.marker.newHeading(data['course']) self.heading = data['course'] @pyqtSlot(float) def onScaleChange(self, ): ''' Slot called when the map is zoomed :param scale: New scale :type scale: float ''' self.marker.updatePosition() @pyqtSlot() def onCrsChange(self): ''' SLot called when the mapcanvas CRS is changed ''' crsDst = self.canvas.mapSettings().destinationCrs() self.crsXform.setDestinationCrs(crsDst) self.marker.updatePosition() @pyqtSlot(float) def onMagnificationChanged(self, ): ''' Slot called when the map magnification has changed :param scale: New scale :type scale: float ''' self.marker.updateMapMagnification() @pyqtSlot(bool) def setEnabled(self, enabled): ''' Hide or display the item and its track on the map :param enabled: what to do :type enabled: bool ''' self.enabled = enabled self.marker.setVisible(self.enabled) self.marker.resetPosition() self.extData.clear() if self.enabled: self.timer.start(self.timeoutTime) self.timeoutCount = 0 else: self.timer.stop() @pyqtSlot() def deleteTrack(self): ''' Delete the track all points ''' self.marker.deleteTrack() @pyqtSlot() def centerOnMap(self): ''' Center the item on the map ''' if self.coordinates is not None: self.canvas.setCenter(self.coordinates) self.canvas.refresh() def reportPosition(self): ''' Report the position of the item. Used for logging :returns: geographic postion, depth and altitude :rtype: float, float, float, float, float ''' if self.position is None: return -9999.9, -9999.9, -9999.9, 0.0, -9999.9 return self.position.y(), self.position.x( ), self.depth, self.heading, self.altitude @pyqtSlot() def notifyTimeout(self): if self.fadeOut and not self.timedOut: self.marker.setVisible(False) self.timedOut = True if self.notifyCount: self.timeoutCount += 1 if self.timeoutCount == self.notifyCount: msg = self.tr(u'No fix for %s since more than %d seconds!') % ( self.name, self.timeoutTime * self.timeoutCount / 1000) w = self.iface.messageBar().createMessage( self.tr(u'PosiView Attention'), msg) label = QLabel(w) m = QMovie(':/plugins/PosiView/hand.gif') m.setSpeed(75) label.setMovie(m) m.setParent(label) m.start() w.layout().addWidget(label) self.iface.messageBar().pushWidget( w, level=Qgis.Critical, duration=self.notifyDuration) def getTrack(self): tr = [e[1] for e in self.marker.track] return tr def applyTrack(self, track): self.marker.setTrack(track)
class CoordinateCapture: """QGIS Plugin Implementation.""" def __init__(self, iface): """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 """ # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join( self.plugin_dir, 'i18n', 'CoordinateCapture_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) QCoreApplication.installTranslator(self.translator) # Declare instance attributes self.actions = [] self.menu = self.tr(u'&Coordinate Capture') # TODO: We are going to let the user set this up in a future iteration # print "** INITIALIZING CoordinateCapture" self.pluginIsActive = False self.dockwidget = None self.crs = QgsCoordinateReferenceSystem("EPSG:4326") self.transform = QgsCoordinateTransform() self.transform.setDestinationCrs(self.crs) if self.crs.mapUnits() == QgsUnitTypes.DistanceDegrees: self.userCrsDisplayPrecision = 5 else: self.userCrsDisplayPrecision = 3 self.canvasCrsDisplayPrecision = None self.iface.mapCanvas().destinationCrsChanged.connect(self.setSourceCrs) self.setSourceCrs() self.mapTool = CoordinateCaptureMapTool(self.iface.mapCanvas()) self.mapTool.mouseMoved.connect(self.mouseMoved) self.mapTool.mouseClicked.connect(self.mouseClicked) # noinspection PyMethodMayBeStatic def tr(self, message): """Get the translation for a string using Qt translation API. We implement this ourselves since we do not inherit QObject. :param message: String for translation. :type message: str, QString :returns: Translated version of message. :rtype: QString """ # noinspection PyTypeChecker,PyArgumentList,PyCallByClass return QCoreApplication.translate('CoordinateCapture', message) def add_action( self, icon_path, text, callback, enabled_flag=True, add_to_menu=True, add_to_toolbar=True, status_tip=None, whats_this=None, parent=None): """Add a toolbar icon to the toolbar. :param icon_path: Path to the icon for this action. Can be a resource path (e.g. ':/plugins/foo/bar.png') or a normal file system path. :type icon_path: str :param text: Text that should be shown in menu items for this action. :type text: str :param callback: Function to be called when the action is triggered. :type callback: function :param enabled_flag: A flag indicating if the action should be enabled by default. Defaults to True. :type enabled_flag: bool :param add_to_menu: Flag indicating whether the action should also be added to the menu. Defaults to True. :type add_to_menu: bool :param add_to_toolbar: Flag indicating whether the action should also be added to the toolbar. Defaults to True. :type add_to_toolbar: bool :param status_tip: Optional text to show in a popup when mouse pointer hovers over the action. :type status_tip: str :param parent: Parent widget for the new action. Defaults None. :type parent: QWidget :param whats_this: Optional text to show in the status bar when the mouse pointer hovers over the action. :returns: The action that was created. Note that the action is also added to self.actions list. :rtype: QAction """ icon = QIcon(icon_path) action = QAction(icon, text, parent) action.triggered.connect(callback) action.setEnabled(enabled_flag) if status_tip is not None: action.setStatusTip(status_tip) if whats_this is not None: action.setWhatsThis(whats_this) if add_to_toolbar: self.iface.addVectorToolBarIcon(action) if add_to_menu: self.iface.addPluginToVectorMenu( "", action) self.actions.append(action) return action def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" icon_path = ':/plugins/coordinate_capture/coordinate_capture.png' self.add_action( icon_path, text=self.tr(u'Coordinate Capture'), callback=self.run, parent=self.iface.mainWindow()) # -------------------------------------------------------------------------- def onClosePlugin(self): """Cleanup necessary items here when plugin dockwidget is closed""" # print "** CLOSING CoordinateCapture" # disconnects self.dockwidget.closingPlugin.disconnect(self.onClosePlugin) # remove this statement if dockwidget is to remain # for reuse if plugin is reopened # Commented next statement since it causes QGIS crashe # when closing the docked window: # self.dockwidget = None self.pluginIsActive = False self.mapTool.deactivate() def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" # print "** UNLOAD CoordinateCapture" self.mapTool.deactivate() for action in self.actions: self.iface.removePluginVectorMenu( "", action) self.iface.removeVectorToolBarIcon(action) # -------------------------------------------------------------------------- def run(self): """Run method that loads and starts the plugin""" if not self.pluginIsActive: self.pluginIsActive = True # print "** STARTING CoordinateCapture" # dockwidget may not exist if: # first run of plugin # removed on close (see self.onClosePlugin method) if self.dockwidget == None: # Create the dockwidget (after translation) and keep reference self.dockwidget = CoordinateCaptureDockWidget() self.dockwidget.userCrsToolButton.clicked.connect(self.setCrs) self.dockwidget.captureButton.clicked.connect(self.startCapturing) # connect to provide cleanup on closing of dockwidget self.dockwidget.closingPlugin.connect(self.onClosePlugin) # show the dockwidget # TODO: fix to allow choice of dock location self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dockwidget) self.dockwidget.show() def setCrs(self): selector = QgsProjectionSelectionDialog(self.iface.mainWindow()) selector.setCrs(self.crs) if selector.exec(): self.crs = selector.crs() self.transform.setDestinationCrs(self.crs) if self.crs.mapUnits() == QgsUnitTypes.DistanceDegrees: self.userCrsDisplayPrecision = 5 else: self.userCrsDisplayPrecision = 3 def setSourceCrs(self): self.transform.setSourceCrs(self.iface.mapCanvas().mapSettings().destinationCrs()) if self.iface.mapCanvas().mapSettings().destinationCrs().mapUnits() == QgsUnitTypes.DistanceDegrees: self.canvasCrsDisplayPrecision = 5 else: self.canvasCrsDisplayPrecision = 3 def mouseMoved(self, point: QgsPointXY): if self.dockwidget.trackMouseButton.isChecked(): self.update(point) def mouseClicked(self, point: QgsPointXY): self.dockwidget.trackMouseButton.setChecked(False) self.update(point) def update(self, point: QgsPointXY): userCrsPoint = self.transform.transform(point) self.dockwidget.userCrsEdit.setText('{0:.{2}f}, {1:.{2}f}'.format(userCrsPoint.x(), userCrsPoint.y(), self.userCrsDisplayPrecision)) self.dockwidget.canvasCrsEdit.setText('{0:.{2}f}, {1:.{2}f}'.format(point.x(), point.y(), self.canvasCrsDisplayPrecision)) def startCapturing(self): self.iface.mapCanvas().setMapTool(self.mapTool)
def processAlgorithm(self, parameters, context, feedback): vertices = self.parameterAsSource(parameters, 'INPUT1', context) limites = self.parameterAsSource(parameters, 'INPUT2', context) area = self.parameterAsSource(parameters, 'INPUT3', context) meses = { 1: 'janeiro', 2: 'fevereiro', 3: 'março', 4: 'abril', 5: 'maio', 6: 'junho', 7: 'julho', 8: 'agosto', 9: 'setembro', 10: 'outubro', 11: 'novembro', 12: 'dezembro' } # VALIDAÇÃO DOS DADOS DE ENTRADA!!! # atributos codigo deve ser preenchido # ordem do numeros # Pegando informações dos confrontantes (limites) ListaDescr = [] ListaCont = [] soma = 0 for linha in limites.getFeatures(): Lin_coord = linha.geometry().asMultiPolyline()[0] ListaDescr += [[ self.str2HTML(linha['descr_pnt_inicial']), self.str2HTML(linha['confrontante']) ]] cont = len(Lin_coord) ListaCont += [(soma, cont - 1)] soma += cont - 1 # Pegando o SRC do Projeto SRC = QgsProject.instance().crs().description() # Verificando o SRC if QgsProject.instance().crs().isGeographic(): raise QgsProcessingException( self.tr('The Project CRS must be projected!', 'O SRC do Projeto deve ser Projetado!')) feedback.pushInfo( self.tr('Project CRS is {}.', 'SRC do Projeto é {}.').format(SRC)) # Dados do levantamento #Fields = area.fields() #fieldnames = [field.name() for field in Fields] for feat in area.getFeatures(): feat1 = feat break geom = feat1.geometry() centroideG = geom.centroid().asPoint() # Transformar Coordenadas de Geográficas para o sistema UTM coordinateTransformer = QgsCoordinateTransform() coordinateTransformer.setDestinationCrs(QgsProject.instance().crs()) coordinateTransformer.setSourceCrs( QgsCoordinateReferenceSystem('EPSG:4674')) pnts = {} for feat in vertices.getFeatures(): geom = feat.geometry() if geom.isMultipart(): pnts[feat['ordem']] = [ coordinateTransformer.transform(geom.asMultiPoint()[0]), feat['tipo'], feat['codigo'] ] else: pnts[feat['ordem']] = [ coordinateTransformer.transform(geom.asPoint()), feat['tipo'], feat['codigo'] ] # Cálculo dos Azimutes e Distâncias tam = len(pnts) Az_lista, Dist = [], [] for k in range(tam): pntA = pnts[k + 1][0] pntB = pnts[max((k + 2) % (tam + 1), 1)][0] Az_lista += [(180 / pi) * self.azimute(pntA, pntB)[0]] Dist += [sqrt((pntA.x() - pntB.x())**2 + (pntA.y() - pntB.y())**2)] # Inserindo dados iniciais do levantamento itens = { '[IMOVEL]': self.str2HTML(feat1['imóvel']), '[PROPRIETARIO]': self.str2HTML(feat1['proprietário']), '[UF]': feat1['UF'], '[MATRICULAS]': self.str2HTML(feat1['matrícula']), '[AREA]': '{:,.2f}'.format(feat1['area']).replace(',', 'X').replace( '.', ',').replace('X', '.'), '[SRC]': SRC, '[COMARCA]': self.str2HTML(feat1['município'] + ' - ' + feat1['UF']), '[MUNICIPIO]': self.str2HTML(feat1['município']), '[PERIMETRO]': '{:,.2f}'.format(feat1['perimetro']).replace(',', 'X').replace( '.', ',').replace('X', '.') } for item in itens: self.texto_inicial = self.texto_inicial.replace(item, itens[item]) LINHAS = self.texto_inicial #feedback.pushInfo(str(ListaCont)) for w, t in enumerate(ListaCont): linha0 = self.texto_var1 itens = { '[Vn]': pnts[t[0] + 1][2], '[En]': '{:,.2f}'.format(pnts[t[0] + 1][0].x()).replace( ',', 'X').replace('.', ',').replace('X', '.'), '[Nn]': '{:,.2f}'.format(pnts[t[0] + 1][0].y()).replace( ',', 'X').replace('.', ',').replace('X', '.'), '[Az_n]': self.str2HTML( self.dd2dms(Az_lista[t[0]], 2).replace('.', ',')), '[Dist_n]': '{:,.2f}'.format(Dist[t[0]]).replace(',', 'X').replace( '.', ',').replace('X', '.'), '[Descr_k]': ListaDescr[w][0], '[Confront_k]': ListaDescr[w][1] } for item in itens: linha0 = linha0.replace(item, itens[item]) LINHAS += linha0 LIN0 = '' for k in range(t[0] + 1, t[0] + t[1]): linha1 = self.texto_var2 itens = { '[Vn]': pnts[k + 1][2], '[En]': '{:,.2f}'.format(pnts[k + 1][0].x()).replace( ',', 'X').replace('.', ',').replace('X', '.'), '[Nn]': '{:,.2f}'.format(pnts[k + 1][0].y()).replace( ',', 'X').replace('.', ',').replace('X', '.'), '[Az_n]': self.str2HTML( self.dd2dms(Az_lista[k], 2).replace('.', ',')), '[Dist_n]': '{:,.2f}'.format(Dist[k]).replace(',', 'X').replace( '.', ',').replace('X', '.') } for item in itens: linha1 = linha1.replace(item, itens[item]) LIN0 += linha1 LINHAS += LIN0 # Inserindo dados finais itens = { '[P-01]': pnts[1][2], '[N1]': '{:,.2f}'.format(pnts[1][0].y()).replace(',', 'X').replace( '.', ',').replace('X', '.'), '[E1]': '{:,.2f}'.format(pnts[1][0].x()).replace(',', 'X').replace( '.', ',').replace('X', '.'), '[FUSO]': str(self.FusoHemisf(centroideG)[1]), '[HEMISFERIO]': self.FusoHemisf(centroideG)[0], '[RESP_TEC]': self.str2HTML(feat1['Resp_Tecnico']), '[CREA]': self.str2HTML(feat1['CREA']), '[LOCAL]': self.str2HTML((feat1['município']).title() + ' - ' + (feat1['UF']).upper()), '[DATA]': ((feat1['data_levantamento'].toPyDate()).strftime("%d de {} de %Y") ).format(meses[feat1['data_levantamento'].month()]) } for item in itens: self.texto_final = self.texto_final.replace(item, itens[item]) LINHAS += self.texto_final output = self.parameterAsFileOutput(parameters, self.HTML, context) arq = open(output, 'w') arq.write(LINHAS) arq.close() # Check for cancelation if feedback.isCanceled(): return {} feedback.pushInfo(self.tr('Operation completed successfully!')) feedback.pushInfo('Leandro França - Eng Cart') return {self.HTML: output}
def physiocap_filtrer(self, src, csv_sans_0, csv_avec_0, csv_0_seul, nom_dir_segment, nom_session, chemin_session, diametre_filtre, nom_fichier_synthese, err, mindiam, maxdiam, max_sarments_metre, segment_mini_vitesse, segment_maxi_vitesse, segment_mini_point, segment_max_pdop, segment_max_derive, segment_pas_de_derive, details, eer, eec, d, hv, laProjectionCRS, laProjectionTXT, version_3="NO"): """Fonction de traitement. Filtre ligne brute par ligne brute les données de source (src) pour les valeurs comprises entre mindiam et maxdiam et verifie si on n'a pas atteint le max_sarments_metre. Le résultat est écrit au fur et à mesure dans les fichiers csv_sans_0, csv_avec_0 et depuis v3 dans csv_0_seul mais aussi diametre_filtre La synthese est allongé "details" pilote l'ecriture de 5 parametres ou de la totalité des 10 parametres """ leModeDeTrace = self.fieldComboModeTrace.currentText() # S'il n'existe pas de données parcellaire, le script travaille avec les données brutes titre = "" titre_partie_details = " ; NBSARMM2 ; NBSARCEP ; BIOMMM2 ; BIOMGM2 ; BIOMGCEP " if version_3 == "NO": titre_sans_detail = "X ; Y ; XL93 ; YL93 ; NBSARM ; DIAM ; BIOM ; DATE ; VITESSE" else: # Ajout en version 3 de l'altitude titre_sans_detail = "ID;X ; Y ; XL93 ; YL93 ; ALTITUDE; PDOP ; DISTANCE; DERIVE; AZIMUTH; NBSART; NBSARM ; DIAM ; BIOM ; DATE ; VITESSE" if details == "NO": titre = titre_sans_detail else: #S'il existe des données parcellaire, le script travaille avec les données brutes et les données calculées titre = titre_sans_detail + titre_partie_details # Ecriture de l'entete pour tous les cas csv_sans_0.write("{0}\n".format(titre)) csv_avec_0.write("{0}\n".format(titre)) csv_0_seul.write("{0}\n".format(titre)) # Pour progress bar entre 15 et 40 lignes_brutes = src.readlines() max_lignes = len(lignes_brutes) progress_step = int(max_lignes / 25) #physiocap_log("Bar step: " + str( progress_step), leModeDeTrace) progress_bar = 15 barre = 1 precedent = [] on_coupe = "PREMIER" segment_en_cours = [] gid_en_cours = [] gid_sans_mesure = [] manquant_en_cours = [] info_en_cours = {} derive_en_cours = [] mes_lignes_sans_coupure = [] info_lignes_sans_coupure = [] nombre_segments_sans_coupure = 0 # Récuperer le CRS choisi, les extensions et le calculateur de distance distancearea, EXT_CRS_SHP, EXT_CRS_PRJ, EXT_CRS_RASTER, \ laProjectionCRS, laProjectionTXT, EPSG_NUMBER = \ physiocap_quelle_projection_et_lib_demandee( self) for numero_point, ligne_brute in enumerate(lignes_brutes): if not ligne_brute: break # Progress BAR de 15 à 40 % if (numero_point > barre * progress_step): progress_bar = progress_bar + 1 barre = barre + 1 self.progressBar.setValue(progress_bar) comptage = ligne_brute.count(",") # compte le nombre de virgules result = ligne_brute.split(",") # split en fonction des virgules try: # Transform GPS en L93 # on extrait les Colonnnes 1 à 8 (XY, puis GPS jusqu'à vitesse) # en on les transforme en float ### On utilise XY[0 et 1] puis Altitude XY[2] Pdop XY[5] et vitesse XY[7] XY = [float(x) for x in result[1:9]] # Puis on transforme les WGS84 (du capteur) en L93 (probablement utile) # TODO: ?V3.x autres EPSG ? et eviter cet appel dans la boucle crsDest = QgsCoordinateReferenceSystem.fromEpsgId( EPSG_NUMBER_L93) # Lambert 93 crsSrc = QgsCoordinateReferenceSystem.fromEpsgId( EPSG_NUMBER_GPS) # WGS 84 transformer = QgsCoordinateTransform() transformer.setSourceCrs(crsSrc) transformer.setDestinationCrs(crsDest) if not transformer.isValid(): raise physiocap_exception_no_transform(numero_point) # On assure la tranformation par compatibilité du CVS en GPS et L93 point_L93 = transformer.transform(QgsPointXY(XY[0], XY[1])) XY_L93 = [point_L93.x(), point_L93.y()] # aMsg = "Transformation faite X {0} et Y {1}". \ # format( XY_L93[0], XY_L93[1]) # physiocap_log( aMsg , leModeDeTrace) # physiocap_log( "La projection {0}". format( laProjectionTXT), leModeDeTrace) if (laProjectionTXT == "GPS"): le_point_projete = QgsPointXY(XY[0], XY[1]) else: # Pour le moment seulement L93 le_point_projete = QgsPointXY(XY_L93[0], XY_L93[1]) XY_projete = [le_point_projete.x(), le_point_projete.y()] except: aMsg = "{0} Erreur bloquante durant tranformation SCR : pour la ligne brute numéro {1}". \ format ( PHYSIOCAP_STOP, numero_point) physiocap_error(self, aMsg) err.write(aMsg) # on écrit la ligne dans le fichier ERREUR # monter directemenr exception raise # TODO: ?V3.x marquer les points à conserver (non filtré et dans un segment) # pour creer un 4eme csv POINTS_VALIDES # ce qui reste compliqué pour les segments courts que je ne connais pas encore try: # SEGMENT si V3 # On regarde les points sans mesure avant SEGMENT diams = [float(x) for x in result[9:NB_VIRGULES + 1] ] # on extrait les diams et on les transforme en float diamsF = [ i for i in diams if i > mindiam and i < maxdiam ] # on filtre les diams avec les paramètres entrés ci-dessus derive = 0.0 ma_distance = 0.0 mon_azimuth = 0.0 # SEGMENT si V3 if version_3 == "NO": pass elif precedent == [] or on_coupe == "PREMIER": #physiocap_log( "SEGMENT ==>> point {0} PREMIER".format( numero_point), TRACE_SEGMENT + "_DEBUG") # Stocker le premier point pour comparer au prochain tour # et la Date début precedent = XY_projete # TODO: ?V3.y passage en 3D mettre en Z la dérive info_en_cours[DATE_DEBUT] = result[0] if len(diamsF) == 0: # On ne STOCKE pas les points sans MESURE gid_sans_mesure.append(numero_point) else: gid_en_cours.append(numero_point) derive_en_cours.append(0) segment_en_cours.append(QgsPointXY(le_point_projete)) on_coupe = "NON" else: # On vérifie qualité de mesure # ################################################ # Filtre des points pour découpage en SEGMENT ou # pour montrer les limites de la capture # On cherche si le point est dans la zone attendue # calcul basé sur la vitesse annoncé par GPS sur # le point en cours et PDOP # ################################################# # Quand vitesse plus de 2.5 et moins de 8 et pdop reste cohérent segment_max_pdop if XY[7] >= segment_mini_vitesse and XY[ 7] < segment_maxi_vitesse and XY[5] < segment_max_pdop: # on est en vitesse de croisière # Calcul de la distance théorique par rapport au precedent # Introduire un calcul de distance length et l'azimuth le_point_precedent = QgsPointXY(precedent[0], precedent[1]) ma_distance = distancearea.measureLine( le_point_projete, le_point_precedent) mon_azimuth = le_point_projete.azimuth(le_point_precedent) # TODO: ?V3.y Traiter l'azimuth depuis le début du segment distance_theorique = XY[ 7] * 1000 / 3600 # On suppose une seconde d'avancement derive = (ma_distance - distance_theorique) / distance_theorique * 100 # physiocap_log( "Vitesse {3} Distance théorique {1:.2f} et ma distance {0:.2f} \ # sont distantes de \n {2:.1f} soit une derive de {4:.1f}".\ # format(ma_distance, distance_theorique, \ # ( ma_distance - distance_theorique), XY[7], derive ), \ # TRACE_SEGMENT) #remplacer le precedent par l'actuel precedent = XY_projete # Vérification de dérive if abs(derive) > (segment_max_derive + (2 * segment_pas_de_derive)): physiocap_log( "{0} DECOUPAGE point {1} : l'avancée dérive GRAVE ===> {2:.1f} ! ".\ format(PHYSIOCAP_WARNING, numero_point, derive ), \ TRACE_SEGMENT_DECOUPES) on_coupe = "OUI" elif abs(derive) > (segment_max_derive + segment_pas_de_derive): physiocap_log( "{0} DECOUPAGE point {1} : l'avancée dérive de PLUS d'un PAS ==> {2:.1f} ! ".\ format(PHYSIOCAP_WARNING, numero_point, derive ), \ TRACE_SEGMENT_DECOUPES) on_coupe = "OUI" elif abs(derive) > segment_max_derive: physiocap_log("{0} DECOUPAGE point {1} : l'avancée dérive => {2:.1f} ! ".\ format(PHYSIOCAP_WARNING, numero_point, derive ), \ TRACE_SEGMENT_DECOUPES) on_coupe = "OUI" else: # La derive < segment_max_derive en % : # Stocker ligne "droite" = orientation et sens d'avancement # Créer un flux des avancement stables pour identifier l'écartement problable # Ajouter un point à la ligne segment_en_cours.append(QgsPointXY(le_point_projete)) info_en_cours[DATE_FIN] = result[0] if len(diamsF) == 0: # On ne STOCKE pas les points sans MESURE gid_sans_mesure.append(numero_point) else: gid_en_cours.append(numero_point) derive_en_cours.append(derive) on_coupe = "NON" else: # Cas d'arret (fin de rang) ou pdop on_coupe = "OUI" # Tracer cas decoupe vitessse if XY[7] < segment_mini_vitesse: if len(segment_en_cours) > 0: physiocap_log("{0} DECOUPAGE point {1} : vitesse {2:.1f} alors que min est {3:.1f}! ".\ format(PHYSIOCAP_WARNING, numero_point, XY[7], segment_mini_vitesse), \ TRACE_SEGMENT_DECOUPES) if XY[7] > segment_maxi_vitesse: if len(segment_en_cours) > 0: physiocap_log("{0} DECOUPAGE point {1} : vitesse {2:.1f} que max est {3:.1f}! ".\ format(PHYSIOCAP_WARNING, numero_point, XY[7], segment_maxi_vitesse), \ TRACE_SEGMENT_DECOUPES) # Tracer cas decoupe pdop if XY[5] >= segment_max_pdop: physiocap_log("{0} DECOUPAGE point {1} : pdop {2:.1f} max est {3:.1f}! ".\ format(PHYSIOCAP_WARNING, numero_point, XY[5], segment_max_pdop ), \ TRACE_SEGMENT_DECOUPES) if on_coupe == "OUI": # Cas de fin de ligne if len(segment_en_cours) > segment_mini_point: # Le segment est à garder manquant_en_cours.append(numero_point) # Mémoriser la ligne des points cohérents mes_lignes_sans_coupure.append(segment_en_cours) info_en_cours[NUM_SEG] = nombre_segments_sans_coupure info_en_cours[DATE_FIN] = result[0] info_en_cours[NOMBRE] = len(segment_en_cours) info_en_cours[GID_GARDE] = gid_en_cours info_en_cours[GID_SANS_MESURE] = gid_sans_mesure info_en_cours[GID_TROU] = manquant_en_cours info_en_cours[DERIVE] = np.mean(derive_en_cours) # stocker jour_heure début et fin et derive moyenne ... info_lignes_sans_coupure.append(info_en_cours) nombre_segments_sans_coupure = nombre_segments_sans_coupure + 1 manquant_en_cours = [] else: # Vérifier les gid_sans_mesure # On ne perd pas les points manquants qui seront ajouter dans GID_TROU pour le segment suivant # On aditionne des gid en cours avec les manquants... for gid_perdu in gid_en_cours: manquant_en_cours.append(gid_perdu) manquant_en_cours.append(numero_point) if len(segment_en_cours) > 0: physiocap_log("{0} SEGMENT {1} IGNORE : trop cours == {2} points, le mini est {3} ".\ format(PHYSIOCAP_WARNING, nombre_segments_sans_coupure, len(segment_en_cours), segment_mini_point ), TRACE_SEGMENT_DECOUPES) info_en_cours = {} gid_en_cours = [] gid_sans_mesure = [] precedent = [] on_coupe = "PREMIER" segment_en_cours = [] except: aMsg = "{0} Erreur bloquante durant extraction des segments : pour la ligne brute numéro {1}". \ format ( PHYSIOCAP_STOP, numero_point) physiocap_error(self, aMsg) err.write(aMsg) # on écrit la ligne dans le fichier ERREUR # monter directemenr exception raise try: # On filtre vraiement if details == "NO": if len( diamsF ) == 0: # si le nombre de diamètre après filtrage = 0 alors pas de mesures nbsarm = 0 nbsart = 0 diam = 0 biom = 0 # Ecrire les seuls_0 et aussi les points avec 0 if version_3 == "NO": csv_0_seul.write("%.7f%s%.7f%s%.7f%s%.7f%s%i%s%i%s%i%s%s%s%0.2f\n" \ %(XY[0],";",XY[1],";",XY_L93[0],";",XY_L93[1],";",nbsarm,";",diam ,";",biom,";",result[0],";",XY[7])) # on écrit la ligne dans le csv avec ZERO SEUL csv_avec_0.write("%.7f%s%.7f%s%.7f%s%.7f%s%i%s%i%s%i%s%s%s%0.2f\n" \ %(XY[0],";",XY[1],";",XY_L93[0],";",XY_L93[1],";",nbsarm,";",diam ,";",biom,";",result[0],";",XY[7])) # on écrit la ligne dans le fcsv avec ZERO else: # V3 on ajoute altitude, pdop, distance au point precedent et la dérive # puis AZIMUTH et NBSART = 0 a_ecrire = "{0};{1:.7f};{2:.7f};{3:.7f};{4:.7f}; \ {5:.2f};{6:.2f};{7:.2f};{8:.2f};{9:.2f};0;0;0;0;{10};{11:.7f}\n" . \ format(numero_point, XY[0],XY[1],XY_L93[0],XY_L93[1], \ XY[2],XY[5],ma_distance,derive,mon_azimuth, result[0],XY[7]) csv_0_seul.write(a_ecrire) csv_avec_0.write(a_ecrire) elif comptage == NB_VIRGULES and len( diamsF ) > 0: # si le nombre de diamètre après filtrage != 0 alors mesures # Nombre sarment total nbsart = len(diamsF) if XY[7] != 0: # Si vitesse non nulle nbsarm = len(diamsF) / (XY[7] * 1000 / 3600) else: nbsarm = 0 if nbsarm > 1 and nbsarm < max_sarments_metre: diam = sum(diamsF) / len(diamsF) biom = 3.1416 * (diam / 2) * (diam / 2) * nbsarm if version_3 == "NO": csv_avec_0.write("%.7f%s%.7f%s%.7f%s%.7f%s%0.2f%s%.2f%s%.2f%s%s%s%0.2f\n" \ %(XY[0],";",XY[1],";",XY_L93[0],";",XY_L93[1],";",nbsarm,";",diam,";",biom,";",result[0],";",XY[7])) # on écrit la ligne dans le csv avec ZERO csv_sans_0.write("%.7f%s%.7f%s%.7f%s%.7f%s%0.2f%s%.2f%s%.2f%s%s%s%0.2f\n" \ %(XY[0],";",XY[1],";",XY_L93[0],";",XY_L93[1],";",nbsarm,";",diam,";",biom,";",result[0],";",XY[7])) # on écrit la ligne dans le csv sans ZERO else: # V3 on ajoute altitude, pdop,distance au point precedent et risque de dérive # puis AZIMUTH et NBSART a_ecrire = "{0};{1:.7f};{2:.7f};{3:.7f};{4:.7f}; \ {5:.2f};{6:.2f};{7:.2f};{8:.2f};{9:.2f};{10}; \ {11:.2f}; {12:.2f};{13:.2f};{14};{15:.7f}\n" . \ format( numero_point, XY[0], XY[1], XY_L93[0] ,XY_L93[1], \ XY[2],XY[5],ma_distance,derive,mon_azimuth,nbsart, \ nbsarm,diam,biom,result[0],XY[7]) csv_avec_0.write(a_ecrire) csv_sans_0.write(a_ecrire) for n in range(len(diamsF)): diametre_filtre.write("%f%s" % (diamsF[n], ";")) elif details == "YES": if len( diamsF ) == 0: # si le nombre de diamètre après filtrage = 0 alors pas de mesures nbsart = 0 nbsarm = 0 diam = 0 biom = 0 nbsarmm2 = 0 nbsarcep = 0 biommm2 = 0 biomgm2 = 0 biomgcep = 0 if version_3 == "NO": csv_0_seul.write("%.7f%s%.7f%s%.7f%s%.7f%s%i%s%i%s%i%s%s%s%0.2f%s%i%s%i%s%i%s%i%s%i\n" \ %(XY[0],";",XY[1],";",XY_L93[0],";",XY_L93[1],";",nbsarm,";",diam ,";",biom,";",result[0],";",XY[7],";",nbsarmm2,";",nbsarcep,";",biommm2,";",biomgm2,";",biomgcep)) csv_avec_0.write("%.7f%s%.7f%s%.7f%s%.7f%s%i%s%i%s%i%s%s%s%0.2f%s%i%s%i%s%i%s%i%s%i\n" \ %(XY[0],";",XY[1],";",XY_L93[0],";",XY_L93[1],";",nbsarm,";",diam ,";",biom,";",result[0],";",XY[7],";",nbsarmm2,";",nbsarcep,";",biommm2,";",biomgm2,";",biomgcep)) else: # Q3 on ajoute altitude, pdop, distance au point precedent et la dérive # puis AZIMUTH et NBSART = 0 a_ecrire = "{0};{1:.7f};{2:.7f};{3:.7f};{4:.7f}; \ {5:.2f};{6:.2f};{7:.2f};{8:.2f};{9:.2f};0;0;0;0;{10};{11:.7f}" . \ format(numero_point, XY[0],XY[1],XY_L93[0],XY_L93[1], XY[2],XY[5],ma_distance,derive,mon_azimuth, result[0],XY[7]) a_ecrire_detail = ";0;0;0;0;0\n" a_ecrire_complet = a_ecrire + a_ecrire_detail csv_0_seul.write(a_ecrire_complet) csv_avec_0.write(a_ecrire_complet) elif comptage == NB_VIRGULES and len( diamsF ) > 0: # si le nombre de diamètre après filtrage != 0 alors mesures nbsart = len(diamsF) if XY[7] != 0: nbsarm = len(diamsF) / (XY[7] * 1000 / 3600) else: nbsarm = 0 if nbsarm > 1 and nbsarm < max_sarments_metre: diam = sum(diamsF) / len(diamsF) biom = 3.1416 * (diam / 2) * (diam / 2) * nbsarm nbsarmm2 = nbsarm / eer * 100 nbsarcep = nbsarm * eec / 100 biommm2 = biom / eer * 100 biomgm2 = biom * d * hv / eer biomgcep = biom * d * hv * eec / 100 / 100 if version_3 == "NO": csv_avec_0.write("%.7f%s%.7f%s%.7f%s%.7f%s%.2f%s%.2f%s%.2f%s%s%s%.2f%s%.2f%s%.2f%s%.2f%s%.2f%s%.2f\n" \ %(XY[0],";",XY[1],";",XY_L93[0],";",XY_L93[1],";",nbsarm,";",diam ,";",biom,";",result[0],";",XY[7],";",nbsarmm2,";",nbsarcep,";",biommm2,";",biomgm2,";",biomgcep)) csv_sans_0.write("%.7f%s%.7f%s%.7f%s%.7f%s%.2f%s%.2f%s%.2f%s%s%s%.2f%s%.2f%s%.2f%s%.2f%s%.2f%s%.2f\n" \ %(XY[0],";",XY[1],";",XY_L93[0],";",XY_L93[1],";",nbsarm,";",diam ,";",biom,";",result[0],";",XY[7],";",nbsarmm2,";",nbsarcep,";",biommm2,";",biomgm2,";",biomgcep)) else: # Q3 on ajoute altitude, pdop,distance au point precedent et risque de dérive # puis AZIMUTH et NBSART a_ecrire = "{0};{1:.7f};{2:.7f};{3:.7f};{4:.7f}; \ {5:.2f};{6:.2f};{7:.2f};{8:.2f};{9:.2f};{10}; \ {11:.2f}; {12:.2f};{13:.2f};{14};{15:.7f}" . \ format( numero_point, XY[0], XY[1], XY_L93[0] ,XY_L93[1], XY[2],XY[5],ma_distance,derive,mon_azimuth,nbsart, nbsarm,diam,biom,result[0],XY[7]) a_ecrire_detail = ";{0:.7f};{1:.7f};{2:.7f};{3:.7f};{4:.7f}\n". \ format( nbsarmm2, nbsarcep,biommm2,biomgm2,biomgcep) a_ecrire_complet = a_ecrire + a_ecrire_detail csv_avec_0.write(a_ecrire_complet) csv_sans_0.write(a_ecrire_complet) # Memorise diametre filtré pour histo for n in range(len(diamsF)): diametre_filtre.write("%f%s" % (diamsF[n], ";")) except: aMsg = "{0} Erreur bloquante durant filtrage : pour la ligne brute numéro {1}". \ format ( PHYSIOCAP_STOP, numero_point) physiocap_error(self, aMsg) err.write(aMsg) # on écrit la ligne dans le fichier ERREUR # Pour monter directement exception raise physiocap_exception_err_csv(nom_court_csv_concat) if version_3 == "NO": vecteur_segment = None vecteur_segment_brise = None else: if len(info_lignes_sans_coupure) != nombre_segments_sans_coupure: physiocap_error( self, "{0} on a trouvé {1} segments et {2} infos". \ format( PHYSIOCAP_INFO, nombre_segments_sans_coupure, len( info_lignes_sans_coupure))) raise physiocap_exception_calcul_segment_invalid( "Segment et leurs infos sont différents") i = 0 for info_segment in info_lignes_sans_coupure: i = i + 1 try: physiocap_log( "{0} Segment {1} contient {2} points et une dérive moyenne de {3:.1f}". \ format( PHYSIOCAP_INFO, i, info_segment[NOMBRE], info_segment[DERIVE]), TRACE_SEGMENT) physiocap_log( "gid des points :{0} \net les sans mesure\n{1}". \ format(info_segment[GID_GARDE], info_segment[GID_SANS_MESURE]), TRACE_SEGMENT) except: physiocap_error( self, "Problème : manque attribut dans info segment") raise physiocap_exception_calcul_segment_invalid( "Un attribut n'est pas présent") # try: # physiocap_log( "Date début {0} et fin {1}". \ # format( info_segment[DATE_DEBUT], info_segment[DATE_FIN]), # TRACE_SEGMENT) # except: # physiocap_error( self, "Problème : pas de date dans le segment") # raise physiocap_exception_calcul_segment_invalid( "Date non présente") # Creer les lignes simplifiés ou brisés de ces segments et infos vecteur_segment = physiocap_segment_vers_vecteur( self, chemin_session, nom_dir_segment, nom_session, mes_lignes_sans_coupure, info_lignes_sans_coupure, version_3) vecteur_segment_brise = physiocap_segment_vers_vecteur( self, chemin_session, nom_dir_segment, nom_session, mes_lignes_sans_coupure, info_lignes_sans_coupure, version_3, "BRISE") physiocap_log( "{0} {1} Fin du filtrage OK des {2} lignes.". \ format( PHYSIOCAP_INFO, PHYSIOCAP_UNI, str(numero_point - 1)), leModeDeTrace) return vecteur_segment, vecteur_segment_brise
def processAlgorithm(self, parameters, context, feedback): vertices = self.parameterAsSource(parameters, self.PONTOLIMITE, context) area = self.parameterAsSource(parameters, self.AREAIMOVEL, context) if vertices is None: raise QgsProcessingException(self.invalidSourceError(parameters, self.PONTOLIMITE)) if area is None: raise QgsProcessingException(self.invalidSourceError(parameters, self.AREAIMOVEL)) # Pegando o SRC do Projeto SRC = QgsProject.instance().crs().description() # Verificando o SRC do Projeto if QgsProject.instance().crs().isGeographic(): raise QgsProcessingException(self.tr('The Project CRS must be projected!', 'O SRC do Projeto deve ser Projetado!')) feedback.pushInfo(self.tr('Project CRS is {}.', 'SRC do Projeto é {}.').format(SRC)) # Transformar Coordenadas de Geográficas para o sistema UTM coordinateTransformer = QgsCoordinateTransform() coordinateTransformer.setDestinationCrs(QgsProject.instance().crs()) coordinateTransformer.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:4674')) # Dados do levantamento #Fields = area.fields() #fieldnames = [field.name() for field in Fields] for feat in area.getFeatures(): feat1 = feat break INICIO = '''<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"> <title>Cálculo Analítico de Área e Perímetro</title> </head> <body> <div style="text-align: center;"><big><big><span style="font-weight: bold;">Cálculo Analítico de Área, Azimutes, Lados, Coordenadas Planas e Geodésicas</span><br style="font-weight: bold;"> </big></big> <div style="text-align: left;"><br> <span style="font-weight: bold;">Imóvel:</span> [IMOVEL]<br> <span style="font-weight: bold;">Município:</span> [MUNICIPIO] - [UF]<br style="font-weight: bold;"> <span style="font-weight: bold;">SGR:</span> SIRGAS2000<br> <span style="font-weight: bold;">Projeção:</span> [UTM] <br> </div> </div> <table style="text-align: center; width: 100%;" border="1" cellpadding="0" cellspacing="0"> <tbody> <tr> <td style="text-align: center; font-weight: bold;">Estação</td> <td style="text-align: center; font-weight: bold;">Vante</td> <td style="text-align: center; font-weight: bold;">Este (m)</td> <td style="text-align: center; font-weight: bold;">Norte (m)</td> <td style="text-align: center; font-weight: bold;">Azimute</td> <td style="text-align: center; font-weight: bold;">Distância (m)</td> <td style="text-align: center; font-weight: bold;">Longitude</td> <td style="text-align: center; font-weight: bold;">Latitude</td> </tr> ''' linha = '''<tr> <td>[EST1]</td> <td>[EST2]</td> <td>[E]</td> <td>[N]</td> <td>[AZ]</td> <td>[D]</td> <td>[LON]</td> <td>[LAT]</td> </tr> ''' FIM = '''</tbody> </table> <br> <span style="font-weight: bold;">Perímetro:</span> [PERIMETRO] m<br> <span style="font-weight: bold;">Área Total:</span> [AREA] m² / [AREA_HA] ha </body> </html> ''' # Inserindo dados iniciais do levantamento itens = {'[IMOVEL]': self.str2HTML(feat1['imóvel']), '[UF]': feat1['UF'], '[AREA]': '{:,.2f}'.format(feat1['area']).replace(',', 'X').replace('.', ',').replace('X', '.'), '[UTM]': (SRC.split('/')[-1]).replace('zone', 'fuso'), '[MUNICIPIO]': self.str2HTML(feat1['município']), '[PERIMETRO]': '{:,.2f}'.format(feat1['perimetro']).replace(',', 'X').replace('.', ',').replace('X', '.') } for item in itens: INICIO = INICIO.replace(item, itens[item]) # Inserindo dados finais do levantamento itens = { '[AREA]': '{:,.2f}'.format(feat1['area']).replace(',', 'X').replace('.', ',').replace('X', '.'), '[AREA_HA]': '{:,.2f}'.format(feat1['area']/1e4).replace(',', 'X').replace('.', ',').replace('X', '.'), '[PERIMETRO]': '{:,.2f}'.format(feat1['perimetro']).replace(',', 'X').replace('.', ',').replace('X', '.') } for item in itens: FIM = FIM.replace(item, itens[item]) LINHAS = INICIO pnts_UTM = {} for feat in vertices.getFeatures(): pnt = feat.geometry().asMultiPoint()[0] pnts_UTM[feat['ordem']] = [coordinateTransformer.transform(pnt), feat['codigo'], pnt] # Cálculo dos Azimutes e Distâncias tam = len(pnts_UTM) feedback.pushInfo(str(tam)) Az_lista, Dist = [], [] for k in range(tam): pntA = pnts_UTM[k+1][0] pntB = pnts_UTM[1 if k+2 > tam else k+2][0] Az_lista += [(180/pi)*self.azimute(pntA, pntB)[0]] Dist += [sqrt((pntA.x() - pntB.x())**2 + (pntA.y() - pntB.y())**2)] for k in range(tam): linha0 = linha itens = { '[EST1]': pnts_UTM[k+1][1], '[EST2]': pnts_UTM[1 if k+2 > tam else k+2][1], '[E]': '{:,.2f}'.format(pnts_UTM[k+1][0].x()).replace(',', 'X').replace('.', ',').replace('X', '.'), '[N]': '{:,.2f}'.format(pnts_UTM[k+1][0].y()).replace(',', 'X').replace('.', ',').replace('X', '.'), '[AZ]': self.str2HTML(self.dd2dms(Az_lista[k],1).replace('.', ',')), '[D]': '{:,.2f}'.format(Dist[k]).replace(',', 'X').replace('.', ',').replace('X', '.'), '[LON]': self.str2HTML(self.dd2dms(pnts_UTM[k+1][2].x(),4)), '[LAT]': self.str2HTML(self.dd2dms(pnts_UTM[k+1][2].y(),4)) } for item in itens: linha0 = linha0.replace(item, itens[item]) LINHAS += linha0 LINHAS += FIM # Check for cancelation if feedback.isCanceled(): return {} output = self.parameterAsFileOutput(parameters, self.HTML, context) arq = open(output, 'w') arq.write(LINHAS) arq.close() feedback.pushInfo(self.tr('Operation completed successfully!')) feedback.pushInfo('Leandro França - Eng Cart') return {self.HTML: output}