GRASS Programmer's Manual  6.5.svn(2014)-r66266
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
wxdigit.py
Go to the documentation of this file.
1 """!
2 @package vdigit.wxdigit
3 
4 @brief wxGUI vector digitizer (base class)
5 
6 Code based on wxVdigit C++ component from GRASS 6.4.0
7 (gui/wxpython/vdigit). Converted to Python in 2010/12-2011/01.
8 
9 List of classes:
10  - wxdigit::VDigitError
11  - wxdigit::IVDigit
12 
13 @todo Read large amounts of data from Vlib into arrays, which could
14 then be processed using NumPy and rendered using glDrawArrays or
15 glDrawElements, so no per-line/per-vertex processing in Python. Bulk
16 data processing with NumPy is much faster than iterating in Python
17 (and NumPy would be an excellent candidate for acceleration via
18 e.g. OpenCL or CUDA; I'm surprised it hasn't happened already).
19 
20 (C) 2007-2011 by the GRASS Development Team
21 
22 This program is free software under the GNU General Public License
23 (>=v2). Read the file COPYING that comes with GRASS for details.
24 
25 @author Martin Landa <landa.martin gmail.com>
26 """
27 
28 import grass.script.core as grass
29 
30 from core.gcmd import GError
31 from core.debug import Debug
32 from core.settings import UserSettings
33 from vdigit.wxdisplay import DisplayDriver
34 
35 try:
36  from grass.lib.gis import *
37  from grass.lib.vector import *
38  from grass.lib.vedit import *
39  from grass.lib.dbmi import *
40 except ImportError:
41  pass
42 
44  def __init__(self, parent):
45  """!Class for managing error messages of vector digitizer
46 
47  @param parent parent window for dialogs
48  """
49  self.parent = parent
50  self.caption = _('Digitization Error')
51 
52  def NoMap(self, name = None):
53  """!No map for editing"""
54  if name:
55  message = _('Unable to open vector map <%s>.') % name
56  else:
57  message = _('No vector map open for editing.')
58  GError(message + ' ' + _('Operation canceled.'),
59  parent = self.parent,
60  caption = self.caption)
61 
62  def WriteLine(self):
63  """!Writing line failed
64  """
65  GError(message = _('Writing new feature failed. '
66  'Operation cancelled.'),
67  parent = self.parent,
68  caption = self.caption)
69 
70  def ReadLine(self, line):
71  """!Reading line failed
72  """
73  GError(message = _('Reading feature id %d failed. '
74  'Operation canceled.') % line,
75  parent = self.parent,
76  caption = self.caption)
77 
78  def DbLink(self, dblink):
79  """!No dblink available
80  """
81  GError(message = _('Database link %d not available. '
82  'Operation canceled.') % dblink,
83  parent = self.parent,
84  caption = self.caption)
85 
86  def Driver(self, driver):
87  """!Staring driver failed
88  """
89  GError(message = _('Unable to start database driver <%s>. '
90  'Operation canceled.') % driver,
91  parent = self.parent,
92  caption = self.caption)
93 
94  def Database(self, driver, database):
95  """!Opening database failed
96  """
97  GError(message = _('Unable to open database <%(db)s> by driver <%(driver)s>. '
98  'Operation canceled.') % { 'db' : database, 'driver' : driver},
99  parent = self.parent,
100  caption = self.caption)
101 
102  def DbExecute(self, sql):
103  """!Sql query failed
104  """
105  GError(message = _("Unable to execute SQL query '%s'. "
106  "Operation canceled.") % sql,
107  parent = self.parent,
108  caption = self.caption)
109 
110  def DeadLine(self, line):
111  """!Dead line
112  """
113  GError(message = _("Feature id %d is marked as dead. "
114  "Operation canceled.") % line,
115  parent = self.parent,
116  caption = self.caption)
117 
118  def FeatureType(self, ftype):
119  """!Unknown feature type
120  """
121  GError(message = _("Unsupported feature type %d. "
122  "Operation canceled.") % ftype,
123  parent = self.parent,
124  caption = self.caption)
125 
126 class IVDigit:
127  def __init__(self, mapwindow):
128  """!Base class for vector digitizer (ctypes interface)
129 
130  @parem mapwindow reference for map window (BufferedWindow)
131  """
132  self.poMapInfo = None # pointer to Map_info
133  self.mapWindow = mapwindow
134 
135  # background map
136  self.bgMapInfo = Map_info()
137  self.poBgMapInfo = self.popoBgMapInfo = None
138 
139  if not mapwindow.parent.IsStandalone():
140  goutput = mapwindow.parent.GetLayerManager().GetLogWindow()
141  log = goutput.GetLog(err = True)
142  progress = goutput.GetProgressBar()
143  else:
144  log = sys.stderr
145  progress = None
146 
147  self.toolbar = mapwindow.parent.toolbars['vdigit']
148 
149  self._error = VDigitError(parent = self.mapWindow)
150 
151  self._display = DisplayDriver(device = mapwindow.pdcVector,
152  deviceTmp = mapwindow.pdcTmp,
153  mapObj = mapwindow.Map,
154  window = mapwindow,
155  glog = log,
156  gprogress = progress)
157 
158  # GRASS lib
161 
162  # self.SetCategory()
163 
164  # layer / max category
165  self.cats = dict()
166 
167  self._settings = dict()
168  self.UpdateSettings() # -> self._settings
169 
170  # undo/redo
171  self.changesets = dict()
172  self.changesetCurrent = -1 # first changeset to apply
173  self.changesetEnd = -1 # last changeset to be applied
174 
175  if self.poMapInfo:
176  self.InitCats()
177 
178  def __del__(self):
179  Debug.msg(1, "IVDigit.__del__()")
181  self.poPoints = None
183  self.poCats = None
184 
185  if self.poBgMapInfo:
186  Vect_close(self.poBgMapInfo)
187  self.poBgMapInfo = self.popoBgMapInfo = None
188  del self.bgMapInfo
189 
191  """!Close background vector map"""
192  if not self.poBgMapInfo:
193  return
194 
195  Vect_close(self.poBgMapInfo)
196  self.poBgMapInfo = self.popoBgMapInfo = None
197 
198  def OpenBackgroundMap(self, bgmap):
199  """!Open background vector map
200 
201  @todo support more background maps then only one
202 
203  @param bgmap name of vector map to be opened
204 
205  @return pointer to map_info
206  @return None on error
207  """
208  name = create_string_buffer(GNAME_MAX)
209  mapset = create_string_buffer(GMAPSET_MAX)
210  if not G__name_is_fully_qualified(bgmap, name, mapset):
211  name = str(bgmap)
212  mapset = str(G_find_vector2(bgmap, ''))
213  else:
214  name = str(name.value)
215  mapset = str(mapset.value)
216 
217  if (name == Vect_get_name(self.poMapInfo) and \
218  mapset == Vect_get_mapset(self.poMapInfo)):
219  self.poBgMapInfo = self.popoBgMapInfo = None
220  self._error.NoMap(bgmap)
221  return
222 
223  self.poBgMapInfo = pointer(self.bgMapInfo)
224  self.popoBgMapInfo = pointer(self.poBgMapInfo)
225  if Vect_open_old(self.poBgMapInfo, name, mapset) == -1:
226  self.poBgMapInfo = self.popoBgMapInfo = None
227  self._error.NoMap(bgmap)
228  return
229 
230  def _getSnapMode(self):
231  """!Get snapping mode
232 
233  - snap to vertex
234  - snap to nodes
235  - no snapping
236 
237  @return snap mode
238  """
239  threshold = self._display.GetThreshold()
240  if threshold > 0.0:
241  if UserSettings.Get(group = 'vdigit', key = 'snapToVertex', subkey = 'enabled'):
242  return SNAPVERTEX
243  else:
244  return SNAP
245  else:
246  return NO_SNAP
247 
248  def _breakLineAtIntersection(self, line, pointsLine, changeset):
249  """!Break given line at intersection
250 
251  \param line line id
252  \param pointsLine line geometry
253  \param changeset id
254 
255  \return number of modified lines
256  """
257  if not self._checkMap():
258  return -1
259 
260  if not Vect_line_alive(self.poMapInfo, line):
261  return 0
262 
263  if not pointsLine:
264  if Vect_read_line(self.poMapInfo, self.poPoints, None, line) < 0:
265  self._error.ReadLine(line)
266  return -1
267  points = self.poPoints
268  else:
269  points = pointsLine
270 
271  listLine = Vect_new_list()
272  listRef = Vect_new_list()
273  listBreak = Vect_new_list()
274 
275  pointsCheck = Vect_new_line_struct()
276 
277  lineBox = bound_box()
278  # find all relevant lines
279  Vect_get_line_box(self.poMapInfo, line, byref(lineBox))
280  Vect_select_lines_by_box(self.poMapInfo, byref(lineBox),
281  GV_LINES, listLine)
282 
283  # check for intersection
284  Vect_list_append(listBreak, line)
285  Vect_list_append(listRef, line)
286  for i in range(listLine.contents.n_values):
287  lineBreak = listLine.contents.value[i]
288  if lineBreak == line:
289  continue
290 
291  ltype = Vect_read_line(self.poMapInfo, pointsCheck, None, lineBreak)
292  if not (ltype & GV_LINES):
293  continue
294 
295  if Vect_line_check_intersection(self.poPoints, pointsCheck,
296  WITHOUT_Z):
297  Vect_list_append(listBreak, lineBreak)
298 
299  nlines = Vect_get_num_lines(self.poMapInfo)
300 
301  for i in range(listBreak.contents.n_values):
302  self._addActionToChangeset(changeset, listBreak.contents.value[i], add = False)
303 
304  ret = Vect_break_lines_list(self.poMapInfo, listBreak, listRef,
305  GV_LINES, None)
306 
307  for i in range(listBreak.contents.n_values):
308  if Vect_line_alive(self.poMapInfo, listBreak.contents.value[i]):
309  self._removeActionFromChangeset(changeset, listBreak.contents.value[i],
310  add = False)
311 
312  for line in range(nlines + 1, Vect_get_num_lines(self.poMapInfo) + 1):
313  self._addActionToChangeset(changeset, line, add = True)
314 
315  Vect_destroy_line_struct(pointsCheck)
316 
317  Vect_destroy_list(listLine)
318  Vect_destroy_list(listBreak)
319  Vect_destroy_list(listRef)
320 
321  return ret
322 
323  def _addActionsBefore(self):
324  """!Register action before operation
325 
326  @return changeset id
327  """
328  changeset = len(self.changesets)
329  for line in self._display.selected['ids']:
330  if Vect_line_alive(self.poMapInfo, line):
331  self._addActionToChangeset(changeset, line, add = False)
332 
333  return changeset
334 
335  def _applyChangeset(self, changeset, undo):
336  """!Apply changeset (undo/redo changeset)
337 
338  @param changeset changeset id
339  @param undo True for undo otherwise redo
340 
341  @return 1 changeset applied
342  @return 0 changeset not applied
343  @return -1 on error
344  """
345  if changeset < 0 or changeset > len(self.changesets.keys()):
346  return -1
347 
348  if self.changesetEnd < 0:
349  self.changesetEnd = changeset
350 
351  ret = 0
352  actions = self.changesets[changeset]
353  for action in actions:
354  add = action['add']
355  line = action['line']
356  if (undo and add) or \
357  (not undo and not add):
358  if Vect_line_alive(self.poMapInfo, line):
359  Debug.msg(3, "IVDigit._applyChangeset(): changeset=%d, action=add, line=%d -> deleted",
360  changeset, line)
361  Vect_delete_line(self.poMapInfo, line)
362  ret = 1
363  else:
364  Debug.msg(3, "Digit.ApplyChangeset(): changeset=%d, action=add, line=%d dead",
365  changeset, line)
366  else: # delete
367  offset = action['offset']
368  if not Vect_line_alive(self.poMapInfo, line):
369  Debug.msg(3, "Digit.ApplyChangeset(): changeset=%d, action=delete, line=%d -> added",
370  changeset, line)
371  if Vect_restore_line(self.poMapInfo, line, offset) < 0:
372  return -1
373  ret = 1
374  else:
375  Debug.msg(3, "Digit.ApplyChangeset(): changeset=%d, action=delete, line=%d alive",
376  changeset, line)
377 
378  return ret
379 
380  def _addActionsAfter(self, changeset, nlines):
381  """!Register action after operation
382 
383  @param changeset changeset id
384  @param nline number of lines
385  """
386  for line in self._display.selected['ids']:
387  if Vect_line_alive(self.poMapInfo, line):
388  self._removeActionFromChangeset(changeset, line, add = False)
389 
390  for line in range(nlines + 1, Vect_get_num_lines(self.poMapInfo)):
391  if Vect_line_alive(self.poMapInfo, line):
392  self._addActionToChangeset(changeset, line, add = True)
393 
394  def _addActionToChangeset(self, changeset, line, add):
395  """!Add action to changeset
396 
397  @param changeset id of changeset
398  @param line feature id
399  @param add True to add, otherwise delete
400  """
401  if not self._checkMap():
402  return
403 
404  if not Vect_line_alive(self.poMapInfo, line):
405  return
406 
407  offset = Vect_get_line_offset(self.poMapInfo, line)
408 
409  if changeset not in self.changesets:
410  self.changesets[changeset] = list()
411  self.changesetCurrent = changeset
412 
413  self.changesets[changeset].append({ 'add' : add,
414  'line' : line,
415  'offset' : offset })
416 
417  Debug.msg(3, "IVDigit._addActionToChangeset(): changeset=%d, add=%d, line=%d, offset=%d",
418  changeset, add, line, offset)
419 
420  def _removeActionFromChangeset(self, changeset, line, add):
421  """!Remove action from changeset
422 
423  @param changeset changeset id
424  @param line line id
425  @param add True for add, False for delete
426 
427  @return number of actions in changeset
428  @return -1 on error
429  """
430  if changeset not in self.changesets.keys():
431  return -1
432 
433  alist = self.changesets[changeset]
434  for action in alist:
435  if action['add'] == add and action['line'] == line:
436  alist.remove(action)
437 
438  return len(alist)
439 
440  def AddFeature(self, ftype, points):
441  """!Add new feature
442 
443  @param ftype feature type (point, line, centroid, boundary)
444  @param points tuple of points ((x, y), (x, y), ...)
445 
446  @return tuple (number of added features, feature ids)
447  """
448  if UserSettings.Get(group = 'vdigit', key = "categoryMode", subkey = 'selection') == 2:
449  layer = -1 # -> no category
450  cat = -1
451  else:
452  layer = UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value')
453  cat = self.SetCategory()
454 
455  if ftype == 'point':
456  vtype = GV_POINT
457  elif ftype == 'line':
458  vtype = GV_LINE
459  elif ftype == 'centroid':
460  vtype = GV_CENTROID
461  elif ftype == 'boundary':
462  vtype = GV_BOUNDARY
463  elif ftype == 'area':
464  vtype = GV_AREA
465  else:
466  GError(parent = self.mapWindow,
467  message = _("Unknown feature type '%s'") % ftype)
468  return (-1, None)
469 
470  if vtype & GV_LINES and len(points) < 2:
471  GError(parent = self.mapWindow,
472  message = _("Not enough points for line"))
473  return (-1, None)
474 
475  self.toolbar.EnableUndo()
476 
477  return self._addFeature(vtype, points, layer, cat,
478  self._getSnapMode(), self._display.GetThreshold())
479 
481  """!Delete selected features
482 
483  @return number of deleted features
484  """
485  deleteRec = UserSettings.Get(group = 'vdigit', key = 'delRecord', subkey = 'enabled')
486  if not self._checkMap():
487  return -1
488 
489  n_dblinks = Vect_get_num_dblinks(self.poMapInfo)
490  Cats_del = None
491 
492  # collect categories for delete if requested
493  if deleteRec:
494  poCatsDel = Vect_new_cats_struct()
495  for i in self._display.selected['ids']:
496  if Vect_read_line(self.poMapInfo, None, self.poCats, i) < 0:
497  Vect_destroy_cats_struct(poCatsDel)
498  self._error.ReadLine(i)
499  return -1
500 
501  cats = self.poCats.contents
502  for j in range(cats.n_cats):
503  Vect_cat_set(poCatsDel, cats.field[j], cats.cat[j])
504 
505  # register changeset
506  changeset = self._addActionsBefore()
507  poList = self._display.GetSelectedIList()
508  nlines = Vedit_delete_lines(self.poMapInfo, poList)
509 
510  Vect_destroy_list(poList)
511  self._display.selected['ids'] = list()
512 
513  if nlines > 0 and deleteRec:
514  handle = dbHandle()
515  poHandle = pointer(handle)
516  stmt = dbString()
517  poStmt = pointer(stmt)
518 
519  for dblink in range(n_dblinks):
520  poFi = Vect_get_dblink(self.poMapInfo, dblink)
521  if poFi is None:
522  self._error.DbLink(dblink)
523  return -1
524 
525  Fi = poFi.contents
526  poDriver = db_start_driver(Fi.driver)
527  if poDriver is None:
528  self._error.Driver(Fi.driver)
529  return -1
530 
531  db_init_handle(poHandle)
532  db_set_handle(poHandle, Fi.database, None)
533  if db_open_database(poDriver, poHandle) != DB_OK:
534  self._error.Database(Fi.driver, Fi.database)
535  return -1
536 
537  db_init_string(poStmt)
538  db_set_string(poStmt, "DELETE FROM %s WHERE" % Fi.table)
539  n_cats = 0;
540  catsDel = poCatsDel.contents
541  for c in range(catsDel.n_cats):
542  if catsDel.field[c] == Fi.number:
543  if n_cats > 0:
544  db_append_string(poStmt, " or")
545 
546  db_append_string(poStmt, " %s = %d" % (Fi.key, catsDel.cat[c]))
547  n_cats += 1
548 
549  Vect_cat_del(poCatsDel, Fi.number)
550 
551  if n_cats and \
552  db_execute_immediate(poDriver, poStmt) != DB_OK:
553  self._error.DbExecute(db_get_string(poStmt))
554  return -1
555 
556  db_close_database(poDriver)
557  db_shutdown_driver(poDriver)
558 
559  if poCatsDel:
560  Vect_destroy_cats_struct(poCatsDel)
561 
562  if nlines > 0:
563  self.toolbar.EnableUndo()
564 
565  return nlines
566 
567  def MoveSelectedLines(self, move):
568  """!Move selected features
569 
570  @param move direction (x, y)
571  """
572  if not self._checkMap():
573  return -1
574 
575  thresh = self._display.GetThreshold()
576  snap = self._getSnapMode()
577 
578  nlines = Vect_get_num_lines(self.poMapInfo)
579 
580  # register changeset
581  changeset = self._addActionsBefore()
582 
583  poList = self._display.GetSelectedIList()
584  nlines = Vedit_move_lines(self.poMapInfo, self.popoBgMapInfo, int(self.poBgMapInfo is not None),
585  poList,
586  move[0], move[1], 0,
587  snap, thresh)
588  Vect_destroy_list(poList)
589 
590  if nlines > 0:
591  self._addActionsAfter(changeset, nlines)
592  else:
593  del self.changesets[changeset]
594 
595  if nlines > 0 and self._settings['breakLines']:
596  for i in range(1, nlines):
597  self._breakLineAtIntersection(nlines + i, None, changeset)
598 
599  if nlines > 0:
600  self.toolbar.EnableUndo()
601 
602  return nlines
603 
604  def MoveSelectedVertex(self, point, move):
605  """!Move selected vertex of the line
606 
607  @param point location point
608  @param move x,y direction
609 
610  @return id of new feature
611  @return 0 vertex not moved (not found, line is not selected)
612  @return -1 on error
613  """
614  if not self._checkMap():
615  return -1
616 
617  if len(self._display.selected['ids']) != 1:
618  return -1
619 
621  Vect_append_point(self.poPoints, point[0], point[1], 0.0)
622 
623  nlines = Vect_get_num_lines(self.poMapInfo)
624 
625  changeset = self._addActionsBefore()
626 
627  # move only first found vertex in bbox
628  poList = self._display.GetSelectedIList()
629  moved = Vedit_move_vertex(self.poMapInfo, self.popoBgMapInfo, int(self.poBgMapInfo is not None),
630  poList, self.poPoints,
631  self._display.GetThreshold(type = 'selectThresh'),
632  self._display.GetThreshold(),
633  move[0], move[1], 0.0,
634  1, self._getSnapMode())
635  Vect_destroy_list(poList)
636 
637  if moved > 0:
638  self._addActionsAfter(changeset, nlines)
639  else:
640  del self.changesets[changeset]
641 
642  if moved > 0 and self._settings['breakLines']:
644  None, changeset)
645 
646  if moved > 0:
647  self.toolbar.EnableUndo()
648 
649  return moved
650 
651  def AddVertex(self, coords):
652  """!Add new vertex to the selected line/boundary on position 'coords'
653 
654  @param coords coordinates to add vertex
655 
656  @return id of new feature
657  @return 0 nothing changed
658  @return -1 on failure
659  """
660  added = self._ModifyLineVertex(coords, add = True)
661 
662  if added > 0:
663  self.toolbar.EnableUndo()
664 
665  return added
666 
667  def RemoveVertex(self, coords):
668  """!Remove vertex from the selected line/boundary on position 'coords'
669 
670  @param coords coordinates to remove vertex
671 
672  @return id of new feature
673  @return 0 nothing changed
674  @return -1 on failure
675  """
676  deleted = self._ModifyLineVertex(coords, add = False)
677 
678  if deleted > 0:
679  self.toolbar.EnableUndo()
680 
681  return deleted
682 
683 
684  def SplitLine(self, point):
685  """!Split/break selected line/boundary on given position
686 
687  @param point point where to split line
688 
689  @return 1 line modified
690  @return 0 nothing changed
691  @return -1 error
692  """
693  thresh = self._display.GetThreshold('selectThresh')
694  if not self._checkMap():
695  return -1
696 
697  poList = self._display.GetSelectedIList()
699  Vect_append_point(self.poPoints, point[0], point[1], 0.0)
700 
701  nlines = Vect_get_num_lines(self.poMapInfo)
702 
703  changeset = self._addActionsBefore()
704 
705  ret = Vedit_split_lines(self.poMapInfo, poList,
706  self.poPoints, thresh, None)
707  Vect_destroy_list(poList)
708 
709  if ret > 0:
710  self._addActionsAfter(changeset, nlines)
711  self.toolbar.EnableUndo()
712  else:
713  del self.changesets[changeset]
714 
715  return ret
716 
717  def EditLine(self, line, coords):
718  """!Edit existing line/boundary
719 
720  @param line feature id to be modified
721  @param coords list of coordinates of modified line
722 
723  @return feature id of new line
724  @return -1 on error
725  """
726  if not self._checkMap():
727  return -1
728 
729  if len(coords) < 2:
730  self.DeleteSelectedLines()
731  return 0
732 
733  if not Vect_line_alive(self.poMapInfo, line):
734  self._error.DeadLine(line)
735  return -1
736 
737  # read original feature
738  ltype = Vect_read_line(self.poMapInfo, None, self.poCats, line)
739  if ltype < 0:
740  self._error.ReadLine(line)
741  return -1
742 
743  # build feature geometry
745  for p in coords:
746  Vect_append_point(self.poPoints, p[0], p[1], 0.0)
747 
748  # apply snapping (node or vertex)
749  snap = self._getSnapMode()
750  if snap != NO_SNAP:
751  modeSnap = not (snap == SNAP)
753  int(self.poBgMapInfo is not None),
754  -1, self.poPoints, self._display.GetThreshold(), modeSnap)
755 
756  nlines = Vect_get_num_lines(self.poMapInfo)
757 
758  changeset = self._addActionsBefore()
759  newline = Vect_rewrite_line(self.poMapInfo, line, ltype,
760  self.poPoints, self.poCats)
761  if newline > 0:
762  self._addActionsAfter(changeset, nlines)
763  self.toolbar.EnableUndo()
764  else:
765  del self.changesets[changeset]
766 
767  if newline > 0 and self._settings['breakLines']:
768  self._breakLineAtIntersection(newline, None, changeset)
769 
770  return newline
771 
772  def FlipLine(self):
773  """!Flip selected lines/boundaries
774 
775  @return number of modified lines
776  @return -1 on error
777  """
778  if not self._checkMap():
779  return -1
780 
781  nlines = Vect_get_num_lines(self.poMapInfo)
782 
783  # register changeset
784  changeset = self._addActionsBefore()
785 
786  poList = self._display.GetSelectedIList()
787  ret = Vedit_flip_lines(self.poMapInfo, poList)
788  Vect_destroy_list(poList)
789 
790  if ret > 0:
791  self._addActionsAfter(changeset, nlines)
792  self.toolbar.EnableUndo()
793  else:
794  del self.changesets[changeset]
795 
796  return ret
797 
798  def MergeLine(self):
799  """!Merge selected lines/boundaries
800 
801  @return number of modified lines
802  @return -1 on error
803  """
804  if not self._checkMap():
805  return -1
806 
807  nlines = Vect_get_num_lines(self.poMapInfo)
808 
809  changeset = self._addActionsBefore()
810 
811  poList = self._display.GetSelectedIList()
812  ret = Vedit_merge_lines(self.poMapInfo, poList)
813  Vect_destroy_list(poList)
814 
815  if ret > 0:
816  self._addActionsAfter(changeset, nlines)
817  self.toolbar.EnableUndo()
818  else:
819  del self.changesets[changeset]
820 
821  return ret
822 
823  def BreakLine(self):
824  """!Break selected lines/boundaries
825 
826  @return number of modified lines
827  @return -1 on error
828  """
829  if not self._checkMap():
830  return -1
831 
832  nlines = Vect_get_num_lines(self.poMapInfo)
833 
834  changeset = self._addActionsBefore()
835 
836  poList = self._display.GetSelectedIList()
837  ret = Vect_break_lines_list(self.poMapInfo, poList, None,
838  GV_LINES, None)
839  Vect_destroy_list(poList)
840 
841  if ret > 0:
842  self._addActionsAfter(changeset, nlines)
843  self.toolbar.EnableUndo()
844  else:
845  del self.changesets[changeset]
846 
847  return ret
848 
849  def SnapLine(self):
850  """!Snap selected lines/boundaries
851 
852  @return on success
853  @return -1 on error
854  """
855  if not self._checkMap():
856  return -1
857 
858  nlines = Vect_get_num_lines(self.poMapInfo)
859 
860  changeset = self._addActionsBefore()
861 
862  poList = self._display.GetSelectedIList()
863  Vect_snap_lines_list(self.poMapInfo, poList,
864  self._display.GetThreshold(), None)
865  Vect_destroy_list(poList)
866 
867  if nlines < Vect_get_num_lines(self.poMapInfo):
868  self._addActionsAfter(changeset, nlines)
869  self.toolbar.EnableUndo()
870  else:
871  del self.changesets[changeset]
872 
873  def ConnectLine(self):
874  """!Connect selected lines/boundaries
875 
876  @return 1 lines connected
877  @return 0 lines not connected
878  @return -1 on error
879  """
880  if not self._checkMap():
881  return -1
882 
883  nlines = Vect_get_num_lines(self.poMapInfo)
884 
885  # register changeset
886  changeset = self._addActionsBefore()
887 
888  poList = self._display.GetSelectedIList()
889  ret = Vedit_connect_lines(self.poMapInfo, poList,
890  self._display.GetThreshold())
891  Vect_destroy_list(poList)
892 
893  if ret > 0:
894  self._addActionsAfter(changeset, nlines)
895  self.toolbar.EnableUndo()
896  else:
897  del self.changesets[changeset]
898 
899  return ret
900 
901  def CopyLine(self, ids = []):
902  """!Copy features from (background) vector map
903 
904  @param ids list of line ids to be copied
905 
906  @return number of copied features
907  @return -1 on error
908  """
909  if not self._checkMap():
910  return -1
911 
912  nlines = Vect_get_num_lines(self.poMapInfo)
913 
914  poList = self._display.GetSelectedIList(ids)
915  ret = Vedit_copy_lines(self.poMapInfo, self.poBgMapInfo,
916  poList)
917  Vect_destroy_list(poList)
918 
919  if ret > 0:
920  changeset = len(self.changesets)
921  for line in (range(nlines + 1, Vect_get_num_lines(self.poMapInfo))):
922  self._addActionToChangeset(changeset, line, add = True)
923  self.toolbar.EnableUndo()
924  else:
925  del self.changesets[changeset]
926 
927  if ret > 0 and self.poBgMapInfo and self._settings['breakLines']:
928  for i in range(1, ret):
929  self._breakLineAtIntersection(nlines + i, None, changeset)
930 
931  return ret
932 
933  def CopyCats(self, fromId, toId, copyAttrb = False):
934  """!Copy given categories to objects with id listed in ids
935 
936  @param cats ids of 'from' feature
937  @param ids ids of 'to' feature(s)
938 
939  @return number of modified features
940  @return -1 on error
941  """
942  if len(fromId) < 1 or len(toId) < 1:
943  return 0
944 
945  poCatsFrom = self.poCats
946  poCatsTo = Vect_new_cats_struct();
947 
948  nlines = 0
949 
950  for fline in fromId:
951  if not Vect_line_alive(self.poMapInfo, fline):
952  continue
953 
954  if Vect_read_line(self.poMapInfo, None, poCatsFrom, fline) < 0:
955  self._error.ReadLine(fline)
956  return -1
957 
958  for tline in toId:
959  if not Vect_line_alive(self.poMapInfo, tline):
960  continue
961 
962  ltype = Vect_read_line(self.poMapInfo, self.poPoints, poCatsTo, tline)
963  if ltype < 0:
964  self._error.ReadLine(fline)
965  return -1
966 
967  catsFrom = poCatsFrom.contents
968  for i in range(catsFrom.n_cats):
969  if not copyAttrb:
970  # duplicate category
971  cat = catsFrom.cat[i]
972  else:
973  # duplicate attributes
974  cat = self.cats[catsFrom.field[i]] + 1
975  self.cats[catsFrom.field[i]] = cat
976  poFi = Vect_get_field(self.poMapInfo, catsFrom.field[i])
977  if not poFi:
978  self._error.DbLink(i)
979  return -1
980 
981  fi = poFi.contents
982  driver = db_start_driver(fi.driver)
983  if not driver:
984  self._error.Driver(fi.driver)
985  return -1
986 
987  handle = dbHandle()
988  db_init_handle(byref(handle))
989  db_set_handle(byref(handle), fi.database, None)
990  if db_open_database(driver, byref(handle)) != DB_OK:
991  db_shutdown_driver(driver)
992  self._error.Database(fi.driver, fi.database)
993  return -1
994 
995  stmt = dbString()
996  db_init_string(byref(stmt))
997  db_set_string(byref(stmt),
998  "SELECT * FROM %s WHERE %s=%d" % (fi.table, fi.key,
999  catsFrom.cat[i]))
1000 
1001  cursor = dbCursor()
1002  if db_open_select_cursor(driver, byref(stmt), byref(cursor),
1003  DB_SEQUENTIAL) != DB_OK:
1005  return -1
1006 
1007  table = db_get_cursor_table(byref(cursor))
1008  ncols = db_get_table_number_of_columns(table)
1009 
1010  sql = "INSERT INTO %s VALUES (" % fi.table
1011  # fetch the data
1012  more = c_int()
1013  while True:
1014  if db_fetch(byref(cursor), DB_NEXT, byref(more)) != DB_OK:
1016  return -1
1017  if not more.value:
1018  break
1019 
1020  value_string = dbString()
1021  for col in range(ncols):
1022  if col > 0:
1023  sql += ","
1024 
1025  column = db_get_table_column(table, col)
1026  if db_get_column_name(column) == fi.key:
1027  sql += "%d" % cat
1028  continue
1029 
1030  value = db_get_column_value(column)
1031  db_convert_column_value_to_string(column, byref(value_string))
1032  if db_test_value_isnull(value):
1033  sql += "NULL"
1034  else:
1036  if ctype != DB_C_TYPE_STRING:
1037  sql += db_get_string(byref(value_string))
1038  else:
1039  sql += "'%s'" % db_get_string(byref(value_string))
1040 
1041  sql += ")"
1042  db_set_string(byref(stmt), sql)
1043  if db_execute_immediate(driver, byref(stmt)) != DB_OK:
1045  return -1
1046 
1048  G_free(poFi)
1049 
1050  if Vect_cat_set(poCatsTo, catsFrom.field[i], cat) < 1:
1051  continue
1052 
1053  if Vect_rewrite_line(self.poMapInfo, tline, ltype, self.poPoints, poCatsTo) < 0:
1054  self._error.WriteLine()
1055  return -1
1056 
1057  nlines +=1
1058 
1059  Vect_destroy_cats_struct(poCatsTo)
1060 
1061  if nlines > 0:
1062  self.toolbar.EnableUndo()
1063 
1064  return nlines
1065 
1066  def _selectLinesByQueryThresh(self):
1067  """!Generic method used for SelectLinesByQuery() -- to get
1068  threshold value"""
1069  thresh = 0.0
1070  if UserSettings.Get(group = 'vdigit', key = 'query', subkey = 'selection') == 0:
1071  thresh = UserSettings.Get(group = 'vdigit', key = 'queryLength', subkey = 'thresh')
1072  if UserSettings.Get(group = 'vdigit', key = "queryLength", subkey = 'than-selection') == 0:
1073  thresh = -1 * thresh
1074  else:
1075  thresh = UserSettings.Get(group = 'vdigit', key = 'queryDangle', subkey = 'thresh')
1076  if UserSettings.Get(group = 'vdigit', key = "queryDangle", subkey = 'than-selection') == 0:
1077  thresh = -1 * thresh
1078 
1079  return thresh
1080 
1081  def SelectLinesByQuery(self, bbox):
1082  """!Select features by query
1083 
1084  @todo layer / 3D
1085 
1086  @param bbox bounding box definition
1087  """
1088  if not self._checkMap():
1089  return -1
1090 
1091  thresh = self._selectLinesByQueryThresh()
1092 
1093  query = QUERY_UNKNOWN
1094  if UserSettings.Get(group = 'vdigit', key = 'query', subkey = 'selection') == 0:
1095  query = QUERY_LENGTH
1096  else:
1097  query = QUERY_DANGLE
1098 
1099  ftype = GV_POINTS | GV_LINES # TODO: 3D
1100  layer = 1 # TODO
1101 
1102  ids = list()
1103  poList = Vect_new_list()
1104  coList = poList.contents
1105  if UserSettings.Get(group = 'vdigit', key = 'query', subkey = 'box'):
1107  x1, y1 = bbox[0]
1108  x2, y2 = bbox[1]
1109  z1 = z2 = 0.0
1110 
1111  Vect_append_point(self.poPoints, x1, y1, z1)
1112  Vect_append_point(self.poPoints, x2, y1, z2)
1113  Vect_append_point(self.poPoints, x2, y2, z1)
1114  Vect_append_point(self.poPoints, x1, y2, z2)
1115  Vect_append_point(self.poPoints, x1, y1, z1)
1116 
1117  Vect_select_lines_by_polygon(self.poMapInfo, self.poPoints, 0, None,
1118  ftype, poList)
1119 
1120  if coList.n_values == 0:
1121  return ids
1122 
1124  ftype, layer, thresh, query,
1125  poList)
1126 
1127  for i in range(coList.n_values):
1128  ids.append(int(coList.value[i]))
1129 
1130  Debug.msg(3, "IVDigit.SelectLinesByQuery(): lines=%d", coList.n_values)
1131  Vect_destroy_list(poList)
1132 
1133  return ids
1134 
1135  def IsVector3D(self):
1136  """!Check if open vector map is 3D
1137  """
1138  if not self._checkMap():
1139  return False
1140 
1141  return Vect_is_3d(self.poMapInfo)
1142 
1143  def GetLineLength(self, line):
1144  """!Get line length
1145 
1146  @param line feature id
1147 
1148  @return line length
1149  @return -1 on error
1150  """
1151  if not self._checkMap():
1152  return -1
1153 
1154  if not Vect_line_alive(self.poMapInfo, line):
1155  return -1
1156 
1157  ltype = Vect_read_line(self.poMapInfo, self.poPoints, None, line)
1158  if ltype < 0:
1159  self._error.ReadLine(line)
1160  return ret
1161 
1162  length = -1
1163  if ltype & GV_LINES: # lines & boundaries
1164  length = Vect_line_length(self.poPoints)
1165 
1166  return length
1167 
1168  def GetAreaSize(self, centroid):
1169  """!Get area size
1170 
1171  @param centroid centroid id
1172 
1173  @return area size
1174  @return -1 on error
1175  """
1176  if not self._checkMap():
1177  return -1
1178 
1179  ltype = Vect_read_line(self.poMapInfo, None, None, centroid)
1180  if ltype < 0:
1181  self._error.ReadLine(line)
1182  return ret
1183 
1184  if ltype != GV_CENTROID:
1185  return -1
1186 
1187  area = Vect_get_centroid_area(self.poMapInfo, centroid)
1188  size = -1
1189  if area > 0:
1190  if not Vect_area_alive(self.poMapInfo, area):
1191  return size
1192 
1193  size = Vect_get_area_area(self.poMapInfo, area)
1194 
1195  return size
1196 
1197  def GetAreaPerimeter(self, centroid):
1198  """!Get area perimeter
1199 
1200  @param centroid centroid id
1201 
1202  @return area size
1203  @return -1 on error
1204  """
1205  if not self._checkMap():
1206  return -1
1207 
1208  ltype = Vect_read_line(self.poMapInfo, None, None, centroid)
1209  if ltype < 0:
1210  self._error.ReadLine(line)
1211  return ret
1212 
1213  if ltype != GV_CENTROID:
1214  return -1
1215 
1216  area = Vect_get_centroid_area(self.poMapInfo, centroid)
1217  perimeter = -1
1218  if area > 0:
1219  if not Vect_area_alive(self.poMapInfo, area):
1220  return -1
1221 
1222  Vect_get_area_points(self.poMapInfo, area, self.poPoints)
1223  perimeter = Vect_area_perimeter(self.poPoints)
1224 
1225  return perimeter
1226 
1227  def SetLineCats(self, line, layer, cats, add = True):
1228  """!Set categories for given line and layer
1229 
1230  @param line feature id
1231  @param layer layer number (-1 for first selected line)
1232  @param cats list of categories
1233  @param add if True to add, otherwise do delete categories
1234 
1235  @return new feature id (feature need to be rewritten)
1236  @return -1 on error
1237  """
1238  if not self._checkMap():
1239  return -1
1240 
1241  if line < 1 and len(self._display.selected['ids']) < 1:
1242  return -1
1243 
1244  update = False
1245  if line == -1:
1246  update = True
1247  line = self._display.selected['ids'][0]
1248 
1249  if not Vect_line_alive(self.poMapInfo, line):
1250  return -1
1251 
1252  ltype = Vect_read_line(self.poMapInfo, self.poPoints, self.poCats, line)
1253  if ltype < 0:
1254  self._error.ReadLine(line)
1255  return -1
1256 
1257  for c in cats:
1258  if add:
1259  Vect_cat_set(self.poCats, layer, c)
1260  else:
1261  Vect_field_cat_del(self.poCats, layer, c)
1262 
1263  nlines = Vect_get_num_lines(self.poMapInfo)
1264  changeset = self._addActionsBefore()
1265  newline = Vect_rewrite_line(self.poMapInfo, line, ltype,
1266  self.poPoints, self.poCats)
1267 
1268  if newline > 0:
1269  self._addActionsAfter(changeset, nlines)
1270  self.toolbar.EnableUndo()
1271 
1272  if update:
1273  # update line id since the line was rewritten
1274  self._display.selected['ids'][0] = newline
1275 
1276  return newline
1277 
1279  """!Feature type conversion for selected objects.
1280 
1281  Supported conversions:
1282  - point <-> centroid
1283  - line <-> boundary
1284 
1285  @return number of modified features
1286  @return -1 on error
1287  """
1288  if not self._checkMap():
1289  return -1
1290 
1291  nlines = Vect_get_num_lines(self.poMapInfo)
1292 
1293  # register changeset
1294  changeset = self._addActionsBefore()
1295 
1296  poList = self._display.GetSelectedIList()
1297  ret = Vedit_chtype_lines(self.poMapInfo, poList)
1298  Vect_destroy_list(poList)
1299 
1300  if ret > 0:
1301  self._addActionsAfter(changeset, nlines)
1302  self.toolbar.EnableUndo()
1303  else:
1304  del self.changesets[changeset]
1305 
1306  return ret
1307 
1308  def Undo(self, level = -1):
1309  """!Undo action
1310 
1311  @param level levels to undo (0 to revert all)
1312 
1313  @return id of current changeset
1314  """
1315  changesetLast = len(self.changesets.keys()) - 1
1316 
1317  if changesetLast < 0:
1318  return changesetLast
1319 
1320  if self.changesetCurrent == -2: # value uninitialized
1321  self.changesetCurrent = changesetLast
1322 
1323  if level > 0 and self.changesetCurrent < 0:
1324  self.changesetCurrent = 0
1325 
1326  if level == 0:
1327  # 0 -> undo all
1328  level = -1 * changesetLast + 1
1329 
1330  Debug.msg(2, "Digit.Undo(): changeset_last=%d, changeset_current=%d, level=%d",
1331  changesetLast, self.changesetCurrent, level)
1332 
1333  if level < 0: # undo
1334  if self.changesetCurrent + level < -1:
1335  return changesetCurrent;
1336  for changeset in range(self.changesetCurrent, self.changesetCurrent + level, -1):
1337  self._applyChangeset(changeset, undo = True)
1338  elif level > 0: # redo
1339  if self.changesetCurrent + level > len(self.changesets.keys()):
1340  return self.changesetCurrent
1341  for changeset in range(self.changesetCurrent, self.changesetCurrent + level):
1342  self._applyChangeset(changeset, undo = False)
1343 
1344  self.changesetCurrent += level
1345 
1346  Debug.msg(2, "Digit.Undo(): changeset_current=%d, changeset_last=%d, changeset_end=%d",
1347  self.changesetCurrent, changesetLast, self.changesetEnd)
1348 
1349  if self.changesetCurrent == self.changesetEnd:
1350  self.changesetEnd = changesetLast
1351  return -1
1352 
1353  self.mapWindow.UpdateMap(render = False)
1354 
1355  if self.changesetCurrent < 0: # disable undo tool
1356  self.toolbar.EnableUndo(False)
1357 
1358  def ZBulkLines(self, pos1, pos2, start, step):
1359  """!Z-bulk labeling
1360 
1361  @param pos1 reference line (start point)
1362  @param pos1 reference line (end point)
1363  @param start starting value
1364  @param step step value
1365 
1366  @return number of modified lines
1367  @return -1 on error
1368  """
1369  if not self._checkMap():
1370  return -1
1371 
1372  nlines = Vect_get_num_lines(self.poMapInfo)
1373 
1374  # register changeset
1375  changeset = self._addActionsBefore()
1376 
1377  poList = self._display.GetSelectedIList()
1378  ret = Vedit_bulk_labeling(self.poMapInfo, poList,
1379  pos1[0], pos1[1], pos2[0], pos2[1],
1380  start, step)
1381  Vect_destroy_list(poList)
1382 
1383  if ret > 0:
1384  self._addActionsAfter(changeset, nlines)
1385  self.toolbar.EnableUndo()
1386  else:
1387  del self.changesets[changeset]
1388 
1389  return ret
1390 
1391  def GetDisplay(self):
1392  """!Get display driver instance"""
1393  return self._display
1394 
1395  def OpenMap(self, name):
1396  """!Open vector map for editing
1397 
1398  @param map name of vector map to be set up
1399  """
1400  Debug.msg (3, "AbstractDigit.SetMapName map=%s" % name)
1401 
1402  name, mapset = name.split('@')
1403 
1404  self.poMapInfo = self._display.OpenMap(str(name), str(mapset), True)
1405 
1406  if self.poMapInfo:
1407  self.InitCats()
1408 
1409  return self.poMapInfo
1410 
1411  def CloseMap(self):
1412  """!Close currently open vector map
1413  """
1414  if not self._checkMap():
1415  return
1416 
1417  self._display.CloseMap()
1418 
1419  def InitCats(self):
1420  """!Initialize categories information
1421 
1422  @return 0 on success
1423  @return -1 on error
1424  """
1425  self.cats.clear()
1426  if not self._checkMap():
1427  return -1
1428 
1429  ndblinks = Vect_get_num_dblinks(self.poMapInfo)
1430  for i in range(ndblinks):
1431  fi = Vect_get_dblink(self.poMapInfo, i).contents
1432  if fi:
1433  self.cats[fi.number] = None
1434 
1435  # find max category
1436  nfields = Vect_cidx_get_num_fields(self.poMapInfo)
1437  Debug.msg(2, "wxDigit.InitCats(): nfields=%d", nfields)
1438 
1439  for i in range(nfields):
1440  field = Vect_cidx_get_field_number(self.poMapInfo, i)
1442  if field <= 0:
1443  continue
1444  for j in range(ncats):
1445  cat = c_int()
1446  type = c_int()
1447  id = c_int()
1449  byref(cat), byref(type), byref(id))
1450  if field in self.cats:
1451  if cat > self.cats[field]:
1452  self.cats[field] = cat.value
1453  else:
1454  self.cats[field] = cat.value
1455  Debug.msg(3, "wxDigit.InitCats(): layer=%d, cat=%d", field, self.cats[field])
1456 
1457  # set default values
1458  for field, cat in self.cats.iteritems():
1459  if cat == None:
1460  self.cats[field] = 0 # first category 1
1461  Debug.msg(3, "wxDigit.InitCats(): layer=%d, cat=%d", field, self.cats[field])
1462 
1463  def _checkMap(self):
1464  """!Check if map is open
1465  """
1466  if not self.poMapInfo:
1467  self._error.NoMap()
1468  return False
1469 
1470  return True
1471 
1472  def _addFeature(self, ftype, coords, layer, cat, snap, threshold):
1473  """!Add new feature(s) to the vector map
1474 
1475  @param ftype feature type (GV_POINT, GV_LINE, GV_BOUNDARY, ...)
1476  @coords tuple of coordinates ((x, y), (x, y), ...)
1477  @param layer layer number (-1 for no cat)
1478  @param cat category number
1479  @param snap snap to node/vertex
1480  @param threshold threshold for snapping
1481 
1482  @return tuple (number of added features, list of fids)
1483  @return number of features -1 on error
1484  """
1485  fids = list()
1486  if not self._checkMap():
1487  return (-1, None)
1488 
1489  is3D = bool(Vect_is_3d(self.poMapInfo))
1490 
1491  Debug.msg(2, "IVDigit._addFeature(): npoints=%d, layer=%d, cat=%d, snap=%d",
1492  len(coords), layer, cat, snap)
1493 
1494  if not (ftype & (GV_POINTS | GV_LINES | GV_AREA)): # TODO: 3D
1495  self._error.FeatureType(ftype)
1496  return (-1, None)
1497 
1498  # set category
1499  Vect_reset_cats(self.poCats)
1500  if layer > 0 and ftype != GV_AREA:
1501  Vect_cat_set(self.poCats, layer, cat)
1502  self.cats[layer] = max(cat, self.cats.get(layer, 1))
1503 
1504  # append points
1506  for c in coords:
1507  Vect_append_point(self.poPoints, c[0], c[1], 0.0)
1508 
1509  if ftype & (GV_BOUNDARY | GV_AREA):
1510  # close boundary
1511  points = self.poPoints.contents
1512  last = points.n_points - 1
1513  if Vect_points_distance(points.x[0], points.y[0], points.z[0],
1514  points.x[last], points.y[last], points.z[last],
1515  is3D) <= threshold:
1516  points.x[last] = points.x[0]
1517  points.y[last] = points.y[0]
1518  points.z[last] = points.z[0]
1519 
1520  if snap != NO_SNAP:
1521  # apply snapping (node or vertex)
1522  modeSnap = not (snap == SNAP)
1523  Vedit_snap_line(self.poMapInfo, self.popoBgMapInfo, int(self.poBgMapInfo is not None),
1524  -1, self.poPoints, threshold, modeSnap)
1525 
1526  if ftype == GV_AREA:
1527  ltype = GV_BOUNDARY
1528  else:
1529  ltype = ftype
1530  newline = Vect_write_line(self.poMapInfo, ltype, self.poPoints, self.poCats)
1531  if newline < 0:
1532  self._error.WriteLine()
1533  return (-1, None)
1534  else:
1535  fids.append(newline)
1536 
1537  left = right = -1
1538  if ftype & GV_AREA:
1539  # add centroids for left/right area
1540  bpoints = Vect_new_line_struct()
1541  cleft = c_int()
1542  cright = c_int()
1543 
1544  Vect_get_line_areas(self.poMapInfo, newline,
1545  byref(cleft), byref(cright))
1546  left = cleft.value
1547  right = cright.value
1548 
1549  Debug.msg(3, "IVDigit._addFeature(): area - left=%d right=%d",
1550  left, right)
1551 
1552  # check if area exists and has no centroid inside
1553  if layer > 0 and (left > 0 or right > 0):
1554  Vect_cat_set(self.poCats, layer, cat)
1555  self.cats[layer] = max(cat, self.cats.get(layer, 0))
1556 
1557  x = c_double()
1558  y = c_double()
1559  if left > 0 and \
1560  Vect_get_area_centroid(self.poMapInfo, left) == 0:
1561  # if Vect_get_area_points(self.poMapInfo, left, bpoints) > 0 and
1562  # Vect_find_poly_centroid(bpoints, byref(x), byref(y)) == 0:
1563  if Vect_get_point_in_area(self.poMapInfo, left, byref(x), byref(y)) == 0:
1564  Vect_reset_line(bpoints)
1565  Vect_append_point(bpoints, x.value, y.value, 0.0)
1566  newline = Vect_write_line(self.poMapInfo, GV_CENTROID,
1567  bpoints, self.poCats)
1568  if newline < 0:
1569  self._error.WriteLine()
1570  return (len(fids), fids)
1571  else:
1572  fids.append(newline)
1573 
1574  if right > 0 and \
1575  Vect_get_area_centroid(self.poMapInfo, right) == 0:
1576  # if Vect_get_area_points(byref(self.poMapInfo), right, bpoints) > 0 and
1577  # Vect_find_poly_centroid(bpoints, byref(x), byref(y)) == 0:
1578  if Vect_get_point_in_area(self.poMapInfo, right, byref(x), byref(y)) == 0:
1579  Vect_reset_line(bpoints)
1580  Vect_append_point(bpoints, x.value, y.value, 0.0)
1581  newline = Vect_write_line(self.poMapInfo, GV_CENTROID,
1582  bpoints, self.poCats)
1583  if newline < 0:
1584  self._error.WriteLine()
1585  return (len(fids, fids))
1586  else:
1587  fids.append(newline)
1588 
1589  Vect_destroy_line_struct(bpoints)
1590 
1591  # register changeset
1592  changeset = len(self.changesets)
1593  self._addActionToChangeset(changeset, newline, add = True)
1594 
1595  # break at intersection
1596  if self._settings['breakLines']:
1597  self._breakLineAtIntersection(newline, self.poPoints, changeset)
1598 
1599  return (len(fids), fids)
1600 
1601  def _ModifyLineVertex(self, coords, add = True):
1602  """!Add or remove vertex
1603 
1604  Shape of line/boundary is not changed when adding new vertex.
1605 
1606  @param coords coordinates of point
1607  @param add True to add, False to remove
1608 
1609  @return id id of the new feature
1610  @return 0 nothing changed
1611  @return -1 error
1612  """
1613  if not self._checkMap():
1614  return -1
1615 
1616  selected = self._display.selected
1617  if len(selected['ids']) != 1:
1618  return 0
1619 
1620  poList = self._display.GetSelectedIList()
1622  Vect_append_point(self.poPoints, coords[0], coords[1], 0.0)
1623 
1624  nlines = Vect_get_num_lines(self.poMapInfo)
1625  thresh = self._display.GetThreshold(type = 'selectThresh')
1626 
1627  changeset = self._addActionsBefore()
1628 
1629  if add:
1630  ret = Vedit_add_vertex(self.poMapInfo, poList,
1631  self.poPoints, thresh)
1632  else:
1633  ret = Vedit_remove_vertex(self.poMapInfo, poList,
1634  self.poPoints, thresh)
1635  Vect_destroy_list(poList)
1636 
1637  if ret > 0:
1638  self._addActionsAfter(changeset, nlines)
1639  else:
1640  del self.changesets[changeset]
1641 
1642  if not add and ret > 0 and self._settings['breakLines']:
1644  None, changeset)
1645 
1646  return nlines + 1 # feature is write at the end of the file
1647 
1648  def GetLineCats(self, line):
1649  """!Get list of layer/category(ies) for selected feature.
1650 
1651  @param line feature id (-1 for first selected feature)
1652 
1653  @return list of layer/cats
1654  """
1655  ret = dict()
1656  if not self._checkMap():
1657  return ret
1658 
1659  if line == -1 and len(self._display.selected['ids']) < 1:
1660  return ret
1661 
1662  if line == -1:
1663  line = self._display.selected['ids'][0]
1664 
1665  if not Vect_line_alive(self.poMapInfo, line):
1666  self._error.DeadLine(line)
1667  return ret
1668 
1669  if Vect_read_line(self.poMapInfo, None, self.poCats, line) < 0:
1670  self._error.ReadLine(line)
1671  return ret
1672 
1673  cats = self.poCats.contents
1674  for i in range(cats.n_cats):
1675  field = cats.field[i]
1676  if field not in ret:
1677  ret[field] = list()
1678  ret[field].append(cats.cat[i])
1679 
1680  return ret
1681 
1682  def GetLayers(self):
1683  """!Get list of layers
1684 
1685  Requires self.InitCats() to be called.
1686 
1687  @return list of layers
1688  """
1689  return self.cats.keys()
1690 
1691  def UpdateSettings(self):
1692  """!Update digit (and display) settings
1693  """
1694  self._display.UpdateSettings()
1695 
1696  self._settings['breakLines'] = bool(UserSettings.Get(group = 'vdigit', key = "breakLines",
1697  subkey = 'enabled'))
1698 
1699  def SetCategory(self):
1700  """!Update self.cats based on settings"""
1701  sel = UserSettings.Get(group = 'vdigit', key = 'categoryMode', subkey = 'selection')
1702  cat = None
1703  if sel == 0: # next to usep
1704  cat = self._setCategoryNextToUse()
1705  elif sel == 1:
1706  cat = UserSettings.Get(group = 'vdigit', key = 'category', subkey = 'value')
1707 
1708  if cat:
1709  layer = UserSettings.Get(group = 'vdigit', key = 'layer', subkey = 'value')
1710  self.cats[layer] = cat
1711 
1712  return cat
1713 
1714  def _setCategoryNextToUse(self):
1715  """!Find maximum category number for the given layer and
1716  update the settings
1717 
1718  @return category to be used
1719  """
1720  # get max category number for given layer and update the settings
1721  layer = UserSettings.Get(group = 'vdigit', key = 'layer', subkey = 'value')
1722  cat = self.cats.get(layer, 0) + 1
1723  UserSettings.Set(group = 'vdigit', key = 'category', subkey = 'value',
1724  value = cat)
1725  Debug.msg(1, "IVDigit._setCategoryNextToUse(): cat=%d", cat)
1726 
1727  return cat
1728 
1730  """!Select features from background map
1731 
1732  @param bbox bounding box definition
1733 
1734  @return list of selected feature ids
1735  """
1736  # try select features by box first
1737  if self._display.SelectLinesByBox(bbox, poMapInfo = self.poBgMapInfo) < 1:
1738  self._display.SelectLineByPoint(bbox[0], poMapInfo = self.poBgMapInfo)['line']
1739 
1740  return self._display.selected['ids']
1741 
1742  def GetUndoLevel(self):
1743  """!Get undo level (number of active changesets)
1744 
1745  Note: Changesets starts wiht 0
1746  """
1747  return self.changesetCurrent
int Vedit_flip_lines(struct Map_info *Map, struct ilist *List)
Flip direction of selected lines.
Definition: flip.c:25
dbColumn * db_get_table_column(dbTable *table, int n)
returns column structure for given table and column number
int db_test_value_isnull(dbValue *value)
Definition: value.c:10
int Vect_destroy_list(struct ilist *list)
Frees all memory associated with a struct ilist, including the struct itself.
def WriteLine
Writing line failed.
Definition: wxdigit.py:62
void G_free(void *buf)
Free allocated memory.
Definition: gis/alloc.c:142
int Vect_get_area_centroid(struct Map_info *Map, int area)
Returns centroid number of area.
struct field_info * Vect_get_field(struct Map_info *Map, int field)
Get information about link to database.
Definition: field.c:404
def IsVector3D
Check if open vector map is 3D.
Definition: wxdigit.py:1135
wxGUI command interface
int Vect_field_cat_del(struct line_cats *Cats, int field, int cat)
Delete field/cat from line_cats structure.
def ConnectLine
Connect selected lines/boundaries.
Definition: wxdigit.py:873
const char * db_get_column_name(dbColumn *column)
returns column name for given column
def OpenBackgroundMap
Open background vector map.
Definition: wxdigit.py:198
def _ModifyLineVertex
Add or remove vertex.
Definition: wxdigit.py:1601
def GetAreaSize
Get area size.
Definition: wxdigit.py:1168
const char * Vect_get_name(struct Map_info *Map)
Get map name.
def FlipLine
Flip selected lines/boundaries.
Definition: wxdigit.py:772
def MergeLine
Merge selected lines/boundaries.
Definition: wxdigit.py:798
GRASS Python scripting module (core functions)
int db_close_database_shutdown_driver(dbDriver *driver)
Close driver/database connection.
Definition: db.c:62
int Vect_get_line_areas(struct Map_info *Map, int line, int *left, int *right)
Get area/isle ids on the left and right.
Definition: level_two.c:272
struct line_pnts * Vect_new_line_struct()
Creates and initializes a struct line_pnts.
Definition: line.c:57
int Vect_cat_del(struct line_cats *Cats, int field)
Delete all categories of given layer.
wxGUI debugging
int Vect_cidx_get_num_cats_by_index(struct Map_info *Map, int index)
Get number of categories for given layer index.
Definition: Vlib/cindex.c:121
def BreakLine
Break selected lines/boundaries.
Definition: wxdigit.py:823
struct ilist * Vect_new_list(void)
Creates and initializes a struct ilist.
int db_shutdown_driver(dbDriver *driver)
Closedown the driver, and free the driver structure.
Definition: shutdown.c:36
int db_close_database(dbDriver *driver)
Close database connection.
Definition: c_closedb.c:26
def FeatureType
Unknown feature type.
Definition: wxdigit.py:118
def _addActionsAfter
Register action after operation.
Definition: wxdigit.py:380
int Vect_line_check_intersection(struct line_pnts *APoints, struct line_pnts *BPoints, int with_z)
Check if 2 lines intersect.
def SelectLinesFromBackgroundMap
Select features from background map.
Definition: wxdigit.py:1729
def GetDisplay
Get display driver instance.
Definition: wxdigit.py:1391
int Vect_reset_line(struct line_pnts *Points)
Reset line.
Definition: line.c:148
int Vect_cidx_get_field_number(struct Map_info *Map, int index)
Get layer number for given index.
Definition: Vlib/cindex.c:56
int Vect_reset_cats(struct line_cats *Cats)
Reset category structure to make sure cats structure is clean to be re-used.
char * G_find_vector2(const char *name, const char *mapset)
find a vector map (look but don&#39;t touch)
Definition: find_vect.c:75
def SetCategory
Update self.cats based on settings.
Definition: wxdigit.py:1699
int Vect_cidx_get_cat_by_index(struct Map_info *Map, int field_index, int cat_index, int *cat, int *type, int *id)
Get number of categories for given field and category index.
Definition: Vlib/cindex.c:225
def EditLine
Edit existing line/boundary.
Definition: wxdigit.py:717
int Vedit_bulk_labeling(struct Map_info *Map, struct ilist *List, double x1, double y1, double x2, double y2, double start, double step)
Lines z-bulk labeling.
Definition: zbulk.c:32
#define max(x, y)
Definition: draw2.c:69
int Vect_restore_line(struct Map_info *Map, int line, long offset)
Restore previously deleted feature.
int db_execute_immediate(dbDriver *driver, dbString *SQLstatement)
Execute SQL statements.
Definition: c_execute.c:27
def ReadLine
Reading line failed.
Definition: wxdigit.py:70
def Undo
Undo action.
Definition: wxdigit.py:1308
int Vect_append_point(struct line_pnts *Points, double x, double y, double z)
Appends one point to the end of a line.
Definition: line.c:168
int Vect_get_area_points(struct Map_info *Map, int area, struct line_pnts *BPoints)
Returns the polygon array of points in BPoints.
int Vedit_remove_vertex(struct Map_info *Map, struct ilist *List, struct line_pnts *coord, double thresh)
Remove vertex from line.
Definition: vertex.c:282
int Vedit_move_lines(struct Map_info *Map, struct Map_info **BgMap, int nbgmaps, struct ilist *List, double move_x, double move_y, double move_z, int snap, double thresh)
Move selected primitives.
Definition: move.c:29
int db_convert_column_value_to_string(dbColumn *column, dbString *string)
Definition: columnfmt.c:43
def SplitLine
Split/break selected line/boundary on given position.
Definition: wxdigit.py:684
def GetLineLength
Get line length.
Definition: wxdigit.py:1143
def DeleteSelectedLines
Delete selected features.
Definition: wxdigit.py:480
def DeadLine
Dead line.
Definition: wxdigit.py:110
int db_append_string(dbString *x, const char *s)
Definition: string.c:193
int db_sqltype_to_Ctype(int sqltype)
Definition: sqlCtype.c:9
def _breakLineAtIntersection
Break given line at intersection.
Definition: wxdigit.py:248
def _setCategoryNextToUse
Find maximum category number for the given layer and update the settings.
Definition: wxdigit.py:1714
int Vect_cat_set(struct line_cats *Cats, int field, int cat)
Add new field/cat to category structure if doesn&#39;t exist yet.
int db_fetch(dbCursor *cursor, int position, int *more)
Fetch data.
Definition: c_fetch.c:28
def _selectLinesByQueryThresh
Generic method used for SelectLinesByQuery() – to get threshold value.
Definition: wxdigit.py:1066
int Vect_is_3d(struct Map_info *Map)
Check if vector map is 3D (with z)
def _checkMap
Check if map is open.
Definition: wxdigit.py:1463
dbTable * db_get_cursor_table(dbCursor *cursor)
Definition: cursor.c:55
int Vedit_snap_line(struct Map_info *Map, struct Map_info **BgMap, int nbgmaps, int line, struct line_pnts *Points, double thresh, int to_vertex)
Snap selected primitive to its nearest primitive.
Definition: vedit/snap.c:99
def _applyChangeset
Apply changeset (undo/redo changeset)
Definition: wxdigit.py:335
def _getSnapMode
Get snapping mode.
Definition: wxdigit.py:230
def CloseMap
Close currently open vector map.
Definition: wxdigit.py:1411
def ZBulkLines
Z-bulk labeling.
Definition: wxdigit.py:1358
int Vedit_merge_lines(struct Map_info *Map, struct ilist *List)
Merge lines/boundaries.
Definition: merge.c:47
int Vedit_delete_lines(struct Map_info *Map, struct ilist *List)
Delete selected primitives.
def _addActionsBefore
Register action before operation.
Definition: wxdigit.py:323
int Vedit_chtype_lines(struct Map_info *Map, struct ilist *List)
Change primitive type.
Definition: chtype.c:29
def AddFeature
Add new feature.
Definition: wxdigit.py:440
int db_get_column_sqltype(dbColumn *column)
returns column sqltype for column (the function db_sqltype_name() returns sqltype description) ...
def __init__
Base class for vector digitizer (ctypes interface)
Definition: wxdigit.py:127
def __init__
Class for managing error messages of vector digitizer.
Definition: wxdigit.py:44
int db_get_table_number_of_columns(dbTable *table)
def RemoveVertex
Remove vertex from the selected line/boundary on position &#39;coords&#39;.
Definition: wxdigit.py:667
int Vect_rewrite_line(struct Map_info *Map, int line, int type, struct line_pnts *points, struct line_cats *cats)
Rewrites feature info at the given offset.
int Vect_get_num_dblinks(struct Map_info *map)
Get number of defined dblinks.
Definition: level_two.c:158
def TypeConvForSelectedLines
Feature type conversion for selected objects.
Definition: wxdigit.py:1278
void Vect_snap_lines_list(struct Map_info *Map, struct ilist *List_lines, double thresh, struct Map_info *Err)
Snap selected lines to existing vertex in threshold.
Definition: Vlib/snap.c:110
def SetLineCats
Set categories for given line and layer.
Definition: wxdigit.py:1227
def MoveSelectedVertex
Move selected vertex of the line.
Definition: wxdigit.py:604
int Vedit_select_by_query(struct Map_info *Map, int type, int layer, double thresh, int query, struct ilist *List)
Select primitives by query (based on geometry properties)
dbValue * db_get_column_value(dbColumn *column)
returns column value for given column structure
def _removeActionFromChangeset
Remove action from changeset.
Definition: wxdigit.py:420
int Vect_destroy_cats_struct(struct line_cats *p)
Frees all memory associated with line_cats structure, including the struct itself.
int Vect_list_append(struct ilist *list, int val)
Append new item to the end of list if not yet present.
def CopyCats
Copy given categories to objects with id listed in ids.
Definition: wxdigit.py:933
int Vect_select_lines_by_polygon(struct Map_info *Map, struct line_pnts *Polygon, int nisles, struct line_pnts **Isles, int type, struct ilist *List)
Select lines by Polygon with optional isles.
long Vect_get_line_offset(const struct Map_info *Map, int line)
Get feature offset.
def GetLayers
Get list of layers.
Definition: wxdigit.py:1682
def GetUndoLevel
Get undo level (number of active changesets)
Definition: wxdigit.py:1742
int Vedit_copy_lines(struct Map_info *Map, struct Map_info *FromMap, struct ilist *List)
Copy selected primitives.
def DbLink
No dblink available.
Definition: wxdigit.py:78
int Vect_break_lines_list(struct Map_info *Map, struct ilist *List_break, struct ilist *List_ref, int type, struct Map_info *Err)
Break selected lines in vector map at each intersection.
Definition: break_lines.c:66
int db_set_handle(dbHandle *handle, const char *dbName, const char *dbSchema)
Definition: handle.c:22
def NoMap
No map for editing.
Definition: wxdigit.py:52
int Vect_open_old(struct Map_info *Map, const char *name, const char *mapset)
Open existing vector for reading.
def AddVertex
Add new vertex to the selected line/boundary on position &#39;coords&#39;.
Definition: wxdigit.py:651
int Vect_line_alive(struct Map_info *Map, int line)
Check if feature is alive or dead.
def SelectLinesByQuery
Select features by query.
Definition: wxdigit.py:1081
int Vect_close(struct Map_info *Map)
Close vector data file.
Definition: close.c:64
struct field_info * Vect_get_dblink(struct Map_info *Map, int link)
Get information about link to database.
Definition: field.c:364
def _addActionToChangeset
Add action to changeset.
Definition: wxdigit.py:394
int Vect_select_lines_by_box(struct Map_info *Map, BOUND_BOX *Box, int type, struct ilist *list)
Select lines by box.
struct line_cats * Vect_new_cats_struct()
Creates and initializes line_cats structure.
int Vect_get_point_in_area(struct Map_info *Map, int area, double *X, double *Y)
Get point inside area and outside all islands.
Definition: Vlib/poly.c:61
int Vect_cidx_get_num_fields(struct Map_info *Map)
Get number of layer in category index.
Definition: Vlib/cindex.c:41
double Vect_line_length(struct line_pnts *Points)
Calculate line length, 3D-length in case of 3D vector line.
Definition: line.c:555
int Vect_get_num_lines(struct Map_info *map)
Fetch number of features (points, lines, boundaries, centroids) in vector map.
Definition: level_two.c:69
int Vedit_add_vertex(struct Map_info *Map, struct ilist *List, struct line_pnts *coord, double thresh)
Add new vertex to line.
Definition: vertex.c:194
char * db_get_string(dbString *x)
Definition: string.c:131
double Vect_get_area_area(struct Map_info *Map, int area)
Returns area of area without areas of isles.
def CopyLine
Copy features from (background) vector map.
Definition: wxdigit.py:901
int Vedit_connect_lines(struct Map_info *Map, struct ilist *List, double thresh)
Connect lines in given threshold.
Definition: break.c:155
def DbExecute
Sql query failed.
Definition: wxdigit.py:102
double Vect_area_perimeter(struct line_pnts *Points)
Calculate area perimeter.
void db_init_handle(dbHandle *handle)
Definition: handle.c:10
def MoveSelectedLines
Move selected features.
Definition: wxdigit.py:567
int Vedit_move_vertex(struct Map_info *Map, struct Map_info **BgMap, int nbgmaps, struct ilist *List, struct line_pnts *coord, double thresh_coords, double thresh_snap, double move_x, double move_y, double move_z, int move_first, int snap)
Move all vertices in bounding box(es)
Definition: vertex.c:33
int Vect_delete_line(struct Map_info *Map, int line)
Delete feature.
def InitCats
Initialize categories information.
Definition: wxdigit.py:1419
int db_set_string(dbString *x, const char *s)
Definition: string.c:33
double Vect_points_distance(double x1, double y1, double z1, double x2, double y2, double z2, int with_z)
Calculate distance of 2 points.
Definition: line.c:745
def GetLineCats
Get list of layer/category(ies) for selected feature.
Definition: wxdigit.py:1648
int Vect_get_centroid_area(struct Map_info *Map, int centroid)
Get area id the centroid is within.
Definition: level_two.c:353
int Vect_get_line_box(struct Map_info *Map, int line, BOUND_BOX *Box)
Get boundary box of line.
Definition: Vlib/box.c:208
long Vect_write_line(struct Map_info *Map, int type, struct line_pnts *points, struct line_cats *cats)
Writes new feature to the end of file (table)
def Database
Opening database failed.
Definition: wxdigit.py:94
const char * Vect_get_mapset(struct Map_info *Map)
Get mapset name.
Default GUI settings.
wxGUI vector digitizer (display driver)
int db_open_database(dbDriver *driver, dbHandle *handle)
Open database connection.
Definition: c_opendb.c:27
int Vect_area_alive(struct Map_info *Map, int area)
Check if area is alive or dead.
def UpdateSettings
Update digit (and display) settings.
Definition: wxdigit.py:1691
def Driver
Staring driver failed.
Definition: wxdigit.py:86
tuple range
Definition: tools.py:1406
int Vedit_split_lines(struct Map_info *Map, struct ilist *List, struct line_pnts *coord, double thresh, struct ilist *List_updated)
Split selected lines on given position.
Definition: break.c:31
dbDriver * db_start_driver(const char *name)
Initialize a new dbDriver for db transaction.
Definition: start.c:43
def GetAreaPerimeter
Get area perimeter.
Definition: wxdigit.py:1197
def CloseBackgroundMap
Close background vector map.
Definition: wxdigit.py:190
int db_open_select_cursor(dbDriver *driver, dbString *select, dbCursor *cursor, int mode)
Open select cursor.
Definition: c_openselect.c:29
def _addFeature
Add new feature(s) to the vector map.
Definition: wxdigit.py:1472
void db_init_string(dbString *x)
Definition: string.c:11
int Vect_destroy_line_struct(struct line_pnts *p)
Frees all memory associated with a struct line_pnts, including the struct itself. ...
Definition: line.c:90
def SnapLine
Snap selected lines/boundaries.
Definition: wxdigit.py:849
int Vect_read_line(struct Map_info *Map, struct line_pnts *line_p, struct line_cats *line_c, int line)
Read vector feature.
def OpenMap
Open vector map for editing.
Definition: wxdigit.py:1395
int G__name_is_fully_qualified(const char *fullname, char *name, char *mapset)
Check if map name is fully qualified (map @ mapset)
Definition: nme_in_mps.c:57