GRASS Programmer's Manual
6.4.2(2012)
|
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