GRASS Programmer's Manual  6.5.svn(2014)-r66266
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
vdigit/mapwindow.py
Go to the documentation of this file.
1 """!
2 @package vdigit.mapwindow
3 
4 @brief Map display canvas for wxGUI vector digitizer
5 
6 Classes:
7  - mapwindow::VDigitWindow
8 
9 (C) 2011 by the GRASS Development Team
10 
11 This program is free software under the GNU General Public License
12 (>=v2). Read the file COPYING that comes with GRASS for details.
13 
14 @author Martin Landa <landa.martin gmail.com>
15 """
16 
17 import wx
18 
19 from dbmgr.dialogs import DisplayAttributesDialog
20 from core.gcmd import RunCommand, GMessage, GError
21 from core.debug import Debug
22 from mapdisp.mapwindow import BufferedWindow
23 from core.settings import UserSettings
24 from core.utils import ListOfCatsToRange
25 from core.globalvar import QUERYLAYER
26 from vdigit.dialogs import VDigitCategoryDialog, VDigitZBulkDialog, VDigitDuplicatesDialog
27 
29  """!A Buffered window extended for vector digitizer.
30  """
31  def __init__(self, parent, id = wx.ID_ANY,
32  Map = None, tree = None, lmgr = None,
33  style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
34  BufferedWindow.__init__(self, parent, id, Map, tree, lmgr,
35  style, **kwargs)
36 
37  self.pdcVector = wx.PseudoDC()
38  self.toolbar = self.parent.GetToolbar('vdigit')
39  self.digit = None # wxvdigit.IVDigit
40 
41  self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
42 
43  def GetDisplay(self):
44  if self.digit:
45  return self.digit.GetDisplay()
46  return None
47 
48  def SetToolbar(self, toolbar):
49  """!Set up related toolbar
50  """
51  self.toolbar = toolbar
52 
53  def _onMotion(self, coord, precision):
54  """!Track mouse motion and update statusbar (see self.Motion)
55 
56  @parem coord easting, northing
57  @param precision formatting precision
58  """
59  e, n = coord
60 
61  if self.toolbar.GetAction() != 'addLine' or \
62  self.toolbar.GetAction('type') not in ('line', 'boundary') or \
63  len(self.polycoords) == 0:
64  return False
65 
66  # for linear feature show segment and total length
67  distance_seg = self.Distance(self.polycoords[-1],
68  (e, n), screen = False)[0]
69  distance_tot = distance_seg
70  for idx in range(1, len(self.polycoords)):
71  distance_tot += self.Distance(self.polycoords[idx-1],
72  self.polycoords[idx],
73  screen = False)[0]
74  self.parent.SetStatusText("%.*f, %.*f (seg: %.*f; tot: %.*f)" % \
75  (precision, e, precision, n,
76  precision, distance_seg,
77  precision, distance_tot), 0)
78 
79  return True
80 
81  def OnKeyDown(self, event):
82  """!Key pressed"""
83  shift = event.ShiftDown()
84  kc = event.GetKeyCode()
85 
86  event = None
87  if not shift:
88  if kc == ord('P'):
89  event = wx.CommandEvent(winid = self.toolbar.addPoint)
90  tool = self.toolbar.OnAddPoint
91  elif kc == ord('L'):
92  event = wx.CommandEvent(winid = self.toolbar.addLine)
93  tool = self.toolbar.OnAddLine
94  if event:
95  self.toolbar.OnTool(event)
96  tool(event)
97 
98  def _updateMap(self):
99  if not self.toolbar or \
100  not self.toolbar.GetLayer():
101  return
102 
103  # set region
104  self.digit.GetDisplay().UpdateRegion()
105  # re-calculate threshold for digitization tool
106  # self.parent.digit.GetDisplay().GetThreshold()
107  # draw map
108  # self.pdcVector.Clear()
109  self.pdcVector.RemoveAll()
110 
111  try:
112  item = self.tree.FindItemByData('maplayer', self.toolbar.GetLayer())
113  except TypeError:
114  item = None
115 
116  if item and self.tree.IsItemChecked(item):
117  self.redrawAll = True
118  self.digit.GetDisplay().DrawMap()
119 
120  # translate tmp objects (pointer position)
121  if self.toolbar.GetAction() == 'moveLine' and \
122  hasattr(self, "moveInfo"):
123  if 'beginDiff' in self.moveInfo:
124  # move line
125  for id in self.moveInfo['id']:
126  self.pdcTmp.TranslateId(id,
127  self.moveInfo['beginDiff'][0],
128  self.moveInfo['beginDiff'][1])
129  del self.moveInfo['beginDiff']
130 
131  def OnLeftDownAddLine(self, event):
132  """!Left mouse button pressed - add new feature
133  """
134  try:
135  mapLayer = self.toolbar.GetLayer().GetName()
136  except:
137  return
138 
139  if self.toolbar.GetAction('type') in ['point', 'centroid']:
140  # add new point / centroiud
141  east, north = self.Pixel2Cell(self.mouse['begin'])
142  nfeat, fids = self.digit.AddFeature(self.toolbar.GetAction('type'), [(east, north)])
143  if nfeat < 1:
144  return
145 
146  self.UpdateMap(render = False) # redraw map
147 
148  # add new record into atribute table
149  if UserSettings.Get(group = 'vdigit', key = "addRecord", subkey = 'enabled'):
150  # select attributes based on layer and category
151  cats = { fids[0] : {
152  UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value') :
153  (UserSettings.Get(group = 'vdigit', key = "category", subkey = 'value'), )
154  }}
155 
156  posWindow = self.ClientToScreen((self.mouse['end'][0] + self.dialogOffset,
157  self.mouse['end'][1] + self.dialogOffset))
158 
159  addRecordDlg = DisplayAttributesDialog(parent = self, map = mapLayer,
160  cats = cats,
161  pos = posWindow,
162  action = "add", ignoreError = True)
163 
164  if self.toolbar.GetAction('type') == 'centroid':
165  for fid in fids:
166  self._geomAttrb(fid, addRecordDlg, 'area')
167  self._geomAttrb(fid, addRecordDlg, 'perimeter')
168 
169  if addRecordDlg.mapDBInfo and \
170  addRecordDlg.ShowModal() == wx.ID_OK:
171  sqlfile = tempfile.NamedTemporaryFile(mode = "w")
172  for sql in addRecordDlg.GetSQLString():
173  sqlfile.file.write(sql + ";\n")
174  sqlfile.file.flush()
175 
176  RunCommand('db.execute',
177  parent = self,
178  quiet = True,
179  input = sqlfile.name)
180 
181  if addRecordDlg.mapDBInfo:
182  self._updateATM()
183 
184  elif self.toolbar.GetAction('type') in ["line", "boundary", "area"]:
185  # add new point to the line
186  self.polycoords.append(self.Pixel2Cell(event.GetPositionTuple()[:]))
187  self.DrawLines(pdc = self.pdcTmp)
188 
189  def _geomAttrb(self, fid, dialog, attrb):
190  """!Define geometry attributes
191  """
192  mapLayer = self.toolbar.GetLayer()
193  item = self.tree.FindItemByData('maplayer', mapLayer)
194  vdigit = self.tree.GetPyData(item)[0]['vdigit']
195  if not vdigit or \
196  'geomAttr' not in vdigit or \
197  attrb not in vdigit['geomAttr']:
198  return
199 
200  val = -1
201  if attrb == 'length':
202  val = self.digit.GetLineLength(fid)
203  type = attrb
204  elif attrb == 'area':
205  val = self.digit.GetAreaSize(fid)
206  type = attrb
207  elif attrb == 'perimeter':
208  val = self.digit.GetAreaPerimeter(fid)
209  type = 'length'
210 
211  if val > 0:
212  layer = int(UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value'))
213  column = vdigit['geomAttr'][attrb]['column']
214  val = UnitsConvertValue(val, type, vdigit['geomAttr'][attrb]['units'])
215  dialog.SetColumnValue(layer, column, val)
216  dialog.OnReset()
217 
218  def _geomAttrbUpdate(self, fids):
219  """!Update geometry atrributes of currently selected features
220 
221  @param fid list feature id
222  """
223  mapLayer = self.parent.toolbars['vdigit'].GetLayer()
224  vectorName = mapLayer.GetName()
225  item = self.tree.FindItemByData('maplayer', mapLayer)
226  vdigit = self.tree.GetPyData(item)[0]['vdigit']
227 
228  if vdigit is None or 'geomAttr' not in vdigit:
229  return
230 
231  dbInfo = gselect.VectorDBInfo(vectorName)
232  sqlfile = tempfile.NamedTemporaryFile(mode = "w")
233  for fid in fids:
234  for layer, cats in self.digit.GetLineCats(fid).iteritems():
235  table = dbInfo.GetTable(layer)
236  for attrb, item in vdigit['geomAttr'].iteritems():
237  val = -1
238  if attrb == 'length':
239  val = self.digit.GetLineLength(fid)
240  type = attrb
241  elif attrb == 'area':
242  val = self.digit.GetAreaSize(fid)
243  type = attrb
244  elif attrb == 'perimeter':
245  val = self.digit.GetAreaPerimeter(fid)
246  type = 'length'
247 
248  if val < 0:
249  continue
250  val = UnitsConvertValue(val, type, item['units'])
251 
252  for cat in cats:
253  sqlfile.write('UPDATE %s SET %s = %f WHERE %s = %d;\n' % \
254  (table, item['column'], val,
255  dbInfo.GetKeyColumn(layer), cat))
256 
257  sqlfile.file.flush()
258  RunCommand('db.execute',
259  parent = True,
260  quiet = True,
261  input = sqlfile.name)
262 
263  def _updateATM(self):
264  """!Update open Attribute Table Manager
265 
266  @todo: use AddDataRow() instead
267  """
268  # update ATM
269  digitVector = self.toolbar.GetLayer().GetName()
270 
271  for atm in self.lmgr.dialogs['atm']:
272  atmVector = atm.GetVectorName()
273  if atmVector == digitVector:
274  layer = UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value')
275  # TODO: use AddDataRow instead
276  atm.LoadData(layer)
277 
278  def OnLeftDownEditLine(self, event):
279  """!Left mouse button pressed - edit linear feature - add new
280  vertex.
281  """
282  self.polycoords.append(self.Pixel2Cell(self.mouse['begin']))
283  self.moveInfo['id'].append(wx.NewId())
284  self.DrawLines(pdc = self.pdcTmp)
285 
286  def OnLeftDownMoveLine(self, event):
287  """!Left mouse button pressed - vector digitizer move
288  feature/vertex, edit linear feature
289  """
290  self.moveInfo = dict()
291  # geographic coordinates of initial position (left-down)
292  self.moveInfo['begin'] = None
293  # list of ids to modify
294  self.moveInfo['id'] = list()
295 
296  # set pen
297  if self.toolbar.GetAction() in ["moveVertex", "editLine"]:
298  pcolor = UserSettings.Get(group = 'vdigit', key = "symbol",
299  subkey = ["highlight", "color"])
300  self.pen = self.polypen = wx.Pen(colour = pcolor,
301  width = 2, style = wx.SHORT_DASH)
302  self.pdcTmp.SetPen(self.polypen)
303 
304  def OnLeftDownDisplayCA(self, event):
305  """!Left mouse button pressed - vector digitizer display categories
306  or attributes action
307  """
308  try:
309  mapLayer = self.toolbar.GetLayer().GetName()
310  except:
311  return
312 
313  coords = self.Pixel2Cell(self.mouse['begin'])
314 
315  # unselect
316  self.digit.GetDisplay().SetSelected([])
317 
318  # select feature by point
319  cats = {}
320  self.digit.GetDisplay().SelectLineByPoint(coords)
321 
322  if not self.digit.GetDisplay().GetSelected():
323  for key in ('attributes', 'category'):
324  if self.parent.dialogs[key] and \
325  self.parent.dialogs[key].IsShown():
326  self.parent.dialogs[key].Hide()
327  self.UpdateMap(render = False, renderVector = True)
328  return
329 
330  if UserSettings.Get(group = 'vdigit', key = 'checkForDupl',
331  subkey = 'enabled'):
332  lines = self.digit.GetDisplay().GetSelected()
333  else:
334  lines = (self.digit.GetDisplay().GetSelected()[0],) # only first found
335 
336  for line in lines:
337  cats[line] = self.digit.GetLineCats(line)
338 
339  posWindow = self.ClientToScreen((self.mouse['end'][0] + self.dialogOffset,
340  self.mouse['end'][1] + self.dialogOffset))
341 
342  if self.toolbar.GetAction() == "displayAttrs":
343  # select attributes based on coordinates (all layers)
344  if self.parent.dialogs['attributes'] is None:
345  self.parent.dialogs['attributes'] = \
346  DisplayAttributesDialog(parent = self, map = mapLayer,
347  cats = cats,
348  action = "update")
349  else:
350  # upgrade dialog
351  self.parent.dialogs['attributes'].UpdateDialog(cats = cats)
352 
353  if self.parent.dialogs['attributes'] and \
354  self.parent.dialogs['attributes'].mapDBInfo:
355  if len(cats.keys()) > 0:
356  # highlight feature & re-draw map
357  if not self.parent.dialogs['attributes'].IsShown():
358  self.parent.dialogs['attributes'].Show()
359  else:
360  if self.parent.dialogs['attributes'] and \
361  self.parent.dialogs['attributes'].IsShown():
362  self.parent.dialogs['attributes'].Hide()
363 
364  else: # displayCats
365  if self.parent.dialogs['category'] is None:
366  # open new dialog
367  dlg = VDigitCategoryDialog(parent = self,
368  vectorName = mapLayer,
369  cats = cats,
370  pos = posWindow,
371  title = _("Update categories"))
372  self.parent.dialogs['category'] = dlg
373  else:
374  # update currently open dialog
375  self.parent.dialogs['category'].UpdateDialog(cats = cats)
376 
377  if self.parent.dialogs['category']:
378  if len(cats.keys()) > 0:
379  # highlight feature & re-draw map
380  if not self.parent.dialogs['category'].IsShown():
381  self.parent.dialogs['category'].Show()
382  else:
383  if self.parent.dialogs['category'].IsShown():
384  self.parent.dialogs['category'].Hide()
385 
386  self.UpdateMap(render = False, renderVector = True)
387 
388  def OnLeftDownCopyCA(self, event):
389  """!Left mouse button pressed - vector digitizer copy
390  categories or attributes action
391  """
392  if not hasattr(self, "copyCatsList"):
393  self.copyCatsList = []
394  else:
395  self.copyCatsIds = []
396  self.mouse['box'] = 'box'
397 
398  def OnLeftDownCopyLine(self, event):
399  """!Left mouse button pressed - vector digitizer copy lines
400  action
401  """
402  if not hasattr(self, "copyIds"):
403  self.copyIds = []
404  self.layerTmp = None
405 
406  def OnLeftDownBulkLine(self, event):
407  """!Left mouse button pressed - vector digitizer label 3D
408  vector lines
409  """
410  if len(self.polycoords) > 1: # start new line
411  self.polycoords = []
412  self.ClearLines(pdc = self.pdcTmp)
413  self.polycoords.append(self.Pixel2Cell(event.GetPositionTuple()[:]))
414  if len(self.polycoords) == 1:
415  begin = self.Pixel2Cell(self.polycoords[-1])
416  end = self.Pixel2Cell(self.mouse['end'])
417  else:
418  end = self.Pixel2Cell(self.polycoords[-1])
419  begin = self.Pixel2Cell(self.mouse['begin'])
420 
421  self.DrawLines(self.pdcTmp, polycoords = (begin, end))
422 
423  def OnLeftDownUndo(self, event):
424  """!Left mouse button pressed with control key - vector
425  digitizer undo functionality
426  """
427  if self.mouse["use"] != "pointer" or not self.toolbar:
428  return
429 
430  action = self.toolbar.GetAction()
431  if (action == "addLine" and \
432  self.toolbar.GetAction('type') in ["line", "boundary", "area"]) or \
433  action == "editLine":
434  # add line or boundary -> remove last point from the line
435  try:
436  removed = self.polycoords.pop()
437  Debug.msg(4, "BufferedWindow.OnMiddleDown(): polycoords_poped=%s" % \
438  [removed,])
439  # self.mouse['begin'] = self.Cell2Pixel(self.polycoords[-1])
440  except:
441  pass
442 
443  if action == "editLine":
444  # remove last vertex & line
445  if len(self.moveInfo['id']) > 1:
446  self.moveInfo['id'].pop()
447 
448  self.UpdateMap(render = False, renderVector = False)
449 
450  elif action in ["deleteLine", "moveLine", "splitLine",
451  "addVertex", "removeVertex", "moveVertex",
452  "copyCats", "flipLine", "mergeLine",
453  "snapLine", "connectLine", "copyLine",
454  "queryLine", "breakLine", "typeConv"]:
455  # varios tools -> unselected selected features
456  self.digit.GetDisplay().SetSelected([])
457  if action in ["moveLine", "moveVertex", "editLine"] and \
458  hasattr(self, "moveInfo"):
459  del self.moveInfo
460 
461  elif action == "copyCats":
462  try:
463  del self.copyCatsList
464  del self.copyCatsIds
465  except AttributeError:
466  pass
467 
468  elif action == "copyLine":
469  del self.copyIds
470  if self.layerTmp:
471  self.Map.DeleteLayer(self.layerTmp)
472  self.UpdateMap(render = True, renderVector = False)
473  del self.layerTmp
474 
475  self.polycoords = []
476  self.UpdateMap(render = False) # render vector
477 
478  elif action == "zbulkLine":
479  # reset polyline
480  self.polycoords = []
481  self.digit.GetDisplay().SetSelected([])
482  self.UpdateMap(render = False)
483 
484  self.redrawAll = True
485  self.UpdateMap(render = False, renderVector = False)
486 
487  def _onLeftDown(self, event):
488  """!Left mouse button donw - vector digitizer various actions
489  """
490  try:
491  mapLayer = self.toolbar.GetLayer().GetName()
492  except:
493  GMessage(parent = self,
494  message = _("No vector map selected for editing."))
495  event.Skip()
496  return
497 
498  action = self.toolbar.GetAction()
499 
500  if not action:
501  GMessage(parent = self,
502  message = _("Nothing to do. "
503  "Choose appropriate tool from digitizer toolbar."))
504  event.Skip()
505  return
506 
507  if action not in ("moveVertex",
508  "addVertex",
509  "removeVertex",
510  "editLine"):
511  # set pen
512  self.pen = wx.Pen(colour = UserSettings.Get(group = 'vdigit', key = 'symbol',
513  subkey = ['newSegment', 'color']),
514  width = 2, style = wx.SHORT_DASH)
515  self.polypen = wx.Pen(colour = UserSettings.Get(group = 'vdigit', key = 'symbol',
516  subkey = ['newLine', 'color']),
517  width = 2, style = wx.SOLID)
518 
519  if action in ("addVertex",
520  "removeVertex",
521  "splitLines"):
522  # unselect
523  self.digit.GetDisplay().SetSelected([])
524 
525  if action == "addLine":
526  self.OnLeftDownAddLine(event)
527 
528  elif action == "editLine" and \
529  hasattr(self, "moveInfo"):
530  self.OnLeftDownEditLine(event)
531 
532  elif action in ("moveLine", "moveVertex", "editLine") and \
533  not hasattr(self, "moveInfo"):
534  self.OnLeftDownMoveLine(event)
535 
536  elif action in ("displayAttrs"
537  "displayCats"):
538  self.OnLeftDownDisplayCA(event)
539 
540  elif action in ("copyCats",
541  "copyAttrs"):
542  self.OnLeftDownCopyCA(event)
543 
544  elif action == "copyLine":
545  self.OnLeftDownCopyLine(event)
546 
547  elif action == "zbulkLine":
548  self.OnLeftDownBulkLine(event)
549 
550  def OnLeftUpVarious(self, event):
551  """!Left mouse button released - vector digitizer various
552  actions
553  """
554  pos1 = self.Pixel2Cell(self.mouse['begin'])
555  pos2 = self.Pixel2Cell(self.mouse['end'])
556 
557  nselected = 0
558  action = self.toolbar.GetAction()
559  # -> delete line || move line || move vertex
560  if action in ("moveVertex",
561  "editLine"):
562  if len(self.digit.GetDisplay().GetSelected()) == 0:
563  nselected = self.digit.GetDisplay().SelectLineByPoint(pos1)['point']
564 
565  if action == "editLine":
566  try:
567  selVertex = self.digit.GetDisplay().GetSelectedVertex(pos1)[0]
568  except IndexError:
569  selVertex = None
570 
571  if selVertex:
572  # self.UpdateMap(render=False)
573  ids = self.digit.GetDisplay().GetSelected(grassId = False)
574  # move this line to tmp layer
575  self.polycoords = []
576  for id in ids:
577  if id % 2: # register only vertices
578  e, n = self.Pixel2Cell(self.pdcVector.GetIdBounds(id)[0:2])
579  self.polycoords.append((e, n))
580  self.digit.GetDisplay().DrawSelected(False)
581 
582  if selVertex < ids[-1] / 2:
583  # choose first or last node of line
584  self.moveInfo['id'].reverse()
585  self.polycoords.reverse()
586  else:
587  # unselect
588  self.digit.GetDisplay().SetSelected([])
589  del self.moveInfo
590 
591  self.UpdateMap(render = False)
592 
593  elif action in ("copyCats",
594  "copyAttrs"):
595  if not hasattr(self, "copyCatsIds"):
596  # 'from' -> select by point
597  nselected = self.digit.GetDisplay().SelectLineByPoint(pos1)['point']
598  if nselected:
599  self.copyCatsList = self.digit.GetDisplay().GetSelected()
600  else:
601  # -> 'to' -> select by bbox
602  self.digit.GetDisplay().SetSelected([])
603  # return number of selected features (by box/point)
604  nselected = self.digit.GetDisplay().SelectLinesByBox((pos1, pos2))
605  if nselected == 0:
606  if self.digit.GetDisplay().SelectLineByPoint(pos1) is not None:
607  nselected = 1
608 
609  if nselected > 0:
610  self.copyCatsIds = self.digit.GetDisplay().GetSelected()
611 
612  elif action == "queryLine":
613  selected = self.digit.SelectLinesByQuery(bbox = (pos1, pos2))
614  nselected = len(selected)
615  if nselected > 0:
616  self.digit.GetDisplay().SetSelected(selected)
617 
618  else:
619  # -> moveLine || deleteLine, etc. (select by point/box)
620  if action == 'moveLine' and \
621  len(self.digit.GetDisplay().GetSelected()) > 0:
622  nselected = 0
623  else:
624  if action == 'moveLine':
625  drawSeg = True
626  else:
627  drawSeg = False
628 
629  nselected = self.digit.GetDisplay().SelectLinesByBox(bbox = (pos1, pos2),
630  drawSeg = drawSeg)
631  if nselected == 0:
632  if self.digit.GetDisplay().SelectLineByPoint(pos1) is not None:
633  nselected = 1
634 
635  if nselected > 0:
636  if action in ("moveLine", "moveVertex") and \
637  hasattr(self, "moveInfo"):
638  # get pseudoDC id of objects which should be redrawn
639  if action == "moveLine":
640  # -> move line
641  self.moveInfo['id'] = self.digit.GetDisplay().GetSelected(grassId = False)
642  else: # moveVertex
643  self.moveInfo['id'] = self.digit.GetDisplay().GetSelectedVertex(pos1)
644  if len(self.moveInfo['id']) == 0: # no vertex found
645  self.digit.GetDisplay().SetSelected([])
646 
647  #
648  # check for duplicates
649  #
650  if UserSettings.Get(group = 'vdigit', key = 'checkForDupl', subkey = 'enabled'):
651  dupl = self.digit.GetDisplay().GetDuplicates()
652  self.UpdateMap(render = False)
653 
654  if dupl:
655  posWindow = self.ClientToScreen((self.mouse['end'][0] + self.dialogOffset,
656  self.mouse['end'][1] + self.dialogOffset))
657 
658  dlg = VDigitDuplicatesDialog(parent = self, data = dupl, pos = posWindow)
659 
660  if dlg.ShowModal() == wx.ID_OK:
661  self.digit.GetDisplay().UnSelect(dlg.GetUnSelected())
662  # update selected
663  self.UpdateMap(render = False)
664 
665  if action != "editLine":
666  # -> move line || move vertex
667  self.UpdateMap(render = False)
668 
669  else: # no vector object found
670  if not (action in ("moveLine",
671  "moveVertex") and \
672  hasattr(self, "moveInfo") and \
673  len(self.moveInfo['id']) > 0):
674  # avoid left-click when features are already selected
675  self.UpdateMap(render = False, renderVector = False)
676 
677  def OnLeftUpModifyLine(self, event):
678  """!Left mouse button released - vector digitizer split line,
679  add/remove vertex action
680  """
681  pos1 = self.Pixel2Cell(self.mouse['begin'])
682 
683  pointOnLine = self.digit.GetDisplay().SelectLineByPoint(pos1)['point']
684  if not pointOnLine:
685  return
686 
687  if self.toolbar.GetAction() in ["splitLine", "addVertex"]:
688  self.UpdateMap(render = False) # highlight object
689  self.DrawCross(pdc = self.pdcTmp, coords = self.Cell2Pixel((pointOnLine[0], pointOnLine[1])),
690  size = 5)
691  else: # removeVertex
692  # get only id of vertex
693  try:
694  id = self.digit.GetDisplay().GetSelectedVertex(pos1)[0]
695  except IndexError:
696  id = None
697 
698  if id:
699  x, y = self.pdcVector.GetIdBounds(id)[0:2]
700  self.pdcVector.RemoveId(id)
701  self.UpdateMap(render = False) # highlight object
702  self.DrawCross(pdc = self.pdcTmp, coords = (x, y),
703  size = 5)
704  else:
705  # unselect
706  self.digit.GetDisplay().SetSelected([])
707  self.UpdateMap(render = False)
708 
709  def OnLeftUpCopyLine(self, event):
710  """!Left mouse button released - vector digitizer copy feature
711  action
712  """
713  pos1 = self.Pixel2Cell(self.mouse['begin'])
714  pos2 = self.Pixel2Cell(self.mouse['end'])
715 
716  if UserSettings.Get(group = 'vdigit', key = 'bgmap',
717  subkey = 'value', internal = True) == '':
718  # no background map -> copy from current vector map layer
719  nselected = self.bdigit.GetDisplay().SelectLinesByBox((pos1, pos2))
720 
721  if nselected > 0:
722  # highlight selected features
723  self.UpdateMap(render = False)
724  else:
725  self.UpdateMap(render = False, renderVector = False)
726  else:
727  # copy features from background map
728  self.copyIds = self.digit.SelectLinesFromBackgroundMap(bbox = (pos1, pos2))
729  if len(self.copyIds) > 0:
730  color = UserSettings.Get(group = 'vdigit', key = 'symbol',
731  subkey = ['highlight', 'color'])
732  colorStr = str(color[0]) + ":" + str(color[1]) + ":" + str(color[2])
733  dVectTmp = ['d.vect',
734  'map=%s' % UserSettings.Get(group = 'vdigit', key = 'bgmap',
735  subkey = 'value', internal = True),
736  'cats=%s' % ListOfCatsToRange(self.copyIds),
737  '-i',
738  'color=%s' % colorStr,
739  'fcolor=%s' % colorStr,
740  'type=point,line,boundary,centroid',
741  'width=2']
742 
743  if not self.layerTmp:
744  self.layerTmp = self.Map.AddLayer(type = 'vector',
745  name = QUERYLAYER,
746  command = dVectTmp)
747  else:
748  self.layerTmp.SetCmd(dVectTmp)
749  else:
750  if self.layerTmp:
751  self.Map.DeleteLayer(self.layerTmp)
752  self.layerTmp = None
753 
754  self.UpdateMap(render = True, renderVector = True)
755 
756  def OnLeftUpBulkLine(self, event):
757  """!Left mouse button released - vector digitizer z-bulk line
758  action
759  """
760  # select lines to be labeled
761  pos1 = self.polycoords[0]
762  pos2 = self.polycoords[1]
763  nselected = self.digit.GetDisplay().SelectLinesByBox((pos1, pos2))
764 
765  if nselected > 0:
766  # highlight selected features
767  self.UpdateMap(render = False)
768  self.DrawLines(pdc = self.pdcTmp) # redraw temp line
769  else:
770  self.UpdateMap(render = False, renderVector = False)
771 
772  def OnLeftUpConnectLine(self, event):
773  """!Left mouse button released - vector digitizer connect line
774  action
775  """
776  if len(self.digit.GetDisplay().GetSelected()) > 0:
777  self.UpdateMap(render = False)
778 
779  def _onLeftUp(self, event):
780  """!Left mouse button released"""
781  if hasattr(self, "moveInfo"):
782  if len(self.digit.GetDisplay().GetSelected()) == 0:
783  self.moveInfo['begin'] = self.Pixel2Cell(self.mouse['begin']) # left down
784 
785  # eliminate initial mouse moving efect
786  self.mouse['begin'] = self.mouse['end']
787 
788  action = self.toolbar.GetAction()
789  if action in ("deleteLine",
790  "moveLine",
791  "moveVertex",
792  "copyCats",
793  "copyAttrs",
794  "editLine",
795  "flipLine",
796  "mergeLine",
797  "snapLine",
798  "queryLine",
799  "breakLine",
800  "typeConv",
801  "connectLine"):
802  self.OnLeftUpVarious(event)
803 
804  elif action in ("splitLine",
805  "addVertex",
806  "removeVertex"):
807  self.OnLeftUpModifyLine(event)
808 
809  elif action == "copyLine":
810  self.OnLeftUpCopyLine(event)
811 
812  elif action == "zbulkLine" and \
813  len(self.polycoords) == 2:
814  self.OnLeftUpBulkLine(event)
815 
816  elif action == "connectLine":
817  self.OnLeftUpConnectLine(event)
818 
819  if len(self.digit.GetDisplay().GetSelected()) > 0:
820  self.redrawAll = None
821 
822  def _onRightDown(self, event):
823  # digitization tool (confirm action)
824  action = self.toolbar.GetAction()
825  if action in ("moveLine", "moveVertex") and \
826  hasattr(self, "moveInfo"):
827  pFrom = self.moveInfo['begin']
828  pTo = self.Pixel2Cell(event.GetPositionTuple())
829 
830  move = (pTo[0] - pFrom[0],
831  pTo[1] - pFrom[1])
832 
833  if action == "moveLine":
834  # move line
835  if self.digit.MoveSelectedLines(move) < 0:
836  return
837  elif action == "moveVertex":
838  # move vertex
839  fid = self.digit.MoveSelectedVertex(pFrom, move)
840  if fid < 0:
841  return
842 
843  self._geomAttrbUpdate([fid,])
844 
845  del self.moveInfo
846 
847  def _onRightUp(self, event):
848  """!Right mouse button released (confirm action)
849  """
850  action = self.toolbar.GetAction()
851  if action == "addLine" and \
852  self.toolbar.GetAction('type') in ["line", "boundary", "area"]:
853  # -> add new line / boundary
854  try:
855  mapName = self.toolbar.GetLayer().GetName()
856  except:
857  mapName = None
858  GError(parent = self,
859  message = _("No vector map selected for editing."))
860 
861  if mapName:
862  if self.toolbar.GetAction('type') == 'line':
863  line = True
864  else:
865  line = False
866 
867  if len(self.polycoords) < 2: # ignore 'one-point' lines
868  return
869 
870  nfeat, fids = self.digit.AddFeature(self.toolbar.GetAction('type'), self.polycoords)
871  if nfeat < 0:
872  return
873 
874  position = self.Cell2Pixel(self.polycoords[-1])
875  self.polycoords = []
876  self.UpdateMap(render = False)
877  self.redrawAll = True
878  self.Refresh()
879 
880  # add new record into atribute table
881  if UserSettings.Get(group = 'vdigit', key = "addRecord", subkey = 'enabled') and \
882  (line is True or \
883  (not line and nfeat > 0)):
884  posWindow = self.ClientToScreen((position[0] + self.dialogOffset,
885  position[1] + self.dialogOffset))
886 
887  # select attributes based on layer and category
888  cats = { fids[0] : {
889  UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value') :
890  (UserSettings.Get(group = 'vdigit', key = "category", subkey = 'value'), )
891  }}
892 
893  addRecordDlg = DisplayAttributesDialog(parent = self, map = mapName,
894  cats = cats,
895  pos = posWindow,
896  action = "add", ignoreError = True)
897 
898  for fid in fids:
899  self._geomAttrb(fid, addRecordDlg, 'length')
900  # auto-placing centroid
901  self._geomAttrb(fid, addRecordDlg, 'area')
902  self._geomAttrb(fid, addRecordDlg, 'perimeter')
903 
904 
905  if addRecordDlg.mapDBInfo and \
906  addRecordDlg.ShowModal() == wx.ID_OK:
907  sqlfile = tempfile.NamedTemporaryFile(mode = "w")
908  for sql in addRecordDlg.GetSQLString():
909  sqlfile.file.write(sql + ";\n")
910  sqlfile.file.flush()
911  RunCommand('db.execute',
912  parent = True,
913  quiet = True,
914  input = sqlfile.name)
915 
916  if addRecordDlg.mapDBInfo:
917  self._updateATM()
918 
919  elif action == "deleteLine":
920  # -> delete selected vector features
921  if self.digit.DeleteSelectedLines() < 0:
922  return
923  self._updateATM()
924  elif action == "splitLine":
925  # split line
926  if self.digit.SplitLine(self.Pixel2Cell(self.mouse['begin'])) < 0:
927  return
928  elif action == "addVertex":
929  # add vertex
930  fid = self.digit.AddVertex(self.Pixel2Cell(self.mouse['begin']))
931  if fid < 0:
932  return
933  elif action == "removeVertex":
934  # remove vertex
935  fid = self.digit.RemoveVertex(self.Pixel2Cell(self.mouse['begin']))
936  if fid < 0:
937  return
938  self._geomAttrbUpdate([fid,])
939  elif action in ("copyCats", "copyAttrs"):
940  if action == 'copyCats':
941  if self.digit.CopyCats(self.copyCatsList,
942  self.copyCatsIds, copyAttrb = False) < 0:
943  return
944  else:
945  if self.digit.CopyCats(self.copyCatsList,
946  self.copyCatsIds, copyAttrb = True) < 0:
947  return
948 
949  del self.copyCatsList
950  del self.copyCatsIds
951 
952  self._updateATM()
953 
954  elif action == "editLine" and \
955  hasattr(self, "moveInfo"):
956  line = self.digit.GetDisplay().GetSelected()[0]
957  if self.digit.EditLine(line, self.polycoords) < 0:
958  return
959 
960  del self.moveInfo
961 
962  elif action == "flipLine":
963  if self.digit.FlipLine() < 0:
964  return
965  elif action == "mergeLine":
966  if self.digit.MergeLine() < 0:
967  return
968  elif action == "breakLine":
969  if self.digit.BreakLine() < 0:
970  return
971  elif action == "snapLine":
972  if self.digit.SnapLine() < 0:
973  return
974  elif action == "connectLine":
975  if len(self.digit.GetDisplay().GetSelected()) > 1:
976  if self.digit.ConnectLine() < 0:
977  return
978  elif action == "copyLine":
979  if self.digit.CopyLine(self.copyIds) < 0:
980  return
981  del self.copyIds
982  if self.layerTmp:
983  self.Map.DeleteLayer(self.layerTmp)
984  self.UpdateMap(render = True, renderVector = False)
985  del self.layerTmp
986 
987  elif action == "zbulkLine" and len(self.polycoords) == 2:
988  pos1 = self.polycoords[0]
989  pos2 = self.polycoords[1]
990 
991  selected = self.digit.GetDisplay().GetSelected()
992  dlg = VDigitZBulkDialog(parent = self, title = _("Z bulk-labeling dialog"),
993  nselected = len(selected))
994  if dlg.ShowModal() == wx.ID_OK:
995  if self.digit.ZBulkLines(pos1, pos2, dlg.value.GetValue(),
996  dlg.step.GetValue()) < 0:
997  return
998  self.UpdateMap(render = False)
999  elif action == "typeConv":
1000  # -> feature type conversion
1001  # - point <-> centroid
1002  # - line <-> boundary
1003  if self.digit.TypeConvForSelectedLines() < 0:
1004  return
1005 
1006  if action != "addLine":
1007  # unselect and re-render
1008  self.digit.GetDisplay().SetSelected([])
1009  self.polycoords = []
1010  self.UpdateMap(render = False)
1011 
1012  def _onMouseMoving(self, event):
1013  self.mouse['end'] = event.GetPositionTuple()[:]
1014 
1015  Debug.msg (5, "BufferedWindow.OnMouseMoving(): coords=%f,%f" % \
1016  (self.mouse['end'][0], self.mouse['end'][1]))
1017 
1018  action = self.toolbar.GetAction()
1019  if action == "addLine" and \
1020  self.toolbar.GetAction('type') in ["line", "boundary", "area"]:
1021  if len(self.polycoords) > 0:
1022  self.MouseDraw(pdc = self.pdcTmp, begin = self.Cell2Pixel(self.polycoords[-1]))
1023 
1024  elif action in ["moveLine", "moveVertex", "editLine"] \
1025  and hasattr(self, "moveInfo"):
1026  dx = self.mouse['end'][0] - self.mouse['begin'][0]
1027  dy = self.mouse['end'][1] - self.mouse['begin'][1]
1028 
1029  # draw lines on new position
1030  if action == "moveLine" and \
1031  len(self.moveInfo['id']) > 0:
1032  # move line
1033  for id in self.moveInfo['id']:
1034  self.pdcTmp.TranslateId(id, dx, dy)
1035  elif action in ["moveVertex", "editLine"]:
1036  # move vertex ->
1037  # (vertex, left vertex, left line,
1038  # right vertex, right line)
1039 
1040  # do not draw static lines
1041  if action == "moveVertex" and \
1042  len(self.moveInfo['id']) > 0:
1043  self.polycoords = []
1044  self.pdcTmp.RemoveId(self.moveInfo['id'][0])
1045  if self.moveInfo['id'][1] > 0: # previous vertex
1046  x, y = self.Pixel2Cell(self.pdcTmp.GetIdBounds(self.moveInfo['id'][1])[0:2])
1047  self.pdcTmp.RemoveId(self.moveInfo['id'][1] + 1)
1048  self.polycoords.append((x, y))
1049  self.polycoords.append(self.Pixel2Cell(self.mouse['end']))
1050 
1051  if self.moveInfo['id'][2] > 0: # next vertex
1052  x, y = self.Pixel2Cell(self.pdcTmp.GetIdBounds(self.moveInfo['id'][2])[0:2])
1053  self.pdcTmp.RemoveId(self.moveInfo['id'][2]-1)
1054  self.polycoords.append((x, y))
1055 
1056  self.ClearLines(pdc = self.pdcTmp)
1057  self.DrawLines(pdc = self.pdcTmp)
1058 
1059  if action == "editLine":
1060  self.MouseDraw(pdc = self.pdcTmp,
1061  begin = self.Cell2Pixel(self.polycoords[-1]))
1062 
1063  self.Refresh() # TODO: use RefreshRect()
1064  self.mouse['begin'] = self.mouse['end']
1065 
1066  elif action == "zbulkLine":
1067  if len(self.polycoords) == 1:
1068  # draw mouse moving
1069  self.MouseDraw(self.pdcTmp)
1070 
1071  def _zoom(self, event):
1072  tmp1 = self.mouse['end']
1073  tmp2 = self.Cell2Pixel(self.moveInfo['begin'])
1074  dx = tmp1[0] - tmp2[0]
1075  dy = tmp1[1] - tmp2[1]
1076  self.moveInfo['beginDiff'] = (dx, dy)
1077  for id in self.moveInfo['id']:
1078  self.pdcTmp.RemoveId(id)
def _geomAttrb
Define geometry attributes.
def DrawLines
Draw polyline in PseudoDC.
A Buffered window extended for vector digitizer.
wxGUI command interface
def OnLeftDownCopyLine
Left mouse button pressed - vector digitizer copy lines action.
def ListOfCatsToRange
Convert list of category number to range(s)
Definition: core/utils.py:207
def OnLeftDownMoveLine
Left mouse button pressed - vector digitizer move feature/vertex, edit linear feature.
wxGUI debugging
def OnLeftDownAddLine
Left mouse button pressed - add new feature.
def OnLeftUpVarious
Left mouse button released - vector digitizer various actions.
def SetToolbar
Set up related toolbar.
redrawAll
self.OnSize(None)
def DrawCross
Draw cross in PseudoDC.
def _updateATM
Update open Attribute Table Manager.
def UpdateDialog
Definition: forms.py:294
def OnLeftUpCopyLine
Left mouse button released - vector digitizer copy feature action.
def OnLeftUpModifyLine
Left mouse button released - vector digitizer split line, add/remove vertex action.
def UpdateMap
Updates the canvas anytime there is a change to the underlaying images or to the geometry of the canv...
def _geomAttrbUpdate
Update geometry atrributes of currently selected features.
DBM-related dialogs.
def OnLeftDownCopyCA
Left mouse button pressed - vector digitizer copy categories or attributes action.
wxGUI vector digitizer dialogs
def OnLeftUpBulkLine
Left mouse button released - vector digitizer z-bulk line action.
def OnLeftDownUndo
Left mouse button pressed with control key - vector digitizer undo functionality. ...
Misc utilities for wxGUI.
def OnLeftDownBulkLine
Left mouse button pressed - vector digitizer label 3D vector lines.
def OnLeftDownDisplayCA
Left mouse button pressed - vector digitizer display categories or attributes action.
Map display canvas - buffered window.
Global variables used by wxGUI.
def OnLeftDownEditLine
Left mouse button pressed - edit linear feature - add new vertex.
def Distance
Calculete distance.
def MouseDraw
Mouse box or line from &#39;begin&#39; to &#39;end&#39;.
Default GUI settings.
def OnLeftUpConnectLine
Left mouse button released - vector digitizer connect line action.
tuple range
Definition: tools.py:1406
Class providing information about attribute tables linked to a vector map.
Definition: gselect.py:549
def OnKeyDown
Key pressed.
A Buffered window class (2D view mode)
def RunCommand
Run GRASS command.
Definition: gcmd.py:625
def ClearLines
Clears temporary drawn lines from PseudoDC.