QGIS/python/plugins/osm/map_tools/CreateLineMapTool.py
2009-07-30 11:08:18 +00:00

338 lines
12 KiB
Python

"""@package CreateLineMapTool
This module holds all structures and methods required to perform
"create line" operation on current OSM data.
Snapping to existing points is supported when creating new line.
Process generates some rubberBands and vertexMarkers so that user can watch
the whole operation on the map in a nice way.
There is also an interaction with plugin's "OSM Feature" dialog.
Points to which snapping is performed are loaded to it dynamically.
"""
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import *
from qgis.gui import *
class CreateLineMapTool(QgsMapTool):
"""This class holds all structures and methods required to perform
"create line" operation on current OSM data.
Snapping to existing points is supported when creating new line.
Process generates some rubberBands and vertexMarkers so that user can watch
the whole operation on the map in a nice way.
There is also an interaction with plugin's "OSM Feature" dialog.
Points to which snapping is performed are loaded to it dynamically.
"""
def __init__(self, plugin):
"""The constructor.
Initializes the map tool, creates necessary snappers.
@param plugin pointer to OSM Plugin instance
"""
QgsMapTool.__init__(self,plugin.canvas)
self.canvas=plugin.canvas
self.dockWidget=plugin.dockWidget
self.dbm=plugin.dbm
self.ur=plugin.undoredo
# initialization
self.snappingEnabled=True
self.lastPointIsStable=True
self.linePoints=[]
self.snappedPoint=None
self.snapFeat=None
self.snapFeatType=None
# creating rubberband which will be on new line
self.lineRubBand=self.createLineRubberband()
# creating rubberband for snapped objects
self.snapVerMarker=self.createSnapVertexMarker()
# creating snapper to this map tool
self.snapper=self.createSnapper(self.canvas.mapRenderer())
def databaseChanged(self,dbKey):
"""This function is called automatically when current OSM database has changed.
Function does re-initialization of maptool and create new snappers again (if necessary).
@param dbKey key of database with new current OSM data
"""
# re-initialization
self.snappingEnabled=True
self.snapFeat=None
self.snapFeatType=None
self.snapVerMarker.setCenter(QgsPoint(-1000,-1000))
del self.snapVerMarker
self.snapVerMarker=self.createSnapVertexMarker()
self.lineRubBand.reset(False)
self.lastPointIsStable=True
self.linePoints=[]
self.snappedPoint=None
if dbKey:
del self.snapper
self.snapper=self.createSnapper(self.canvas.mapRenderer())
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("")
def createLineRubberband(self):
"""Function creates rubberband that is used for marking new line on the map.
@return rubberband that marks new line
"""
# get qgis settings of line width and color for rubberband
settings=QSettings()
qgsLineWidth=settings.value("/qgis/digitizing/line_width",QVariant(10)).toInt()
qgsLineRed=settings.value("/qgis/digitizing/line_color_red",QVariant(255)).toInt()
qgsLineGreen=settings.value("/qgis/digitizing/line_color_green",QVariant(0)).toInt()
qgsLineBlue=settings.value("/qgis/digitizing/line_color_blue",QVariant(0)).toInt()
rband=QgsRubberBand(self.canvas,False)
rband.setColor(QColor(qgsLineRed[0],qgsLineGreen[0],qgsLineBlue[0]))
rband.setWidth(qgsLineWidth[0])
return rband
def createSnapVertexMarker(self):
"""Function creates vertexMarker that is used for marking feature
to which snapping was done.
@return vertex marker - QgsVertexMarker object
"""
# get qgis settings
settings=QSettings()
qgsLineWidth=settings.value("/qgis/digitizing/line_width",QVariant(10)).toInt()
qgsLineRed=settings.value("/qgis/digitizing/line_color_red",QVariant(255)).toInt()
qgsLineGreen=settings.value("/qgis/digitizing/line_color_green",QVariant(0)).toInt()
qgsLineBlue=settings.value("/qgis/digitizing/line_color_blue",QVariant(0)).toInt()
verMarker=QgsVertexMarker(self.canvas)
verMarker.setIconType(2)
verMarker.setIconSize(13)
verMarker.setColor(QColor(qgsLineRed[0],qgsLineGreen[0],qgsLineBlue[0]))
verMarker.setPenWidth(qgsLineWidth[0])
verMarker.setCenter(QgsPoint(-1000,-1000))
return verMarker
def createSnapper(self,canvasRenderer):
"""Function creates snapper that snaps within standard qgis tolerance.
Snapping of this snapper is done to all segments and vertexes
of all three layers of current OSM database.
@param canvasRenderer renderer of current map canvas
@return instance of vertex+segment QgsSnapper
"""
if not self.dbm.currentKey:
# there is no current database -> no layer for snapping
return QgsSnapper(self.canvas.mapRenderer())
snapper=QgsSnapper(self.canvas.mapRenderer())
snapLayers=[]
# snap to osm layers from current database only
sLayer=QgsSnapper.SnapLayer()
sLayer.mLayer=self.dbm.pointLayers[self.dbm.currentKey]
sLayer.mTolerance=QgsTolerance.vertexSearchRadius(sLayer.mLayer,self.canvas.mapRenderer())
sLayer.mSnapTo=QgsSnapper.SnapToVertex
snapLayers.append(sLayer)
sLayer=QgsSnapper.SnapLayer()
sLayer.mLayer=self.dbm.lineLayers[self.dbm.currentKey]
sLayer.mTolerance=QgsTolerance.vertexSearchRadius(sLayer.mLayer,self.canvas.mapRenderer())
sLayer.mSnapTo=QgsSnapper.SnapToVertex
snapLayers.append(sLayer)
sLayer=QgsSnapper.SnapLayer()
sLayer.mLayer=self.dbm.polygonLayers[self.dbm.currentKey]
sLayer.mTolerance=QgsTolerance.vertexSearchRadius(sLayer.mLayer,self.canvas.mapRenderer())
sLayer.mSnapTo=QgsSnapper.SnapToVertex
snapLayers.append(sLayer)
snapper.setSnapLayers(snapLayers)
return snapper
def deactivate(self):
"""Functions is called when create line map-tool is being deactivated.
Function performs standard cleaning; re-initialization etc.
"""
self.lineRubBand.reset()
self.snapVerMarker.setCenter(QgsPoint(-1000,-1000))
self.snappingEnabled=True
self.lastPointIsStable=True
self.linePoints=[]
self.dockWidget.toolButtons.setExclusive(False)
self.dockWidget.createLineButton.setChecked(False)
self.dockWidget.toolButtons.setExclusive(True)
self.dockWidget.activeEditButton=self.dockWidget.dummyButton
def keyPressEvent(self, event):
"""This function is called after keyPressEvent(QKeyEvent *) signal
is emmited when using this map tool.
If Control key was pressed, function disables snapping til key is released again.
@param event event that occured when key pressing
"""
if (event.key() == Qt.Key_Control):
self.snappingEnabled = False
self.snapVerMarker.setCenter(QgsPoint(-1000,-1000))
self.snappedPoint=None
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("Snapping OFF.")
def keyReleaseEvent(self, event):
"""This function is called after keyReleaseEvent(QKeyEvent *) signal
is emmited when using this map tool.
If Control key was released, function enables snapping again.
@param event event that occured when key releasing
"""
if (event.key() == Qt.Key_Control):
self.snappingEnabled = True
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("Snapping ON. Hold Ctrl to disable it.")
def canvasMoveEvent(self, event):
"""This function is called when mouse moving.
@param event event that occured when mouse moving.
"""
self.mapPoint=self.dockWidget.canvasToOsmCoords(event.pos())
if len(self.linePoints)>0:
if not self.lastPointIsStable:
self.lineRubBand.removeLastPoint()
self.lineRubBand.addPoint(QgsPoint(self.mapPoint.x(),self.mapPoint.y()))
self.lastPointIsStable=False
if not self.snappingEnabled:
self.snapVerMarker.setCenter(self.mapPoint)
return
# snapping! first reset old snapping vertexMarker
self.snapVerMarker.setCenter(QgsPoint(-1000,-1000))
# try snapping to the closest vertex/segment
(retval,snappingResults)=self.snapper.snapPoint(event.pos(),[])
if len(snappingResults)==0:
self.snapVerMarker.setCenter(self.mapPoint)
self.snappedPoint=None
self.snapFeat=None
self.snapFeatType=None
if self.dockWidget.feature:
self.dockWidget.clear()
return
# process snapping result (get point, set vertex marker)
self.snappedPoint=QgsPoint(snappingResults[0].snappedVertex)
self.snapVerMarker.setCenter(self.snappedPoint)
if len(self.linePoints)>0:
self.lineRubBand.removeLastPoint()
self.lineRubBand.addPoint(QgsPoint(self.snappedPoint.x(),self.snappedPoint.y()))
# start identification
feature=self.dbm.findFeature(self.snappedPoint)
if feature:
(self.snapFeat,self.snapFeatType)=feature
if not self.dockWidget.feature or self.snapFeat.id()<>self.dockWidget.feature.id():
self.dockWidget.loadFeature(self.snapFeat,self.snapFeatType)
def canvasReleaseEvent(self, event):
"""This function is called after mouse button releasing when using this map tool.
If left button is released new vertex of line is created (pre-created).
If right button is released the whole process of line creation is finished.
@param event event that occured when button releasing
"""
# we are interested in left/right button clicking only
if event.button() not in (Qt.LeftButton,Qt.RightButton):
return
if event.button()==Qt.LeftButton:
# where we are exactly?
actualMapPoint = self.dockWidget.canvasToOsmCoords(event.pos())
# what point will be the next line member?
newLinePoint=actualMapPoint
if self.snappedPoint:
newLinePoint=self.snappedPoint
# add new point into rubberband (and removing last one if neccessary) and into new line members list
if not self.lastPointIsStable:
self.lineRubBand.removeLastPoint()
self.lastPointIsStable=True
self.lineRubBand.addPoint(newLinePoint)
self.linePoints.append((newLinePoint,self.snapFeat,self.snapFeatType))
# right button clicking signalizes the last line member!
elif event.button()==Qt.RightButton:
# line must have at least 2 member points (else it's point rather than line)
if len(self.linePoints)<2:
self.lineRubBand.reset()
self.snapVerMarker.setCenter(QgsPoint(-1000,-1000))
self.lastPointIsStable=True
self.linePoints=[]
return
self.ur.startAction("Create a line.")
# call function of database manager that will create new line
(line,affected)=self.dbm.createLine(self.linePoints)
self.ur.stopAction(affected)
self.dbm.recacheAffectedNow(affected)
if line:
self.dockWidget.loadFeature(line,"Line",2)
# cleaning..
self.lineRubBand.reset()
self.linePoints=[]
# after line creation canvas must be refresh so that changes take effect on map
self.canvas.refresh()