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')])
Ejemplo n.º 3
0
    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)
Ejemplo n.º 4
0
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()
Ejemplo n.º 5
0
    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')])
Ejemplo n.º 6
0
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)
Ejemplo n.º 8
0
    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}
Ejemplo n.º 9
0
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
Ejemplo n.º 10
0
    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&aacute;lculo Anal&iacute;tico de
&Aacute;rea e Per&iacute;metro</title>
</head>
<body>
<div style="text-align: center;"><big><big><span
 style="font-weight: bold;">C&aacute;lculo
Anal&iacute;tico de &Aacute;rea, Azimutes, Lados, Coordenadas
Planas e Geod&eacute;sicas</span><br
 style="font-weight: bold;">
</big></big>
<div style="text-align: left;"><br>
<span style="font-weight: bold;">Im&oacute;vel:</span>
[IMOVEL]<br>
<span style="font-weight: bold;">Munic&iacute;pio:</span>
[MUNICIPIO] - [UF]<br style="font-weight: bold;">
<span style="font-weight: bold;">SGR:</span>
SIRGAS2000<br>
<span style="font-weight: bold;">Proje&ccedil;&atilde;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&ccedil;&atilde;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&acirc;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&iacute;metro:</span>
&nbsp;[PERIMETRO] m<br>
<span style="font-weight: bold;">&Aacute;rea Total:</span>
[AREA] m&sup2; / [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}