1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003 |
- """!
- @package wxvdriver.py
- @brief wxGUI vector digitizer (display driver)
- Code based on wxVdigit C++ component from GRASS 6.4.0
- (gui/wxpython/vdigit). Converted to Python in 2010/12-2011/01.
- List of classes:
- - DisplayDriver
- (C) 2007-2011 by the GRASS Development Team
- This program is free software under the GNU General Public License
- (>=v2). Read the file COPYING that comes with GRASS for details.
- @author Martin Landa <landa.martin gmail.com>
- """
- import math
- import wx
- from debug import Debug
- from preferences import globalSettings as UserSettings
- from grass.lib.grass import *
- from grass.lib.vector import *
- from grass.lib.vedit import *
- log = None
- progress = None
- def print_error(msg, type):
- """!Redirect stderr"""
- global log
- if log:
- log.write(msg)
- else:
- print msg
-
- return 0
- def print_progress(value):
- """!Redirect progress info"""
- global progress
- if progress:
- progress.SetValue(value)
- else:
- print value
-
- return 0
- errtype = CFUNCTYPE(UNCHECKED(c_int), String, c_int)
- errfunc = errtype(print_error)
- pertype = CFUNCTYPE(UNCHECKED(c_int), c_int)
- perfunc = pertype(print_progress)
- class DisplayDriver:
- def __init__(self, device, deviceTmp, mapObj, window, glog, gprogress):
- """!Display driver used by vector digitizer
-
- @param device wx.PseudoDC device where to draw vector objects
- @param deviceTmp wx.PseudoDC device where to draw temporary vector objects
- @param mapOng Map Object (render.Map)
- @param windiow parent window for dialogs
- @param glog logging device (None to discard messages)
- @param gprogress progress bar device (None to discard message)
- """
- global errfunc, perfunc, log, progress
- log = glog
- progress = gprogress
-
- G_gisinit('') # initialize GRASS libs
- G_set_error_routine(errfunc)
- G_set_percent_routine(perfunc)
-
- self.mapInfo = None # open vector map (Map_Info structure)
- self.poMapInfo = None # pointer to self.mapInfo
- self.is3D = False # is open vector map 3D
-
- self.dc = device # PseudoDC devices
- self.dcTmp = deviceTmp
- self.mapObj = mapObj
- self.region = mapObj.GetCurrentRegion()
- self.window = window
- self.log = log # log device
- self.firstNode = True # track PseudoDC Id of selected features
- self.lastNodeId = -1
-
- # GRASS lib
- self.poPoints = Vect_new_line_struct()
- self.poCats = Vect_new_cats_struct()
-
- # selected objects
- self.selected = {
- 'field' : -1, # field number
- 'cats' : list(), # list of cats
- 'ids' : list(), # list of ids
- 'idsDupl' : list(), # list of duplicated features
- }
-
- # digitizer settings
- self.settings = {
- 'highlight' : None,
- 'highlightDupl' : { 'enabled' : False,
- 'color' : None },
- 'point' : { 'enabled' : False,
- 'color' : None },
- 'line' : { 'enabled' : False,
- 'color' : None },
- 'boundaryNo' : { 'enabled' : False,
- 'color' : None },
- 'boundaryOne' : { 'enabled' : False,
- 'color' : None },
- 'boundaryTwo' : { 'enabled' : False,
- 'color' : None },
- 'centroidIn' : { 'enabled' : False,
- 'color' : None },
- 'centroidOut' : { 'enabled' : False,
- 'color' : None },
- 'centroidDup' : { 'enabled' : False,
- 'color' : None },
- 'nodeOne' : { 'enabled' : False,
- 'color' : None },
- 'nodeTwo' : { 'enabled' : False,
- 'color' : None },
- 'vertex' : { 'enabled' : False,
- 'color' : None },
- 'area' : { 'enabled' : False,
- 'color' : None },
- 'direction' : { 'enabled' : False,
- 'color' : None },
- 'lineWidth' : -1, # screen units
- }
-
- # topology
- self._resetTopology()
-
- self._drawSelected = False
- self._drawSegments = False
-
- self.UpdateSettings()
-
- def __del__(self):
- """!Close currently open vector map"""
- G_unset_error_routine()
- G_unset_percent_routine()
-
- if self.poMapInfo:
- self.CloseMap()
-
- Vect_destroy_line_struct(self.poPoints)
- Vect_destroy_cats_struct(self.poCats)
- def _resetTopology(self):
- """!Reset topology dict
- """
- self.topology = {
- 'highlight' : 0,
- 'point' : 0,
- 'line' : 0,
- 'boundaryNo' : 0,
- 'boundaryOne' : 0,
- 'boundaryTwo' : 0,
- 'centroidIn' : 0,
- 'centroidOut' : 0,
- 'centroidDup' : 0,
- 'nodeOne' : 0,
- 'nodeTwo' : 0,
- 'vertex' : 0,
- }
-
- def _cell2Pixel(self, east, north, elev):
- """!Conversion from geographic coordinates (east, north)
- to screen (x, y)
-
- @todo 3D stuff...
- @param east, north, elev geographical coordinates
- @return x, y screen coordinates (integer)
- """
- map_res = max(self.region['ewres'], self.region['nsres'])
- w = self.region['center_easting'] - (self.mapObj.width / 2) * map_res
- n = self.region['center_northing'] + (self.mapObj.height / 2) * map_res
-
- return int((east - w) / map_res), int((n - north) / map_res)
-
- def _drawCross(self, pdc, point, size = 5):
- """!Draw cross symbol of given size to device content
-
- Used for points, nodes, vertices
- @param[in,out] PseudoDC where to draw
- @param point coordinates of center
- @param size size of the cross symbol
-
- @return 0 on success
- @return -1 on failure
- """
- if not pdc or not point:
- return -1
-
- pdc.DrawLine(point.x - size, point.y, point.x + size, point.y)
- pdc.DrawLine(point.x, point.y - size, point.x, point.y + size)
-
- return 0
-
- def _drawObject(self, robj):
- """!Draw given object to the device
-
- The object is defined as robject() from vedit.h.
-
- @param robj object to be rendered
-
- @return 1 on success
- @return -1 on failure (vector feature marked as dead, etc.)
- """
- if not self.dc or not self.dcTmp:
- return -1
-
- Debug.msg(3, "_drawObject(): type=%d npoints=%d", robj.type, robj.npoints)
- brush = None
- if self._isSelected(robj.fid):
- pdc = self.dcTmp
- if self.settings['highlightDupl']['enabled'] and self._isDuplicated(robj.fid):
- pen = wx.Pen(self.settings['highlightDupl']['color'], self.settings['lineWidth'], wx.SOLID)
- else:
- pen = wx.Pen(self.settings['highlight'], self.settings['lineWidth'], wx.SOLID)
-
- dcId = 1
- self.topology['highlight'] += 1
- if not self._drawSelected:
- return
- else:
- pdc = self.dc
- pen, brush = self._definePen(robj.type)
- dcId = 0
-
- pdc.SetPen(pen)
- if brush:
- pdc.SetBrush(brush)
-
- if robj.type & (TYPE_POINT | TYPE_CENTROIDIN | TYPE_CENTROIDOUT | TYPE_CENTROIDDUP |
- TYPE_NODEONE | TYPE_NODETWO | TYPE_VERTEX): # -> point
- if dcId > 0:
- if robj.type == TYPE_VERTEX:
- dcId = 3 # first vertex
- elif robj.type & (TYPE_NODEONE | TYPE_NODETWO):
- if self.firstNode:
- dcId = 1
- self.firstNode = False
- else:
- dcId = self.lastNodeId
-
- for i in range(robj.npoints):
- p = robj.point[i]
- if dcId > 0:
- pdc.SetId(dcId)
- dcId += 2
- self._drawCross(pdc, p)
- else:
- if dcId > 0 and self._drawSegments:
- self.fisrtNode = True
- self.lastNodeId = robj.npoints * 2 - 1
- dcId = 2 # first segment
- i = 0
- while i < robj.npoints - 1:
- point_beg = wx.Point(robj.point[i].x, robj.point[i].y)
- point_end = wx.Point(robj.point[i+1].x, robj.point[i+1].y)
- pdc.SetId(dcId) # set unique id & set bbox for each segment
- pdc.SetPen(pen)
- pdc.SetIdBounds(dcId - 1, wx.Rect(point_beg.x, point_beg.y, 0, 0))
- pdc.SetIdBounds(dcId, wx.RectPP(point_beg, point_end))
- pdc.DrawLine(point_beg.x, point_beg.y,
- point_end.x, point_end.y)
- i += 1
- dcId += 2
- pdc.SetIdBounds(dcId - 1, wx.Rect(robj.point[robj.npoints - 1].x,
- robj.point[robj.npoints - 1].y,
- 0, 0))
- else:
- points = list()
- for i in range(robj.npoints):
- p = robj.point[i]
- points.append(wx.Point(p.x, p.y))
-
- if robj.type == TYPE_AREA:
- pdc.DrawPolygon(points)
- else:
- pdc.DrawLines(points)
-
- def _definePen(self, rtype):
- """!Define pen/brush based on rendered object)
-
- Updates also self.topology dict
- @return pen, brush
- """
- if rtype == TYPE_POINT:
- key = 'point'
- elif rtype == TYPE_LINE:
- key = 'line'
- elif rtype == TYPE_BOUNDARYNO:
- key = 'boundaryNo'
- elif rtype == TYPE_BOUNDARYTWO:
- key = 'boundaryTwo'
- elif rtype == TYPE_BOUNDARYONE:
- key = 'boundaryOne'
- elif rtype == TYPE_CENTROIDIN:
- key = 'centroidIn'
- elif rtype == TYPE_CENTROIDOUT:
- key = 'centroidOut'
- elif rtype == TYPE_CENTROIDDUP:
- key = 'centroidDup'
- elif rtype == TYPE_NODEONE:
- key = 'nodeOne'
- elif rtype == TYPE_NODETWO:
- key = 'nodeTwo'
- elif rtype == TYPE_VERTEX:
- key = 'vertex'
- elif rtype == TYPE_AREA:
- key = 'area'
- elif rtype == TYPE_ISLE:
- key = 'isle'
- elif rtype == TYPE_DIRECTION:
- key = 'direction'
-
- if key not in ('direction', 'area', 'isle'):
- self.topology[key] += 1
-
- if key in ('area', 'isle'):
- pen = wx.TRANSPARENT_PEN
- if key == 'area':
- brush = wx.Brush(self.settings[key]['color'], wx.SOLID)
- else:
- brush = wx.TRANSPARENT_BRUSH
- else:
- pen = wx.Pen(self.settings[key]['color'], self.settings['lineWidth'], wx.SOLID)
- brush = None
-
- return pen, brush
-
- def _getDrawFlag(self):
- """!Get draw flag from the settings
-
- See vedit.h for list of draw flags.
-
- @return draw flag (int)
- """
- ret = 0
- if self.settings['point']['enabled']:
- ret |= DRAW_POINT
- if self.settings['line']['enabled']:
- ret |= DRAW_LINE
- if self.settings['boundaryNo']['enabled']:
- ret |= DRAW_BOUNDARYNO
- if self.settings['boundaryTwo']['enabled']:
- ret |= DRAW_BOUNDARYTWO
- if self.settings['boundaryOne']['enabled']:
- ret |= DRAW_BOUNDARYONE
- if self.settings['centroidIn']['enabled']:
- ret |= DRAW_CENTROIDIN
- if self.settings['centroidOut']['enabled']:
- ret |= DRAW_CENTROIDOUT
- if self.settings['centroidDup']['enabled']:
- ret |= DRAW_CENTROIDDUP
- if self.settings['nodeOne']['enabled']:
- ret |= DRAW_NODEONE
- if self.settings['nodeTwo']['enabled']:
- ret |= DRAW_NODETWO
- if self.settings['vertex']['enabled']:
- ret |= DRAW_VERTEX
- if self.settings['area']['enabled']:
- ret |= DRAW_AREA
- if self.settings['direction']['enabled']:
- ret |= DRAW_DIRECTION
-
- return ret
-
- def _isSelected(self, line, force = False):
- """!Check if vector object selected?
-
- @param line feature id
- @return True if vector object is selected
- @return False if vector object is not selected
- """
- if len(self.selected['cats']) < 1 or force:
- # select by id
- if line in self.selected['ids']:
- return True
- else:
- # select by cat
- cats = self.poCats.contents
- for i in range(cats.n_cats):
- if cats.field[i] == self.selected['field'] and \
- cats.cat[i] in self.selected['cats']:
- # remember id
- # -> after drawing all features selected.cats is reseted */
- self.selected['ids'].append(line)
- return True
-
- return False
- def _isDuplicated(self, line):
- """!Check for already marked duplicates
-
- @param line feature id
- @return True line already marked as duplicated
- @return False not duplicated
- """
- return line in self.selected['idsDupl']
-
- def _getRegionBox(self):
- """!Get bound_box() from current region
- @return bound_box
- """
- box = bound_box()
-
- box.N = self.region['n']
- box.S = self.region['s']
- box.E = self.region['e']
- box.W = self.region['w']
- box.T = PORT_DOUBLE_MAX
- box.B = -PORT_DOUBLE_MAX
-
- return box
- def DrawMap(self, force = False):
- """!Draw content of the vector map to the device
-
- @param force force drawing
- @return number of drawn features
- @return -1 on error
- """
- Debug.msg(1, "DisplayDriver.DrawMap(): force=%d", force)
-
- if not self.poMapInfo or not self.dc or not self.dcTmp:
- return -1
-
- rlist = Vedit_render_map(self.poMapInfo, byref(self._getRegionBox()), self._getDrawFlag(),
- self.region['center_easting'], self.region['center_northing'],
- self.mapObj.width, self.mapObj.height,
- max(self.region['nsres'], self.region['ewres'])).contents
-
- self._resetTopology()
-
- self.dc.BeginDrawing()
- self.dcTmp.BeginDrawing()
-
- # draw objects
- for i in range(rlist.nitems):
- robj = rlist.item[i].contents
- self._drawObject(robj)
-
- self.dc.EndDrawing()
- self.dcTmp.EndDrawing()
-
- # reset list of selected features by cat
- # list of ids - see IsSelected()
- self.selected['field'] = -1
- self.selected['cats'] = list()
-
- def _getSelectType(self):
- """!Get type(s) to be selected
- Used by SelectLinesByBox() and SelectLineByPoint()
- """
- ftype = 0
- for feature in (('point', GV_POINT),
- ('line', GV_LINE),
- ('centroid', GV_CENTROID),
- ('boundary', GV_BOUNDARY)):
- if UserSettings.Get(group = 'vdigit', key = 'selectType',
- subkey = [feature[0], 'enabled']):
- ftype |= feature[1]
-
- return ftype
- def _validLine(self, line):
- """!Check if feature id is valid
- @param line feature id
- @return True valid feature id
- @return False invalid
- """
- if line > 0 and line <= Vect_get_num_lines(self.poMapInfo):
- return True
-
- return False
-
- def SelectLinesByBox(self, bbox, drawSeg = False, poMapInfo = None):
- """!Select vector objects by given bounding box
-
- If line id is already in the list of selected lines, then it will
- be excluded from this list.
-
- @param bbox bounding box definition
- @param drawSeg True to draw segments of line
- @param poMapInfo use external Map_info, None for self.poMapInfo
- @return number of selected features
- @return None on error
- """
- thisMapInfo = poMapInfo is None
- if not poMapInfo:
- poMapInfo = self.poMapInfo
-
- if not poMapInfo:
- return None
-
- if thisMapInfo:
- self._drawSegments = drawSeg
- self._drawSelected = True
-
- # select by ids
- self.selected['cats'] = list()
-
- if thisMapInfo:
- selected = self.selected['ids']
- else:
- selected = list()
-
- poList = Vect_new_list()
- x1, y1 = bbox[0]
- x2, y2 = bbox[1]
- poBbox = Vect_new_line_struct()
- Vect_append_point(poBbox, x1, y1, 0.0)
- Vect_append_point(poBbox, x2, y1, 0.0)
- Vect_append_point(poBbox, x2, y2, 0.0)
- Vect_append_point(poBbox, x1, y2, 0.0)
- Vect_append_point(poBbox, x1, y1, 0.0)
-
- Vect_select_lines_by_polygon(poMapInfo, poBbox,
- 0, None, # isles
- self._getSelectType(), poList)
-
- flist = poList.contents
- nlines = flist.n_values
- Debug.msg(1, "DisplayDriver.SelectLinesByBox() num = %d", nlines)
- for i in range(nlines):
- line = flist.value[i]
- if UserSettings.Get(group = 'vdigit', key = 'selectInside',
- subkey = 'enabled'):
- inside = True
- if not self._validLine(line):
- return None
- Vect_read_line(poMapInfo, self.poPoints, None, line)
- points = self.poPoints.contents
- for p in range(points.n_points):
- if not Vect_point_in_poly(points.x[p], points.y[p],
- poBbox):
- inside = False
- break
-
- if not inside:
- continue # skip lines just overlapping bbox
-
- if not self._isSelected(line):
- selected.append(line)
- else:
- selected.remove(line)
-
- Vect_destroy_line_struct(poBbox)
- Vect_destroy_list(poList)
-
- return nlines
- def SelectLineByPoint(self, point, poMapInfo = None):
- """!Select vector feature by given point in given
- threshold
-
- Only one vector object can be selected. Bounding boxes of
- all segments are stores.
-
- @param point points coordinates (x, y)
- @param poMapInfo use external Map_info, None for self.poMapInfo
- @return dict {'line' : feature id, 'point' : point on line}
- """
- thisMapInfo = poMapInfo is None
- if not poMapInfo:
- poMapInfo = self.poMapInfo
-
- if not poMapInfo:
- return { 'line' : -1, 'point': None }
-
- if thisMapInfo:
- self._drawSelected = True
- # select by ids
- self.selected['cats'] = list()
-
- if thisMapInfo:
- selected = self.selected['ids']
- else:
- selected = list()
-
- poFound = Vect_new_list()
-
- lineNearest = Vect_find_line_list(poMapInfo, point[0], point[1], 0,
- self._getSelectType(), self.GetThreshold(), self.is3D,
- None, poFound)
- Debug.msg(1, "DisplayDriver.SelectLineByPoint() found = %d", lineNearest)
-
- if lineNearest > 0:
- if not self._isSelected(lineNearest):
- selected.append(lineNearest)
- else:
- selected.remove(lineNearest)
-
- px = c_double()
- py = c_double()
- pz = c_double()
- if not self._validLine(lineNearest):
- return { 'line' : -1, 'point': None }
- ftype = Vect_read_line(poMapInfo, self.poPoints, self.poCats, lineNearest)
- Vect_line_distance (self.poPoints, point[0], point[1], 0.0, self.is3D,
- byref(px), byref(py), byref(pz),
- None, None, None)
-
- # check for duplicates
- if self.settings['highlightDupl']['enabled']:
- found = poFound.contents
- for i in range(found.n_values):
- line = found.value[i]
- if line != lineNearest:
- selected.append(line)
-
- self.GetDuplicates()
-
- for i in range(found.n_values):
- line = found.value[i]
- if line != lineNearest and not self._isDuplicated(line):
- selected.remove(line)
-
- Vect_destroy_list(poFound)
-
- if thisMapInfo:
- # drawing segments can be very expensive
- # only one features selected
- self._drawSegments = True
-
- return { 'line' : lineNearest,
- 'point' : (px.value, py.value, pz.value) }
-
- def _listToIList(self, plist):
- """!Generate from list struct_ilist
- """
- ilist = Vect_new_list()
- for val in plist:
- Vect_list_append(ilist, val)
-
- return ilist
-
- def GetSelectedIList(self, ilist = None):
- """!Get list of selected objects as struct_ilist
- Returned IList must be freed by Vect_destroy_list().
-
- @return struct_ilist
- """
- if ilist:
- return self._listToIList(ilist)
-
- return self._listToIList(self.selected['ids'])
-
- def GetSelected(self, grassId = True):
- """!Get ids of selected objects
-
- @param grassId True for feature id, False for PseudoDC id
-
- @return list of ids of selected vector objects
- """
- if grassId:
- return self.selected['ids']
-
- dc_ids = list()
-
- if not self._drawSegments:
- dc_ids.append(1)
- elif len(self.selected['ids']) > 0:
- # only first selected feature
- Vect_read_line(self.poMapInfo, self.poPoints, None,
- self.selected['ids'][0])
- points = self.poPoints.contents
- # node - segment - vertex - segment - node
- for i in range(1, 2 * points.n_points):
- dc_ids.append(i)
-
- return dc_ids
-
- def SetSelected(self, ids, layer = -1):
- """!Set selected vector objects
- @param list of ids (None to unselect features)
- @param layer layer number for features selected based on category number
- """
- if ids:
- self._drawSelected = True
- else:
- self._drawSelected = False
-
- if layer > 0:
- selected.field = layer
- self.selected['cats'] = ids
- else:
- field = -1
- self.selected['ids'] = ids
-
- def GetSelectedVertex(self, pos):
- """!Get PseudoDC vertex id of selected line
- Set bounding box for vertices of line.
-
- @param pos position
-
- @return id of center, left and right vertex
- @return 0 no line found
- @return -1 on error
- """
- returnId = list()
- # only one object can be selected
- if len(self.selected['ids']) != 1 or not self._drawSegments:
- return returnId
-
- startId = 1
- line = self.selected['ids'][0]
-
- if not self._validLine(line):
- return -1
- ftype = Vect_read_line(self.poMapInfo, self.poPoints, self.poCats, line)
-
- minDist = 0.0
- Gid = -1
- # find the closest vertex (x, y)
- DCid = 1
- points = self.poPoints.contents
- for idx in range(points.n_points):
- dist = Vect_points_distance(pos[0], pos[1], 0.0,
- points.x[idx], points.y[idx], points.z[idx], 0)
-
- if idx == 0:
- minDist = dist
- Gid = idx
- else:
- if minDist > dist:
- minDist = dist
- Gid = idx
-
- vx, vy = self._cell2Pixel(points.x[idx], points.y[idx], points.z[idx])
- rect = wx.Rect(vx, vy, 0, 0)
- self.dc.SetIdBounds(DCid, rect)
- DCid += 2
-
- if minDist > self.GetThreshold():
- return returnId
-
- # translate id
- DCid = Gid * 2 + 1
-
- # add selected vertex
- returnId.append(DCid)
- # left vertex
- if DCid == startId:
- returnId.append(-1)
- else:
- returnId.append(DCid - 2)
- # right vertex
- if DCid == (points.n_points - 1) * 2 + startId:
- returnId.append(-1)
- else:
- returnId.append(DCid + 2)
-
- return returnId
- def DrawSelected(self, flag):
- """!Draw selected features
-
- @param flag True to draw selected features
- """
- self._drawSelected = bool(flag)
-
- def CloseMap(self):
- """!Close vector map
-
- @return 0 on success
- @return non-zero on error
- """
- ret = 0
- if self.poMapInfo:
- # rebuild topology
- Vect_build_partial(self.poMapInfo, GV_BUILD_NONE)
- Vect_build(self.poMapInfo)
- # close map and store topo/cidx
- ret = Vect_close(self.poMapInfo)
- del self.mapInfo
- self.poMapInfo = self.mapInfo = None
-
- return ret
-
- def OpenMap(self, name, mapset, update = True):
- """!Open vector map by the driver
-
- @param name name of vector map to be open
- @param mapset name of mapset where the vector map lives
-
- @return map_info
- @return None on error
- """
- Debug.msg("DisplayDriver.OpenMap(): name=%s mapset=%s updated=%d",
- name, mapset, update)
- if not self.mapInfo:
- self.mapInfo = Map_info()
- self.poMapInfo = pointer(self.mapInfo)
-
- # open existing map
- if update:
- ret = Vect_open_update(self.poMapInfo, name, mapset)
- else:
- ret = Vect_open_old(self.poMapInfo, name, mapset)
- self.is3D = Vect_is_3d(self.poMapInfo)
-
- if ret == -1: # error
- del self.mapInfo
- self.poMapInfo = self.mapInfo = None
- elif ret < 2:
- dlg = wx.MessageDialog(parent = self.window,
- message = _("Topology for vector map <%s> is not available. "
- "Topology is required by digitizer. Do you want to "
- "rebuild topology (takes some time) and open the vector map "
- "for editing?") % name,
- caption=_("Topology missing"),
- style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION | wx.CENTRE)
- ret = dlg.ShowModal()
- if ret != wx.ID_YES:
- del self.mapInfo
- self.poMapInfo = self.mapInfo = None
- else:
- Vect_build(self.poMapInfo)
-
- return self.poMapInfo
-
- def GetMapBoundingBox(self):
- """!Get bounding box of (opened) vector map layer
- @return (w,s,b,e,n,t)
- """
- if not self.poMapInfo:
- return None
-
- bbox = bound_box()
- Vect_get_map_box(self.poMapInfo, byref(bbox))
- return bbox.W, bbox.S, bbox.B, \
- bbox.E, bbox.N, bbox.T
-
- def UpdateSettings(self, alpha = 255):
- """!Update display driver settings
- @todo map units
-
- @alpha color value for aplha channel
- """
- color = dict()
- for key in self.settings.keys():
- if key == 'lineWidth':
- self.settings[key] = int(UserSettings.Get(group = 'vdigit', key = 'lineWidth',
- subkey = 'value'))
- continue
-
- color = wx.Color(UserSettings.Get(group = 'vdigit', key = 'symbol',
- subkey = [key, 'color'])[0],
- UserSettings.Get(group = 'vdigit', key = 'symbol',
- subkey = [key, 'color'])[1],
- UserSettings.Get(group = 'vdigit', key = 'symbol',
- subkey = [key, 'color'])[2])
-
- if key == 'highlight':
- self.settings[key] = color
- continue
-
- if key == 'highlightDupl':
- self.settings[key]['enabled'] = bool(UserSettings.Get(group = 'vdigit', key = 'checkForDupl',
- subkey = 'enabled'))
- else:
- self.settings[key]['enabled'] = bool(UserSettings.Get(group = 'vdigit', key = 'symbol',
- subkey = [key, 'enabled']))
-
- self.settings[key]['color'] = color
-
- def UpdateRegion(self):
- """!Update geographical region used by display driver
- """
- self.region = self.mapObj.GetCurrentRegion()
-
- def GetThreshold(self, type = 'snapping', value = None, units = None):
- """!Return threshold value in map units
-
- @param type snapping mode (node, vertex)
- @param value threshold to be set up
- @param units units (map, screen)
- @return threshold value
- """
- if value is None:
- value = UserSettings.Get(group = 'vdigit', key = type, subkey = 'value')
-
- if units is None:
- units = UserSettings.Get(group = 'vdigit', key = type, subkey = 'units')
-
- if value < 0:
- value = (self.region['nsres'] + self.region['ewres']) / 2.0
-
- if units == "screen pixels":
- # pixel -> cell
- res = max(self.region['nsres'], self.region['ewres'])
- return value * res
-
- return value
-
- def GetDuplicates(self):
- """!Return ids of (selected) duplicated vector features
- """
- if not self.poMapInfo:
- return
-
- ids = dict()
- APoints = Vect_new_line_struct()
- BPoints = Vect_new_line_struct()
-
- self.selected['idsDupl'] = list()
-
- for i in range(len(self.selected['ids'])):
- line1 = self.selected['ids'][i]
- if self._isDuplicated(line1):
- continue
-
- Vect_read_line(self.poMapInfo, APoints, None, line1)
-
- for line2 in self.selected['ids']:
- if line1 == line2 or self._isDuplicated(line2):
- continue
-
- Vect_read_line(self.poMapInfo, BPoints, None, line2)
-
- if Vect_line_check_duplicate(APoints, BPoints, WITHOUT_Z):
- if i not in ids:
- ids[i] = list()
- ids[i].append((line1, self._getCatString(line1)))
- self.selected['idsDupl'].append(line1)
-
- ids[i].append((line2, self._getCatString(line2)))
- self.selected['idsDupl'].append(line2)
-
- Vect_destroy_line_struct(APoints)
- Vect_destroy_line_struct(BPoints)
- return ids
-
- def _getCatString(self, line):
- Vect_read_line(self.poMapInfo, None, self.poCats, line)
-
- cats = self.poCats.contents
- catsDict = dict()
- for i in range(cats.n_cats):
- layer = cats.field[i]
- if layer not in catsDict:
- catsDict[layer] = list()
- catsDict[layer].append(cats.cat[i])
-
- catsStr = ''
- for l, c in catsDict.iteritems():
- catsStr = '%d: (%s)' % (l, ','.join(map(str, c)))
-
- return catsStr
- def UnSelect(self, lines):
- """!Unselect vector features
- @param lines list of feature id(s)
- """
- checkForDupl = False
- for line in lines:
- if self._isSelected(line):
- self.selected['ids'].remove(line)
- if self.settings['highlightDupl']['enabled'] and self._isDuplicated(line):
- checkForDupl = True
- if checkForDupl:
- self.GetDuplicates()
-
- return len(self.selected['ids'])
-
|