Exemple #1
0
class AddPoints(QgsMapTool):
    ''' Provide a tool to add new points and their attributes to an editing shapefile '''
    def __init__(self, parent):
        QgsMapTool.__init__(self, parent.canvas)
        
        # debugging
        print "Class AddPoints()"
        
        ''' This class is initiated whenever the add points action is
            selected.  The add points action is set to unselected
            whenever the active layer is changed, so the instance variables below
            always get updated whenever the active layer changes.
        '''
        
        # make handle to mainwindow
        self.mainwindow = parent
        self.canvas = parent.canvas

#######################################################################
    ''' Overridden QgsMapTool Events '''
#######################################################################

    def canvasPressEvent(self, event):
        ''' Get point and transform to map coordinates '''
        # get the current activeVLayer from mainwindow
        self.activeVLayer = self.mainwindow.activeVLayer
        if self.activeVLayer == None:
            return
        point = event.pos()
        transform = self.canvas.getCoordinateTransform()
        # returns a QgsPoint object in map coordinates
        self.qgsPoint = transform.toMapCoordinates(point.x(), point.y())
        print "The point is " + str(self.qgsPoint)
        
        # check if the proper editing layer is selected
        currentLayerName = self.mainwindow.legend.currentItem().canvasLayer.layer().name()
        if shared.checkSelectedLayer(self.mainwindow, self.mainwindow.scenarioType, 
                                                         currentLayerName) == "Cancel":
            self.qgsPoint = None
            return # if wrong edit layer cancel drawing
        # Check constraints on the added point for the scenario edit type
        # and prompt the user if constraints are not met. Method returns False 
        # if the constraints are not met.
        if not shared.checkConstraints(self.mainwindow, self.qgsPoint):
            self.qgsPoint = None
            return
        else: pass
        
        # correct editing layer selected and constraints check OK so get the new attributes
        self.getNewAttributes()

    def canvasReleaseEvent(self, event):
        pass
     
######################################################################
    ''' Core Methods '''
######################################################################
 
    def getNewAttributes(self):
        # debugging
        print "Class AddPoints() getNewAttributes()"
        
        self.dlg = DlgAddAttributes(self.mainwindow)

        if self.dlg.exec_(): # The user has clicked "OK"
            attributes = self.dlg.getNewAttributes() # method has the same name in DlgAddAttributes()
            #attributes = {0 : QtCore.QVariant(id), 1 : QtCore.QVariant(type)}
            self.markPoint(attributes) 
    
    def markPoint(self, attributes):
        ''' Add the new feature and display '''
        # debugging
        print "markPoint starting"
        # set the current provider
        self.provider = self.mainwindow.provider
        # make a list of the original points in the active layer
        self.originalFeats = shared.listOriginalFeatures(self.provider)
        # need to update the mainwindow instance variable for call to Tools.shared.deleteEdits
        self.mainwindow.originalFeats = self.originalFeats
        
        feat = QgsFeature()
        vlayerName = self.mainwindow.activeVLayer.name()
        # add the point geometry to the feature
        feat.setGeometry(QgsGeometry.fromPoint(self.qgsPoint))
        feat.setAttributeMap(attributes)
        # this actually writes the added point to disk!
        try:
            self.mainwindow.provider.addFeatures( [ feat ] )
        except (IOError, OSError), e:
            error = unicode(e)
            print error                    
            QtGui.QMessageBox.warning(self, "Failed to add feature(s)", "Please check if "
                                 + vlayerName + " is open in another program and then try again.")
        
        
        
        # reset the id numbers for the editing layer
        shared.resetIdNumbers(self.provider, self.mainwindow.geom)
        
        # update the attribute table if open
        if self.mainwindow.attrTable and self.mainwindow.attrTable.isVisible():
            self.mainwindow.openVectorAttributeTable()
        
        # set the edit flag to unsaved
        self.mainwindow.editDirty = self.activeVLayer.name()
        # enable the save edits action
        self.mainwindow.mpActionSaveEdits.setDisabled(False)
        
        # debugging
        print "the edit flag was set to " + self.activeVLayer.name() + " by MarkPoint."
        print "the number of features added is " + str(shared.numberFeaturesAdded
                                                         (self.activeVLayer, self.originalFeats))
        # The method below works for deleting features, but it doesn't work
        # for adding features.  The extents are NOT updated in any variation.
        shared.updateExtents(self.mainwindow, self.mainwindow.provider, self.mainwindow.activeVLayer, 
                                                                    self.mainwindow.canvas)
class AddLinesPolygons(QgsMapTool):
    ''' Provide a tool to add new lines or polygons, and their attributes, to an editing shapefile '''
    def __init__(self, parent):
        QgsMapTool.__init__(self, parent.canvas)
        
        # debugging
        print "Tools.addlinespolygons.AddLinesPolygons() class"
        
        ''' 
        This class is instantiated once when Main.mainwindow is instantiated. The instance 
        variables below always get updated from the mainwindow whenever the active layer 
        changes, so there is no need to instantiate this class more than once.
        
        '''
        
        self.mainwindow = parent
        self.canvas = parent.canvas
        self.down = False
        self.started = False
        self.rubberBand = None
            
#######################################################################
    ''' Overridden QgsMapTool Events '''
#######################################################################
   
    def canvasPressEvent(self, event):
        ''' Record the mouse down event '''
        # debugging
        print"Tools.addlinespolygons.AddLinesPolygons.canvasPressEvent()"
        
        # Set the active vector layer. Note that this method cannot be called unless the
        # currently active layer is the correct editing layer for the scenario edit type.
        self.activeVLayer = self.mainwindow.activeVLayer
        if self.activeVLayer == None: return

        # set the current geometry and some variables for the QgsRubberBand
        if self.mainwindow.geom:
            if self.mainwindow.geom == 1: self.geom = False # line
            else: self.geom = True # polygon
        
        self.down = True # starts the drawing process

    def canvasReleaseEvent(self, event):
        ''' Handle the mouse release event '''
        # debugging
        print"Tools.addlinespolygons.AddLinesPolygons.canvasReleaseEvent()"

        if self.down == True:
            if (self.started == False) and (event.button()== QtCore.Qt.RightButton):
                # We have a right button but have not started a poly... just return
                return
            # mouse is released so initialize rubber band
            if self.started==False:
                # Initialize Rubber Band
                self.rubberBand = QgsRubberBand(self.canvas, self.geom)
                self.rubberBand.setWidth(5)
                self.rubberBand.show()
                self.numberOfPoints = 0
                            
            # getCoordinateTransform returns a QgsMapToPixel object
            # which transforms between device coordinates and map coordinates 
            transform = self.canvas.getCoordinateTransform()
            # toMapCoordinates is a QgsMapToPixel method that 
            # takes a QPoint (from device) as a parameter and returns a 
            # QgsPoint object transformed to map coordinates
            self.qgsPoint = transform.toMapCoordinates(event.pos().x(),
                                            event.pos().y())
            
            # We have the first point of either a line or polygon. If it is a line then it is a new road
            # so check constraints for new roads. This method will also check if the point is near a 
            # previously saved new road and snap to it if it is.
            if self.started == False: # only checks the first point
                qPoint = event.pos()
                if self.geom == False:
                    # prompts user and returns false if constraints not met
                    if not shared.checkConstraints(self.mainwindow, self.qgsPoint, qPoint): 
                        return
            
            self.rubberBand.addPoint(self.qgsPoint)
            self.started=True
            self.numberOfPoints = self.numberOfPoints + 1
            if self.geom: # polygon
                if (event.button() == QtCore.Qt.RightButton) and (self.numberOfPoints > 2):
                    #self.down=False
                    #self.started=False
                    self.getNewAttributes()
            else: # line
                if (event.button() == QtCore.Qt.RightButton) and (self.numberOfPoints > 1):
                    #self.down=False
                    #self.started=False
                    self.getNewAttributes()
               
    def canvasMoveEvent(self,event):
        ''' Handle the mouse move event '''
        # debugging
        print"Tools.addlinespolygons.AddLinesPolygons.canvasMoveEvent()"

        if self.started == True:    
            transform = self.canvas.getCoordinateTransform()
            qgsPoint = transform.toMapCoordinates(event.pos().x(), event.pos().y())
            self.rubberBand.movePoint(qgsPoint)

#######################################################################
    ''' Core Methods '''
#######################################################################
 
    def getNewAttributes(self):
        ''' Dialog to get attribute information for the current scenario edit type '''
        # debugging
        print "Tools.addlinespolygons.AddLinesPolygons().getNewAttributes()"
        
        # set the msgFlag to none so user gets no warning when canceling adding a new line or polygon
        self.mainwindow.msgFlag = None
           
        self.dlg = DlgAddAttributes(self.mainwindow)

        if self.dlg.exec_(): # The user has clicked "OK"
            # validation
            attributes = self.dlg.getNewAttributes()
            self.addLinePolygon(attributes) 
        else: # User has clicked "Cancel"
            
            # debugging
            print "Tools.addlinespolygons.AddLinesPolygons().getNewAttributes(): Canceled"
            # just set the point to nothing
            self.qgsPoint = None
            self.rubberBand.reset(self.geom)
            return  
       
    def addLinePolygon(self, attributes):
        ''' Add the new line or polygon and display '''
        # debugging
        print "Tools.addlinespolygons.AddLinesPolygons.addLinePolygon()"
        
        # Set the data provider
        self.provider = self.mainwindow.provider
        
        feat = QgsFeature()
        vlayerName = unicode(self.mainwindow.activeVLayer.name())
        # add the line or polygon geometry to the feature
        feat.setGeometry(self.rubberBand.asGeometry())
        feat.setAttributeMap(attributes)
        # this actually writes the added point to disk!
        # the space between parentheses, brackets and the parameter are needed!
        try:
            self.provider.addFeatures( [ feat ] )
        except (IOError, OSError), e:
            error = unicode(e)
            print error                    
            QtGui.QMessageBox.warning(self, "Failed to add feature(s)", "Please check if "
                                 + vlayerName + " is open in another program and then try again.")
   
        
        # The feature has been drawn so reset the QgsRubberBand so color of feature returns to default
        self.resetDraw()

        # reset the editing layer id numbers
        shared.resetIdNumbers(self.provider, self.mainwindow.geom)
        
        # update the attribute table if open
        if self.mainwindow.attrTable and self.mainwindow.attrTable.isVisible():
            self.mainwindow.openVectorAttributeTable()
        
        #set the edit flag to unsaved
        self.mainwindow.editDirty = True
        # enable the save edits button
        self.mainwindow.mpActionSaveEdits.setDisabled(False)
        
        # debugging
        print "Tools.addlinespolygons.AddLinesPolygons().addLinePolygon(): the edit flag was set to "\
                                                             + self.activeVLayer.name() + " by addLinePolygon()."
        print "Tools.addlinespolygons.AddLinesPolygons().addLinePolygon(): the number of features added is "\
                                    + str(shared.numberFeaturesAdded(self.activeVLayer, self.mainwindow.originalEditLayerFeats))
        
        # update layer extents
        shared.updateExtents(self.mainwindow, self.activeVLayer, self.canvas)
class AddPoints(QgsMapTool):
    ''' Provide a tool to add new points and their attributes to an editing shapefile '''
    def __init__(self, parent):
        QgsMapTool.__init__(self, parent.canvas)
        
        # debugging
        print "Tools.addpoints.AddPoints() class"
        
        ''' 
        This class is instantiated once when Main.mainwindow is instantiated. The instance 
        variables below always get updated from the mainwindow whenever the active layer 
        changes, so there is no need to instantiate this class more than once.
        
        '''
        
        # make handle to mainwindow
        self.mainwindow = parent
        self.canvas = parent.canvas

#######################################################################
    ''' Overridden QgsMapTool Events '''
#######################################################################

    def canvasPressEvent(self, event):
        ''' Get point and transform to map coordinates '''
        # Set the active vector layer. Note that this method cannot be called unless the
        # currently active layer is the correct editing layer for the scenario edit type.
        self.activeVLayer = self.mainwindow.activeVLayer
        if self.activeVLayer == None: return
       
        qPoint = event.pos()
        transform = self.canvas.getCoordinateTransform()
        # returns a QgsPoint object in map coordinates
        self.qgsPoint = transform.toMapCoordinates(qPoint.x(), qPoint.y())
        
        #debugging
        print "Tools.addpoints.AddPoints().canvasPressEvent(): The original clicked point in map coordinates is " + str(self.qgsPoint)
        
        ''' 
            Check constraints on the added point for the scenario edit type, 
            and prompt the user if constraints are not met.
        '''
 
        # If the point is a culvert/bridge, check if it can be snapped to a new road in the scenario.
        if self.mainwindow.scenarioEditType == config.scenarioEditTypesList[0]:
            # returns the snapped qgs point if the point can be snapped to a new road, or returns False
            retval = shared.snapToNewRoad(self.mainwindow, qPoint) 
            if retval:
                self.qgsPoint = retval # if the point is returned, set it to be the new feature's geometry
        
        # If not editing a new road check constraints.
        # This method returns False if the constraints are not met.
        if not shared.checkConstraints(self.mainwindow, self.qgsPoint, qPoint):
            self.qgsPoint = None
            return
        # correct editing layer selected and constraints check OK so get the new attributes
        else: self.getNewAttributes()

    def canvasReleaseEvent(self, event):
        pass
     
######################################################################
    ''' Core Methods '''
######################################################################
 
    def getNewAttributes(self):
        # debugging
        print "Tools.addpoints.AddPoints().getNewAttributes()"
        
        # set the msgFlag to none so user gets no warning when canceling adding a new point
        self.mainwindow.msgFlag = None
                
        self.dlg = DlgAddAttributes(self.mainwindow)

        if self.dlg.exec_(): # The user has clicked "OK"
            attributes = self.dlg.getNewAttributes() # method has the same name in DlgAddAttributes()
            self.markPoint(attributes) 
 
    def markPoint(self, attributes):
        ''' Add the new feature and display '''
        # debugging
        print "Tools.addpoints.AddPoints().markPoint(): markPoint starting"
        print "Tools.addpoints.AddPoints().markPoint(): The self.qgsPoint is " + str(self.qgsPoint)
        
        # set the current provider
        self.provider = self.mainwindow.provider
        
        feat = QgsFeature()
        geometry = QgsGeometry()
        # Convert QStrings to unicode unless they are used immediately in a Qt method. 
        # This ensures that we never ask Python to slice a QString, which produces a type error.
        vlayerName = unicode(self.activeVLayer.name())
        # add the point geometry to the feature
        feat.setGeometry(geometry.fromPoint(self.qgsPoint))
        # add the user's input attributes to the feature
        feat.setAttributeMap(attributes)
        # this actually writes the added point to disk!
        try:
            self.mainwindow.provider.addFeatures( [ feat ] )
        except (IOError, OSError), e:
            error = unicode(e)
            print error                    
            QtGui.QMessageBox.warning(self, "Failed to add feature(s)", "Please check if "
                                 + vlayerName + " is open in another program and then try again.")
      
        # reset the id numbers for the editing layer
        shared.resetIdNumbers(self.provider, self.mainwindow.geom)
        
        # update the attribute table if open
        if self.mainwindow.attrTable and self.mainwindow.attrTable.isVisible():
            self.mainwindow.openVectorAttributeTable()
        
        # set the edit flag to unsaved
        self.mainwindow.editDirty = True
        
        # debugging
        print "Tools.addpoints.AddPoints().markPoint(): the edit flag was set to " + vlayerName 
        print "Tools.addpoints.AddPoints().markPoint(): The vlayer name is " + vlayerName
        print "Tools.addpoints.AddPoints().markPoint(): the number of features added is " + str(
                                                shared.numberFeaturesAdded(self.activeVLayer, self.mainwindow.originalEditLayerFeats))
        
        # enable the save edits action
        self.mainwindow.mpActionSaveEdits.setDisabled(False)
        # refresh the extents of the map on the canvas
        shared.updateExtents(self.mainwindow, self.activeVLayer, self.canvas)
class AddLinesPolygons(QgsMapTool):
    ''' Provide a tool to add new lines or polygons, and their attributes, to an editing shapefile '''
    def __init__(self, parent):
        QgsMapTool.__init__(self, parent.canvas)
        
        # debigging
        print "Class AddLinesPolygons()"
        
        ''' This class is initiated whenever the add line or add polygon action is
            selected.  The add line and add polygon actions are set to unselected
            whenever the active layer is changed, so the instance variables below
            always get updated whenever the active layer changes.
        '''
        
        self.mainwindow = parent
        self.canvas = parent.canvas
        self.down = False
        self.started = False
        self.rubberBand = None
            
#######################################################################
    ''' Overridden QgsMapTool Events '''
#######################################################################
   
    def canvasPressEvent(self, event):
        ''' Record the mouse down event '''
        # set the active vector layer
        self.activeVLayer = self.mainwindow.activeVLayer
        if self.activeVLayer == None:
            return
        
        # set the current geometry and some variables for the QgsRubberBand
        if self.mainwindow.geom:
            if self.mainwindow.geom == 1: # line
                self.geom = False
            else: self.geom = True # polygon
        
        # check if the editing layer is selected but only on the first click
        if self.started == False:
            currentLayerName = self.mainwindow.legend.currentItem().canvasLayer.layer().name()
            if shared.checkSelectedLayer(self.mainwindow, self.mainwindow.scenarioType, 
                                                               currentLayerName) == "Cancel":    
                return # return without starting to draw
        self.down = True # starts the drawing process

    def canvasReleaseEvent(self, event):
        if self.down == True:
            if (self.started == False) and (event.button()== QtCore.Qt.RightButton):
                # We have a right button but have not started a poly... just return
                return
            # mouse is down, before release initialize rubber band
            if self.started==False:
                # Initialize Rubber Band
                self.rubberBand = QgsRubberBand(self.canvas, self.geom)
                self.rubberBand.setWidth(.6)
                self.rubberBand.show()
                self.numberOfPoints = 0

            # getCoordinateTransform returns a QgsMapToPixel object
            # which transforms between device coordinates and map coordinates 
            transform = self.canvas.getCoordinateTransform()
            # toMapCoordinates is a QgsMapToPixel method that 
            # takes a QPoint (from device) as a parameter and returns a 
            # QgsPoint object transformed to map coordinates
            qgsPoint = transform.toMapCoordinates(event.pos().x(),
                                            event.pos().y())
            self.rubberBand.addPoint(qgsPoint)
            self.started=True
            self.numberOfPoints = self.numberOfPoints + 1
            if self.geom:
                if (event.button() == QtCore.Qt.RightButton) and (self.numberOfPoints > 2):
                    #self.down=False
                    #self.started=False
                    self.getNewAttributes()
            else: 
                if (event.button() == QtCore.Qt.RightButton) and (self.numberOfPoints > 1):
                    #self.down=False
                    #self.started=False
                    self.getNewAttributes()
               
    def canvasMoveEvent(self,event):
        if self.started == True:    
            transform = self.canvas.getCoordinateTransform()
            qgsPoint = transform.toMapCoordinates(event.pos().x(), event.pos().y())
            self.rubberBand.movePoint(qgsPoint)

#######################################################################
    ''' Core Methods '''
#######################################################################
 
    def getNewAttributes(self):
        ''' Dialog to get attribute information for the current scenario edit type '''
        # debugging
        print "Class AddLinesPolygons() getNewAttributes()"
        
        self.dlg = DlgAddAttributes(self.mainwindow)

        if self.dlg.exec_(): # The user has clicked "OK"
            # validation
            attributes = self.dlg.getNewAttributes()
            self.addLinePolygon(attributes) 
        else: # User has clicked "Cancel"
            
            # debugging
            print "Canceled"
            # just set the point to nothing
            self.qgsPoint = None
            self.rubberBand.reset(self.geom)
            return  
       
    def addLinePolygon(self, attributes):
        ''' Add the new line or polygon and display '''
        # debugging
        print "AddLinesPolygons.addLinePolygon() starting"
        # Set the data provider
        self.provider = self.mainwindow.provider
        # make a list of the original points in the active layer
        self.originalFeats = shared.listOriginalFeatures(self.provider)
        # need to update the mainwindow instance variable for call to Tools.shared.deleteEdits
        self.mainwindow.originalFeats = self.originalFeats
        
        feat = QgsFeature()
        vlayerName = self.mainwindow.activeVLayer.name()
        # add the line or polygon geometry to the feature
        feat.setGeometry(self.rubberBand.asGeometry())
        feat.setAttributeMap(attributes)
        # this actually writes the added point to disk!
        # the space between parentheses, brackets and the parameter are needed!
        try:
            self.provider.addFeatures( [ feat ] )
        except (IOError, OSError), e:
            error = unicode(e)
            print error                    
            QtGui.QMessageBox.warning(self, "Failed to add feature(s)", "Please check if "
                                 + vlayerName + " is open in another program and then try again.")
   
        
        # reset the editing layer id numbers
        shared.resetIdNumbers(self.provider, self.mainwindow.geom)
        
        # update the attribute table if open
        if self.mainwindow.attrTable and self.mainwindow.attrTable.isVisible():
            self.mainwindow.openVectorAttributeTable()
        
        # reset the QgsRubberBand so color of feature returns to default
        self.resetDraw()

        #set the edit flag to unsaved
        self.mainwindow.editDirty = self.activeVLayer.name()
        # enable the save edits button
        self.mainwindow.mpActionSaveEdits.setDisabled(False)
        
        # debugging
        print "the edit flag was set to " + self.activeVLayer.name() + " by addLinePolygon()."
        print "the number of features added is " + str(shared.numberFeaturesAdded
                                                       (self.activeVLayer, self.originalFeats))
        
        # update layer extents
        shared.updateExtents(self.mainwindow, self.mainwindow.provider, self.mainwindow.activeVLayer, 
                                                                    self.mainwindow.canvas)