1
"""@package OsmCreateLineMT
2
This module holds all structures and methods required to perform
3
"create line" operation on current OSM data.
5
Snapping to existing points is supported when creating new line.
6
Process generates some rubberBands and vertexMarkers so that user can watch
7
the whole operation on the map in a nice way.
9
There is also an interaction with plugin's "OSM Feature" dockwidget.
10
Points to which snapping is performed are loaded to it dynamically.
14
from PyQt4.QtCore import *
15
from PyQt4.QtGui import *
16
from qgis.core import *
17
from qgis.gui import *
20
class OsmCreateLineMT(QgsMapTool):
21
"""This class holds all structures and methods required to perform
22
"create line" operation on current OSM data.
24
Snapping to existing points is supported when creating new line.
25
Process generates some rubberBands and vertexMarkers so that user can watch
26
the whole operation on the map in a nice way.
28
There is also an interaction with plugin's "OSM Feature" dockwidget.
29
Points to which snapping is performed are loaded to it dynamically.
33
def __init__(self, plugin):
36
Initializes the map tool, creates necessary snappers.
38
@param plugin pointer to OSM Plugin instance
41
QgsMapTool.__init__(self,plugin.canvas)
43
self.canvas=plugin.canvas
44
self.dockWidget=plugin.dockWidget
46
self.ur=plugin.undoredo
49
self.snappingEnabled=True
50
self.lastPointIsStable=True
52
self.snappedPoint=None
54
self.snapFeatType=None
56
# creating rubberband which will be on new line
57
self.lineRubBand=self.createLineRubberband()
59
# creating rubberband for snapped objects
60
self.snapVerMarker=self.createSnapVertexMarker()
62
# creating snapper to this map tool
63
self.snapper=self.createSnapper(self.canvas.mapRenderer())
66
def databaseChanged(self,dbKey):
67
"""This function is called automatically when current OSM database has changed.
69
Function does re-initialization of maptool and create new snappers again (if necessary).
71
@param dbKey key of database with new current OSM data
75
self.snappingEnabled=True
77
self.snapFeatType=None
78
self.snapVerMarker.setCenter(QgsPoint(-1000,-1000))
79
del self.snapVerMarker
80
self.snapVerMarker=self.createSnapVertexMarker()
81
self.lineRubBand.reset(False)
83
self.lastPointIsStable=True
85
self.snappedPoint=None
89
self.snapper=self.createSnapper(self.canvas.mapRenderer())
91
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("")
94
def createLineRubberband(self):
95
"""Function creates rubberband that is used for marking new line on the map.
97
@return rubberband that marks new line
100
# get qgis settings of line width and color for rubberband
102
qgsLineWidth=2 # use fixed width
103
qgsLineRed=settings.value("/qgis/digitizing/line_color_red",QVariant(255)).toInt()
104
qgsLineGreen=settings.value("/qgis/digitizing/line_color_green",QVariant(0)).toInt()
105
qgsLineBlue=settings.value("/qgis/digitizing/line_color_blue",QVariant(0)).toInt()
107
rband=QgsRubberBand(self.canvas,False)
108
rband.setColor(QColor(qgsLineRed[0],qgsLineGreen[0],qgsLineBlue[0]))
109
rband.setWidth(qgsLineWidth)
114
def createSnapVertexMarker(self):
115
"""Function creates vertexMarker that is used for marking feature
116
to which snapping was done.
118
@return vertex marker - QgsVertexMarker object
123
qgsLineWidth=2 # use fixed width
124
qgsLineRed=settings.value("/qgis/digitizing/line_color_red",QVariant(255)).toInt()
125
qgsLineGreen=settings.value("/qgis/digitizing/line_color_green",QVariant(0)).toInt()
126
qgsLineBlue=settings.value("/qgis/digitizing/line_color_blue",QVariant(0)).toInt()
128
verMarker=QgsVertexMarker(self.canvas)
129
verMarker.setIconType(2)
130
verMarker.setIconSize(13)
131
verMarker.setColor(QColor(qgsLineRed[0],qgsLineGreen[0],qgsLineBlue[0]))
132
verMarker.setPenWidth(qgsLineWidth)
133
verMarker.setCenter(QgsPoint(-1000,-1000))
138
def createSnapper(self,canvasRenderer):
139
"""Function creates snapper that snaps within standard qgis tolerance.
141
Snapping of this snapper is done to all segments and vertexes
142
of all three layers of current OSM database.
144
@param canvasRenderer renderer of current map canvas
145
@return instance of vertex+segment QgsSnapper
148
if not self.dbm.currentKey:
149
# there is no current database -> no layer for snapping
150
return QgsSnapper(self.canvas.mapRenderer())
152
snapper=QgsSnapper(self.canvas.mapRenderer())
155
# snap to osm layers from current database only
156
sLayer=QgsSnapper.SnapLayer()
157
sLayer.mLayer=self.dbm.pointLayers[self.dbm.currentKey]
158
sLayer.mTolerance=QgsTolerance.vertexSearchRadius(sLayer.mLayer,self.canvas.mapRenderer())
159
sLayer.mSnapTo=QgsSnapper.SnapToVertex
160
snapLayers.append(sLayer)
162
sLayer=QgsSnapper.SnapLayer()
163
sLayer.mLayer=self.dbm.lineLayers[self.dbm.currentKey]
164
sLayer.mTolerance=QgsTolerance.vertexSearchRadius(sLayer.mLayer,self.canvas.mapRenderer())
165
sLayer.mSnapTo=QgsSnapper.SnapToVertex
166
snapLayers.append(sLayer)
168
sLayer=QgsSnapper.SnapLayer()
169
sLayer.mLayer=self.dbm.polygonLayers[self.dbm.currentKey]
170
sLayer.mTolerance=QgsTolerance.vertexSearchRadius(sLayer.mLayer,self.canvas.mapRenderer())
171
sLayer.mSnapTo=QgsSnapper.SnapToVertex
172
snapLayers.append(sLayer)
174
snapper.setSnapLayers(snapLayers)
178
def deactivate(self):
179
"""Functions is called when create line map-tool is being deactivated.
181
Function performs standard cleaning; re-initialization etc.
184
self.lineRubBand.reset()
185
self.snapVerMarker.setCenter(QgsPoint(-1000,-1000))
186
self.snappingEnabled=True
187
self.lastPointIsStable=True
190
self.dockWidget.toolButtons.setExclusive(False)
191
self.dockWidget.createLineButton.setChecked(False)
192
self.dockWidget.toolButtons.setExclusive(True)
193
self.dockWidget.activeEditButton=self.dockWidget.dummyButton
196
def keyPressEvent(self, event):
197
"""This function is called after keyPressEvent(QKeyEvent *) signal
198
is emmited when using this map tool.
200
If Control key was pressed, function disables snapping til key is released again.
202
@param event event that occured when key pressing
205
if (event.key() == Qt.Key_Control):
206
self.snappingEnabled = False
207
self.snapVerMarker.setCenter(QgsPoint(-1000,-1000))
208
self.snappedPoint=None
209
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("Snapping OFF.")
212
def keyReleaseEvent(self, event):
213
"""This function is called after keyReleaseEvent(QKeyEvent *) signal
214
is emmited when using this map tool.
216
If Control key was released, function enables snapping again.
218
@param event event that occured when key releasing
221
if (event.key() == Qt.Key_Control):
222
self.snappingEnabled = True
223
self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("Snapping ON. Hold Ctrl to disable it.")
226
def canvasMoveEvent(self, event):
227
"""This function is called when mouse moving.
229
@param event event that occured when mouse moving.
232
self.mapPoint=self.dockWidget.canvasToOsmCoords(event.pos())
234
if len(self.linePoints)>0:
235
if not self.lastPointIsStable:
236
self.lineRubBand.removeLastPoint()
237
self.lineRubBand.addPoint(QgsPoint(self.mapPoint.x(),self.mapPoint.y()))
238
self.lastPointIsStable=False
240
if not self.snappingEnabled:
241
self.snapVerMarker.setCenter(self.mapPoint)
244
# snapping! first reset old snapping vertexMarker
245
self.snapVerMarker.setCenter(QgsPoint(-1000,-1000))
247
# try snapping to the closest vertex/segment
248
(retval,snappingResults)=self.snapper.snapPoint(event.pos(),[])
250
if len(snappingResults)==0:
251
self.snapVerMarker.setCenter(self.mapPoint)
252
self.snappedPoint=None
254
self.snapFeatType=None
256
if self.dockWidget.feature:
257
self.dockWidget.clear()
260
# process snapping result (get point, set vertex marker)
261
self.snappedPoint=QgsPoint(snappingResults[0].snappedVertex)
262
self.snapVerMarker.setCenter(self.snappedPoint)
264
if len(self.linePoints)>0:
265
self.lineRubBand.removeLastPoint()
266
self.lineRubBand.addPoint(QgsPoint(self.snappedPoint.x(),self.snappedPoint.y()))
268
# start identification
269
feature=self.dbm.findFeature(self.snappedPoint)
271
(self.snapFeat,self.snapFeatType)=feature
272
if not self.dockWidget.feature or self.snapFeat.id()<>self.dockWidget.feature.id():
273
self.dockWidget.loadFeature(self.snapFeat,self.snapFeatType)
276
def canvasReleaseEvent(self, event):
277
"""This function is called after mouse button releasing when using this map tool.
279
If left button is released new vertex of line is created (pre-created).
280
If right button is released the whole process of line creation is finished.
282
@param event event that occured when button releasing
285
# we are interested in left/right button clicking only
286
if event.button() not in (Qt.LeftButton,Qt.RightButton):
289
if event.button()==Qt.LeftButton:
291
# where we are exactly?
292
actualMapPoint = self.dockWidget.canvasToOsmCoords(event.pos())
294
# what point will be the next line member?
295
newLinePoint=actualMapPoint
296
if self.snappedPoint:
297
newLinePoint=self.snappedPoint
299
# add new point into rubberband (and removing last one if necessary) and into new line members list
300
if not self.lastPointIsStable:
301
self.lineRubBand.removeLastPoint()
302
self.lastPointIsStable=True
304
self.lineRubBand.addPoint(newLinePoint)
305
self.linePoints.append((newLinePoint,self.snapFeat,self.snapFeatType))
307
# right button clicking signalizes the last line member!
308
elif event.button()==Qt.RightButton:
310
# line must have at least 2 member points (else it's point rather than line)
311
if len(self.linePoints)<2:
313
self.lineRubBand.reset()
314
self.snapVerMarker.setCenter(QgsPoint(-1000,-1000))
315
self.lastPointIsStable=True
319
self.ur.startAction("Create a line.")
320
# call function of database manager that will create new line
321
(line,affected)=self.dbm.createLine(self.linePoints)
322
self.ur.stopAction(affected)
323
self.dbm.recacheAffectedNow(affected)
326
self.dockWidget.loadFeature(line,"Line",2)
329
self.lineRubBand.reset()
332
# after line creation canvas must be refresh so that changes take effect on map
333
self.canvas.refresh()