Example #1
0
    def __init__(self, iface, parent=None):
        QWidget.__init__(self, parent)
        self.setupUi(self)

        # store the iface and the events layer
        self.iface = iface
        self.vl = Utils.eventsVl()

        self.canvas = self.iface.mapCanvas()
        self._prevMapTool = None
        self._sharedData = {
        }  # it will contain the classification map (data shared through the all cross sections)

        # create the maptool to define the area of interest
        self.areaDrawer = PolygonDrawer(
            self.iface.mapCanvas(), {
                'color': QColor('#333333'),
                'border': 2,
                'enableSnap': False,
                'keepAfterEnd': True
            })
        self.areaDrawer.setAction(self.drawAreaBtn)
        self.connect(self.areaDrawer, SIGNAL("geometryEmitted"),
                     self.areaCreated)

        # create the maptool to create classification buffers
        self.segmentDrawer = SegmentDrawer(self.iface.mapCanvas(), {
            'color': QColor('cyan'),
            'border': 3,
            'enableSnap': False
        })
        self.segmentDrawer.setAction(self.addBufferBtn)
        self.connect(self.segmentDrawer, SIGNAL("geometryEmitted"),
                     self.midlineBufferCreated)

        # initialize the table that will contain classification buffers
        self.buffersTable.setModel(self.BuffersTableModel(self.buffersTable))
        self.connect(
            self.buffersTable.selectionModel(),
            SIGNAL(
                "currentRowChanged(const QModelIndex &, const QModelIndex &)"),
            self.buffersSelectionChanged)
        self.connect(self.buffersTable.model(), SIGNAL("bufferWidthChanged"),
                     self.updateBuffer)

        # connect actions to the widgets
        self.connect(self.drawAreaBtn, SIGNAL("clicked()"), self.drawArea)
        self.connect(self.clearAreaBtn, SIGNAL("clicked()"), self.clearArea)
        self.connect(self.addBufferBtn, SIGNAL("clicked()"), self.drawBuffer)
        self.connect(self.delBufferBtn, SIGNAL("clicked()"), self.deleteBuffer)
        self.connect(self.crossSectionBtn, SIGNAL("clicked()"),
                     self.openCrossSection)
        self.connect(self.displayClassifiedDataBtn, SIGNAL("clicked()"),
                     self.loadClassifiedData)

        # disable buttons
        self.delBufferBtn.setEnabled(False)
        self.crossSectionBtn.setEnabled(False)
Example #2
0
	def __init__(self, iface, parent=None):
		QWidget.__init__(self, parent)
		self.setupUi(self)

		# store the iface and the event layer
		self.iface = iface
		self.vl = Utils.eventsVl()

		self.canvas = self.iface.mapCanvas()
		self._prevMapTool = None

		# setup the magnitude, depth and range filters
		self.setupFilters()

		# create the maptool to draw polygons
		self.polygonDrawer = PolygonDrawer( self.canvas, {'color':QColor("#666666"), 'enableSnap':False, 'keepAfterEnd':True} )
		self.polygonDrawer.setAction( self.drawPolygonBtn )
		self.connect(self.polygonDrawer, SIGNAL("geometryEmitted"), self.polygonCreated)

		# populate plot type combo
		self.plotTypeCombo.addItem( "Histogram", self.PLOT_HIST )
		self.plotTypeCombo.addItem( "Histogram (log10)", self.PLOT_HIST_LOG )
		self.plotTypeCombo.addItem( "Scatter plot", self.PLOT_SCATTER )
		self.updateAxesCombos()

		# populate both axis combos with field names
		for index, fld in self.vl.dataProvider().fields().iteritems():
			self.xAxisCombo.addItem( fld.name(), QVariant(index) )
			self.yAxisCombo.addItem( fld.name(), QVariant(index) )

		# connect actions to the widgets
		self.connect(self.drawPolygonBtn, SIGNAL("clicked()"), self.drawPolygon)
		self.connect(self.clearPolygonBtn, SIGNAL("clicked()"), self.clearPolygon)
		self.connect(self.plotBtn, SIGNAL("clicked()"), self.createPlot)
		self.connect(self.plotTypeCombo, SIGNAL("currentIndexChanged(int)"), self.updateAxesCombos)
Example #3
0
	def __init__(self, iface, parent=None):
		QWidget.__init__(self, parent)
		self.setupUi(self)

		# store the iface
		self.iface = iface

		self.canvas = self.iface.mapCanvas()
		self._prevMapTool = None

		self.algorithmStacked.setCurrentIndex(0)

		# create the maptool to draw polygons
		self.polygonDrawer = PolygonDrawer( self.canvas, {'color':QColor("#666666"), 'enableSnap':False, 'keepAfterEnd':True} )
		self.polygonDrawer.setAction( self.drawPolygonBtn )
		self.connect(self.polygonDrawer, SIGNAL("geometryEmitted"), self.polygonCreated)

		# connect actions to the widgets
		self.connect(self.drawPolygonBtn, SIGNAL("clicked()"), self.drawPolygon)
		self.connect(self.clearPolygonBtn, SIGNAL("clicked()"), self.clearPolygon)

		QObject.connect(self.declusterWdg, SIGNAL("dataRequested"), self.fillData)
		QObject.connect(self.completenessWdg, SIGNAL("dataRequested"), self.fillData)
		QObject.connect(self.recurrenceWdg, SIGNAL("dataRequested"), self.fillData)
		QObject.connect(self.maxMagnitudeWdg, SIGNAL("dataRequested"), self.fillData)
Example #4
0
    def __init__(self, iface, parent=None):
        QWidget.__init__(self, parent)
        self.setupUi(self)

        # store the iface and the event layer
        self.iface = iface
        self.vl = Utils.eventsVl()

        self.canvas = self.iface.mapCanvas()
        self._prevMapTool = None

        # setup the magnitude, depth and range filters
        self.setupFilters()

        # create the maptool to draw polygons
        self.polygonDrawer = PolygonDrawer(self.canvas, {
            'color': QColor("#666666"),
            'enableSnap': False,
            'keepAfterEnd': True
        })
        self.polygonDrawer.setAction(self.drawPolygonBtn)
        self.connect(self.polygonDrawer, SIGNAL("geometryEmitted"),
                     self.polygonCreated)

        # populate plot type combo
        self.plotTypeCombo.addItem("Histogram", self.PLOT_HIST)
        self.plotTypeCombo.addItem("Histogram (log10)", self.PLOT_HIST_LOG)
        self.plotTypeCombo.addItem("Scatter plot", self.PLOT_SCATTER)
        self.updateAxesCombos()

        # populate both axis combos with field names
        for index, fld in self.vl.dataProvider().fields().iteritems():
            self.xAxisCombo.addItem(fld.name(), QVariant(index))
            self.yAxisCombo.addItem(fld.name(), QVariant(index))

        # connect actions to the widgets
        self.connect(self.drawPolygonBtn, SIGNAL("clicked()"),
                     self.drawPolygon)
        self.connect(self.clearPolygonBtn, SIGNAL("clicked()"),
                     self.clearPolygon)
        self.connect(self.plotBtn, SIGNAL("clicked()"), self.createPlot)
        self.connect(self.plotTypeCombo, SIGNAL("currentIndexChanged(int)"),
                     self.updateAxesCombos)
Example #5
0
    def __init__(self, iface, parent=None):
        QWidget.__init__(self, parent)
        self.setupUi(self)

        # store the iface
        self.iface = iface

        self.canvas = self.iface.mapCanvas()
        self._prevMapTool = None

        self.algorithmStacked.setCurrentIndex(0)

        # create the maptool to draw polygons
        self.polygonDrawer = PolygonDrawer(self.canvas, {
            'color': QColor("#666666"),
            'enableSnap': False,
            'keepAfterEnd': True
        })
        self.polygonDrawer.setAction(self.drawPolygonBtn)
        self.connect(self.polygonDrawer, SIGNAL("geometryEmitted"),
                     self.polygonCreated)

        # connect actions to the widgets
        self.connect(self.drawPolygonBtn, SIGNAL("clicked()"),
                     self.drawPolygon)
        self.connect(self.clearPolygonBtn, SIGNAL("clicked()"),
                     self.clearPolygon)

        QObject.connect(self.declusterWdg, SIGNAL("dataRequested"),
                        self.fillData)
        QObject.connect(self.completenessWdg, SIGNAL("dataRequested"),
                        self.fillData)
        QObject.connect(self.recurrenceWdg, SIGNAL("dataRequested"),
                        self.fillData)
        QObject.connect(self.maxMagnitudeWdg, SIGNAL("dataRequested"),
                        self.fillData)
Example #6
0
	def __init__(self, iface, parent=None):
		QWidget.__init__(self, parent)
		self.setupUi(self)

		# store the iface and the events layer
		self.iface = iface
		self.vl = Utils.eventsVl()

		self.canvas = self.iface.mapCanvas()
		self._prevMapTool = None
		self._sharedData = {}	# it will contain the classification map (data shared through the all cross sections)

		# create the maptool to define the area of interest
		self.areaDrawer = PolygonDrawer(self.iface.mapCanvas(), {'color':QColor('#333333'), 'border':2, 'enableSnap':False, 'keepAfterEnd':True})
		self.areaDrawer.setAction( self.drawAreaBtn )
		self.connect(self.areaDrawer, SIGNAL("geometryEmitted"), self.areaCreated)

		# create the maptool to create classification buffers
		self.segmentDrawer = SegmentDrawer(self.iface.mapCanvas(), {'color':QColor('cyan'), 'border':3, 'enableSnap':False})
		self.segmentDrawer.setAction( self.addBufferBtn )
		self.connect(self.segmentDrawer, SIGNAL("geometryEmitted"), self.midlineBufferCreated)

		# initialize the table that will contain classification buffers
		self.buffersTable.setModel( self.BuffersTableModel(self.buffersTable) )
		self.connect( self.buffersTable.selectionModel(), SIGNAL("currentRowChanged(const QModelIndex &, const QModelIndex &)"), self.buffersSelectionChanged)
		self.connect( self.buffersTable.model(), SIGNAL("bufferWidthChanged"), self.updateBuffer)

		# connect actions to the widgets
		self.connect(self.drawAreaBtn, SIGNAL("clicked()"), self.drawArea)
		self.connect(self.clearAreaBtn, SIGNAL("clicked()"), self.clearArea)
		self.connect(self.addBufferBtn, SIGNAL("clicked()"), self.drawBuffer)
		self.connect(self.delBufferBtn, SIGNAL("clicked()"), self.deleteBuffer)
		self.connect(self.crossSectionBtn, SIGNAL("clicked()"), self.openCrossSection)
		self.connect(self.displayClassifiedDataBtn, SIGNAL("clicked()"), self.loadClassifiedData)

		# disable buttons
		self.delBufferBtn.setEnabled(False)
		self.crossSectionBtn.setEnabled(False)
Example #7
0
class ProcessingWdg(QWidget, Ui_ProcessingWdg):
    def __init__(self, iface, parent=None):
        QWidget.__init__(self, parent)
        self.setupUi(self)

        # store the iface
        self.iface = iface

        self.canvas = self.iface.mapCanvas()
        self._prevMapTool = None

        self.algorithmStacked.setCurrentIndex(0)

        # create the maptool to draw polygons
        self.polygonDrawer = PolygonDrawer(self.canvas, {
            'color': QColor("#666666"),
            'enableSnap': False,
            'keepAfterEnd': True
        })
        self.polygonDrawer.setAction(self.drawPolygonBtn)
        self.connect(self.polygonDrawer, SIGNAL("geometryEmitted"),
                     self.polygonCreated)

        # connect actions to the widgets
        self.connect(self.drawPolygonBtn, SIGNAL("clicked()"),
                     self.drawPolygon)
        self.connect(self.clearPolygonBtn, SIGNAL("clicked()"),
                     self.clearPolygon)

        QObject.connect(self.declusterWdg, SIGNAL("dataRequested"),
                        self.fillData)
        QObject.connect(self.completenessWdg, SIGNAL("dataRequested"),
                        self.fillData)
        QObject.connect(self.recurrenceWdg, SIGNAL("dataRequested"),
                        self.fillData)
        QObject.connect(self.maxMagnitudeWdg, SIGNAL("dataRequested"),
                        self.fillData)

    def storePrevMapTool(self):
        prevMapTool = self.canvas.mapTool()
        if prevMapTool not in (self.polygonDrawer, ):
            self._prevMapTool = prevMapTool

    def restorePrevMapTool(self):
        self.polygonDrawer.stopCapture()
        if self._prevMapTool:
            self.canvas.setMapTool(self._prevMapTool)

    def showEvent(self, event):
        self.showRubberBands(True)
        QWidget.showEvent(self, event)

    def hideEvent(self, event):
        self.showRubberBands(False)
        self.restorePrevMapTool()
        QWidget.hideEvent(self, event)

    def deleteLater(self, *args):
        #print "deleting", self
        self.clearPolygon()

        # restore the previous maptool
        self.restorePrevMapTool()

        # delete the polygon drawer maptool
        self.polygonDrawer.deleteLater()
        self.polygonDrawer = None

        QWidget.deleteLater(self, *args)

    def showRubberBands(self, show=True):
        """ show/hide all the rubberbands """
        if self.polygonDrawer.isEmittingPoints:
            self.polygonDrawer.reset()
        else:
            self.polygonDrawer.rubberBand.show(
            ) if show else self.polygonDrawer.rubberBand.hide()

    def drawPolygon(self):
        # store the previous maptool
        self.storePrevMapTool()

        # set the polygon drawer as current maptool
        self.polygonDrawer.startCapture()

    def clearPolygon(self):
        # remove the displayed polygon
        self.polygonDrawer.reset()

    def polygonCreated(self, polygon):
        # restore the previous maptool
        self.restorePrevMapTool()

    def fillData(self, data, panMap):
        """ fetch data from the classified layer and put them into the 
			passed arguments:
			**data** list will contain the selected features attributes, 
			**panMap** dictionary will keep the association between fields and 
			 their position in the data list """

        classifiedVl = Utils.classifiedVl()
        pr = classifiedVl.dataProvider()

        # spatial filter
        spatialFilter = self.polygonDrawer.geometry()
        if not spatialFilter:
            extent = QgsRectangle()
        else:
            # convert the spatial filter to the layer CRS
            toLayerCrsTransform = QgsCoordinateTransform(
                self.canvas.mapRenderer().destinationCrs(), classifiedVl.crs())
            ret = spatialFilter.transform(toLayerCrsTransform)
            if ret != 0:
                QMessageBox.warning(
                    self, "Invalid area",
                    "Unable to tranform the selected area to the layer CRS.")
                return
            extent = spatialFilter.boundingBox()

        index2key = Utils.index2keyFieldMap(pr.fields())

        # fetch and loop through the features
        pr = classifiedVl.dataProvider()
        pr.select(classifiedVl.pendingAllAttributesList(), extent, True)

        f = QgsFeature()
        while pr.nextFeature(f):
            # filter features by spatial filter
            if spatialFilter and not spatialFilter.contains(f.geometry()):
                continue

            # create a new row: [id, *fields]
            attrs = f.attributeMap()
            row = [f.id()]
            for index, val in sorted(attrs.iteritems()):
                row.append(attrs[index])

                # store the index of well-known field in the pan map so they
                # can be found easily later
                key = index2key.get(index, None)
                if key is not None:
                    panMap[key] = len(row) - 1

            # append to the data buffer
            data.append(row)

        if len(data) <= 0:
            QMessageBox.information(self, "Processing",
                                    "No features in the result")
            return
Example #8
0
class FilterWdg(QWidget, Ui_FilterWdg):

    PLOT_HIST, PLOT_HIST_LOG, PLOT_SCATTER = range(3)

    def __init__(self, iface, parent=None):
        QWidget.__init__(self, parent)
        self.setupUi(self)

        # store the iface and the event layer
        self.iface = iface
        self.vl = Utils.eventsVl()

        self.canvas = self.iface.mapCanvas()
        self._prevMapTool = None

        # setup the magnitude, depth and range filters
        self.setupFilters()

        # create the maptool to draw polygons
        self.polygonDrawer = PolygonDrawer(self.canvas, {
            'color': QColor("#666666"),
            'enableSnap': False,
            'keepAfterEnd': True
        })
        self.polygonDrawer.setAction(self.drawPolygonBtn)
        self.connect(self.polygonDrawer, SIGNAL("geometryEmitted"),
                     self.polygonCreated)

        # populate plot type combo
        self.plotTypeCombo.addItem("Histogram", self.PLOT_HIST)
        self.plotTypeCombo.addItem("Histogram (log10)", self.PLOT_HIST_LOG)
        self.plotTypeCombo.addItem("Scatter plot", self.PLOT_SCATTER)
        self.updateAxesCombos()

        # populate both axis combos with field names
        for index, fld in self.vl.dataProvider().fields().iteritems():
            self.xAxisCombo.addItem(fld.name(), QVariant(index))
            self.yAxisCombo.addItem(fld.name(), QVariant(index))

        # connect actions to the widgets
        self.connect(self.drawPolygonBtn, SIGNAL("clicked()"),
                     self.drawPolygon)
        self.connect(self.clearPolygonBtn, SIGNAL("clicked()"),
                     self.clearPolygon)
        self.connect(self.plotBtn, SIGNAL("clicked()"), self.createPlot)
        self.connect(self.plotTypeCombo, SIGNAL("currentIndexChanged(int)"),
                     self.updateAxesCombos)

    def storePrevMapTool(self):
        prevMapTool = self.canvas.mapTool()
        if prevMapTool not in (self.polygonDrawer, ):
            self._prevMapTool = prevMapTool

    def restorePrevMapTool(self):
        self.polygonDrawer.stopCapture()
        if self._prevMapTool:
            self.canvas.setMapTool(self._prevMapTool)

    def showEvent(self, event):
        self.showRubberBands(True)
        QWidget.showEvent(self, event)

    def hideEvent(self, event):
        self.showRubberBands(False)
        self.restorePrevMapTool()
        QWidget.hideEvent(self, event)

    def deleteLater(self, *args):
        #print "deleting", self
        self.clearPolygon()

        # restore the previous maptool
        self.restorePrevMapTool()

        # delete the polygon drawer maptool
        self.polygonDrawer.deleteLater()
        self.polygonDrawer = None

        QWidget.deleteLater(self, *args)

    def _filterForKey(self, key):
        if key == 'magnitude': return self.magnitudeRangeFilter
        if key == 'depth': return self.depthRangeFilter
        if key == 'date': return self.dateRangeFilter
        return None

    def _hasPlotYField(self, plotType):
        return plotType not in (self.PLOT_HIST, self.PLOT_HIST_LOG)

    def _getPlotType(self):
        return self.plotTypeCombo.itemData(self.plotTypeCombo.currentIndex())

    def updateAxesCombos(self):
        self.yAxisCombo.setEnabled(self._hasPlotYField(self._getPlotType()))

    def setupFilters(self):
        # setup the magnitude, depth and range filters
        self.magnitudeRangeFilter.setEnabled(False)
        self.magnitudeRangeFilter.setOrientation(Qt.Horizontal)
        self.magnitudeRangeFilter.setDecimals(1)
        self.magnitudeRangeFilter.setMinimum(0)
        self.magnitudeRangeFilter.setMaximum(10)

        self.depthRangeFilter.setEnabled(False)
        self.depthRangeFilter.setOrientation(Qt.Horizontal)
        self.depthRangeFilter.setMinimum(0)
        self.depthRangeFilter.setMaximum(1000)

        self.dateRangeFilter.setEnabled(False)
        self.dateRangeFilter.setOrientation(Qt.Horizontal)

        # take min/max values index from the data provider,
        # buf first let's reset the subset string to get real min/max
        pr = self.vl.dataProvider()
        pr.setSubsetString("")

        key2index = Utils.key2indexFieldMap(pr.fields())
        for key, index in key2index.iteritems():
            filterWdg = self._filterForKey(key)
            if not filterWdg:
                continue

            minVal = pr.minimumValue(index)
            maxVal = pr.maximumValue(index)

            if minVal.isValid() and maxVal.isValid():
                # check for empty strings (the provider could be unable to retrieve values)
                if minVal.toString().isEmpty():
                    minVal = None
                if maxVal.toString().isEmpty():
                    maxVal = None

                if minVal is None or maxVal is None:
                    # let's search the real min/max values
                    self.vl.select([index], QgsRectangle(), False)
                    f = QgsFeature()
                    while self.vl.nextFeature(f):
                        fval = Utils.valueFromQVariant(f.attributeMap()[index])
                        if not minVal or fval < minVal:
                            minVal = fval
                        if not maxVal or fval > maxVal:
                            maxVal = fval
                else:
                    minVal = Utils.valueFromQVariant(minVal)
                    maxVal = Utils.valueFromQVariant(maxVal)

                # setup filter min/max range
                try:
                    filterWdg.setMinimum(minVal)
                    filterWdg.setLowValue(minVal)
                    filterWdg.setMaximum(maxVal)
                    filterWdg.setHighValue(maxVal)
                except:
                    raise
                    # unable to set min/max, skip the filter
                    continue

                filterWdg.setEnabled(True)
                self.connect(filterWdg, SIGNAL("changeFinished"),
                             self.updateMap)

        # filter default ranges
        self.magnitudeRangeFilter.setLowValue(3.5)
        self.magnitudeRangeFilter.setHighValue(10)
        self.depthRangeFilter.setLowValue(0)
        self.depthRangeFilter.setHighValue(250)

        self.updateMap()

    def updateMap(self, *args):
        pr = self.vl.dataProvider()
        key2index = Utils.key2indexFieldMap(pr.fields())

        # convert filters to subset string
        subsets = []
        for key, index in key2index.iteritems():
            filterWdg = self._filterForKey(key)
            if not filterWdg or not filterWdg.isEnabled(
            ) or not filterWdg.isActive():
                continue

            name = pr.fields()[index].name()

            # define a new subset string when the low value is greather then the minimum value
            if filterWdg.lowValue() > filterWdg.minimum():
                minVal = QVariant(filterWdg.lowValue())
                if minVal.type() in (QVariant.Date, QVariant.DateTime):
                    dataFormat = "yyyy/MM/dd" if self.vl.providerType(
                    ) == 'ogr' else "yyyy-MM-dd"
                    minVal = u"'%s'" % minVal.toDate().toString(dataFormat)
                else:
                    minVal = minVal.toString()
                subsets.append(u"\"%s\" >= %s" %
                               (name.replace('"', '""'), minVal))

            # define a new subset string when the high value is less then the maximum value
            if filterWdg.highValue() < filterWdg.maximum():
                maxVal = QVariant(filterWdg.highValue())
                if maxVal.type() in (QVariant.Date, QVariant.DateTime):
                    dataFormat = "yyyy/MM/dd" if self.vl.providerType(
                    ) == 'ogr' else "yyyy-MM-dd"
                    maxVal = u"'%s'" % maxVal.toDate().toString(dataFormat)
                else:
                    maxVal = maxVal.toString()
                subsets.append(u"\"%s\" <= %s" %
                               (name.replace('"', '""'), maxVal))

        # set the subset string, then update the layer
        if self.vl.setSubsetString(u" AND ".join(subsets)):
            self.vl.triggerRepaint()

    def showRubberBands(self, show=True):
        """ show/hide all the rubberbands """
        if self.polygonDrawer.isEmittingPoints:
            self.polygonDrawer.reset()
        else:
            self.polygonDrawer.rubberBand.show(
            ) if show else self.polygonDrawer.rubberBand.hide()

    def drawPolygon(self):
        # store the previous maptool
        self.storePrevMapTool()

        # set the polygon drawer as current maptool
        self.polygonDrawer.startCapture()

    def clearPolygon(self):
        # remove the displayed polygon
        self.polygonDrawer.reset()

    def polygonCreated(self, polygon):
        # restore the previous maptool
        self.restorePrevMapTool()

    def createPlot(self):
        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
        try:
            dlg = self._createPlotDlg()
        finally:
            QApplication.restoreOverrideCursor()

        if dlg:
            dlg.show()
            dlg.exec_()
            dlg.deleteLater()

    def _createPlotDlg(self):
        plotType = self._getPlotType()
        hasYField = self._hasPlotYField(plotType)

        # spatial filter
        spatialFilter = self.polygonDrawer.geometry()
        if not spatialFilter:
            extent = QgsRectangle()
        else:
            # convert the spatial filter to the layer CRS
            toLayerCrsTransform = QgsCoordinateTransform(
                self.canvas.mapRenderer().destinationCrs(), self.vl.crs())
            ret = spatialFilter.transform(toLayerCrsTransform)
            if ret != 0:
                QMessageBox.warning(
                    self, "Invalid area",
                    "Unable to tranform the selected area to the layer CRS.")
                return
            extent = spatialFilter.boundingBox()

        # get the indexes of fields selected in the combos
        xIndex = self.xAxisCombo.itemData(
            self.xAxisCombo.currentIndex()).toInt()[0]
        yIndex = self.yAxisCombo.itemData(
            self.yAxisCombo.currentIndex()).toInt()[0]

        pr = self.vl.dataProvider()
        index2key = Utils.index2keyFieldMap(pr.fields())

        indexes = []
        for index, fld in pr.fields().iteritems():
            if index == xIndex:
                indexes.append(xIndex)
                continue

            if index == yIndex and hasYField:
                indexes.append(yIndex)
                continue

            filterWdg = self._filterForKey(Utils.fieldName2key(fld.name()))
            if filterWdg and filterWdg.isActive():
                indexes.append(index)

        # the following lists will contain x and y values
        x, y = ([], [])

        # fetch and loop through the features
        pr.select(indexes, extent, True)

        f = QgsFeature()
        while pr.nextFeature(f):
            # filter features by spatial filter
            if spatialFilter and not spatialFilter.contains(f.geometry()):
                continue

            # filter features by attribute values
            attrs = f.attributeMap()

            ok = True
            for index, val in attrs.iteritems():
                if not index2key.has_key(index):
                    continue  # unused field

                filterWdg = self._filterForKey(index2key[index])
                if not filterWdg:
                    continue  # the field has no associated filter widget

                if filterWdg.isActive() and not filterWdg.checkValue(val):
                    ok = False
                    break

            if not ok:  # the feature was filtered out
                continue

            # append feature values to the lists
            x.append(attrs[xIndex])
            if hasYField: y.append(attrs[yIndex])

        if len(x) <= 0:
            QMessageBox.information(self, "Plot", "No features in the result")
            return

        from plot_wdg import HistogramPlotDlg, ScatterPlotDlg
        if plotType == self.PLOT_HIST:
            dlg = HistogramPlotDlg(
                None, [x], [self.xAxisCombo.currentText(), "Frequency"],
                self.titleEdit.text())
        elif plotType == self.PLOT_HIST_LOG:
            dlg = HistogramPlotDlg(
                None, [x], [self.xAxisCombo.currentText(), "Frequency"],
                self.titleEdit.text(), {'yscale': 'log'})
        elif plotType == self.PLOT_SCATTER:
            dlg = ScatterPlotDlg(
                None, [x, y],
                [self.xAxisCombo.currentText(),
                 self.yAxisCombo.currentText()], self.titleEdit.text())
        else:
            return

        return dlg
Example #9
0
class FilterWdg(QWidget, Ui_FilterWdg):

	PLOT_HIST, PLOT_HIST_LOG, PLOT_SCATTER = range(3)

	def __init__(self, iface, parent=None):
		QWidget.__init__(self, parent)
		self.setupUi(self)

		# store the iface and the event layer
		self.iface = iface
		self.vl = Utils.eventsVl()

		self.canvas = self.iface.mapCanvas()
		self._prevMapTool = None

		# setup the magnitude, depth and range filters
		self.setupFilters()

		# create the maptool to draw polygons
		self.polygonDrawer = PolygonDrawer( self.canvas, {'color':QColor("#666666"), 'enableSnap':False, 'keepAfterEnd':True} )
		self.polygonDrawer.setAction( self.drawPolygonBtn )
		self.connect(self.polygonDrawer, SIGNAL("geometryEmitted"), self.polygonCreated)

		# populate plot type combo
		self.plotTypeCombo.addItem( "Histogram", self.PLOT_HIST )
		self.plotTypeCombo.addItem( "Histogram (log10)", self.PLOT_HIST_LOG )
		self.plotTypeCombo.addItem( "Scatter plot", self.PLOT_SCATTER )
		self.updateAxesCombos()

		# populate both axis combos with field names
		for index, fld in self.vl.dataProvider().fields().iteritems():
			self.xAxisCombo.addItem( fld.name(), QVariant(index) )
			self.yAxisCombo.addItem( fld.name(), QVariant(index) )

		# connect actions to the widgets
		self.connect(self.drawPolygonBtn, SIGNAL("clicked()"), self.drawPolygon)
		self.connect(self.clearPolygonBtn, SIGNAL("clicked()"), self.clearPolygon)
		self.connect(self.plotBtn, SIGNAL("clicked()"), self.createPlot)
		self.connect(self.plotTypeCombo, SIGNAL("currentIndexChanged(int)"), self.updateAxesCombos)


	def storePrevMapTool(self):
		prevMapTool = self.canvas.mapTool()
		if prevMapTool not in (self.polygonDrawer,):
			self._prevMapTool = prevMapTool

	def restorePrevMapTool(self):
		self.polygonDrawer.stopCapture()
		if self._prevMapTool: 
			self.canvas.setMapTool(self._prevMapTool)


	def showEvent(self, event):
		self.showRubberBands(True)
		QWidget.showEvent(self, event)

	def hideEvent(self, event):
		self.showRubberBands(False)
		self.restorePrevMapTool()
		QWidget.hideEvent(self, event)


	def deleteLater(self, *args):
		#print "deleting", self
		self.clearPolygon()

		# restore the previous maptool
		self.restorePrevMapTool()

		# delete the polygon drawer maptool
		self.polygonDrawer.deleteLater()
		self.polygonDrawer = None

		QWidget.deleteLater(self, *args)


	def _filterForKey(self, key):
		if key == 'magnitude': return self.magnitudeRangeFilter
		if key == 'depth': return self.depthRangeFilter
		if key == 'date': return self.dateRangeFilter
		return None

	def _hasPlotYField(self, plotType):
		return plotType not in (self.PLOT_HIST, self.PLOT_HIST_LOG)

	def _getPlotType(self):
		return self.plotTypeCombo.itemData( self.plotTypeCombo.currentIndex() )

	def updateAxesCombos(self):
		self.yAxisCombo.setEnabled( self._hasPlotYField( self._getPlotType() ) )


	def setupFilters(self):
		# setup the magnitude, depth and range filters
		self.magnitudeRangeFilter.setEnabled(False)
		self.magnitudeRangeFilter.setOrientation( Qt.Horizontal )
		self.magnitudeRangeFilter.setDecimals( 1 )
		self.magnitudeRangeFilter.setMinimum( 0 )
		self.magnitudeRangeFilter.setMaximum( 10 )

		self.depthRangeFilter.setEnabled(False)
		self.depthRangeFilter.setOrientation( Qt.Horizontal )
		self.depthRangeFilter.setMinimum( 0 )
		self.depthRangeFilter.setMaximum( 1000 )

		self.dateRangeFilter.setEnabled(False)
		self.dateRangeFilter.setOrientation( Qt.Horizontal )

		# take min/max values index from the data provider,
		# buf first let's reset the subset string to get real min/max
		pr = self.vl.dataProvider()
		pr.setSubsetString("")

		key2index = Utils.key2indexFieldMap( pr.fields() )
		for key, index in key2index.iteritems():
			filterWdg = self._filterForKey( key )
			if not filterWdg:
				continue

			minVal = pr.minimumValue( index )
			maxVal = pr.maximumValue( index )

			if minVal.isValid() and maxVal.isValid():
				# check for empty strings (the provider could be unable to retrieve values)
				if minVal.toString().isEmpty():
					minVal = None
				if maxVal.toString().isEmpty():
					maxVal = None

				if minVal is None or maxVal is None:
					# let's search the real min/max values
					self.vl.select([index], QgsRectangle(), False)
					f = QgsFeature()
					while self.vl.nextFeature( f ):
						fval = Utils.valueFromQVariant( f.attributeMap()[index] )
						if not minVal or fval < minVal:
							minVal = fval
						if not maxVal or fval > maxVal:
							maxVal = fval
				else:
					minVal = Utils.valueFromQVariant( minVal )
					maxVal = Utils.valueFromQVariant( maxVal )

				# setup filter min/max range
				try:
					filterWdg.setMinimum( minVal )
					filterWdg.setLowValue( minVal )
					filterWdg.setMaximum( maxVal )
					filterWdg.setHighValue( maxVal )
				except:
					raise
					# unable to set min/max, skip the filter
					continue

				filterWdg.setEnabled(True)
				self.connect(filterWdg, SIGNAL("changeFinished"), self.updateMap)

		# filter default ranges
		self.magnitudeRangeFilter.setLowValue( 3.5 )
		self.magnitudeRangeFilter.setHighValue( 10 )
		self.depthRangeFilter.setLowValue( 0 )
		self.depthRangeFilter.setHighValue( 250 )

		self.updateMap()


	def updateMap(self, *args):
		pr = self.vl.dataProvider()
		key2index = Utils.key2indexFieldMap( pr.fields() )

		# convert filters to subset string
		subsets = []
		for key, index in key2index.iteritems():
			filterWdg = self._filterForKey( key )
			if not filterWdg or not filterWdg.isEnabled() or not filterWdg.isActive():
				continue

			name = pr.fields()[index].name()

			# define a new subset string when the low value is greather then the minimum value
			if filterWdg.lowValue() > filterWdg.minimum():
				minVal = QVariant(filterWdg.lowValue())
				if minVal.type() in (QVariant.Date, QVariant.DateTime):
					dataFormat = "yyyy/MM/dd" if self.vl.providerType() == 'ogr' else "yyyy-MM-dd"
					minVal = u"'%s'" % minVal.toDate().toString(dataFormat)
				else:
					minVal = minVal.toString()
				subsets.append( u"\"%s\" >= %s" % (name.replace('"', '""'), minVal) )

			# define a new subset string when the high value is less then the maximum value
			if filterWdg.highValue() < filterWdg.maximum():
				maxVal = QVariant(filterWdg.highValue())
				if maxVal.type() in (QVariant.Date, QVariant.DateTime):
					dataFormat = "yyyy/MM/dd" if self.vl.providerType() == 'ogr' else "yyyy-MM-dd"
					maxVal = u"'%s'" % maxVal.toDate().toString(dataFormat)
				else:
					maxVal = maxVal.toString()
				subsets.append( u"\"%s\" <= %s" % (name.replace('"', '""'), maxVal) )

		# set the subset string, then update the layer
		if self.vl.setSubsetString( u" AND ".join(subsets) ):
			self.vl.triggerRepaint()


	def showRubberBands(self, show=True):
		""" show/hide all the rubberbands """
		if self.polygonDrawer.isEmittingPoints:
			self.polygonDrawer.reset()
		else:
			self.polygonDrawer.rubberBand.show() if show else self.polygonDrawer.rubberBand.hide()

	def drawPolygon(self):
		# store the previous maptool
		self.storePrevMapTool()

		# set the polygon drawer as current maptool
		self.polygonDrawer.startCapture()

	def clearPolygon(self):
		# remove the displayed polygon
		self.polygonDrawer.reset()

	def polygonCreated(self, polygon):
		# restore the previous maptool
		self.restorePrevMapTool()


	def createPlot(self):
		QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
		try:
			dlg = self._createPlotDlg()
		finally:
			QApplication.restoreOverrideCursor()

		if dlg:
			dlg.show()
			dlg.exec_()
			dlg.deleteLater()


	def _createPlotDlg(self):
		plotType = self._getPlotType()
		hasYField = self._hasPlotYField( plotType )

		# spatial filter
		spatialFilter = self.polygonDrawer.geometry()
		if not spatialFilter:
			extent = QgsRectangle()
		else:
			# convert the spatial filter to the layer CRS
			toLayerCrsTransform = QgsCoordinateTransform( self.canvas.mapRenderer().destinationCrs(), self.vl.crs() )
			ret = spatialFilter.transform( toLayerCrsTransform )
			if ret != 0:
				QMessageBox.warning(self, "Invalid area", "Unable to tranform the selected area to the layer CRS.")
				return
			extent = spatialFilter.boundingBox()

		# get the indexes of fields selected in the combos
		xIndex = self.xAxisCombo.itemData( self.xAxisCombo.currentIndex() ).toInt()[0]
		yIndex = self.yAxisCombo.itemData( self.yAxisCombo.currentIndex() ).toInt()[0]

		pr = self.vl.dataProvider()
		index2key = Utils.index2keyFieldMap( pr.fields() )

		indexes = []
		for index, fld in pr.fields().iteritems():
			if index == xIndex:
				indexes.append( xIndex )
				continue

			if index == yIndex and hasYField:
				indexes.append( yIndex )
				continue

			filterWdg = self._filterForKey( Utils.fieldName2key( fld.name() ) )
			if filterWdg and filterWdg.isActive():
				indexes.append( index )


		# the following lists will contain x and y values
		x, y = ([], [])

		# fetch and loop through the features
		pr.select( indexes, extent, True )

		f = QgsFeature()
		while pr.nextFeature( f ):
			# filter features by spatial filter
			if spatialFilter and not spatialFilter.contains( f.geometry() ):
				continue

			# filter features by attribute values
			attrs = f.attributeMap()

			ok = True
			for index, val in attrs.iteritems():
				if not index2key.has_key( index ):
					continue	# unused field

				filterWdg = self._filterForKey( index2key[ index ] )
				if not filterWdg:
					continue	# the field has no associated filter widget

				if filterWdg.isActive() and not filterWdg.checkValue( val ):
					ok = False
					break

			if not ok:	# the feature was filtered out
				continue

			# append feature values to the lists
			x.append( attrs[ xIndex ] )
			if hasYField: y.append( attrs[ yIndex ] )


		if len(x) <= 0:
			QMessageBox.information(self, "Plot", "No features in the result")
			return

		from plot_wdg import HistogramPlotDlg, ScatterPlotDlg
		if plotType == self.PLOT_HIST:
			dlg = HistogramPlotDlg(None, [x], [self.xAxisCombo.currentText(), "Frequency"], self.titleEdit.text())
		elif plotType == self.PLOT_HIST_LOG:
			dlg = HistogramPlotDlg(None, [x], [self.xAxisCombo.currentText(), "Frequency"], self.titleEdit.text(), {'yscale':'log'})
		elif plotType == self.PLOT_SCATTER:
			dlg = ScatterPlotDlg(None, [x, y], [self.xAxisCombo.currentText(), self.yAxisCombo.currentText()], self.titleEdit.text())
		else:
			return

		return dlg
Example #10
0
class ClassificationWdg(QWidget, Ui_ClassificationWdg):
    def __init__(self, iface, parent=None):
        QWidget.__init__(self, parent)
        self.setupUi(self)

        # store the iface and the events layer
        self.iface = iface
        self.vl = Utils.eventsVl()

        self.canvas = self.iface.mapCanvas()
        self._prevMapTool = None
        self._sharedData = {
        }  # it will contain the classification map (data shared through the all cross sections)

        # create the maptool to define the area of interest
        self.areaDrawer = PolygonDrawer(
            self.iface.mapCanvas(), {
                'color': QColor('#333333'),
                'border': 2,
                'enableSnap': False,
                'keepAfterEnd': True
            })
        self.areaDrawer.setAction(self.drawAreaBtn)
        self.connect(self.areaDrawer, SIGNAL("geometryEmitted"),
                     self.areaCreated)

        # create the maptool to create classification buffers
        self.segmentDrawer = SegmentDrawer(self.iface.mapCanvas(), {
            'color': QColor('cyan'),
            'border': 3,
            'enableSnap': False
        })
        self.segmentDrawer.setAction(self.addBufferBtn)
        self.connect(self.segmentDrawer, SIGNAL("geometryEmitted"),
                     self.midlineBufferCreated)

        # initialize the table that will contain classification buffers
        self.buffersTable.setModel(self.BuffersTableModel(self.buffersTable))
        self.connect(
            self.buffersTable.selectionModel(),
            SIGNAL(
                "currentRowChanged(const QModelIndex &, const QModelIndex &)"),
            self.buffersSelectionChanged)
        self.connect(self.buffersTable.model(), SIGNAL("bufferWidthChanged"),
                     self.updateBuffer)

        # connect actions to the widgets
        self.connect(self.drawAreaBtn, SIGNAL("clicked()"), self.drawArea)
        self.connect(self.clearAreaBtn, SIGNAL("clicked()"), self.clearArea)
        self.connect(self.addBufferBtn, SIGNAL("clicked()"), self.drawBuffer)
        self.connect(self.delBufferBtn, SIGNAL("clicked()"), self.deleteBuffer)
        self.connect(self.crossSectionBtn, SIGNAL("clicked()"),
                     self.openCrossSection)
        self.connect(self.displayClassifiedDataBtn, SIGNAL("clicked()"),
                     self.loadClassifiedData)

        # disable buttons
        self.delBufferBtn.setEnabled(False)
        self.crossSectionBtn.setEnabled(False)

    def storePrevMapTool(self):
        prevMapTool = self.canvas.mapTool()
        if prevMapTool and prevMapTool not in (self.areaDrawer,
                                               self.segmentDrawer):
            self._prevMapTool = prevMapTool

    def restorePrevMapTool(self):
        self.areaDrawer.stopCapture()
        self.segmentDrawer.stopCapture()
        if self._prevMapTool:
            self.canvas.setMapTool(self._prevMapTool)

    def showEvent(self, event):
        self.showRubberBands(True)
        QWidget.showEvent(self, event)

    def hideEvent(self, event):
        self.showRubberBands(False)
        self.restorePrevMapTool()
        QWidget.hideEvent(self, event)

    def deleteLater(self, *args):
        #print "deleting", self
        # clear rubberbands
        self.clearArea()
        self.clearBuffers()

        # restore the previous maptool
        self.restorePrevMapTool()

        # delete the maptools
        self.areaDrawer.deleteLater()
        self.areaDrawer = None
        self.segmentDrawer.deleteLater()
        self.segmentDrawer = None

        return QWidget.deleteLater(self, *args)

    def showRubberBands(self, show=True):
        """ show/hide all the rubberbands """
        if self.areaDrawer.isEmittingPoints:
            self.areaDrawer.reset()
        else:
            self.areaDrawer.rubberBand.show(
            ) if show else self.areaDrawer.rubberBand.hide()
        self.segmentDrawer.reset()

        model = self.buffersTable.model()
        for row in range(model.rowCount()):
            # get item data
            index = model.index(row, 0)
            buffersize = model.getBufferSize(index)
            segment, (midlineRb,
                      bufferRb), dlg = model.getAdditionalData(index)

            midlineRb.show() if show else midlineRb.hide()
            bufferRb.show() if show else bufferRb.hide()
            if dlg:
                dlg.hide()

    def drawArea(self):
        # store the previous maptool
        self.storePrevMapTool()

        # set the polygon drawer as current maptool
        self.areaDrawer.startCapture()

    def clearArea(self):
        # remove the displayed polygon
        self.areaDrawer.reset()

    def areaCreated(self, polygon):
        # restore the previous maptool
        self.restorePrevMapTool()

    def drawBuffer(self):
        """ set the maptool to draw the buffer midline """
        # store the previous maptool
        self.storePrevMapTool()

        # set the segment drawer as current maptool
        self.segmentDrawer.startCapture()

    def clearBuffers(self):
        """ delete all the classification buffers and related rubberbands """
        self.segmentDrawer.reset()

        model = self.buffersTable.model()
        for row in range(model.rowCount() - 1, -1, -1):
            self.deleteBuffer(row)

        self.buffersTable.model().clear()

    def midlineBufferCreated(self, line):
        """ called after the buffer midline is drawn by the user """
        # restore the previous maptool
        self.restorePrevMapTool()

        # check for a valid segment
        if not line:
            return

        segment = line.asPolyline()
        if len(segment) != 2:
            return

        # create the midline rubber band
        midlineRb = QgsRubberBand(self.canvas, False)
        midlineRb.setColor(QColor('cyan'))
        midlineRb.setWidth(3)

        # create the buffer rubber band
        bufferRb = QgsRubberBand(self.canvas, True)
        bufferRb.setColor(QColor('fuchsia'))
        bufferRb.setWidth(1)

        # define buffer width in layer CRS unit
        units = self.canvas.mapUnits()
        if units == QGis.Meters:
            bufferwidth = 100000  # 100 Km
        elif units == QGis.Feet:
            bufferwidth = 300000  # 300 Kft
        else:
            bufferwidth = 1.0  # 1 degree

        # append the new classification buffer to the table
        data = [segment, (midlineRb, bufferRb), None]
        row = self.buffersTable.model().append(bufferwidth, data)
        self.buffersTable.setCurrentIndex(self.buffersTable.model().index(
            row, 0))

    def redrawMidlineRubberBand(self, rubberBand, segment):
        """ re-draw the midline rubberband by segment """
        rubberBand.reset(False)

        # add points to the midline rubber band
        rubberBand.addPoint(segment[0], False)
        rubberBand.addPoint(segment[1], True)

        rubberBand.show()

    def redrawBufferRubberBand(self, rubberBand, segment, width):
        """ re-draw the buffer rubberband by segment and width """
        rubberBand.reset(True)

        # create a buffer around the line
        import math
        (x1, y1), (x2, y2) = segment
        angle = math.atan(float(y2 - y1) /
                          (x2 - x1)) if x2 - x1 != 0 else math.pi / 2

        xincr, yincr = width * math.sin(angle), width * math.cos(angle)

        # add the buffer geom points to the rubber band
        rubberBand.addPoint(QgsPoint(x1 + xincr, y1 - yincr), False)
        rubberBand.addPoint(QgsPoint(x1 - xincr, y1 + yincr), False)
        rubberBand.addPoint(QgsPoint(x2 - xincr, y2 + yincr), False)
        rubberBand.addPoint(QgsPoint(x2 + xincr, y2 - yincr), True)

        rubberBand.show()

    def deleteBuffer(self, row=None):
        """ delete the classification buffer at row and its rubberbands """
        model = self.buffersTable.model()

        if row is None:
            row = self.buffersTable.currentIndex().row()

        if row < 0 or row >= model.rowCount():
            return

        # get item data
        segment, (midlineRb,
                  bufferRb), dlg = model.getAdditionalData(model.index(row, 0))

        # delete the item
        model.removeRows(row, 1)

        # destroy item data
        midlineRb.reset(False)
        bufferRb.reset(True)
        if dlg:
            self.disconnect(self, SIGNAL("classificationUpdated"), dlg.refresh)
            dlg.close()
            dlg.deleteLater()

    def updateBuffer(self, index):
        """ re-draw the rubberbands for the classification buffer at index """
        model = self.buffersTable.model()

        buffersize = model.getBufferSize(index)
        segment, (midlineRb, bufferRb), dlg = model.getAdditionalData(index)

        self.redrawBufferRubberBand(bufferRb, segment, buffersize)
        self.redrawMidlineRubberBand(midlineRb, segment)

        if dlg:
            dlg.refresh()

    def buffersSelectionChanged(self, current, previous):
        """ update buttons, then highlight the rubberbands for the 
			selected classification buffer """
        self.delBufferBtn.setEnabled(current.isValid())
        self.crossSectionBtn.setEnabled(current.isValid())

        model = self.buffersTable.model()
        for index in (previous, current):
            if not index.isValid():
                continue

            buffersize = model.getBufferSize(index)
            segment, (midlineRb,
                      bufferRb), dlg = model.getAdditionalData(index)

            midlineRb.setColor(
                QColor('#88FFFF')) if index == current else midlineRb.setColor(
                    QColor('#00FFFF'))  # color cyan
            bufferRb.setColor(
                QColor('#FF88FF')) if index == current else bufferRb.setColor(
                    QColor('#FF00FF'))  # color fuchsia

            self.redrawBufferRubberBand(bufferRb, segment, buffersize)
            self.redrawMidlineRubberBand(midlineRb, segment)

    def openCrossSection(self):
        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
        try:
            dlg = self._openCrossSection()
        finally:
            QApplication.restoreOverrideCursor()

    def _openCrossSection(self):
        """ open a cross section displaying geometries within this 
			classification buffer """
        index = self.buffersTable.currentIndex()
        if not index.isValid():
            return

        # get the geometry which defines the area of interest
        areaGeom = self.areaDrawer.geometry()
        if not areaGeom or areaGeom.isGeosEmpty():
            QMessageBox.warning(
                self, "No Area of interest",
                "Define an Area of interest and then try again.")
            return

        # get midline and area geometries for the selected classification buffer
        model = self.buffersTable.model()
        segment, (midlineRb, bufferRb), dlg = model.getAdditionalData(index)

        midlineGeom = midlineRb.asGeometry()
        bufferGeom = bufferRb.asGeometry()

        # compute the spatial filter
        filteringGeom = bufferGeom.intersection(areaGeom)
        if not filteringGeom or filteringGeom.isGeosEmpty():
            QMessageBox.warning(
                self, "Invalid area",
                "Intersection between the Area of interest and the selected classification buffer area is invalid or empty."
            )
            return

        # convert the spatial filter to the layer CRS
        toLayerCrsTransform = QgsCoordinateTransform(
            self.canvas.mapRenderer().destinationCrs(), self.vl.crs())
        ret = filteringGeom.transform(toLayerCrsTransform)
        if ret != 0:
            QMessageBox.warning(
                self, "Invalid area",
                "Unable to tranform the selected area to the layer CRS.")
            return

        # get the depth field index
        pr = self.vl.dataProvider()
        key2index = Utils.key2indexFieldMap(pr.fields())
        depthIndex = key2index['depth']

        # the following x and y lists will contain respectively the distance
        # along the buffer and the depth, the info list instead will contain
        # additional data
        x, y, info = [], [], []

        # fetch and loop through the features
        pr.select([depthIndex], filteringGeom.boundingBox(), True)

        toMapCrsTransform = QgsCoordinateTransform(
            self.vl.crs(),
            self.canvas.mapRenderer().destinationCrs())
        f = QgsFeature()
        while pr.nextFeature(f):
            geom = f.geometry()

            # filter features by spatial filter
            if not filteringGeom.contains(geom):
                continue

            # transform to map CRS
            if geom.transform(toMapCrsTransform) != 0:
                continue
            geom = QgsGeometry.fromPoint(geom.asPoint())

            # store distance and depth values
            dist = Utils.distanceAlongProfile(midlineGeom, geom)
            x.append(Utils.toDisplayedSize(dist))  # convert to Km/Kft/degrees
            y.append(f.attributeMap()[depthIndex].toDouble()[0] * -1)
            info.append(f.id())

        if len(x) <= 0:
            QMessageBox.information(self, "Cross section",
                                    "No features in the result")
            return

        # plot now!
        if not dlg:
            from cross_section_wdg import CrossSectionDlg
            dlg = CrossSectionDlg(self._sharedData, self)
            self.connect(dlg, SIGNAL("classificationUpdateRequested"),
                         self.updateClassification)
            self.connect(self, SIGNAL("classificationUpdated"), dlg.refresh)

            # store the dialog into the item data
            model.setAdditionalData(index,
                                    [segment, (midlineRb, bufferRb), dlg])

        dlg.setData(x, y, info)
        dlg.setLabels("Distance", "Depth")

        self.updateClassification()
        dlg.show()

    def updateClassification(self):
        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
        try:
            self._updateClassification()
        finally:
            QApplication.restoreOverrideCursor()

    def _updateClassification(self):
        model = self.buffersTable.model()

        # update the earthquakes classification
        self._sharedData.clear()

        for row in range(model.rowCount()):

            dlg = model.getAdditionalData(model.index(row, 0))[2]
            if not dlg:
                continue

            classified = (shallow, deep) = dlg.classify()

            # update the shared data
            for typeIndex, data in enumerate(classified):
                for fid in data:
                    # avoid duplicates
                    if self._sharedData.has_key(fid):
                        # do not update shallow earthquakes
                        if self._sharedData[fid] == 0:
                            continue  # already present

                    self._sharedData[fid] = typeIndex

        self.emit(SIGNAL("classificationUpdated"))

    def loadClassifiedData(self):
        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))

        # store the current render flag state, then unset it
        prev_render_flag = self.iface.mapCanvas().renderFlag()
        self.iface.mapCanvas().setRenderFlag(False)
        try:
            self._loadClassifiedData()
        finally:
            # restore render flag state and cursor
            self.iface.mapCanvas().setRenderFlag(prev_render_flag)
            QApplication.restoreOverrideCursor()

    def _loadClassifiedData(self):
        # get the geometry which defines the area of interest
        areaGeom = self.areaDrawer.geometry()
        if not areaGeom or areaGeom.isGeosEmpty():
            QMessageBox.warning(
                self, "No Area of interest",
                "Define an Area of interest and then try again.")
            return

        # convert the spatial filter to the layer CRS
        toLayerCrsTransform = QgsCoordinateTransform(
            self.canvas.mapRenderer().destinationCrs(), self.vl.crs())
        ret = areaGeom.transform(toLayerCrsTransform)
        if ret != 0:
            QMessageBox.warning(
                self, "Invalid area",
                "Unable to tranform the selected area to the layer CRS.")
            return

        # update the classification
        self.updateClassification()

        classifiedVl = Utils.classifiedVl()
        outpr = classifiedVl.dataProvider()

        # remove all the features in the classified events layer
        classifiedVl.removeSelection()
        classifiedVl.invertSelection()
        outpr.deleteFeatures(classifiedVl.selectedFeaturesIds())

        # fetch and loop through the features
        inpr = self.vl.dataProvider()
        inpr.select(self.vl.pendingAllAttributesList(), areaGeom.boundingBox(),
                    True)

        betweenLayersCrsTransform = QgsCoordinateTransform(
            self.vl.crs(), classifiedVl.crs())
        f = QgsFeature()
        while inpr.nextFeature(f):
            geom = f.geometry()

            # filter features by spatial filter
            if not areaGeom.contains(geom):
                continue

            # skip unclassified data
            if f.id() not in self._sharedData:
                continue
            classType = self._sharedData[f.id()]

            # transform to classified layer CRS
            if geom.transform(betweenLayersCrsTransform) != 0:
                continue
            f.setGeometry(QgsGeometry.fromPoint(geom.asPoint()))

            # set feature attributes
            attrs = {}
            for index, attr in sorted(f.attributeMap().iteritems()):
                attrs[len(attrs)] = attr
            attrs[len(attrs)] = 'shallow' if classType == 0 else 'deep'
            f.setAttributeMap(attrs)

            # add the feature
            outpr.addFeatures([f])

        # update layer's extent when new features have been added
        # because change of extent in provider is not propagated to the layer
        classifiedVl.updateExtents()

        # add the layer to the map
        Utils.addVectorLayer(classifiedVl)

    class BuffersTableModel(QStandardItemModel):
        def __init__(self, parent=None):
            self.header = ["Buffer width"]
            QStandardItemModel.__init__(self, 0, len(self.header), parent)

        def headerData(self, section, orientation, role):
            if role == Qt.DisplayRole:
                if orientation == Qt.Horizontal:
                    return QVariant(self.header[section])
                if orientation == Qt.Vertical:
                    return QVariant(section + 1)
            return QVariant()

        def append(self, buffersize, data):
            item = QStandardItem()
            item.setFlags(item.flags() | Qt.ItemIsEditable)

            self.appendRow([item])
            row = self.rowCount() - 1

            # store buffersize and additional data
            self.blockSignals(True)
            self.setBufferSize(self.index(row, 0), buffersize)
            self.setAdditionalData(self.index(row, 0), data)
            self.blockSignals(False)

            # a new buffer was added, trigger for its repainting
            self.emit(SIGNAL("bufferWidthChanged"), self.index(row, 0))

            return row

        def setData(self, index, data, role=Qt.EditRole):
            ret = QStandardItemModel.setData(self, index, data, role)
            if role == Qt.EditRole and index.column() == 0:
                self.emit(SIGNAL("bufferWidthChanged"), index)
            return ret

        def getBufferSize(self, index):
            if index.isValid():
                displayed_size = self.data(self.index(index.row(),
                                                      0)).toDouble()[0]
                # convert back to m/ft/degrees
                return Utils.fromDisplayedSize(displayed_size)

        def setBufferSize(self, index, buffersize):
            if index.isValid():
                # display Km/Kft/degrees
                displayed_size = Utils.toDisplayedSize(buffersize)
                self.setData(self.index(index.row(), 0),
                             QVariant(displayed_size))

        def getAdditionalData(self, index):
            if index.isValid():
                return self.data(self.index(index.row(), 0),
                                 Qt.UserRole).toPyObject()

        def setAdditionalData(self, index, data):
            if index.isValid():
                self.setData(self.index(index.row(), 0), QVariant(data),
                             Qt.UserRole)
Example #11
0
class ClassificationWdg(QWidget, Ui_ClassificationWdg):

	def __init__(self, iface, parent=None):
		QWidget.__init__(self, parent)
		self.setupUi(self)

		# store the iface and the events layer
		self.iface = iface
		self.vl = Utils.eventsVl()

		self.canvas = self.iface.mapCanvas()
		self._prevMapTool = None
		self._sharedData = {}	# it will contain the classification map (data shared through the all cross sections)

		# create the maptool to define the area of interest
		self.areaDrawer = PolygonDrawer(self.iface.mapCanvas(), {'color':QColor('#333333'), 'border':2, 'enableSnap':False, 'keepAfterEnd':True})
		self.areaDrawer.setAction( self.drawAreaBtn )
		self.connect(self.areaDrawer, SIGNAL("geometryEmitted"), self.areaCreated)

		# create the maptool to create classification buffers
		self.segmentDrawer = SegmentDrawer(self.iface.mapCanvas(), {'color':QColor('cyan'), 'border':3, 'enableSnap':False})
		self.segmentDrawer.setAction( self.addBufferBtn )
		self.connect(self.segmentDrawer, SIGNAL("geometryEmitted"), self.midlineBufferCreated)

		# initialize the table that will contain classification buffers
		self.buffersTable.setModel( self.BuffersTableModel(self.buffersTable) )
		self.connect( self.buffersTable.selectionModel(), SIGNAL("currentRowChanged(const QModelIndex &, const QModelIndex &)"), self.buffersSelectionChanged)
		self.connect( self.buffersTable.model(), SIGNAL("bufferWidthChanged"), self.updateBuffer)

		# connect actions to the widgets
		self.connect(self.drawAreaBtn, SIGNAL("clicked()"), self.drawArea)
		self.connect(self.clearAreaBtn, SIGNAL("clicked()"), self.clearArea)
		self.connect(self.addBufferBtn, SIGNAL("clicked()"), self.drawBuffer)
		self.connect(self.delBufferBtn, SIGNAL("clicked()"), self.deleteBuffer)
		self.connect(self.crossSectionBtn, SIGNAL("clicked()"), self.openCrossSection)
		self.connect(self.displayClassifiedDataBtn, SIGNAL("clicked()"), self.loadClassifiedData)

		# disable buttons
		self.delBufferBtn.setEnabled(False)
		self.crossSectionBtn.setEnabled(False)


	def storePrevMapTool(self):
		prevMapTool = self.canvas.mapTool()
		if prevMapTool and prevMapTool not in (self.areaDrawer, self.segmentDrawer):
			self._prevMapTool = prevMapTool

	def restorePrevMapTool(self):
		self.areaDrawer.stopCapture()
		self.segmentDrawer.stopCapture()
		if self._prevMapTool: 
			self.canvas.setMapTool(self._prevMapTool)


	def showEvent(self, event):
		self.showRubberBands(True)
		QWidget.showEvent(self, event)

	def hideEvent(self, event):
		self.showRubberBands(False)
		self.restorePrevMapTool()
		QWidget.hideEvent(self, event)


	def deleteLater(self, *args):
		#print "deleting", self
		# clear rubberbands
		self.clearArea()
		self.clearBuffers()

		# restore the previous maptool
		self.restorePrevMapTool()

		# delete the maptools
		self.areaDrawer.deleteLater()
		self.areaDrawer = None
		self.segmentDrawer.deleteLater()
		self.segmentDrawer = None

		return QWidget.deleteLater(self, *args)


	def showRubberBands(self, show=True):
		""" show/hide all the rubberbands """
		if self.areaDrawer.isEmittingPoints:
			self.areaDrawer.reset()
		else:
			self.areaDrawer.rubberBand.show() if show else self.areaDrawer.rubberBand.hide()
		self.segmentDrawer.reset()

		model = self.buffersTable.model()
		for row in range(model.rowCount()):
			# get item data
			index = model.index(row, 0)
			buffersize = model.getBufferSize(index)
			segment, (midlineRb, bufferRb), dlg = model.getAdditionalData(index)

			midlineRb.show() if show else midlineRb.hide()
			bufferRb.show() if show else bufferRb.hide()
			if dlg:
				dlg.hide()


	def drawArea(self):
		# store the previous maptool
		self.storePrevMapTool()

		# set the polygon drawer as current maptool
		self.areaDrawer.startCapture()

	def clearArea(self):
		# remove the displayed polygon
		self.areaDrawer.reset()

	def areaCreated(self, polygon):
		# restore the previous maptool
		self.restorePrevMapTool()
	

	def drawBuffer(self):
		""" set the maptool to draw the buffer midline """
		# store the previous maptool
		self.storePrevMapTool()

		# set the segment drawer as current maptool
		self.segmentDrawer.startCapture()


	def clearBuffers(self):
		""" delete all the classification buffers and related rubberbands """
		self.segmentDrawer.reset()

		model = self.buffersTable.model()
		for row in range(model.rowCount()-1, -1, -1):
			self.deleteBuffer(row)

		self.buffersTable.model().clear()


	def midlineBufferCreated(self, line):
		""" called after the buffer midline is drawn by the user """
		# restore the previous maptool
		self.restorePrevMapTool()

		# check for a valid segment
		if not line:
			return

		segment = line.asPolyline()
		if len(segment) != 2:
			return

		# create the midline rubber band
		midlineRb = QgsRubberBand(self.canvas, False)
		midlineRb.setColor( QColor('cyan') )
		midlineRb.setWidth( 3 )

		# create the buffer rubber band
		bufferRb = QgsRubberBand(self.canvas, True)
		bufferRb.setColor( QColor('fuchsia') )
		bufferRb.setWidth( 1 )

		# define buffer width in layer CRS unit
		units = self.canvas.mapUnits()
		if units == QGis.Meters:
			bufferwidth = 100000 # 100 Km
		elif units == QGis.Feet:
			bufferwidth = 300000 # 300 Kft
		else:
			bufferwidth = 1.0 # 1 degree

		# append the new classification buffer to the table
		data = [segment, (midlineRb, bufferRb), None]
		row = self.buffersTable.model().append( bufferwidth, data )
		self.buffersTable.setCurrentIndex( self.buffersTable.model().index( row, 0 ) )
		

	def redrawMidlineRubberBand(self, rubberBand, segment):
		""" re-draw the midline rubberband by segment """
		rubberBand.reset(False)

		# add points to the midline rubber band
		rubberBand.addPoint( segment[0], False )
		rubberBand.addPoint( segment[1], True )

		rubberBand.show()

	def redrawBufferRubberBand(self, rubberBand, segment, width):
		""" re-draw the buffer rubberband by segment and width """
		rubberBand.reset(True)

		# create a buffer around the line
		import math
		(x1,y1), (x2,y2) = segment
		angle = math.atan(float(y2-y1)/(x2-x1)) if x2-x1 != 0 else math.pi/2

		xincr, yincr = width*math.sin(angle), width*math.cos(angle)

		# add the buffer geom points to the rubber band
		rubberBand.addPoint( QgsPoint(x1+xincr, y1-yincr), False )
		rubberBand.addPoint( QgsPoint(x1-xincr, y1+yincr), False )
		rubberBand.addPoint( QgsPoint(x2-xincr, y2+yincr), False )
		rubberBand.addPoint( QgsPoint(x2+xincr, y2-yincr), True )

		rubberBand.show()


	def deleteBuffer(self, row=None):
		""" delete the classification buffer at row and its rubberbands """
		model = self.buffersTable.model()

		if row is None:
			row = self.buffersTable.currentIndex().row()

		if row < 0 or row >= model.rowCount():
			return

		# get item data
		segment, (midlineRb, bufferRb), dlg = model.getAdditionalData( model.index(row, 0) )

		# delete the item
		model.removeRows( row, 1 )

		# destroy item data
		midlineRb.reset(False)
		bufferRb.reset(True)
		if dlg:
			self.disconnect(self, SIGNAL("classificationUpdated"), dlg.refresh)
			dlg.close()
			dlg.deleteLater()

	def updateBuffer(self, index):
		""" re-draw the rubberbands for the classification buffer at index """
		model = self.buffersTable.model()

		buffersize = model.getBufferSize(index)
		segment, (midlineRb, bufferRb), dlg = model.getAdditionalData(index)

		self.redrawBufferRubberBand(bufferRb, segment, buffersize)
		self.redrawMidlineRubberBand(midlineRb, segment)

		if dlg:
			dlg.refresh()


	def buffersSelectionChanged(self, current, previous):
		""" update buttons, then highlight the rubberbands for the 
			selected classification buffer """
		self.delBufferBtn.setEnabled(current.isValid())
		self.crossSectionBtn.setEnabled(current.isValid())

		model = self.buffersTable.model()
		for index in (previous, current):
			if not index.isValid():
				continue

			buffersize = model.getBufferSize(index)
			segment, (midlineRb, bufferRb), dlg = model.getAdditionalData(index)

			midlineRb.setColor(QColor('#88FFFF')) if index == current else midlineRb.setColor(QColor('#00FFFF'))	# color cyan
			bufferRb.setColor(QColor('#FF88FF')) if index == current else bufferRb.setColor(QColor('#FF00FF'))	# color fuchsia

			self.redrawBufferRubberBand(bufferRb, segment, buffersize)
			self.redrawMidlineRubberBand(midlineRb, segment)


	def openCrossSection(self):
		QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
		try:
			dlg = self._openCrossSection()
		finally:
			QApplication.restoreOverrideCursor()

	def _openCrossSection(self):
		""" open a cross section displaying geometries within this 
			classification buffer """
		index = self.buffersTable.currentIndex()
		if not index.isValid():
			return

		# get the geometry which defines the area of interest
		areaGeom = self.areaDrawer.geometry()
		if not areaGeom or areaGeom.isGeosEmpty():
			QMessageBox.warning(self, "No Area of interest", "Define an Area of interest and then try again.")
			return

		# get midline and area geometries for the selected classification buffer
		model = self.buffersTable.model()
		segment, (midlineRb, bufferRb), dlg = model.getAdditionalData(index)

		midlineGeom = midlineRb.asGeometry()
		bufferGeom = bufferRb.asGeometry()

		# compute the spatial filter
		filteringGeom = bufferGeom.intersection( areaGeom )
		if not filteringGeom or filteringGeom.isGeosEmpty():
			QMessageBox.warning(self, "Invalid area", "Intersection between the Area of interest and the selected classification buffer area is invalid or empty.")
			return

		# convert the spatial filter to the layer CRS
		toLayerCrsTransform = QgsCoordinateTransform( self.canvas.mapRenderer().destinationCrs(), self.vl.crs() )
		ret = filteringGeom.transform( toLayerCrsTransform )
		if ret != 0:
			QMessageBox.warning(self, "Invalid area", "Unable to tranform the selected area to the layer CRS.")
			return

		# get the depth field index
		pr = self.vl.dataProvider()
		key2index = Utils.key2indexFieldMap( pr.fields() )
		depthIndex =  key2index['depth']

		# the following x and y lists will contain respectively the distance 
		# along the buffer and the depth, the info list instead will contain 
		# additional data
		x, y, info = [], [], []

		# fetch and loop through the features
		pr.select([ depthIndex ], filteringGeom.boundingBox(), True)

		toMapCrsTransform = QgsCoordinateTransform( self.vl.crs(), self.canvas.mapRenderer().destinationCrs() )
		f = QgsFeature()
		while pr.nextFeature( f ):
			geom = f.geometry()

			# filter features by spatial filter
			if not filteringGeom.contains( geom ):
				continue

			# transform to map CRS
			if geom.transform( toMapCrsTransform ) != 0:
				continue
			geom = QgsGeometry.fromPoint(geom.asPoint())

			# store distance and depth values
			dist = Utils.distanceAlongProfile( midlineGeom, geom )
			x.append( Utils.toDisplayedSize( dist )	)	# convert to Km/Kft/degrees
			y.append( f.attributeMap()[ depthIndex ].toDouble()[0] * -1 )
			info.append( f.id() )

		if len(x) <= 0:
			QMessageBox.information(self, "Cross section", "No features in the result")
			return

		# plot now!
		if not dlg:
			from cross_section_wdg import CrossSectionDlg
			dlg = CrossSectionDlg(self._sharedData, self)
			self.connect(dlg, SIGNAL("classificationUpdateRequested"), self.updateClassification)
			self.connect(self, SIGNAL("classificationUpdated"), dlg.refresh)

			# store the dialog into the item data
			model.setAdditionalData( index, [segment, (midlineRb, bufferRb), dlg] )

		dlg.setData(x, y, info)
		dlg.setLabels( "Distance", "Depth" )

		self.updateClassification()
		dlg.show()


	def updateClassification(self):
		QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
		try:
			self._updateClassification()
		finally:
			QApplication.restoreOverrideCursor()

	def _updateClassification(self):
		model = self.buffersTable.model()

		# update the earthquakes classification
		self._sharedData.clear()

		for row in range(model.rowCount()):
			
			dlg = model.getAdditionalData(model.index(row, 0))[2]
			if not dlg:
				continue

			classified = (shallow, deep) = dlg.classify()

			# update the shared data
			for typeIndex, data in enumerate( classified ):
				for fid in data:
					# avoid duplicates
					if self._sharedData.has_key(fid):
						# do not update shallow earthquakes
						if self._sharedData[ fid ] == 0:	
							continue	# already present

					self._sharedData[ fid ] = typeIndex

		self.emit( SIGNAL("classificationUpdated") )


	def loadClassifiedData(self):
		QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))

		# store the current render flag state, then unset it
		prev_render_flag = self.iface.mapCanvas().renderFlag()
		self.iface.mapCanvas().setRenderFlag( False )
		try:
			self._loadClassifiedData()
		finally:
			# restore render flag state and cursor
			self.iface.mapCanvas().setRenderFlag( prev_render_flag )
			QApplication.restoreOverrideCursor()

	def _loadClassifiedData(self):
		# get the geometry which defines the area of interest
		areaGeom = self.areaDrawer.geometry()
		if not areaGeom or areaGeom.isGeosEmpty():
			QMessageBox.warning(self, "No Area of interest", "Define an Area of interest and then try again.")
			return

		# convert the spatial filter to the layer CRS
		toLayerCrsTransform = QgsCoordinateTransform( self.canvas.mapRenderer().destinationCrs(), self.vl.crs() )
		ret = areaGeom.transform( toLayerCrsTransform )
		if ret != 0:
			QMessageBox.warning(self, "Invalid area", "Unable to tranform the selected area to the layer CRS.")
			return

		# update the classification
		self.updateClassification()

		classifiedVl = Utils.classifiedVl()
		outpr = classifiedVl.dataProvider()

		# remove all the features in the classified events layer
		classifiedVl.removeSelection()
		classifiedVl.invertSelection()
		outpr.deleteFeatures( classifiedVl.selectedFeaturesIds() )

		# fetch and loop through the features
		inpr = self.vl.dataProvider()
		inpr.select(self.vl.pendingAllAttributesList(), areaGeom.boundingBox(), True)

		betweenLayersCrsTransform = QgsCoordinateTransform( self.vl.crs(), classifiedVl.crs() )
		f = QgsFeature()
		while inpr.nextFeature( f ):
			geom = f.geometry()

			# filter features by spatial filter
			if not areaGeom.contains( geom ):
				continue

			# skip unclassified data
			if f.id() not in self._sharedData:
				continue
			classType = self._sharedData[ f.id() ]

			# transform to classified layer CRS
			if geom.transform( betweenLayersCrsTransform ) != 0:
				continue
			f.setGeometry( QgsGeometry.fromPoint(geom.asPoint()) )

			# set feature attributes
			attrs = {}
			for index, attr in sorted(f.attributeMap().iteritems()):
				attrs[ len(attrs) ] = attr
			attrs[ len(attrs) ] =  'shallow' if classType == 0 else 'deep'
			f.setAttributeMap( attrs )

			# add the feature
			outpr.addFeatures( [f] )

		# update layer's extent when new features have been added
		# because change of extent in provider is not propagated to the layer
		classifiedVl.updateExtents()

		# add the layer to the map
		Utils.addVectorLayer( classifiedVl )


	class BuffersTableModel(QStandardItemModel):
		def __init__(self, parent=None):
			self.header = ["Buffer width"]
			QStandardItemModel.__init__(self, 0, len(self.header), parent)

		def headerData(self, section, orientation, role):
			if role == Qt.DisplayRole:
				if orientation == Qt.Horizontal:
					return QVariant(self.header[section])
				if orientation == Qt.Vertical:
					return QVariant(section+1)
			return QVariant()

		def append(self, buffersize, data):
			item = QStandardItem()
			item.setFlags( item.flags() | Qt.ItemIsEditable )

			self.appendRow( [item] )
			row = self.rowCount()-1

			# store buffersize and additional data
			self.blockSignals(True)
			self.setBufferSize(self.index(row, 0), buffersize)
			self.setAdditionalData(self.index(row, 0), data)
			self.blockSignals(False)

			# a new buffer was added, trigger for its repainting
			self.emit( SIGNAL("bufferWidthChanged"), self.index(row, 0) )

			return row

		def setData(self, index, data, role=Qt.EditRole):
			ret = QStandardItemModel.setData(self, index, data, role)
			if role == Qt.EditRole and index.column() == 0:
				self.emit( SIGNAL("bufferWidthChanged"), index )
			return ret


		def getBufferSize(self, index):
			if index.isValid():
				displayed_size = self.data( self.index(index.row(), 0) ).toDouble()[0]
				# convert back to m/ft/degrees
				return Utils.fromDisplayedSize( displayed_size )

		def setBufferSize(self, index, buffersize):
			if index.isValid():
				# display Km/Kft/degrees
				displayed_size = Utils.toDisplayedSize( buffersize )
				self.setData( self.index(index.row(), 0), QVariant( displayed_size ) )

		def getAdditionalData(self, index):
			if index.isValid():
				return self.data( self.index(index.row(), 0), Qt.UserRole ).toPyObject()

		def setAdditionalData(self, index, data):
			if index.isValid():
				self.setData( self.index(index.row(), 0), QVariant(data), Qt.UserRole )
Example #12
0
class ProcessingWdg(QWidget, Ui_ProcessingWdg):

	def __init__(self, iface, parent=None):
		QWidget.__init__(self, parent)
		self.setupUi(self)

		# store the iface
		self.iface = iface

		self.canvas = self.iface.mapCanvas()
		self._prevMapTool = None

		self.algorithmStacked.setCurrentIndex(0)

		# create the maptool to draw polygons
		self.polygonDrawer = PolygonDrawer( self.canvas, {'color':QColor("#666666"), 'enableSnap':False, 'keepAfterEnd':True} )
		self.polygonDrawer.setAction( self.drawPolygonBtn )
		self.connect(self.polygonDrawer, SIGNAL("geometryEmitted"), self.polygonCreated)

		# connect actions to the widgets
		self.connect(self.drawPolygonBtn, SIGNAL("clicked()"), self.drawPolygon)
		self.connect(self.clearPolygonBtn, SIGNAL("clicked()"), self.clearPolygon)

		QObject.connect(self.declusterWdg, SIGNAL("dataRequested"), self.fillData)
		QObject.connect(self.completenessWdg, SIGNAL("dataRequested"), self.fillData)
		QObject.connect(self.recurrenceWdg, SIGNAL("dataRequested"), self.fillData)
		QObject.connect(self.maxMagnitudeWdg, SIGNAL("dataRequested"), self.fillData)


	def storePrevMapTool(self):
		prevMapTool = self.canvas.mapTool()
		if prevMapTool not in (self.polygonDrawer,):
			self._prevMapTool = prevMapTool

	def restorePrevMapTool(self):
		self.polygonDrawer.stopCapture()
		if self._prevMapTool: 
			self.canvas.setMapTool(self._prevMapTool)


	def showEvent(self, event):
		self.showRubberBands(True)
		QWidget.showEvent(self, event)

	def hideEvent(self, event):
		self.showRubberBands(False)
		self.restorePrevMapTool()
		QWidget.hideEvent(self, event)


	def deleteLater(self, *args):
		#print "deleting", self
		self.clearPolygon()

		# restore the previous maptool
		self.restorePrevMapTool()

		# delete the polygon drawer maptool
		self.polygonDrawer.deleteLater()
		self.polygonDrawer = None

		QWidget.deleteLater(self, *args)


	def showRubberBands(self, show=True):
		""" show/hide all the rubberbands """
		if self.polygonDrawer.isEmittingPoints:
			self.polygonDrawer.reset()
		else:
			self.polygonDrawer.rubberBand.show() if show else self.polygonDrawer.rubberBand.hide()

	def drawPolygon(self):
		# store the previous maptool
		self.storePrevMapTool()

		# set the polygon drawer as current maptool
		self.polygonDrawer.startCapture()

	def clearPolygon(self):
		# remove the displayed polygon
		self.polygonDrawer.reset()

	def polygonCreated(self, polygon):
		# restore the previous maptool
		self.restorePrevMapTool()

	def fillData(self, data, panMap):
		""" fetch data from the classified layer and put them into the 
			passed arguments:
			**data** list will contain the selected features attributes, 
			**panMap** dictionary will keep the association between fields and 
			 their position in the data list """

		classifiedVl = Utils.classifiedVl()
		pr = classifiedVl.dataProvider()

		# spatial filter
		spatialFilter = self.polygonDrawer.geometry()
		if not spatialFilter:
			extent = QgsRectangle()
		else:
			# convert the spatial filter to the layer CRS
			toLayerCrsTransform = QgsCoordinateTransform( self.canvas.mapRenderer().destinationCrs(), classifiedVl.crs() )
			ret = spatialFilter.transform( toLayerCrsTransform )
			if ret != 0:
				QMessageBox.warning(self, "Invalid area", "Unable to tranform the selected area to the layer CRS.")
				return
			extent = spatialFilter.boundingBox()

		index2key = Utils.index2keyFieldMap( pr.fields() )

		# fetch and loop through the features
		pr = classifiedVl.dataProvider()
		pr.select(classifiedVl.pendingAllAttributesList(), extent, True)

		f = QgsFeature()
		while pr.nextFeature( f ):
			# filter features by spatial filter
			if spatialFilter and not spatialFilter.contains( f.geometry() ):
				continue

			# create a new row: [id, *fields]
			attrs = f.attributeMap()
			row = [ f.id() ]
			for index, val in sorted(attrs.iteritems()):
				row.append( attrs[ index ] )

				# store the index of well-known field in the pan map so they
				# can be found easily later
				key = index2key.get(index, None)
				if key is not None:
					panMap[key] = len(row)-1

			# append to the data buffer
			data.append( row )

		if len(data) <= 0:
			QMessageBox.information(self, "Processing", "No features in the result")
			return