GRASS Programmer's Manual  6.4.2(2012)
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
mapdisp_vdigit.py
Go to the documentation of this file.
1 """!
2 @package mapdisp_vdigit.py
3 
4 @brief Map display canvas extended for vector digitizer
5 
6 See also vdigit.py, wxvdriver.py and wxvdigit.py
7 
8 Classes:
9  - VDigitWindow
10 
11 (C) 2011 by the GRASS Development Team
12 This program is free software under the GNU General Public
13 License (>=v2). Read the file COPYING that comes with GRASS
14 for details.
15 
16 @author Martin Landa <landa.martin gmail.com>
17 """
18 
19 import wx
20 
21 import dbm_dialogs
22 
23 import gcmd
24 from debug import Debug
25 from mapdisp_window import BufferedWindow
26 from preferences import globalSettings as UserSettings
27 from utils import ListOfCatsToRange
28 from globalvar import QUERYLAYER
29 from vdigit import VDigitCategoryDialog
30 from vdigit import VDigitZBulkDialog
31 from vdigit import VDigitDuplicatesDialog
32 
33 class VDigitWindow(BufferedWindow):
34  """!A Buffered window extended for vector digitizer.
35  """
36  def __init__(self, parent, id = wx.ID_ANY,
37  Map = None, tree = None, lmgr = None,
38  style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
39  BufferedWindow.__init__(self, parent, id, Map, tree, lmgr,
40  style, **kwargs)
41 
42  self.pdcVector = wx.PseudoDC()
43  self.toolbar = self.parent.toolbars['vdigit']
44  self.digit = None # wxvdigit.IVDigit
45 
46  self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
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.statusbar.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 = dbm_dialogs.DisplayAttributesDialog(parent = self, map = mapLayer,
160  cats = cats,
161  pos = posWindow,
162  action = "add")
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  gcmd.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  gcmd.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  dbm_dialogs.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']:
354  if len(cats.keys()) > 0:
355  # highlight feature & re-draw map
356  if not self.parent.dialogs['attributes'].IsShown():
357  self.parent.dialogs['attributes'].Show()
358  else:
359  if self.parent.dialogs['attributes'] and \
360  self.parent.dialogs['attributes'].IsShown():
361  self.parent.dialogs['attributes'].Hide()
362 
363  else: # displayCats
364  if self.parent.dialogs['category'] is None:
365  # open new dialog
366  dlg = VDigitCategoryDialog(parent = self,
367  vectorName = mapLayer,
368  cats = cats,
369  pos = posWindow,
370  title = _("Update categories"))
371  self.parent.dialogs['category'] = dlg
372  else:
373  # update currently open dialog
374  self.parent.dialogs['category'].UpdateDialog(cats = cats)
375 
376  if self.parent.dialogs['category']:
377  if len(cats.keys()) > 0:
378  # highlight feature & re-draw map
379  if not self.parent.dialogs['category'].IsShown():
380  self.parent.dialogs['category'].Show()
381  else:
382  if self.parent.dialogs['category'].IsShown():
383  self.parent.dialogs['category'].Hide()
384 
385  self.UpdateMap(render = False, renderVector = True)
386 
387  def OnLeftDownCopyCA(self, event):
388  """!Left mouse button pressed - vector digitizer copy
389  categories or attributes action
390  """
391  if not hasattr(self, "copyCatsList"):
392  self.copyCatsList = []
393  else:
394  self.copyCatsIds = []
395  self.mouse['box'] = 'box'
396 
397  def OnLeftDownCopyLine(self, event):
398  """!Left mouse button pressed - vector digitizer copy lines
399  action
400  """
401  if not hasattr(self, "copyIds"):
402  self.copyIds = []
403  self.layerTmp = None
404 
405  def OnLeftDownBulkLine(self, event):
406  """!Left mouse button pressed - vector digitizer label 3D
407  vector lines
408  """
409  if len(self.polycoords) > 1: # start new line
410  self.polycoords = []
411  self.ClearLines(pdc = self.pdcTmp)
412  self.polycoords.append(self.Pixel2Cell(event.GetPositionTuple()[:]))
413  if len(self.polycoords) == 1:
414  begin = self.Pixel2Cell(self.polycoords[-1])
415  end = self.Pixel2Cell(self.mouse['end'])
416  else:
417  end = self.Pixel2Cell(self.polycoords[-1])
418  begin = self.Pixel2Cell(self.mouse['begin'])
419 
420  self.DrawLines(self.pdcTmp, polycoords = (begin, end))
421 
422  def OnLeftDownUndo(self, event):
423  """!Left mouse button pressed with control key - vector
424  digitizer undo functionality
425  """
426  if self.mouse["use"] != "pointer" or not self.toolbar:
427  return
428 
429  action = self.toolbar.GetAction()
430  if (action == "addLine" and \
431  self.toolbar.GetAction('type') in ["line", "boundary", "area"]) or \
432  action == "editLine":
433  # add line or boundary -> remove last point from the line
434  try:
435  removed = self.polycoords.pop()
436  Debug.msg(4, "BufferedWindow.OnMiddleDown(): polycoords_poped=%s" % \
437  [removed,])
438  # self.mouse['begin'] = self.Cell2Pixel(self.polycoords[-1])
439  except:
440  pass
441 
442  if action == "editLine":
443  # remove last vertex & line
444  if len(self.moveInfo['id']) > 1:
445  self.moveInfo['id'].pop()
446 
447  self.UpdateMap(render = False, renderVector = False)
448 
449  elif action in ["deleteLine", "moveLine", "splitLine",
450  "addVertex", "removeVertex", "moveVertex",
451  "copyCats", "flipLine", "mergeLine",
452  "snapLine", "connectLine", "copyLine",
453  "queryLine", "breakLine", "typeConv"]:
454  # varios tools -> unselected selected features
455  self.digit.GetDisplay().SetSelected([])
456  if action in ["moveLine", "moveVertex", "editLine"] and \
457  hasattr(self, "moveInfo"):
458  del self.moveInfo
459 
460  elif action == "copyCats":
461  try:
462  del self.copyCatsList
463  del self.copyCatsIds
464  except AttributeError:
465  pass
466 
467  elif action == "copyLine":
468  del self.copyIds
469  if self.layerTmp:
470  self.Map.DeleteLayer(self.layerTmp)
471  self.UpdateMap(render = True, renderVector = False)
472  del self.layerTmp
473 
474  self.polycoords = []
475  self.UpdateMap(render = False) # render vector
476 
477  elif action == "zbulkLine":
478  # reset polyline
479  self.polycoords = []
480  self.digit.GetDisplay().SetSelected([])
481  self.UpdateMap(render = False)
482 
483  self.redrawAll = True
484  self.UpdateMap(render = False, renderVector = False)
485 
486  def _onLeftDown(self, event):
487  """!Left mouse button donw - vector digitizer various actions
488  """
489  try:
490  mapLayer = self.toolbar.GetLayer().GetName()
491  except:
492  gcmd.GMessage(parent = self,
493  message = _("No vector map selected for editing."))
494  event.Skip()
495  return
496 
497  action = self.toolbar.GetAction()
498  if not action:
499  return
500 
501  if action not in ("moveVertex",
502  "addVertex",
503  "removeVertex",
504  "editLine"):
505  # set pen
506  self.pen = wx.Pen(colour = 'Red', width = 2, style = wx.SHORT_DASH)
507  self.polypen = wx.Pen(colour = 'dark green', width = 2, style = wx.SOLID)
508 
509  if action in ("addVertex",
510  "removeVertex",
511  "splitLines"):
512  # unselect
513  self.digit.GetDisplay().SetSelected([])
514 
515  if action == "addLine":
516  self.OnLeftDownAddLine(event)
517 
518  elif action == "editLine" and \
519  hasattr(self, "moveInfo"):
520  self.OnLeftDownEditLine(event)
521 
522  elif action in ("moveLine", "moveVertex", "editLine") and \
523  not hasattr(self, "moveInfo"):
524  self.OnLeftDownMoveLine(event)
525 
526  elif action in ("displayAttrs"
527  "displayCats"):
528  self.OnLeftDownDisplayCA(event)
529 
530  elif action in ("copyCats",
531  "copyAttrs"):
532  self.OnLeftDownCopyCA(event)
533 
534  elif action == "copyLine":
535  self.OnLeftDownCopyLine(event)
536 
537  elif action == "zbulkLine":
538  self.OnLeftDownBulkLine(event)
539 
540  def OnLeftUpVarious(self, event):
541  """!Left mouse button released - vector digitizer various
542  actions
543  """
544  pos1 = self.Pixel2Cell(self.mouse['begin'])
545  pos2 = self.Pixel2Cell(self.mouse['end'])
546 
547  nselected = 0
548  action = self.toolbar.GetAction()
549  # -> delete line || move line || move vertex
550  if action in ("moveVertex",
551  "editLine"):
552  if len(self.digit.GetDisplay().GetSelected()) == 0:
553  nselected = self.digit.GetDisplay().SelectLineByPoint(pos1)['point']
554 
555  if action == "editLine":
556  try:
557  selVertex = self.digit.GetDisplay().GetSelectedVertex(pos1)[0]
558  except IndexError:
559  selVertex = None
560 
561  if selVertex:
562  # self.UpdateMap(render=False)
563  ids = self.digit.GetDisplay().GetSelected(grassId = False)
564  # move this line to tmp layer
565  self.polycoords = []
566  for id in ids:
567  if id % 2: # register only vertices
568  e, n = self.Pixel2Cell(self.pdcVector.GetIdBounds(id)[0:2])
569  self.polycoords.append((e, n))
570  self.digit.GetDisplay().DrawSelected(False)
571 
572  if selVertex < ids[-1] / 2:
573  # choose first or last node of line
574  self.moveInfo['id'].reverse()
575  self.polycoords.reverse()
576  else:
577  # unselect
578  self.digit.GetDisplay().SetSelected([])
579  del self.moveInfo
580 
581  self.UpdateMap(render = False)
582 
583  elif action in ("copyCats",
584  "copyAttrs"):
585  if not hasattr(self, "copyCatsIds"):
586  # 'from' -> select by point
587  nselected = self.digit.GetDisplay().SelectLineByPoint(pos1)['point']
588  if nselected:
589  self.copyCatsList = self.digit.GetDisplay().GetSelected()
590  else:
591  # -> 'to' -> select by bbox
592  self.digit.GetDisplay().SetSelected([])
593  # return number of selected features (by box/point)
594  nselected = self.digit.GetDisplay().SelectLinesByBox((pos1, pos2))
595  if nselected == 0:
596  if self.digit.GetDisplay().SelectLineByPoint(pos1) is not None:
597  nselected = 1
598 
599  if nselected > 0:
600  self.copyCatsIds = self.digit.GetDisplay().GetSelected()
601 
602  elif action == "queryLine":
603  selected = self.digit.SelectLinesByQuery(bbox = (pos1, pos2))
604  nselected = len(selected)
605  if nselected > 0:
606  self.digit.GetDisplay().SetSelected(selected)
607 
608  else:
609  # -> moveLine || deleteLine, etc. (select by point/box)
610  if action == 'moveLine' and \
611  len(self.digit.GetDisplay().GetSelected()) > 0:
612  nselected = 0
613  else:
614  if action == 'moveLine':
615  drawSeg = True
616  else:
617  drawSeg = False
618 
619  nselected = self.digit.GetDisplay().SelectLinesByBox(bbox = (pos1, pos2),
620  drawSeg = drawSeg)
621  if nselected == 0:
622  if self.digit.GetDisplay().SelectLineByPoint(pos1) is not None:
623  nselected = 1
624 
625  if nselected > 0:
626  if action in ("moveLine", "moveVertex") and \
627  hasattr(self, "moveInfo"):
628  # get pseudoDC id of objects which should be redrawn
629  if action == "moveLine":
630  # -> move line
631  self.moveInfo['id'] = self.digit.GetDisplay().GetSelected(grassId = False)
632  else: # moveVertex
633  self.moveInfo['id'] = self.digit.GetDisplay().GetSelectedVertex(pos1)
634  if len(self.moveInfo['id']) == 0: # no vertex found
635  self.digit.GetDisplay().SetSelected([])
636 
637  #
638  # check for duplicates
639  #
640  if UserSettings.Get(group = 'vdigit', key = 'checkForDupl', subkey = 'enabled'):
641  dupl = self.digit.GetDisplay().GetDuplicates()
642  self.UpdateMap(render = False)
643 
644  if dupl:
645  posWindow = self.ClientToScreen((self.mouse['end'][0] + self.dialogOffset,
646  self.mouse['end'][1] + self.dialogOffset))
647 
648  dlg = VDigitDuplicatesDialog(parent = self, data = dupl, pos = posWindow)
649 
650  if dlg.ShowModal() == wx.ID_OK:
651  self.digit.GetDisplay().UnSelect(dlg.GetUnSelected())
652  # update selected
653  self.UpdateMap(render = False)
654 
655  if action != "editLine":
656  # -> move line || move vertex
657  self.UpdateMap(render = False)
658 
659  else: # no vector object found
660  if not (action in ("moveLine",
661  "moveVertex") and \
662  hasattr(self, "moveInfo") and \
663  len(self.moveInfo['id']) > 0):
664  # avoid left-click when features are already selected
665  self.UpdateMap(render = False, renderVector = False)
666 
667  def OnLeftUpModifyLine(self, event):
668  """!Left mouse button released - vector digitizer split line,
669  add/remove vertex action
670  """
671  pos1 = self.Pixel2Cell(self.mouse['begin'])
672 
673  pointOnLine = self.digit.GetDisplay().SelectLineByPoint(pos1)['point']
674  if not pointOnLine:
675  return
676 
677  if self.toolbar.GetAction() in ["splitLine", "addVertex"]:
678  self.UpdateMap(render = False) # highlight object
679  self.DrawCross(pdc = self.pdcTmp, coords = self.Cell2Pixel((pointOnLine[0], pointOnLine[1])),
680  size = 5)
681  else: # removeVertex
682  # get only id of vertex
683  try:
684  id = self.digit.GetDisplay().GetSelectedVertex(pos1)[0]
685  except IndexError:
686  id = None
687 
688  if id:
689  x, y = self.pdcVector.GetIdBounds(id)[0:2]
690  self.pdcVector.RemoveId(id)
691  self.UpdateMap(render = False) # highlight object
692  self.DrawCross(pdc = self.pdcTmp, coords = (x, y),
693  size = 5)
694  else:
695  # unselect
696  self.digit.GetDisplay().SetSelected([])
697  self.UpdateMap(render = False)
698 
699  def OnLeftUpCopyLine(self, event):
700  """!Left mouse button released - vector digitizer copy feature
701  action
702  """
703  pos1 = self.Pixel2Cell(self.mouse['begin'])
704  pos2 = self.Pixel2Cell(self.mouse['end'])
705 
706  if UserSettings.Get(group = 'vdigit', key = 'bgmap',
707  subkey = 'value', internal = True) == '':
708  # no background map -> copy from current vector map layer
709  nselected = self.bdigit.GetDisplay().SelectLinesByBox((pos1, pos2))
710 
711  if nselected > 0:
712  # highlight selected features
713  self.UpdateMap(render = False)
714  else:
715  self.UpdateMap(render = False, renderVector = False)
716  else:
717  # copy features from background map
718  self.copyIds = self.digit.SelectLinesFromBackgroundMap(bbox = (pos1, pos2))
719  if len(self.copyIds) > 0:
720  color = UserSettings.Get(group = 'vdigit', key = 'symbol',
721  subkey = ['highlight', 'color'])
722  colorStr = str(color[0]) + ":" + str(color[1]) + ":" + str(color[2])
723  dVectTmp = ['d.vect',
724  'map=%s' % UserSettings.Get(group = 'vdigit', key = 'bgmap',
725  subkey = 'value', internal = True),
726  'cats=%s' % ListOfCatsToRange(self.copyIds),
727  '-i',
728  'color=%s' % colorStr,
729  'fcolor=%s' % colorStr,
730  'type=point,line,boundary,centroid',
731  'width=2']
732 
733  if not self.layerTmp:
734  self.layerTmp = self.Map.AddLayer(type = 'vector',
735  name = QUERYLAYER,
736  command = dVectTmp)
737  else:
738  self.layerTmp.SetCmd(dVectTmp)
739  else:
740  if self.layerTmp:
741  self.Map.DeleteLayer(self.layerTmp)
742  self.layerTmp = None
743 
744  self.UpdateMap(render = True, renderVector = True)
745 
746  def OnLeftUpBulkLine(self, event):
747  """!Left mouse button released - vector digitizer z-bulk line
748  action
749  """
750  # select lines to be labeled
751  pos1 = self.polycoords[0]
752  pos2 = self.polycoords[1]
753  nselected = self.digit.GetDisplay().SelectLinesByBox((pos1, pos2))
754 
755  if nselected > 0:
756  # highlight selected features
757  self.UpdateMap(render = False)
758  self.DrawLines(pdc = self.pdcTmp) # redraw temp line
759  else:
760  self.UpdateMap(render = False, renderVector = False)
761 
762  def OnLeftUpConnectLine(self, event):
763  """!Left mouse button released - vector digitizer connect line
764  action
765  """
766  if len(self.digit.GetDisplay().GetSelected()) > 0:
767  self.UpdateMap(render = False)
768 
769  def _onLeftUp(self, event):
770  """!Left mouse button released"""
771  if hasattr(self, "moveInfo"):
772  if len(self.digit.GetDisplay().GetSelected()) == 0:
773  self.moveInfo['begin'] = self.Pixel2Cell(self.mouse['begin']) # left down
774 
775  # eliminate initial mouse moving efect
776  self.mouse['begin'] = self.mouse['end']
777 
778  action = self.toolbar.GetAction()
779  if action in ("deleteLine",
780  "moveLine",
781  "moveVertex",
782  "copyCats",
783  "copyAttrs",
784  "editLine",
785  "flipLine",
786  "mergeLine",
787  "snapLine",
788  "queryLine",
789  "breakLine",
790  "typeConv",
791  "connectLine"):
792  self.OnLeftUpVarious(event)
793 
794  elif action in ("splitLine",
795  "addVertex",
796  "removeVertex"):
797  self.OnLeftUpModifyLine(event)
798 
799  elif action == "copyLine":
800  self.OnLeftUpCopyLine(event)
801 
802  elif action == "zbulkLine" and \
803  len(self.polycoords) == 2:
804  self.OnLeftUpBulkLine(event)
805 
806  elif action == "connectLine":
807  self.OnLeftUpConnectLine(event)
808 
809  if len(self.digit.GetDisplay().GetSelected()) > 0:
810  self.redrawAll = None
811 
812  def _onRightDown(self, event):
813  # digitization tool (confirm action)
814  action = self.toolbar.GetAction()
815  if action in ("moveLine", "moveVertex") and \
816  hasattr(self, "moveInfo"):
817  pFrom = self.moveInfo['begin']
818  pTo = self.Pixel2Cell(event.GetPositionTuple())
819 
820  move = (pTo[0] - pFrom[0],
821  pTo[1] - pFrom[1])
822 
823  if action == "moveLine":
824  # move line
825  if self.digit.MoveSelectedLines(move) < 0:
826  return
827  elif action == "moveVertex":
828  # move vertex
829  fid = self.digit.MoveSelectedVertex(pFrom, move)
830  if fid < 0:
831  return
832 
833  self._geomAttrbUpdate([fid,])
834 
835  del self.moveInfo
836 
837  def _onRightUp(self, event):
838  """!Right mouse button released (confirm action)
839  """
840  action = self.toolbar.GetAction()
841  if action == "addLine" and \
842  self.toolbar.GetAction('type') in ["line", "boundary", "area"]:
843  # -> add new line / boundary
844  try:
845  mapName = self.toolbar.GetLayer().GetName()
846  except:
847  mapName = None
848  gcmd.GError(parent = self,
849  message = _("No vector map selected for editing."))
850 
851  if mapName:
852  if self.toolbar.GetAction('type') == 'line':
853  line = True
854  else:
855  line = False
856 
857  if len(self.polycoords) < 2: # ignore 'one-point' lines
858  return
859 
860  nfeat, fids = self.digit.AddFeature(self.toolbar.GetAction('type'), self.polycoords)
861  if nfeat < 0:
862  return
863 
864  position = self.Cell2Pixel(self.polycoords[-1])
865  self.polycoords = []
866  self.UpdateMap(render = False)
867  self.redrawAll = True
868  self.Refresh()
869 
870  # add new record into atribute table
871  if UserSettings.Get(group = 'vdigit', key = "addRecord", subkey = 'enabled') and \
872  (line is True or \
873  (not line and nfeat > 0)):
874  posWindow = self.ClientToScreen((position[0] + self.dialogOffset,
875  position[1] + self.dialogOffset))
876 
877  # select attributes based on layer and category
878  cats = { fids[0] : {
879  UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value') :
880  (UserSettings.Get(group = 'vdigit', key = "category", subkey = 'value'), )
881  }}
882 
883  addRecordDlg = dbm_dialogs.DisplayAttributesDialog(parent = self, map = mapName,
884  cats = cats,
885  pos = posWindow,
886  action = "add")
887 
888  for fid in fids:
889  self._geomAttrb(fid, addRecordDlg, 'length')
890  # auto-placing centroid
891  self._geomAttrb(fid, addRecordDlg, 'area')
892  self._geomAttrb(fid, addRecordDlg, 'perimeter')
893 
894 
895  if addRecordDlg.mapDBInfo and \
896  addRecordDlg.ShowModal() == wx.ID_OK:
897  sqlfile = tempfile.NamedTemporaryFile(mode = "w")
898  for sql in addRecordDlg.GetSQLString():
899  sqlfile.file.write(sql + ";\n")
900  sqlfile.file.flush()
901  gcmd.RunCommand('db.execute',
902  parent = True,
903  quiet = True,
904  input = sqlfile.name)
905 
906  if addRecordDlg.mapDBInfo:
907  self._updateATM()
908 
909  elif action == "deleteLine":
910  # -> delete selected vector features
911  if self.digit.DeleteSelectedLines() < 0:
912  return
913  self._updateATM()
914  elif action == "splitLine":
915  # split line
916  if self.digit.SplitLine(self.Pixel2Cell(self.mouse['begin'])) < 0:
917  return
918  elif action == "addVertex":
919  # add vertex
920  fid = self.digit.AddVertex(self.Pixel2Cell(self.mouse['begin']))
921  if fid < 0:
922  return
923  elif action == "removeVertex":
924  # remove vertex
925  fid = self.digit.RemoveVertex(self.Pixel2Cell(self.mouse['begin']))
926  if fid < 0:
927  return
928  self._geomAttrbUpdate([fid,])
929  elif action in ("copyCats", "copyAttrs"):
930  if action == 'copyCats':
931  if self.digit.CopyCats(self.copyCatsList,
932  self.copyCatsIds, copyAttrb = False) < 0:
933  return
934  else:
935  if self.digit.CopyCats(self.copyCatsList,
936  self.copyCatsIds, copyAttrb = True) < 0:
937  return
938 
939  del self.copyCatsList
940  del self.copyCatsIds
941 
942  self._updateATM()
943 
944  elif action == "editLine" and \
945  hasattr(self, "moveInfo"):
946  line = self.digit.GetDisplay().GetSelected()[0]
947  if self.digit.EditLine(line, self.polycoords) < 0:
948  return
949 
950  del self.moveInfo
951 
952  elif action == "flipLine":
953  if self.digit.FlipLine() < 0:
954  return
955  elif action == "mergeLine":
956  if self.digit.MergeLine() < 0:
957  return
958  elif action == "breakLine":
959  if self.digit.BreakLine() < 0:
960  return
961  elif action == "snapLine":
962  if self.digit.SnapLine() < 0:
963  return
964  elif action == "connectLine":
965  if len(self.digit.GetDisplay().GetSelected()) > 1:
966  if self.digit.ConnectLine() < 0:
967  return
968  elif action == "copyLine":
969  if self.digit.CopyLine(self.copyIds) < 0:
970  return
971  del self.copyIds
972  if self.layerTmp:
973  self.Map.DeleteLayer(self.layerTmp)
974  self.UpdateMap(render = True, renderVector = False)
975  del self.layerTmp
976 
977  elif action == "zbulkLine" and len(self.polycoords) == 2:
978  pos1 = self.polycoords[0]
979  pos2 = self.polycoords[1]
980 
981  selected = self.digit.GetDisplay().GetSelected()
982  dlg = VDigitZBulkDialog(parent = self, title = _("Z bulk-labeling dialog"),
983  nselected = len(selected))
984  if dlg.ShowModal() == wx.ID_OK:
985  if self.digit.ZBulkLines(pos1, pos2, dlg.value.GetValue(),
986  dlg.step.GetValue()) < 0:
987  return
988  self.UpdateMap(render = False)
989  elif action == "typeConv":
990  # -> feature type conversion
991  # - point <-> centroid
992  # - line <-> boundary
993  if self.digit.TypeConvForSelectedLines() < 0:
994  return
995 
996  if action != "addLine":
997  # unselect and re-render
998  self.digit.GetDisplay().SetSelected([])
999  self.polycoords = []
1000  self.UpdateMap(render = False)
1001 
1002  def _onMouseMoving(self, event):
1003  self.mouse['end'] = event.GetPositionTuple()[:]
1004 
1005  Debug.msg (5, "BufferedWindow.OnMouseMoving(): coords=%f,%f" % \
1006  (self.mouse['end'][0], self.mouse['end'][1]))
1007 
1008  action = self.toolbar.GetAction()
1009  if action == "addLine" and \
1010  self.toolbar.GetAction('type') in ["line", "boundary", "area"]:
1011  if len(self.polycoords) > 0:
1012  self.MouseDraw(pdc = self.pdcTmp, begin = self.Cell2Pixel(self.polycoords[-1]))
1013 
1014  elif action in ["moveLine", "moveVertex", "editLine"] \
1015  and hasattr(self, "moveInfo"):
1016  dx = self.mouse['end'][0] - self.mouse['begin'][0]
1017  dy = self.mouse['end'][1] - self.mouse['begin'][1]
1018 
1019  # draw lines on new position
1020  if action == "moveLine" and \
1021  len(self.moveInfo['id']) > 0:
1022  # move line
1023  for id in self.moveInfo['id']:
1024  self.pdcTmp.TranslateId(id, dx, dy)
1025  elif action in ["moveVertex", "editLine"]:
1026  # move vertex ->
1027  # (vertex, left vertex, left line,
1028  # right vertex, right line)
1029 
1030  # do not draw static lines
1031  if action == "moveVertex" and \
1032  len(self.moveInfo['id']) > 0:
1033  self.polycoords = []
1034  self.pdcTmp.RemoveId(self.moveInfo['id'][0])
1035  if self.moveInfo['id'][1] > 0: # previous vertex
1036  x, y = self.Pixel2Cell(self.pdcTmp.GetIdBounds(self.moveInfo['id'][1])[0:2])
1037  self.pdcTmp.RemoveId(self.moveInfo['id'][1] + 1)
1038  self.polycoords.append((x, y))
1039  self.polycoords.append(self.Pixel2Cell(self.mouse['end']))
1040 
1041  if self.moveInfo['id'][2] > 0: # next vertex
1042  x, y = self.Pixel2Cell(self.pdcTmp.GetIdBounds(self.moveInfo['id'][2])[0:2])
1043  self.pdcTmp.RemoveId(self.moveInfo['id'][2]-1)
1044  self.polycoords.append((x, y))
1045 
1046  self.ClearLines(pdc = self.pdcTmp)
1047  self.DrawLines(pdc = self.pdcTmp)
1048 
1049  if action == "editLine":
1050  self.MouseDraw(pdc = self.pdcTmp,
1051  begin = self.Cell2Pixel(self.polycoords[-1]))
1052 
1053  self.Refresh() # TODO: use RefreshRect()
1054  self.mouse['begin'] = self.mouse['end']
1055 
1056  elif action == "zbulkLine":
1057  if len(self.polycoords) == 1:
1058  # draw mouse moving
1059  self.MouseDraw(self.pdcTmp)
1060 
1061  def _zoom(self, event):
1062  tmp1 = self.mouse['end']
1063  tmp2 = self.Cell2Pixel(self.moveInfo['begin'])
1064  dx = tmp1[0] - tmp2[0]
1065  dy = tmp1[1] - tmp2[1]
1066  self.moveInfo['beginDiff'] = (dx, dy)
1067  for id in self.moveInfo['id']:
1068  self.pdcTmp.RemoveId(id)
1069