GRASS Programmer's Manual  6.4.2(2012)
wxvdriver.py
Go to the documentation of this file.
00001 """!
00002 @package wxvdriver.py
00003 
00004 @brief wxGUI vector digitizer (display driver)
00005 
00006 Code based on wxVdigit C++ component from GRASS 6.4.0
00007 (gui/wxpython/vdigit). Converted to Python in 2010/12-2011/01.
00008 
00009 List of classes:
00010  - DisplayDriver
00011 
00012 (C) 2007-2011 by the GRASS Development Team
00013 
00014 This program is free software under the GNU General Public License
00015 (>=v2). Read the file COPYING that comes with GRASS for details.
00016 
00017 @author Martin Landa <landa.martin gmail.com>
00018 """
00019 
00020 import math
00021 import locale
00022 
00023 import wx
00024 
00025 from debug import Debug
00026 from preferences import globalSettings as UserSettings
00027 
00028 from grass.lib.gis    import *
00029 from grass.lib.vector import *
00030 from grass.lib.vedit  import *
00031 
00032 log      = None
00033 progress = None
00034 
00035 def print_error(msg, type):
00036     """!Redirect stderr"""
00037     global log
00038     if log:
00039         log.write(msg)
00040     else:
00041         print msg
00042     
00043     return 0
00044 
00045 def print_progress(value):
00046     """!Redirect progress info"""
00047     global progress
00048     if progress:
00049         progress.SetValue(value)
00050     else:
00051         print value
00052     
00053     return 0
00054 
00055 errtype = CFUNCTYPE(UNCHECKED(c_int), String, c_int)
00056 errfunc = errtype(print_error)
00057 pertype = CFUNCTYPE(UNCHECKED(c_int), c_int)
00058 perfunc = pertype(print_progress)
00059 
00060 class DisplayDriver:
00061     def __init__(self, device, deviceTmp, mapObj, window, glog, gprogress):
00062         """!Display driver used by vector digitizer
00063         
00064         @param device    wx.PseudoDC device where to draw vector objects
00065         @param deviceTmp wx.PseudoDC device where to draw temporary vector objects
00066         @param mapOng    Map Object (render.Map)
00067         @param windiow   parent window for dialogs
00068         @param glog      logging device (None to discard messages)
00069         @param gprogress progress bar device (None to discard message)
00070         """
00071         global errfunc, perfunc, log, progress
00072         log = glog
00073         progress = gprogress
00074         
00075         G_gisinit('wxvdigit')
00076         locale.setlocale(locale.LC_NUMERIC, 'C')
00077         G_set_error_routine(errfunc) 
00078         G_set_percent_routine(perfunc)
00079         
00080         self.mapInfo   = None     # open vector map (Map_Info structure)
00081         self.poMapInfo = None     # pointer to self.mapInfo
00082         self.is3D      = False    # is open vector map 3D
00083         
00084         self.dc      = device     # PseudoDC devices
00085         self.dcTmp   = deviceTmp
00086         self.mapObj  = mapObj
00087         self.region  = mapObj.GetCurrentRegion()
00088         self.window  = window
00089         self.log     = log        # log device
00090 
00091         self.firstNode = True     # track PseudoDC Id of selected features
00092         self.lastNodeId = -1
00093         
00094         # GRASS lib
00095         self.poPoints = Vect_new_line_struct()
00096         self.poCats   = Vect_new_cats_struct()
00097         
00098         # selected objects
00099         self.selected = {
00100             'field'   : -1,      # field number
00101             'cats'    : list(),  # list of cats
00102             'ids'     : list(),  # list of ids
00103             'idsDupl' : list(),  # list of duplicated features
00104             }
00105         
00106         # digitizer settings
00107         self.settings = {
00108             'highlight'     : None,
00109             'highlightDupl' : { 'enabled' : False,
00110                                 'color'   : None },
00111             'point'         : { 'enabled' : False,
00112                                 'color'   : None },
00113             'line'          : { 'enabled' : False,
00114                                 'color'   : None },
00115             'boundaryNo'    : { 'enabled' : False,
00116                                 'color'   : None },
00117             'boundaryOne'   : { 'enabled' : False,
00118                                 'color'   : None },
00119             'boundaryTwo'   : { 'enabled' : False,
00120                                 'color'   : None },
00121             'centroidIn'    : { 'enabled' : False,
00122                                 'color'   : None },
00123             'centroidOut'   : { 'enabled' : False,
00124                                 'color'   : None },
00125             'centroidDup'   : { 'enabled' : False,
00126                                 'color'   : None },
00127             'nodeOne'       : { 'enabled' : False,
00128                                 'color'   : None },
00129             'nodeTwo'       : { 'enabled' : False,
00130                                 'color'   : None },
00131             'vertex'        : { 'enabled' : False,
00132                                 'color'   : None },
00133             'area'          : { 'enabled' : False,
00134                                 'color'   : None },
00135             'direction'     : { 'enabled' : False,
00136                                 'color'   : None },
00137             'lineWidth'     : -1,    # screen units 
00138             }
00139         
00140         # topology
00141         self._resetTopology()
00142         
00143         self._drawSelected = False
00144         self._drawSegments = False
00145         
00146         self.UpdateSettings()
00147         
00148     def __del__(self):
00149         """!Close currently open vector map"""
00150         G_unset_error_routine()
00151         G_unset_percent_routine()
00152         
00153         if self.poMapInfo:
00154             self.CloseMap()
00155         
00156         Vect_destroy_line_struct(self.poPoints)
00157         Vect_destroy_cats_struct(self.poCats)
00158 
00159     def _resetTopology(self):
00160         """!Reset topology dict
00161         """
00162         self.topology = {
00163             'highlight'   : 0,
00164             'point'       : 0,
00165             'line'        : 0,
00166             'boundaryNo'  : 0,
00167             'boundaryOne' : 0,
00168             'boundaryTwo' : 0,
00169             'centroidIn'  : 0,
00170             'centroidOut' : 0,
00171             'centroidDup' : 0,
00172             'nodeOne'     : 0,
00173             'nodeTwo'     : 0,
00174             'vertex'      : 0,
00175             }
00176         
00177     def _cell2Pixel(self, east, north, elev):
00178         """!Conversion from geographic coordinates (east, north)
00179         to screen (x, y)
00180   
00181         @todo 3D stuff...
00182 
00183         @param east, north, elev geographical coordinates
00184 
00185         @return x, y screen coordinates (integer)
00186         """
00187         map_res = max(self.region['ewres'], self.region['nsres'])
00188         w = self.region['center_easting']  - (self.mapObj.width  / 2) * map_res
00189         n = self.region['center_northing'] + (self.mapObj.height / 2) * map_res
00190         
00191         return int((east - w) / map_res), int((n - north) / map_res)
00192     
00193     def _drawCross(self, pdc, point, size = 5):
00194         """!Draw cross symbol of given size to device content
00195    
00196         Used for points, nodes, vertices
00197 
00198         @param[in,out] PseudoDC where to draw
00199         @param point coordinates of center
00200         @param size size of the cross symbol
00201    
00202         @return 0 on success
00203         @return -1 on failure
00204         """
00205         if not pdc or not point:
00206             return -1
00207         
00208         pdc.DrawLine(point.x - size, point.y, point.x + size, point.y)
00209         pdc.DrawLine(point.x, point.y - size, point.x, point.y + size)
00210         
00211         return 0
00212     
00213     def _drawObject(self, robj):
00214         """!Draw given object to the device
00215         
00216         The object is defined as robject() from vedit.h.
00217         
00218         @param robj object to be rendered
00219         
00220         @return  1 on success
00221         @return -1 on failure (vector feature marked as dead, etc.)
00222         """
00223         if not self.dc or not self.dcTmp:
00224             return -1
00225         
00226         Debug.msg(3, "_drawObject(): type=%d npoints=%d", robj.type, robj.npoints)
00227         brush = None
00228         if self._isSelected(robj.fid):
00229             pdc = self.dcTmp
00230             if self.settings['highlightDupl']['enabled'] and self._isDuplicated(robj.fid):
00231                 pen = wx.Pen(self.settings['highlightDupl']['color'], self.settings['lineWidth'], wx.SOLID)
00232             else:            
00233                 pen = wx.Pen(self.settings['highlight'], self.settings['lineWidth'], wx.SOLID)
00234             
00235             dcId = 1
00236             self.topology['highlight'] += 1
00237             if not self._drawSelected:
00238                 return
00239         else:
00240             pdc = self.dc
00241             pen, brush = self._definePen(robj.type)
00242             dcId = 0
00243         
00244         pdc.SetPen(pen)        
00245         if brush:
00246             pdc.SetBrush(brush)
00247         
00248         if robj.type & (TYPE_POINT | TYPE_CENTROIDIN | TYPE_CENTROIDOUT | TYPE_CENTROIDDUP |
00249                         TYPE_NODEONE | TYPE_NODETWO | TYPE_VERTEX): # -> point
00250             if dcId > 0:
00251                 if robj.type == TYPE_VERTEX:
00252                     dcId = 3 # first vertex
00253                 elif robj.type & (TYPE_NODEONE | TYPE_NODETWO):
00254                     if self.firstNode:
00255                         dcId = 1
00256                         self.firstNode = False
00257                     else:
00258                         dcId = self.lastNodeId
00259             
00260             for i in range(robj.npoints):
00261                 p = robj.point[i]
00262                 if dcId > 0:
00263                     pdc.SetId(dcId)
00264                     dcId += 2
00265                 self._drawCross(pdc, p)
00266         else:
00267             if dcId > 0 and self._drawSegments:
00268                 self.fisrtNode = True
00269                 self.lastNodeId = robj.npoints * 2 - 1
00270                 dcId = 2 # first segment
00271                 i = 0
00272                 while i < robj.npoints - 1:
00273                     point_beg = wx.Point(robj.point[i].x, robj.point[i].y)
00274                     point_end = wx.Point(robj.point[i+1].x, robj.point[i+1].y)
00275                     pdc.SetId(dcId) # set unique id & set bbox for each segment
00276                     pdc.SetPen(pen)
00277                     pdc.SetIdBounds(dcId - 1, wx.Rect(point_beg.x, point_beg.y, 0, 0))
00278                     pdc.SetIdBounds(dcId, wx.RectPP(point_beg, point_end))
00279                     pdc.DrawLine(point_beg.x, point_beg.y,
00280                                  point_end.x, point_end.y)
00281                     i    += 1
00282                     dcId += 2
00283                 pdc.SetIdBounds(dcId - 1, wx.Rect(robj.point[robj.npoints - 1].x,
00284                                                   robj.point[robj.npoints - 1].y,
00285                                                   0, 0))
00286             else:
00287                 points = list()
00288                 for i in range(robj.npoints):
00289                     p = robj.point[i]
00290                     points.append(wx.Point(p.x, p.y))
00291                     
00292                 if robj.type == TYPE_AREA:
00293                     pdc.DrawPolygon(points)
00294                 else:
00295                     pdc.DrawLines(points)
00296         
00297     def _definePen(self, rtype):
00298         """!Define pen/brush based on rendered object)
00299         
00300         Updates also self.topology dict
00301 
00302         @return pen, brush
00303         """
00304         if rtype == TYPE_POINT:
00305             key = 'point'
00306         elif rtype == TYPE_LINE:
00307             key = 'line'
00308         elif rtype == TYPE_BOUNDARYNO:
00309             key = 'boundaryNo'
00310         elif rtype == TYPE_BOUNDARYTWO:
00311             key = 'boundaryTwo'
00312         elif rtype == TYPE_BOUNDARYONE:
00313             key = 'boundaryOne'
00314         elif rtype == TYPE_CENTROIDIN:
00315             key = 'centroidIn'
00316         elif rtype == TYPE_CENTROIDOUT:
00317             key = 'centroidOut'
00318         elif rtype == TYPE_CENTROIDDUP:
00319             key = 'centroidDup'
00320         elif rtype == TYPE_NODEONE:
00321             key = 'nodeOne'
00322         elif rtype == TYPE_NODETWO:
00323             key = 'nodeTwo'
00324         elif rtype == TYPE_VERTEX:
00325             key = 'vertex'
00326         elif rtype == TYPE_AREA:
00327             key = 'area' 
00328         elif rtype == TYPE_ISLE:
00329             key = 'isle'
00330         elif rtype == TYPE_DIRECTION:
00331             key = 'direction'
00332         
00333         if key not in ('direction', 'area', 'isle'):
00334             self.topology[key] += 1
00335         
00336         if key in ('area', 'isle'):
00337             pen = wx.TRANSPARENT_PEN
00338             if key == 'area':
00339                 brush = wx.Brush(self.settings[key]['color'], wx.SOLID)
00340             else:
00341                 brush = wx.TRANSPARENT_BRUSH
00342         else:
00343             pen = wx.Pen(self.settings[key]['color'], self.settings['lineWidth'], wx.SOLID)
00344             brush = None
00345         
00346         return pen, brush
00347         
00348     def _getDrawFlag(self):
00349         """!Get draw flag from the settings
00350         
00351         See vedit.h for list of draw flags.
00352         
00353         @return draw flag (int)
00354         """
00355         ret = 0
00356         if self.settings['point']['enabled']:
00357             ret |= DRAW_POINT
00358         if self.settings['line']['enabled']:
00359             ret |= DRAW_LINE
00360         if self.settings['boundaryNo']['enabled']:
00361             ret |= DRAW_BOUNDARYNO
00362         if self.settings['boundaryTwo']['enabled']:
00363             ret |= DRAW_BOUNDARYTWO
00364         if self.settings['boundaryOne']['enabled']:
00365             ret |= DRAW_BOUNDARYONE
00366         if self.settings['centroidIn']['enabled']:
00367             ret |= DRAW_CENTROIDIN
00368         if self.settings['centroidOut']['enabled']:
00369             ret |= DRAW_CENTROIDOUT
00370         if self.settings['centroidDup']['enabled']:
00371             ret |= DRAW_CENTROIDDUP
00372         if self.settings['nodeOne']['enabled']:
00373             ret |= DRAW_NODEONE
00374         if self.settings['nodeTwo']['enabled']:
00375             ret |= DRAW_NODETWO
00376         if self.settings['vertex']['enabled']:
00377             ret |= DRAW_VERTEX
00378         if self.settings['area']['enabled']:
00379             ret |= DRAW_AREA
00380         if self.settings['direction']['enabled']:
00381             ret |= DRAW_DIRECTION
00382         
00383         return ret
00384         
00385     def _isSelected(self, line, force = False):
00386         """!Check if vector object selected?
00387    
00388         @param line feature id
00389 
00390         @return True if vector object is selected
00391         @return False if vector object is not selected
00392         """
00393         if len(self.selected['cats']) < 1 or force:
00394             # select by id
00395             if line in self.selected['ids']:
00396                 return True
00397         else: 
00398             # select by cat
00399             cats = self.poCats.contents
00400             for i in range(cats.n_cats):
00401                 if cats.field[i] == self.selected['field'] and \
00402                         cats.cat[i] in self.selected['cats']:
00403                     # remember id
00404                     # -> after drawing all features selected.cats is reseted */
00405                     self.selected['ids'].append(line)
00406                     return True
00407         
00408         return False
00409 
00410     def _isDuplicated(self, line):
00411         """!Check for already marked duplicates
00412         
00413         @param line feature id
00414 
00415         @return True line already marked as duplicated
00416         @return False not duplicated
00417         """
00418         return line in self.selected['idsDupl']
00419     
00420     def _getRegionBox(self):
00421         """!Get bound_box() from current region
00422 
00423         @return bound_box
00424         """
00425         box = bound_box()
00426         
00427         box.N = self.region['n']
00428         box.S = self.region['s']
00429         box.E = self.region['e']
00430         box.W = self.region['w']
00431         box.T = PORT_DOUBLE_MAX
00432         box.B = -PORT_DOUBLE_MAX
00433         
00434         return box
00435 
00436     def DrawMap(self, force = False):
00437         """!Draw content of the vector map to the device
00438         
00439         @param force force drawing
00440         @return number of drawn features
00441         @return -1 on error
00442         """
00443         Debug.msg(1, "DisplayDriver.DrawMap(): force=%d", force)
00444         
00445         if not self.poMapInfo or not self.dc or not self.dcTmp:
00446             return -1
00447         
00448         rlist = Vedit_render_map(self.poMapInfo, byref(self._getRegionBox()), self._getDrawFlag(),
00449                                  self.region['center_easting'], self.region['center_northing'],
00450                                  self.mapObj.width, self.mapObj.height,
00451                                  max(self.region['nsres'], self.region['ewres'])).contents
00452         
00453         self._resetTopology()
00454         
00455         self.dc.BeginDrawing()
00456         self.dcTmp.BeginDrawing()
00457         
00458         # draw objects
00459         for i in range(rlist.nitems):
00460             robj = rlist.item[i].contents
00461             self._drawObject(robj)
00462         
00463         self.dc.EndDrawing()
00464         self.dcTmp.EndDrawing()
00465         
00466         # reset list of selected features by cat 
00467         # list of ids - see IsSelected()
00468         self.selected['field'] = -1
00469         self.selected['cats'] = list()
00470         
00471     def _getSelectType(self):
00472         """!Get type(s) to be selected
00473 
00474         Used by SelectLinesByBox() and SelectLineByPoint()
00475         """
00476         ftype = 0
00477         for feature in (('point',    GV_POINT),
00478                         ('line',     GV_LINE),
00479                         ('centroid', GV_CENTROID),
00480                         ('boundary', GV_BOUNDARY)):
00481             if UserSettings.Get(group = 'vdigit', key = 'selectType',
00482                                 subkey = [feature[0], 'enabled']):
00483                 ftype |= feature[1]
00484         
00485         return ftype
00486 
00487     def _validLine(self, line):
00488         """!Check if feature id is valid
00489 
00490         @param line feature id
00491 
00492         @return True valid feature id
00493         @return False invalid
00494         """
00495         if line > 0 and line <= Vect_get_num_lines(self.poMapInfo):
00496             return True
00497         
00498         return False
00499     
00500     def SelectLinesByBox(self, bbox, drawSeg = False, poMapInfo = None):
00501         """!Select vector objects by given bounding box
00502         
00503         If line id is already in the list of selected lines, then it will
00504         be excluded from this list.
00505         
00506         @param bbox bounding box definition
00507         @param drawSeg True to draw segments of line
00508         @param poMapInfo use external Map_info, None for self.poMapInfo
00509 
00510         @return number of selected features
00511         @return None on error
00512         """
00513         thisMapInfo = poMapInfo is None
00514         if not poMapInfo:
00515             poMapInfo = self.poMapInfo
00516         
00517         if not poMapInfo:
00518             return None
00519         
00520         if thisMapInfo:
00521             self._drawSegments = drawSeg
00522             self._drawSelected = True
00523         
00524             # select by ids
00525             self.selected['cats'] = list()
00526         
00527         poList = Vect_new_list()
00528         x1, y1 = bbox[0]
00529         x2, y2 = bbox[1]
00530         poBbox = Vect_new_line_struct()
00531         Vect_append_point(poBbox, x1, y1, 0.0)
00532         Vect_append_point(poBbox, x2, y1, 0.0)
00533         Vect_append_point(poBbox, x2, y2, 0.0)
00534         Vect_append_point(poBbox, x1, y2, 0.0)
00535         Vect_append_point(poBbox, x1, y1, 0.0)
00536         
00537         Vect_select_lines_by_polygon(poMapInfo, poBbox,
00538                                      0, None, # isles
00539                                      self._getSelectType(), poList)
00540         
00541         flist = poList.contents
00542         nlines = flist.n_values
00543         Debug.msg(1, "DisplayDriver.SelectLinesByBox() num = %d", nlines)
00544         for i in range(nlines):
00545             line = flist.value[i]
00546             if UserSettings.Get(group = 'vdigit', key = 'selectInside',
00547                                 subkey = 'enabled'):
00548                 inside = True
00549                 if not self._validLine(line):
00550                     return None
00551                 Vect_read_line(poMapInfo, self.poPoints, None, line)
00552                 points = self.poPoints.contents
00553                 for p in range(points.n_points):
00554                     if not Vect_point_in_poly(points.x[p], points.y[p],
00555                                               poBbox):
00556                         inside = False
00557                         break
00558                     
00559                 if not inside:
00560                     continue # skip lines just overlapping bbox
00561             
00562             if not self._isSelected(line):
00563                 self.selected['ids'].append(line)
00564             else:
00565                 self.selected['ids'].remove(line)
00566         
00567         Vect_destroy_line_struct(poBbox)
00568         Vect_destroy_list(poList)
00569         
00570         return nlines
00571 
00572     def SelectLineByPoint(self, point, poMapInfo = None):
00573         """!Select vector feature by given point in given
00574         threshold
00575    
00576         Only one vector object can be selected. Bounding boxes of
00577         all segments are stores.
00578         
00579         @param point points coordinates (x, y)
00580         @param poMapInfo use external Map_info, None for self.poMapInfo
00581 
00582         @return dict {'line' : feature id, 'point' : point on line}
00583         """
00584         thisMapInfo = poMapInfo is None
00585         if not poMapInfo:
00586             poMapInfo = self.poMapInfo
00587         
00588         if not poMapInfo:
00589             return { 'line' : -1, 'point': None }
00590         
00591         if thisMapInfo:
00592             self._drawSelected = True
00593             # select by ids 
00594             self.selected['cats'] = list()
00595         
00596         poFound = Vect_new_list()
00597         
00598         lineNearest = Vect_find_line_list(poMapInfo, point[0], point[1], 0,
00599                                            self._getSelectType(), self.GetThreshold(), self.is3D,
00600                                            None, poFound)
00601         Debug.msg(1, "DisplayDriver.SelectLineByPoint() found = %d", lineNearest)
00602         
00603         if lineNearest > 0:
00604             if not self._isSelected(lineNearest):
00605                 self.selected['ids'].append(lineNearest)
00606             else:
00607                 self.selected['ids'].remove(lineNearest)
00608         
00609         px = c_double()
00610         py = c_double()
00611         pz = c_double()
00612         if not self._validLine(lineNearest):
00613             return { 'line' : -1, 'point': None }
00614         ftype = Vect_read_line(poMapInfo, self.poPoints, self.poCats, lineNearest)
00615         Vect_line_distance (self.poPoints, point[0], point[1], 0.0, self.is3D,
00616                             byref(px), byref(py), byref(pz),
00617                             None, None, None)
00618         
00619         # check for duplicates 
00620         if self.settings['highlightDupl']['enabled']:
00621             found = poFound.contents
00622             for i in range(found.n_values):
00623                 line = found.value[i]
00624                 if line != lineNearest:
00625                     self.selected['ids'].append(line)
00626             
00627             self.GetDuplicates()
00628             
00629             for i in range(found.n_values):
00630                 line = found.value[i]
00631                 if line != lineNearest and not self._isDuplicated(line):
00632                     self.selected['ids'].remove(line)
00633         
00634         Vect_destroy_list(poFound)
00635         
00636         if thisMapInfo:
00637             # drawing segments can be very expensive
00638             # only one features selected
00639             self._drawSegments = True
00640         
00641         return { 'line'  : lineNearest,
00642                  'point' : (px.value, py.value, pz.value) }
00643     
00644     def _listToIList(self, plist):
00645         """!Generate from list struct_ilist
00646         """
00647         ilist = Vect_new_list()
00648         for val in plist:
00649             Vect_list_append(ilist, val)
00650         
00651         return ilist
00652         
00653     def GetSelectedIList(self, ilist = None):
00654         """!Get list of selected objects as struct_ilist
00655 
00656         Returned IList must be freed by Vect_destroy_list().
00657         
00658         @return struct_ilist
00659         """
00660         if ilist:
00661             return self._listToIList(ilist)
00662         
00663         return self._listToIList(self.selected['ids'])
00664         
00665     def GetSelected(self, grassId = True):
00666         """!Get ids of selected objects
00667         
00668         @param grassId True for feature id, False for PseudoDC id
00669         
00670         @return list of ids of selected vector objects
00671         """
00672         if grassId:
00673             return self.selected['ids']
00674         
00675         dc_ids = list()
00676         
00677         if not self._drawSegments:
00678             dc_ids.append(1)
00679         elif len(self.selected['ids']) > 0:
00680             # only first selected feature
00681             Vect_read_line(self.poMapInfo, self.poPoints, None,
00682                            self.selected['ids'][0])
00683             points = self.poPoints.contents
00684             # node - segment - vertex - segment - node
00685             for i in range(1, 2 * points.n_points):
00686                 dc_ids.append(i)
00687         
00688         return dc_ids
00689         
00690     def SetSelected(self, ids, layer = -1):
00691         """!Set selected vector objects
00692 
00693         @param list of ids (None to unselect features)
00694         @param layer layer number for features selected based on category number
00695         """
00696         if ids:
00697             self._drawSelected = True
00698         else:
00699             self._drawSelected = False
00700         
00701         if layer > 0:
00702             selected.field = layer
00703             self.selected['cats'] = ids
00704         else:
00705             field = -1
00706             self.selected['ids'] = ids
00707         
00708     def GetSelectedVertex(self, pos):
00709         """!Get PseudoDC vertex id of selected line
00710 
00711         Set bounding box for vertices of line.
00712         
00713         @param pos position
00714         
00715         @return id of center, left and right vertex
00716         @return 0 no line found
00717         @return -1 on error
00718         """
00719         returnId = list()
00720         # only one object can be selected
00721         if len(self.selected['ids']) != 1 or not self._drawSegments:
00722             return returnId
00723         
00724         startId = 1
00725         line = self.selected['ids'][0]
00726         
00727         if not self._validLine(line):
00728             return -1
00729         ftype = Vect_read_line(self.poMapInfo, self.poPoints, self.poCats, line)
00730         
00731         minDist = 0.0
00732         Gid = -1
00733         # find the closest vertex (x, y)
00734         DCid = 1
00735         points = self.poPoints.contents
00736         for idx in range(points.n_points):
00737             dist = Vect_points_distance(pos[0], pos[1], 0.0,
00738                                         points.x[idx], points.y[idx], points.z[idx], 0)
00739             
00740             if idx == 0:
00741                 minDist = dist
00742                 Gid     = idx
00743             else:
00744                 if minDist > dist:
00745                     minDist = dist
00746                     Gid = idx
00747             
00748             vx, vy = self._cell2Pixel(points.x[idx], points.y[idx], points.z[idx])
00749             rect = wx.Rect(vx, vy, 0, 0)
00750             self.dc.SetIdBounds(DCid, rect)
00751             DCid += 2
00752         
00753         if minDist > self.GetThreshold():
00754             return returnId
00755         
00756         # translate id
00757         DCid = Gid * 2 + 1
00758         
00759         # add selected vertex
00760         returnId.append(DCid)
00761         # left vertex
00762         if DCid == startId:
00763             returnId.append(-1)
00764         else:
00765             returnId.append(DCid - 2)
00766         # right vertex
00767         if DCid == (points.n_points - 1) * 2 + startId:
00768             returnId.append(-1)
00769         else:
00770             returnId.append(DCid + 2)
00771         
00772         return returnId
00773 
00774     def DrawSelected(self, flag):
00775         """!Draw selected features
00776         
00777         @param flag True to draw selected features
00778         """
00779         self._drawSelected = bool(flag)
00780         
00781     def CloseMap(self):
00782         """!Close vector map
00783         
00784         @return 0 on success
00785         @return non-zero on error
00786         """
00787         ret = 0
00788         if self.poMapInfo:
00789             # rebuild topology
00790             Vect_build_partial(self.poMapInfo, GV_BUILD_NONE)
00791             Vect_build(self.poMapInfo)
00792 
00793             # close map and store topo/cidx
00794             ret = Vect_close(self.poMapInfo)
00795             del self.mapInfo
00796             self.poMapInfo = self.mapInfo = None
00797         
00798         return ret
00799     
00800     def OpenMap(self, name, mapset, update = True):
00801         """!Open vector map by the driver
00802         
00803         @param name name of vector map to be open
00804         @param mapset name of mapset where the vector map lives
00805    
00806         @return map_info
00807         @return None on error
00808         """
00809         Debug.msg("DisplayDriver.OpenMap(): name=%s mapset=%s updated=%d",
00810                   name, mapset, update)
00811         if not self.mapInfo:
00812             self.mapInfo = Map_info()
00813             self.poMapInfo = pointer(self.mapInfo)
00814         
00815         # open existing map
00816         if update:
00817             ret = Vect_open_update(self.poMapInfo, name, mapset)
00818         else:
00819             ret = Vect_open_old(self.poMapInfo, name, mapset)
00820         self.is3D = Vect_is_3d(self.poMapInfo)
00821         
00822         if ret == -1: # error
00823             del self.mapInfo
00824             self.poMapInfo = self.mapInfo = None
00825         elif ret < 2:
00826             dlg = wx.MessageDialog(parent = self.window,
00827                                    message = _("Topology for vector map <%s> is not available. "
00828                                                "Topology is required by digitizer. Do you want to "
00829                                                "rebuild topology (takes some time) and open the vector map "
00830                                                "for editing?") % name,
00831                                    caption=_("Topology missing"),
00832                                    style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION | wx.CENTRE)
00833             ret = dlg.ShowModal()
00834             if ret != wx.ID_YES:
00835                 del self.mapInfo
00836                 self.poMapInfo = self.mapInfo = None
00837             else:
00838                 Vect_build(self.poMapInfo)
00839         
00840         return self.poMapInfo
00841     
00842     def GetMapBoundingBox(self):
00843         """!Get bounding box of (opened) vector map layer
00844 
00845         @return (w,s,b,e,n,t)
00846         """
00847         if not self.poMapInfo:
00848             return None
00849         
00850         bbox = bound_box()
00851         Vect_get_map_box(self.poMapInfo, byref(bbox))
00852 
00853         return bbox.W, bbox.S, bbox.B, \
00854             bbox.E, bbox.N, bbox.T
00855     
00856     def UpdateSettings(self, alpha = 255):
00857         """!Update display driver settings
00858 
00859         @todo map units
00860         
00861         @alpha color value for aplha channel
00862         """
00863         color = dict()
00864         for key in self.settings.keys():
00865             if key == 'lineWidth':
00866                 self.settings[key] = int(UserSettings.Get(group = 'vdigit', key = 'lineWidth',
00867                                                           subkey = 'value'))
00868                 continue
00869             
00870             color = wx.Color(UserSettings.Get(group = 'vdigit', key = 'symbol',
00871                                               subkey = [key, 'color'])[0],
00872                              UserSettings.Get(group = 'vdigit', key = 'symbol',
00873                                               subkey = [key, 'color'])[1],
00874                              UserSettings.Get(group = 'vdigit', key = 'symbol',
00875                                               subkey = [key, 'color'])[2],
00876                              alpha)
00877             
00878             if key == 'highlight':
00879                 self.settings[key] = color
00880                 continue
00881             
00882             if key == 'highlightDupl':
00883                 self.settings[key]['enabled'] = bool(UserSettings.Get(group = 'vdigit', key = 'checkForDupl',
00884                                                                       subkey = 'enabled'))
00885             else:
00886                 self.settings[key]['enabled'] = bool(UserSettings.Get(group = 'vdigit', key = 'symbol',
00887                                                                       subkey = [key, 'enabled']))
00888             
00889             self.settings[key]['color'] = color
00890         
00891     def UpdateRegion(self):
00892         """!Update geographical region used by display driver
00893         """
00894         self.region = self.mapObj.GetCurrentRegion()
00895         
00896     def GetThreshold(self, type = 'snapping', value = None, units = None):
00897         """!Return threshold value in map units
00898         
00899         @param type snapping mode (node, vertex)
00900         @param value threshold to be set up
00901         @param units units (map, screen)
00902 
00903         @return threshold value
00904         """
00905         if value is None:
00906             value = UserSettings.Get(group = 'vdigit', key = type, subkey = 'value')
00907         
00908         if units is None:
00909             units = UserSettings.Get(group = 'vdigit', key = type, subkey = 'units')
00910         
00911         if value < 0:
00912             value = (self.region['nsres'] + self.region['ewres']) / 2.0
00913         
00914         if units == "screen pixels":
00915             # pixel -> cell
00916             res = max(self.region['nsres'], self.region['ewres'])
00917             return value * res
00918         
00919         return value
00920     
00921     def GetDuplicates(self):
00922         """!Return ids of (selected) duplicated vector features
00923         """
00924         if not self.poMapInfo:
00925             return
00926         
00927         ids = dict()
00928         APoints = Vect_new_line_struct()
00929         BPoints = Vect_new_line_struct()
00930         
00931         self.selected['idsDupl'] = list()
00932         
00933         for i in range(len(self.selected['ids'])):
00934             line1 = self.selected['ids'][i]
00935             if self._isDuplicated(line1):
00936                 continue
00937             
00938             Vect_read_line(self.poMapInfo, APoints, None, line1)
00939             
00940             for line2 in self.selected['ids']:
00941                 if line1 == line2 or self._isDuplicated(line2):
00942                     continue
00943                 
00944                 Vect_read_line(self.poMapInfo, BPoints, None, line2)
00945             
00946                 if Vect_line_check_duplicate(APoints, BPoints, WITHOUT_Z):
00947                     if i not in ids:
00948                         ids[i] = list()
00949                         ids[i].append((line1, self._getCatString(line1)))
00950                         self.selected['idsDupl'].append(line1)
00951                     
00952                     ids[i].append((line2, self._getCatString(line2)))
00953                     self.selected['idsDupl'].append(line2)
00954         
00955         Vect_destroy_line_struct(APoints)
00956         Vect_destroy_line_struct(BPoints)
00957 
00958         return ids
00959     
00960     def _getCatString(self, line):
00961         Vect_read_line(self.poMapInfo, None, self.poCats, line)
00962         
00963         cats = self.poCats.contents
00964         catsDict = dict()
00965         for i in range(cats.n_cats):
00966             layer = cats.field[i]
00967             if layer not in catsDict:
00968                 catsDict[layer] = list()
00969             catsDict[layer].append(cats.cat[i])
00970         
00971         catsStr = ''
00972         for l, c in catsDict.iteritems():
00973             catsStr = '%d: (%s)' % (l, ','.join(map(str, c)))
00974         
00975         return catsStr
00976 
00977     def UnSelect(self, lines):
00978         """!Unselect vector features
00979 
00980         @param lines list of feature id(s)
00981         """
00982         checkForDupl = False
00983 
00984         for line in lines:
00985             if self._isSelected(line):
00986                 self.selected['ids'].remove(line)
00987             if self.settings['highlightDupl']['enabled'] and self._isDuplicated(line):
00988                 checkForDupl = True
00989 
00990         if checkForDupl:
00991             self.GetDuplicates()
00992         
00993         return len(self.selected['ids'])
00994     
00995 
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines