GRASS Programmer's Manual  6.5.svn(2014)-r66266
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
wxdisplay.py
Go to the documentation of this file.
1 """!
2 @package vdigit.wxdisplay
3 
4 @brief wxGUI vector digitizer (display driver)
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  - wxdisplay::DisplayDriver
11 
12 (C) 2007-2011 by the GRASS Development Team
13 
14 This program is free software under the GNU General Public License
15 (>=v2). Read the file COPYING that comes with GRASS for details.
16 
17 @author Martin Landa <landa.martin gmail.com>
18 """
19 
20 import locale
21 
22 import wx
23 
24 from core.debug import Debug
25 from core.settings import UserSettings
26 
27 try:
28  from grass.lib.gis import *
29  from grass.lib.vector import *
30  from grass.lib.vedit import *
31 except ImportError:
32  pass
33 
34 log = None
35 progress = None
36 
37 def print_error(msg, type):
38  """!Redirect stderr"""
39  global log
40  if log:
41  log.write(msg)
42  else:
43  print msg
44 
45  return 0
46 
47 def print_progress(value):
48  """!Redirect progress info"""
49  global progress
50  if progress:
51  progress.SetValue(value)
52  else:
53  print value
54 
55  return 0
56 
57 errtype = CFUNCTYPE(UNCHECKED(c_int), String, c_int)
58 errfunc = errtype(print_error)
59 pertype = CFUNCTYPE(UNCHECKED(c_int), c_int)
60 perfunc = pertype(print_progress)
61 
63  def __init__(self, device, deviceTmp, mapObj, window, glog, gprogress):
64  """!Display driver used by vector digitizer
65 
66  @param device wx.PseudoDC device where to draw vector objects
67  @param deviceTmp wx.PseudoDC device where to draw temporary vector objects
68  @param mapOng Map Object (render.Map)
69  @param windiow parent window for dialogs
70  @param glog logging device (None to discard messages)
71  @param gprogress progress bar device (None to discard message)
72  """
73  global errfunc, perfunc, log, progress
74  log = glog
75  progress = gprogress
76 
77  G_gisinit('wxvdigit')
78  locale.setlocale(locale.LC_NUMERIC, 'C')
79  G_set_error_routine(errfunc)
80  G_set_percent_routine(perfunc)
81 
82  self.mapInfo = None # open vector map (Map_Info structure)
83  self.poMapInfo = None # pointer to self.mapInfo
84  self.is3D = False # is open vector map 3D
85 
86  self.dc = device # PseudoDC devices
87  self.dcTmp = deviceTmp
88  self.mapObj = mapObj
89  self.region = mapObj.GetCurrentRegion()
90  self.window = window
91  self.log = log # log device
92 
93  self.firstNode = True # track PseudoDC Id of selected features
94  self.lastNodeId = -1
95 
96  # GRASS lib
99 
100  # selected objects
101  self.selected = {
102  'field' : -1, # field number
103  'cats' : list(), # list of cats
104  'ids' : list(), # list of ids
105  'idsDupl' : list(), # list of duplicated features
106  }
107 
108  # digitizer settings
109  self.settings = {
110  'highlight' : None,
111  'highlightDupl' : { 'enabled' : False,
112  'color' : None },
113  'point' : { 'enabled' : False,
114  'color' : None },
115  'line' : { 'enabled' : False,
116  'color' : None },
117  'boundaryNo' : { 'enabled' : False,
118  'color' : None },
119  'boundaryOne' : { 'enabled' : False,
120  'color' : None },
121  'boundaryTwo' : { 'enabled' : False,
122  'color' : None },
123  'centroidIn' : { 'enabled' : False,
124  'color' : None },
125  'centroidOut' : { 'enabled' : False,
126  'color' : None },
127  'centroidDup' : { 'enabled' : False,
128  'color' : None },
129  'nodeOne' : { 'enabled' : False,
130  'color' : None },
131  'nodeTwo' : { 'enabled' : False,
132  'color' : None },
133  'vertex' : { 'enabled' : False,
134  'color' : None },
135  'area' : { 'enabled' : False,
136  'color' : None },
137  'direction' : { 'enabled' : False,
138  'color' : None },
139  'lineWidth' : -1, # screen units
140  }
141 
142  # topology
143  self._resetTopology()
144 
145  self._drawSelected = False
146  self._drawSegments = False
147 
148  self.UpdateSettings()
149 
150  def __del__(self):
151  """!Close currently open vector map"""
154 
155  if self.poMapInfo:
156  self.CloseMap()
157 
160 
161  def _resetTopology(self):
162  """!Reset topology dict
163  """
164  self.topology = {
165  'highlight' : 0,
166  'point' : 0,
167  'line' : 0,
168  'boundaryNo' : 0,
169  'boundaryOne' : 0,
170  'boundaryTwo' : 0,
171  'centroidIn' : 0,
172  'centroidOut' : 0,
173  'centroidDup' : 0,
174  'nodeOne' : 0,
175  'nodeTwo' : 0,
176  'vertex' : 0,
177  }
178 
179  def _cell2Pixel(self, east, north, elev):
180  """!Conversion from geographic coordinates (east, north)
181  to screen (x, y)
182 
183  @todo 3D stuff...
184 
185  @param east, north, elev geographical coordinates
186 
187  @return x, y screen coordinates (integer)
188  """
189  map_res = max(self.region['ewres'], self.region['nsres'])
190  w = self.region['center_easting'] - (self.mapObj.width / 2) * map_res
191  n = self.region['center_northing'] + (self.mapObj.height / 2) * map_res
192 
193  return int((east - w) / map_res), int((n - north) / map_res)
194 
195  def _drawCross(self, pdc, point, size = 5):
196  """!Draw cross symbol of given size to device content
197 
198  Used for points, nodes, vertices
199 
200  @param[in,out] PseudoDC where to draw
201  @param point coordinates of center
202  @param size size of the cross symbol
203 
204  @return 0 on success
205  @return -1 on failure
206  """
207  if not pdc or not point:
208  return -1
209 
210  pdc.DrawLine(point.x - size, point.y, point.x + size, point.y)
211  pdc.DrawLine(point.x, point.y - size, point.x, point.y + size)
212 
213  return 0
214 
215  def _drawObject(self, robj):
216  """!Draw given object to the device
217 
218  The object is defined as robject() from vedit.h.
219 
220  @param robj object to be rendered
221 
222  @return 1 on success
223  @return -1 on failure (vector feature marked as dead, etc.)
224  """
225  if not self.dc or not self.dcTmp:
226  return -1
227 
228  Debug.msg(3, "_drawObject(): line=%d type=%d npoints=%d", robj.fid, robj.type, robj.npoints)
229  brush = None
230  if self._isSelected(robj.fid):
231  pdc = self.dcTmp
232  if robj.type == TYPE_AREA:
233  return 1
234  else:
235  if self.settings['highlightDupl']['enabled'] and self._isDuplicated(robj.fid):
236  pen = wx.Pen(self.settings['highlightDupl']['color'], self.settings['lineWidth'], wx.SOLID)
237  else:
238  pen = wx.Pen(self.settings['highlight'], self.settings['lineWidth'], wx.SOLID)
239 
240  dcId = 1
241  self.topology['highlight'] += 1
242  if not self._drawSelected:
243  return
244  else:
245  pdc = self.dc
246  pen, brush = self._definePen(robj.type)
247  dcId = 0
248 
249  pdc.SetPen(pen)
250  if brush:
251  pdc.SetBrush(brush)
252 
253  if robj.type & (TYPE_POINT | TYPE_CENTROIDIN | TYPE_CENTROIDOUT | TYPE_CENTROIDDUP |
254  TYPE_NODEONE | TYPE_NODETWO | TYPE_VERTEX): # -> point
255  if dcId > 0:
256  if robj.type == TYPE_VERTEX:
257  dcId = 3 # first vertex
258  elif robj.type & (TYPE_NODEONE | TYPE_NODETWO):
259  if self.firstNode:
260  dcId = 1
261  self.firstNode = False
262  else:
263  dcId = self.lastNodeId
264 
265  for i in range(robj.npoints):
266  p = robj.point[i]
267  if dcId > 0:
268  pdc.SetId(dcId)
269  dcId += 2
270  self._drawCross(pdc, p)
271  else:
272  if dcId > 0 and self._drawSegments:
273  self.fisrtNode = True
274  self.lastNodeId = robj.npoints * 2 - 1
275  dcId = 2 # first segment
276  i = 0
277  while i < robj.npoints - 1:
278  point_beg = wx.Point(robj.point[i].x, robj.point[i].y)
279  point_end = wx.Point(robj.point[i+1].x, robj.point[i+1].y)
280  pdc.SetId(dcId) # set unique id & set bbox for each segment
281  pdc.SetPen(pen)
282  pdc.SetIdBounds(dcId - 1, wx.Rect(point_beg.x, point_beg.y, 0, 0))
283  pdc.SetIdBounds(dcId, wx.RectPP(point_beg, point_end))
284  pdc.DrawLine(point_beg.x, point_beg.y,
285  point_end.x, point_end.y)
286  i += 1
287  dcId += 2
288  pdc.SetIdBounds(dcId - 1, wx.Rect(robj.point[robj.npoints - 1].x,
289  robj.point[robj.npoints - 1].y,
290  0, 0))
291  else:
292  points = list()
293  for i in range(robj.npoints):
294  p = robj.point[i]
295  points.append(wx.Point(p.x, p.y))
296 
297  if robj.type == TYPE_AREA:
298  pdc.DrawPolygon(points)
299  else:
300  pdc.DrawLines(points)
301 
302  def _definePen(self, rtype):
303  """!Define pen/brush based on rendered object)
304 
305  Updates also self.topology dict
306 
307  @return pen, brush
308  """
309  if rtype == TYPE_POINT:
310  key = 'point'
311  elif rtype == TYPE_LINE:
312  key = 'line'
313  elif rtype == TYPE_BOUNDARYNO:
314  key = 'boundaryNo'
315  elif rtype == TYPE_BOUNDARYTWO:
316  key = 'boundaryTwo'
317  elif rtype == TYPE_BOUNDARYONE:
318  key = 'boundaryOne'
319  elif rtype == TYPE_CENTROIDIN:
320  key = 'centroidIn'
321  elif rtype == TYPE_CENTROIDOUT:
322  key = 'centroidOut'
323  elif rtype == TYPE_CENTROIDDUP:
324  key = 'centroidDup'
325  elif rtype == TYPE_NODEONE:
326  key = 'nodeOne'
327  elif rtype == TYPE_NODETWO:
328  key = 'nodeTwo'
329  elif rtype == TYPE_VERTEX:
330  key = 'vertex'
331  elif rtype == TYPE_AREA:
332  key = 'area'
333  elif rtype == TYPE_ISLE:
334  key = 'isle'
335  elif rtype == TYPE_DIRECTION:
336  key = 'direction'
337 
338  if key not in ('direction', 'area', 'isle'):
339  self.topology[key] += 1
340 
341  if key in ('area', 'isle'):
342  pen = wx.TRANSPARENT_PEN
343  if key == 'area':
344  brush = wx.Brush(self.settings[key]['color'], wx.SOLID)
345  else:
346  brush = wx.TRANSPARENT_BRUSH
347  else:
348  pen = wx.Pen(self.settings[key]['color'], self.settings['lineWidth'], wx.SOLID)
349  brush = None
350 
351  return pen, brush
352 
353  def _getDrawFlag(self):
354  """!Get draw flag from the settings
355 
356  See vedit.h for list of draw flags.
357 
358  @return draw flag (int)
359  """
360  ret = 0
361  if self.settings['point']['enabled']:
362  ret |= DRAW_POINT
363  if self.settings['line']['enabled']:
364  ret |= DRAW_LINE
365  if self.settings['boundaryNo']['enabled']:
366  ret |= DRAW_BOUNDARYNO
367  if self.settings['boundaryTwo']['enabled']:
368  ret |= DRAW_BOUNDARYTWO
369  if self.settings['boundaryOne']['enabled']:
370  ret |= DRAW_BOUNDARYONE
371  if self.settings['centroidIn']['enabled']:
372  ret |= DRAW_CENTROIDIN
373  if self.settings['centroidOut']['enabled']:
374  ret |= DRAW_CENTROIDOUT
375  if self.settings['centroidDup']['enabled']:
376  ret |= DRAW_CENTROIDDUP
377  if self.settings['nodeOne']['enabled']:
378  ret |= DRAW_NODEONE
379  if self.settings['nodeTwo']['enabled']:
380  ret |= DRAW_NODETWO
381  if self.settings['vertex']['enabled']:
382  ret |= DRAW_VERTEX
383  if self.settings['area']['enabled']:
384  ret |= DRAW_AREA
385  if self.settings['direction']['enabled']:
386  ret |= DRAW_DIRECTION
387 
388  return ret
389 
390  def _isSelected(self, line, force = False):
391  """!Check if vector object selected?
392 
393  @param line feature id
394 
395  @return True if vector object is selected
396  @return False if vector object is not selected
397  """
398  if line in self.selected['ids']:
399  return True
400 
401  return False
402 
403  def _isDuplicated(self, line):
404  """!Check for already marked duplicates
405 
406  @param line feature id
407 
408  @return True line already marked as duplicated
409  @return False not duplicated
410  """
411  return line in self.selected['idsDupl']
412 
413  def _getRegionBox(self):
414  """!Get bound_box() from current region
415 
416  @return bound_box
417  """
418  box = bound_box()
419 
420  box.N = self.region['n']
421  box.S = self.region['s']
422  box.E = self.region['e']
423  box.W = self.region['w']
424  box.T = PORT_DOUBLE_MAX
425  box.B = -PORT_DOUBLE_MAX
426 
427  return box
428 
429  def DrawMap(self, force = False):
430  """!Draw content of the vector map to the device
431 
432  @param force force drawing
433  @return number of drawn features
434  @return -1 on error
435  """
436  Debug.msg(1, "DisplayDriver.DrawMap(): force=%d", force)
437 
438  if not self.poMapInfo or not self.dc or not self.dcTmp:
439  return -1
440 
441  rlist = Vedit_render_map(self.poMapInfo, byref(self._getRegionBox()), self._getDrawFlag(),
442  self.region['center_easting'], self.region['center_northing'],
443  self.mapObj.width, self.mapObj.height,
444  max(self.region['nsres'], self.region['ewres'])).contents
445 
446  self._resetTopology()
447 
448  self.dc.BeginDrawing()
449  self.dcTmp.BeginDrawing()
450 
451  # draw objects
452  for i in range(rlist.nitems):
453  robj = rlist.item[i].contents
454  self._drawObject(robj)
455 
456  self.dc.EndDrawing()
457  self.dcTmp.EndDrawing()
458 
459  # reset list of selected features by cat
460  # list of ids - see IsSelected()
461  self.selected['field'] = -1
462  self.selected['cats'] = list()
463 
464  def _getSelectType(self):
465  """!Get type(s) to be selected
466 
467  Used by SelectLinesByBox() and SelectLineByPoint()
468  """
469  ftype = 0
470  for feature in (('point', GV_POINT),
471  ('line', GV_LINE),
472  ('centroid', GV_CENTROID),
473  ('boundary', GV_BOUNDARY)):
474  if UserSettings.Get(group = 'vdigit', key = 'selectType',
475  subkey = [feature[0], 'enabled']):
476  ftype |= feature[1]
477 
478  return ftype
479 
480  def _validLine(self, line):
481  """!Check if feature id is valid
482 
483  @param line feature id
484 
485  @return True valid feature id
486  @return False invalid
487  """
488  if line > 0 and line <= Vect_get_num_lines(self.poMapInfo):
489  return True
490 
491  return False
492 
493  def SelectLinesByBox(self, bbox, drawSeg = False, poMapInfo = None):
494  """!Select vector objects by given bounding box
495 
496  If line id is already in the list of selected lines, then it will
497  be excluded from this list.
498 
499  @param bbox bounding box definition
500  @param drawSeg True to draw segments of line
501  @param poMapInfo use external Map_info, None for self.poMapInfo
502 
503  @return number of selected features
504  @return None on error
505  """
506  thisMapInfo = poMapInfo is None
507  if not poMapInfo:
508  poMapInfo = self.poMapInfo
509 
510  if not poMapInfo:
511  return None
512 
513  if thisMapInfo:
514  self._drawSegments = drawSeg
515  self._drawSelected = True
516 
517  # select by ids
518  self.selected['cats'] = list()
519 
520  poList = Vect_new_list()
521  x1, y1 = bbox[0]
522  x2, y2 = bbox[1]
523  poBbox = Vect_new_line_struct()
524  Vect_append_point(poBbox, x1, y1, 0.0)
525  Vect_append_point(poBbox, x2, y1, 0.0)
526  Vect_append_point(poBbox, x2, y2, 0.0)
527  Vect_append_point(poBbox, x1, y2, 0.0)
528  Vect_append_point(poBbox, x1, y1, 0.0)
529 
530  Vect_select_lines_by_polygon(poMapInfo, poBbox,
531  0, None, # isles
532  self._getSelectType(), poList)
533 
534  flist = poList.contents
535  nlines = flist.n_values
536  Debug.msg(1, "DisplayDriver.SelectLinesByBox() num = %d", nlines)
537  for i in range(nlines):
538  line = flist.value[i]
539  if UserSettings.Get(group = 'vdigit', key = 'selectInside',
540  subkey = 'enabled'):
541  inside = True
542  if not self._validLine(line):
543  return None
544  Vect_read_line(poMapInfo, self.poPoints, None, line)
545  points = self.poPoints.contents
546  for p in range(points.n_points):
547  if not Vect_point_in_poly(points.x[p], points.y[p],
548  poBbox):
549  inside = False
550  break
551 
552  if not inside:
553  continue # skip lines just overlapping bbox
554 
555  if not self._isSelected(line):
556  self.selected['ids'].append(line)
557  else:
558  self.selected['ids'].remove(line)
559 
561  Vect_destroy_list(poList)
562 
563  return nlines
564 
565  def SelectLineByPoint(self, point, poMapInfo = None):
566  """!Select vector feature by given point in given
567  threshold
568 
569  Only one vector object can be selected. Bounding boxes of
570  all segments are stores.
571 
572  @param point points coordinates (x, y)
573  @param poMapInfo use external Map_info, None for self.poMapInfo
574 
575  @return dict {'line' : feature id, 'point' : point on line}
576  """
577  thisMapInfo = poMapInfo is None
578  if not poMapInfo:
579  poMapInfo = self.poMapInfo
580 
581  if not poMapInfo:
582  return { 'line' : -1, 'point': None }
583 
584  if thisMapInfo:
585  self._drawSelected = True
586  # select by ids
587  self.selected['cats'] = list()
588 
589  poFound = Vect_new_list()
590 
591  lineNearest = Vect_find_line_list(poMapInfo, point[0], point[1], 0,
592  self._getSelectType(), self.GetThreshold(), self.is3D,
593  None, poFound)
594  Debug.msg(1, "DisplayDriver.SelectLineByPoint() found = %d", lineNearest)
595 
596  if lineNearest > 0:
597  if not self._isSelected(lineNearest):
598  self.selected['ids'].append(lineNearest)
599  else:
600  self.selected['ids'].remove(lineNearest)
601 
602  px = c_double()
603  py = c_double()
604  pz = c_double()
605  if not self._validLine(lineNearest):
606  return { 'line' : -1, 'point': None }
607  ftype = Vect_read_line(poMapInfo, self.poPoints, self.poCats, lineNearest)
608  Vect_line_distance (self.poPoints, point[0], point[1], 0.0, self.is3D,
609  byref(px), byref(py), byref(pz),
610  None, None, None)
611 
612  # check for duplicates
613  if self.settings['highlightDupl']['enabled']:
614  found = poFound.contents
615  for i in range(found.n_values):
616  line = found.value[i]
617  if line != lineNearest:
618  self.selected['ids'].append(line)
619 
620  self.GetDuplicates()
621 
622  for i in range(found.n_values):
623  line = found.value[i]
624  if line != lineNearest and not self._isDuplicated(line):
625  self.selected['ids'].remove(line)
626 
627  Vect_destroy_list(poFound)
628 
629  if thisMapInfo:
630  # drawing segments can be very expensive
631  # only one features selected
632  self._drawSegments = True
633 
634  return { 'line' : lineNearest,
635  'point' : (px.value, py.value, pz.value) }
636 
637  def _listToIList(self, plist):
638  """!Generate from list struct_ilist
639  """
640  ilist = Vect_new_list()
641  for val in plist:
642  Vect_list_append(ilist, val)
643 
644  return ilist
645 
646  def GetSelectedIList(self, ilist = None):
647  """!Get list of selected objects as struct_ilist
648 
649  Returned IList must be freed by Vect_destroy_list().
650 
651  @return struct_ilist
652  """
653  if ilist:
654  return self._listToIList(ilist)
655 
656  return self._listToIList(self.selected['ids'])
657 
658  def GetSelected(self, grassId = True):
659  """!Get ids of selected objects
660 
661  @param grassId True for feature id, False for PseudoDC id
662 
663  @return list of ids of selected vector objects
664  """
665  if grassId:
666  return self.selected['ids']
667 
668  dc_ids = list()
669 
670  if not self._drawSegments:
671  dc_ids.append(1)
672  elif len(self.selected['ids']) > 0:
673  # only first selected feature
674  Vect_read_line(self.poMapInfo, self.poPoints, None,
675  self.selected['ids'][0])
676  points = self.poPoints.contents
677  # node - segment - vertex - segment - node
678  for i in range(1, 2 * points.n_points):
679  dc_ids.append(i)
680 
681  return dc_ids
682 
683  def SetSelected(self, ids, layer = -1):
684  """!Set selected vector objects
685 
686  @param list of ids (None to unselect features)
687  @param layer layer number for features selected based on category number
688  """
689  if ids:
690  self._drawSelected = True
691  else:
692  self._drawSelected = False
693 
694  self.selected['field'] = layer
695  if layer > 0:
696  self.selected['cats'] = ids
697  self.selected['ids'] = list()
698  ### cidx is not up-to-date
699  # Vect_cidx_find_all(self.poMapInfo, layer, GV_POINTS | GV_LINES, lid, ilist)
700  nlines = Vect_get_num_lines(self.poMapInfo)
701  for line in range(1, nlines + 1):
702  if not Vect_line_alive(self.poMapInfo, line):
703  continue
704 
705  ltype = Vect_read_line (self.poMapInfo, None, self.poCats, line)
706  if not (ltype & (GV_POINTS | GV_LINES)):
707  continue
708 
709  found = False
710  cats = self.poCats.contents
711  for i in range(0, cats.n_cats):
712  for cat in self.selected['cats']:
713  if cats.cat[i] == cat:
714  found = True
715  break
716  if found:
717  self.selected['ids'].append(line)
718  else:
719  self.selected['ids'] = ids
720  self.selected['cats'] = []
721 
722  def GetSelectedVertex(self, pos):
723  """!Get PseudoDC vertex id of selected line
724 
725  Set bounding box for vertices of line.
726 
727  @param pos position
728 
729  @return id of center, left and right vertex
730  @return 0 no line found
731  @return -1 on error
732  """
733  returnId = list()
734  # only one object can be selected
735  if len(self.selected['ids']) != 1 or not self._drawSegments:
736  return returnId
737 
738  startId = 1
739  line = self.selected['ids'][0]
740 
741  if not self._validLine(line):
742  return -1
743  ftype = Vect_read_line(self.poMapInfo, self.poPoints, self.poCats, line)
744 
745  minDist = 0.0
746  Gid = -1
747  # find the closest vertex (x, y)
748  DCid = 1
749  points = self.poPoints.contents
750  for idx in range(points.n_points):
751  dist = Vect_points_distance(pos[0], pos[1], 0.0,
752  points.x[idx], points.y[idx], points.z[idx], 0)
753 
754  if idx == 0:
755  minDist = dist
756  Gid = idx
757  else:
758  if minDist > dist:
759  minDist = dist
760  Gid = idx
761 
762  vx, vy = self._cell2Pixel(points.x[idx], points.y[idx], points.z[idx])
763  rect = wx.Rect(vx, vy, 0, 0)
764  self.dc.SetIdBounds(DCid, rect)
765  DCid += 2
766 
767  if minDist > self.GetThreshold():
768  return returnId
769 
770  # translate id
771  DCid = Gid * 2 + 1
772 
773  # add selected vertex
774  returnId.append(DCid)
775  # left vertex
776  if DCid == startId:
777  returnId.append(-1)
778  else:
779  returnId.append(DCid - 2)
780  # right vertex
781  if DCid == (points.n_points - 1) * 2 + startId:
782  returnId.append(-1)
783  else:
784  returnId.append(DCid + 2)
785 
786  return returnId
787 
788  def GetRegionSelected(self):
789  """!Get minimal region extent of selected features
790 
791  @return n,s,w,e
792  """
793  regionBox = bound_box()
794  lineBox = bound_box()
795  setRegion = True
796 
797  nareas = Vect_get_num_areas(self.poMapInfo)
798  for line in self.selected['ids']:
799  area = Vect_get_centroid_area(self.poMapInfo, line)
800 
801  if area > 0 and area <= nareas:
802  if not Vect_get_area_box(self.poMapInfo, area, byref(lineBox)):
803  continue
804  else:
805  if not Vect_get_line_box(self.poMapInfo, line, byref(lineBox)):
806  continue
807 
808  if setRegion:
809  Vect_box_copy(byref(regionBox), byref(lineBox))
810  setRegion = False
811  else:
812  Vect_box_extend(byref(regionBox), byref(lineBox))
813 
814  return regionBox.N, regionBox.S, regionBox.W, regionBox.E
815 
816  def DrawSelected(self, flag):
817  """!Draw selected features
818 
819  @param flag True to draw selected features
820  """
821  self._drawSelected = bool(flag)
822 
823  def CloseMap(self):
824  """!Close vector map
825 
826  @return 0 on success
827  @return non-zero on error
828  """
829  ret = 0
830  if self.poMapInfo:
831  # rebuild topology
832  Vect_build_partial(self.poMapInfo, GV_BUILD_NONE)
833  Vect_build(self.poMapInfo)
834 
835  # close map and store topo/cidx
836  ret = Vect_close(self.poMapInfo)
837  del self.mapInfo
838  self.poMapInfo = self.mapInfo = None
839 
840  return ret
841 
842  def OpenMap(self, name, mapset, update = True):
843  """!Open vector map by the driver
844 
845  @param name name of vector map to be open
846  @param mapset name of mapset where the vector map lives
847 
848  @return map_info
849  @return None on error
850  """
851  Debug.msg("DisplayDriver.OpenMap(): name=%s mapset=%s updated=%d",
852  name, mapset, update)
853  if not self.mapInfo:
854  self.mapInfo = Map_info()
855  self.poMapInfo = pointer(self.mapInfo)
856 
857  # open existing map
858  if update:
859  ret = Vect_open_update(self.poMapInfo, name, mapset)
860  else:
861  ret = Vect_open_old(self.poMapInfo, name, mapset)
862  self.is3D = Vect_is_3d(self.poMapInfo)
863 
864  if ret == -1: # error
865  del self.mapInfo
866  self.poMapInfo = self.mapInfo = None
867  elif ret < 2:
868  dlg = wx.MessageDialog(parent = self.window,
869  message = _("Topology for vector map <%s> is not available. "
870  "Topology is required by digitizer. Do you want to "
871  "rebuild topology (takes some time) and open the vector map "
872  "for editing?") % name,
873  caption=_("Topology missing"),
874  style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION | wx.CENTRE)
875  ret = dlg.ShowModal()
876  if ret != wx.ID_YES:
877  del self.mapInfo
878  self.poMapInfo = self.mapInfo = None
879  else:
880  Vect_build(self.poMapInfo)
881 
882  return self.poMapInfo
883 
884  def GetMapBoundingBox(self):
885  """!Get bounding box of (opened) vector map layer
886 
887  @return (w,s,b,e,n,t)
888  """
889  if not self.poMapInfo:
890  return None
891 
892  bbox = bound_box()
893  Vect_get_map_box(self.poMapInfo, byref(bbox))
894 
895  return bbox.W, bbox.S, bbox.B, \
896  bbox.E, bbox.N, bbox.T
897 
898  def UpdateSettings(self, alpha = 255):
899  """!Update display driver settings
900 
901  @todo map units
902 
903  @alpha color value for aplha channel
904  """
905  color = dict()
906  for key in self.settings.keys():
907  if key == 'lineWidth':
908  self.settings[key] = int(UserSettings.Get(group = 'vdigit', key = 'lineWidth',
909  subkey = 'value'))
910  continue
911 
912  color = wx.Colour(UserSettings.Get(group = 'vdigit', key = 'symbol',
913  subkey = [key, 'color'])[0],
914  UserSettings.Get(group = 'vdigit', key = 'symbol',
915  subkey = [key, 'color'])[1],
916  UserSettings.Get(group = 'vdigit', key = 'symbol',
917  subkey = [key, 'color'])[2],
918  alpha)
919 
920  if key == 'highlight':
921  self.settings[key] = color
922  continue
923 
924  if key == 'highlightDupl':
925  self.settings[key]['enabled'] = bool(UserSettings.Get(group = 'vdigit', key = 'checkForDupl',
926  subkey = 'enabled'))
927  else:
928  self.settings[key]['enabled'] = bool(UserSettings.Get(group = 'vdigit', key = 'symbol',
929  subkey = [key, 'enabled']))
930 
931  self.settings[key]['color'] = color
932 
933  def UpdateRegion(self):
934  """!Update geographical region used by display driver
935  """
936  self.region = self.mapObj.GetCurrentRegion()
937 
938  def GetThreshold(self, type = 'snapping', value = None, units = None):
939  """!Return threshold value in map units
940 
941  @param type snapping mode (node, vertex)
942  @param value threshold to be set up
943  @param units units (map, screen)
944 
945  @return threshold value
946  """
947  if value is None:
948  value = UserSettings.Get(group = 'vdigit', key = type, subkey = 'value')
949 
950  if units is None:
951  units = UserSettings.Get(group = 'vdigit', key = type, subkey = 'units')
952 
953  if value < 0:
954  value = (self.region['nsres'] + self.region['ewres']) / 2.0
955 
956  if units == "screen pixels":
957  # pixel -> cell
958  res = max(self.region['nsres'], self.region['ewres'])
959  return value * res
960 
961  return value
962 
963  def GetDuplicates(self):
964  """!Return ids of (selected) duplicated vector features
965  """
966  if not self.poMapInfo:
967  return
968 
969  ids = dict()
970  APoints = Vect_new_line_struct()
971  BPoints = Vect_new_line_struct()
972 
973  self.selected['idsDupl'] = list()
974 
975  for i in range(len(self.selected['ids'])):
976  line1 = self.selected['ids'][i]
977  if self._isDuplicated(line1):
978  continue
979 
980  Vect_read_line(self.poMapInfo, APoints, None, line1)
981 
982  for line2 in self.selected['ids']:
983  if line1 == line2 or self._isDuplicated(line2):
984  continue
985 
986  Vect_read_line(self.poMapInfo, BPoints, None, line2)
987 
988  if Vect_line_check_duplicate(APoints, BPoints, WITHOUT_Z):
989  if i not in ids:
990  ids[i] = list()
991  ids[i].append((line1, self._getCatString(line1)))
992  self.selected['idsDupl'].append(line1)
993 
994  ids[i].append((line2, self._getCatString(line2)))
995  self.selected['idsDupl'].append(line2)
996 
997  Vect_destroy_line_struct(APoints)
998  Vect_destroy_line_struct(BPoints)
999 
1000  return ids
1001 
1002  def _getCatString(self, line):
1003  Vect_read_line(self.poMapInfo, None, self.poCats, line)
1004 
1005  cats = self.poCats.contents
1006  catsDict = dict()
1007  for i in range(cats.n_cats):
1008  layer = cats.field[i]
1009  if layer not in catsDict:
1010  catsDict[layer] = list()
1011  catsDict[layer].append(cats.cat[i])
1012 
1013  catsStr = ''
1014  for l, c in catsDict.iteritems():
1015  catsStr = '%d: (%s)' % (l, ','.join(map(str, c)))
1016 
1017  return catsStr
1018 
1019  def UnSelect(self, lines):
1020  """!Unselect vector features
1021 
1022  @param lines list of feature id(s)
1023  """
1024  checkForDupl = False
1025 
1026  for line in lines:
1027  if self._isSelected(line):
1028  self.selected['ids'].remove(line)
1029  if self.settings['highlightDupl']['enabled'] and self._isDuplicated(line):
1030  checkForDupl = True
1031 
1032  if checkForDupl:
1033  self.GetDuplicates()
1034 
1035  return len(self.selected['ids'])
def _cell2Pixel
Conversion from geographic coordinates (east, north) to screen (x, y)
Definition: wxdisplay.py:179
def _isSelected
Check if vector object selected?
Definition: wxdisplay.py:390
def _drawCross
Draw cross symbol of given size to device content.
Definition: wxdisplay.py:195
int Vect_destroy_list(struct ilist *list)
Frees all memory associated with a struct ilist, including the struct itself.
def _validLine
Check if feature id is valid.
Definition: wxdisplay.py:480
int G_unset_error_routine(void)
After this call subsequent error messages will be handled in the default method.
def _getRegionBox
Get bound_box() from current region.
Definition: wxdisplay.py:413
def GetSelectedIList
Get list of selected objects as struct_ilist.
Definition: wxdisplay.py:646
def print_progress
Redirect progress info.
Definition: wxdisplay.py:47
def _drawObject
Draw given object to the device.
Definition: wxdisplay.py:215
struct line_pnts * Vect_new_line_struct()
Creates and initializes a struct line_pnts.
Definition: line.c:57
def __init__
Display driver used by vector digitizer.
Definition: wxdisplay.py:63
wxGUI debugging
struct ilist * Vect_new_list(void)
Creates and initializes a struct ilist.
def DrawMap
Draw content of the vector map to the device.
Definition: wxdisplay.py:429
int Vect_find_line_list(struct Map_info *map, double ux, double uy, double uz, int type, double maxdist, int with_z, struct ilist *exclude, struct ilist *found)
Find the nearest line(s).
int G_set_error_routine(int(*error_routine)(const char *, int))
Establishes error_routine as the routine that will handle the printing of subsequent error messages...
tuple pertype
Definition: wxdisplay.py:59
int Vect_get_num_areas(struct Map_info *map)
Get number of areas in vector map.
Definition: level_two.c:81
tuple errtype
Definition: wxdisplay.py:57
def CloseMap
Close vector map.
Definition: wxdisplay.py:823
int Vect_get_area_box(struct Map_info *Map, int area, BOUND_BOX *Box)
Get boundary box of area.
Definition: Vlib/box.c:247
void G_set_percent_routine(int(*percent_routine)(int))
Establishes percent_routine as the routine that will handle the printing of percentage progress messa...
Definition: percent.c:166
#define max(x, y)
Definition: draw2.c:69
def _isDuplicated
Check for already marked duplicates.
Definition: wxdisplay.py:403
def _resetTopology
Reset topology dict.
Definition: wxdisplay.py:161
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
def UnSelect
Unselect vector features.
Definition: wxdisplay.py:1019
def SelectLinesByBox
Select vector objects by given bounding box.
Definition: wxdisplay.py:493
def print_error
Redirect stderr.
Definition: wxdisplay.py:37
int Vect_is_3d(struct Map_info *Map)
Check if vector map is 3D (with z)
int Vect_box_extend(BOUND_BOX *A, BOUND_BOX *B)
Extend box A by box B.
Definition: Vlib/box.c:93
def SetSelected
Set selected vector objects.
Definition: wxdisplay.py:683
int Vect_build(struct Map_info *Map)
Build topology for vector map.
Definition: build.c:53
def _definePen
Define pen/brush based on rendered object)
Definition: wxdisplay.py:302
def GetThreshold
Return threshold value in map units.
Definition: wxdisplay.py:938
int Vect_open_update(struct Map_info *Map, const char *name, const char *mapset)
Open existing vector for reading/writing.
struct robject_list * Vedit_render_map(struct Map_info *Map, struct bound_box *box, int draw_flag, double center_easting, double center_northing, int map_width, int map_height, double map_res)
Render vector features into list.
int Vect_box_copy(BOUND_BOX *A, BOUND_BOX *B)
Copy box B to box A.
Definition: Vlib/box.c:72
def __del__
Close currently open vector map.
Definition: wxdisplay.py:150
int Vect_destroy_cats_struct(struct line_cats *p)
Frees all memory associated with line_cats structure, including the struct itself.
void G_unset_percent_routine(void)
After this call subsequent percentage progress messages will be handled in the default method...
Definition: percent.c:177
int Vect_list_append(struct ilist *list, int val)
Append new item to the end of list if not yet present.
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.
def UpdateSettings
Update display driver settings.
Definition: wxdisplay.py:898
int Vect_get_map_box(struct Map_info *Map, BOUND_BOX *Box)
Get boundary box of map.
Definition: Vlib/box.c:323
def OpenMap
Open vector map by the driver.
Definition: wxdisplay.py:842
int Vect_open_old(struct Map_info *Map, const char *name, const char *mapset)
Open existing vector for reading.
int Vect_line_alive(struct Map_info *Map, int line)
Check if feature is alive or dead.
def _getDrawFlag
Get draw flag from the settings.
Definition: wxdisplay.py:353
int Vect_close(struct Map_info *Map)
Close vector data file.
Definition: close.c:64
int Vect_point_in_poly(double X, double Y, struct line_pnts *Points)
Determines if a point (X,Y) is inside a polygon.
Definition: Vlib/poly.c:665
struct line_cats * Vect_new_cats_struct()
Creates and initializes line_cats structure.
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 Vect_line_check_duplicate(const struct line_pnts *APoints, const struct line_pnts *BPoints, int with_z)
Check for duplicate lines.
def _getSelectType
Get type(s) to be selected.
Definition: wxdisplay.py:464
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 SelectLineByPoint
Select vector feature by given point in given threshold.
Definition: wxdisplay.py:565
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
def GetSelectedVertex
Get PseudoDC vertex id of selected line.
Definition: wxdisplay.py:722
Default GUI settings.
def GetSelected
Get ids of selected objects.
Definition: wxdisplay.py:658
def DrawSelected
Draw selected features.
Definition: wxdisplay.py:816
def GetDuplicates
Return ids of (selected) duplicated vector features.
Definition: wxdisplay.py:963
def _listToIList
Generate from list struct_ilist.
Definition: wxdisplay.py:637
tuple range
Definition: tools.py:1406
def UpdateRegion
Update geographical region used by display driver.
Definition: wxdisplay.py:933
def GetRegionSelected
Get minimal region extent of selected features.
Definition: wxdisplay.py:788
def GetMapBoundingBox
Get bounding box of (opened) vector map layer.
Definition: wxdisplay.py:884
int Vect_build_partial(struct Map_info *Map, int build)
Build partial topology for vector map.
Definition: build.c:107
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
int Vect_read_line(struct Map_info *Map, struct line_pnts *line_p, struct line_cats *line_c, int line)
Read vector feature.