wxvdigit.py 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927
  1. """!
  2. @package wxvdigit.py
  3. @brief wxGUI vector digitizer (base class)
  4. Code based on wxVdigit C++ component from GRASS 6.4.0
  5. (gui/wxpython/vdigit). Converted to Python in 2010/12-2011/01.
  6. List of classes:
  7. - IVDigit
  8. (C) 2007-2011 by the GRASS Development Team
  9. This program is free software under the GNU General Public License
  10. (>=v2). Read the file COPYING that comes with GRASS for details.
  11. @author Martin Landa <landa.martin gmail.com>
  12. """
  13. from debug import Debug
  14. from preferences import globalSettings as UserSettings
  15. from wxvdriver import DisplayDriver
  16. from grass.lib.grass import *
  17. from grass.lib.vector import *
  18. from grass.lib.vedit import *
  19. class IVDigit:
  20. def __init__(self, mapwindow):
  21. """!Base class for vector digitizer (ctypes interface)
  22. @parem mapwindow reference for map window (BufferedWindow)
  23. """
  24. self.mapInfo = None # pointer to Map_info
  25. self.mapWindow = mapwindow
  26. if not mapwindow.parent.IsStandalone():
  27. self.log = mapwindow.parent.GetLayerManager().goutput.cmd_stderr
  28. else:
  29. self.log = sys.stderr
  30. self.toolbar = mapwindow.parent.toolbars['vdigit']
  31. self._display = DisplayDriver(device = mapwindow.pdcVector,
  32. deviceTmp = mapwindow.pdcTmp,
  33. mapObj = mapwindow.Map,
  34. log = self.log)
  35. # self.SetCategory()
  36. # layer / max category
  37. self.cats = dict()
  38. # settings
  39. self.settings = {
  40. 'breakLines' : False,
  41. 'addCentroid' : False,
  42. 'catBoundary' : True,
  43. }
  44. # undo/redo
  45. self.changesets = dict()
  46. self.changesetCurrent = -1 # first changeset to apply
  47. self.changesetEnd = -1 # last changeset to be applied
  48. if self.mapInfo:
  49. self.InitCats()
  50. def __del__(self):
  51. pass # free changesets ?
  52. def _setCategory(self):
  53. pass
  54. def _openBackgroundMap(self, bgmap):
  55. """!Open background vector map
  56. @todo support more background maps then only one
  57. @param bgmap name of vector map to be opened
  58. @return map_info
  59. @return None on error
  60. """
  61. name = c_char()
  62. mapset = c_char()
  63. if not G__name_is_fully_qualified(bgmap, byref(name), byref(mapset)):
  64. name = bgmap
  65. mapset = G_find_vector2(bgmap, '')
  66. else:
  67. name = name.value
  68. mapset = mapset.value
  69. if (name == Vect_get_name(self.mapInfo) and \
  70. mapset == Vect_get_mapset(self.mapInfo)):
  71. return None
  72. bgMapInfo = map_info()
  73. if Vect_open_old(byref(bgMapInfo), name, mapset) == -1:
  74. return None
  75. return bgMapInfo
  76. def _breakLineAtIntersection(self):
  77. pass
  78. def _addActionsBefore(self):
  79. """!Register action before operation
  80. @return changeset id
  81. """
  82. pass
  83. def _addActionsAfter(self):
  84. pass
  85. def _addActionToChangeset(self, changeset, add, line):
  86. """!Add action to changeset
  87. @param changeset id of changeset
  88. @param add True to add, otherwise delete
  89. @param line feature id
  90. """
  91. if not self.mapInfo:
  92. return
  93. if not Vect_line_alive(self.mapInfo, line):
  94. return
  95. offset = Vect_get_line_offset(self.mapInfo, line)
  96. if not self.changesets.has_key(changeset):
  97. self.changesets[changeset] = list()
  98. self.changesetCurrent = changeset
  99. self.changesets[changeset].append((type, line, offset))
  100. Debug.msg(3, "IVDigit._addActionToChangeset(): changeset=%d, type=%d, line=%d, offset=%d",
  101. changeset, type, line, offset)
  102. def _applyChangeset(self):
  103. pass
  104. def _freeChangeset(self):
  105. pass
  106. def _removeActionFromChangeset(self):
  107. pass
  108. def AddFeature(self, ftype, points):
  109. """!Add new feature
  110. @param ftype feature type (point, line, centroid, boundary)
  111. @param points tuple of points ((x, y), (x, y), ...)
  112. @return new feature id
  113. """
  114. if UserSettings.Get(group = 'vdigit', key = "categoryMode", subkey = 'selection') == 2:
  115. layer = -1 # -> no category
  116. cat = -1
  117. else:
  118. layer = UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value')
  119. cat = self.cats.get(layer, 1)
  120. snap, thresh = self._display.GetThreshold()
  121. bgmap = str(UserSettings.Get(group = 'vdigit', key = 'bgmap',
  122. subkey = 'value', internal = True))
  123. if ftype == 'point':
  124. vtype = GV_POINT
  125. elif ftype == 'line':
  126. vtype = GV_LINE
  127. elif ftype == 'centroid':
  128. vtype = GV_CENTROID
  129. elif ftype == 'boundary':
  130. vtype = GV_BOUNDARY
  131. else:
  132. gcmd.GError(parent = self.mapwindow,
  133. message = _("Unknown feature type '%s'") % ftype)
  134. return
  135. if vtype & GV_LINES and len(points) < 2:
  136. gcmd.GError(parent = self.mapwindow,
  137. message = _("Not enough points for line"))
  138. return
  139. self.toolbar.EnableUndo()
  140. return self._addFeature(vtype, points, layer, cat,
  141. bgmap, snap, thresh)
  142. def DeleteSelectedLines(self):
  143. """!Delete selected features
  144. @return number of deleted lines
  145. """
  146. nlines = self.digit.DeleteLines(UserSettings.Get(group='vdigit', key='delRecord', subkey='enabled'))
  147. if nlines > 0:
  148. self.toolbar.EnableUndo()
  149. return nlines
  150. def MoveSelectedLines(self, move):
  151. """!Move selected features
  152. @param move direction (x, y)
  153. """
  154. snap, thresh = self.__getSnapThreshold()
  155. bgmap = str(UserSettings.Get(group='vdigit', key="bgmap",
  156. subkey='value', internal=True))
  157. try:
  158. nlines = self.digit.MoveLines(move[0], move[1], 0.0, # TODO 3D
  159. bgmap, snap, thresh)
  160. except SystemExit:
  161. pass
  162. if nlines > 0:
  163. self.toolbar.EnableUndo()
  164. return nlines
  165. def MoveSelectedVertex(self, coords, move):
  166. """!Move selected vertex of the line
  167. @param coords click coordinates
  168. @param move X,Y direction
  169. @return id of new feature
  170. @return 0 vertex not moved (not found, line is not selected)
  171. """
  172. snap, thresh = self.__getSnapThreshold()
  173. bgmap = str(UserSettings.Get(group='vdigit', key="bgmap",
  174. subkey='value', internal=True))
  175. moved = self.digit.MoveVertex(coords[0], coords[1], 0.0, # TODO 3D
  176. move[0], move[1], 0.0,
  177. bgmap, snap,
  178. self.driver.GetThreshold(type='selectThresh'), thresh)
  179. if moved:
  180. self.toolbar.EnableUndo()
  181. return moved
  182. def AddVertex(self, coords):
  183. """!Add new vertex to the selected line/boundary on position 'coords'
  184. @param coords coordinates to add vertex
  185. @return id of new feature
  186. @return 0 nothing changed
  187. @return -1 on failure
  188. """
  189. added = self.digit.ModifyLineVertex(1, coords[0], coords[1], 0.0, # TODO 3D
  190. self.driver.GetThreshold(type='selectThresh'))
  191. if added > 0:
  192. self.toolbar.EnableUndo()
  193. return added
  194. def RemoveVertex(self, coords):
  195. """!Remove vertex from the selected line/boundary on position 'coords'
  196. @param coords coordinates to remove vertex
  197. @return id of new feature
  198. @return 0 nothing changed
  199. @return -1 on failure
  200. """
  201. deleted = self.digit.ModifyLineVertex(0, coords[0], coords[1], 0.0, # TODO 3D
  202. self.driver.GetThreshold(type='selectThresh'))
  203. if deleted > 0:
  204. self.toolbar.EnableUndo()
  205. return deleted
  206. def SplitLine(self, coords):
  207. """!Split selected line/boundary on position 'coords'
  208. @param coords coordinates to split line
  209. @return 1 line modified
  210. @return 0 nothing changed
  211. @return -1 error
  212. """
  213. ret = self.digit.SplitLine(coords[0], coords[1], 0.0, # TODO 3D
  214. self.driver.GetThreshold('selectThresh'))
  215. if ret > 0:
  216. self.toolbar.EnableUndo()
  217. return ret
  218. def EditLine(self, line, coords):
  219. """!Edit existing line/boundary
  220. @param line id of line to be modified
  221. @param coords list of coordinates of modified line
  222. @return feature id of new line
  223. @return -1 on error
  224. """
  225. try:
  226. lineid = line[0]
  227. except:
  228. lineid = -1
  229. if len(coords) < 2:
  230. self.DeleteSelectedLines()
  231. return 0
  232. listCoords = []
  233. for c in coords:
  234. for x in c:
  235. listCoords.append(x)
  236. snap, thresh = self.__getSnapThreshold()
  237. bgmap = str(UserSettings.Get(group='vdigit', key="bgmap",
  238. subkey='value', internal=True))
  239. try:
  240. ret = self.digit.RewriteLine(lineid, listCoords,
  241. bgmap, snap, thresh)
  242. except SystemExit:
  243. pass
  244. if ret > 0:
  245. self.toolbar.EnableUndo()
  246. return ret
  247. def FlipLine(self):
  248. """!Flip selected lines/boundaries
  249. @return number of modified lines
  250. @return -1 on error
  251. """
  252. ret = self.digit.FlipLines()
  253. if ret > 0:
  254. self.toolbar.EnableUndo()
  255. return ret
  256. def MergeLine(self):
  257. """!Merge selected lines/boundaries
  258. @return number of modified lines
  259. @return -1 on error
  260. """
  261. ret = self.digit.MergeLines()
  262. if ret > 0:
  263. self.toolbar.EnableUndo()
  264. return ret
  265. def BreakLine(self):
  266. """!Break selected lines/boundaries
  267. @return number of modified lines
  268. @return -1 on error
  269. """
  270. ret = self.digit.BreakLines()
  271. if ret > 0:
  272. self.toolbar.EnableUndo()
  273. return ret
  274. def SnapLine(self):
  275. """!Snap selected lines/boundaries
  276. @return on success
  277. @return -1 on error
  278. """
  279. snap, thresh = self.__getSnapThreshold()
  280. ret = self.digit.SnapLines(thresh)
  281. if ret == 0:
  282. self.toolbar.EnableUndo()
  283. return ret
  284. def ConnectLine(self):
  285. """!Connect selected lines/boundaries
  286. @return 1 lines connected
  287. @return 0 lines not connected
  288. @return -1 on error
  289. """
  290. snap, thresh = self.__getSnapThreshold()
  291. ret = self.digit.ConnectLines(thresh)
  292. if ret > 0:
  293. self.toolbar.EnableUndo()
  294. return ret
  295. def CopyLine(self, ids=[]):
  296. """!Copy features from (background) vector map
  297. @param ids list of line ids to be copied
  298. @return number of copied features
  299. @return -1 on error
  300. """
  301. bgmap = str(UserSettings.Get(group='vdigit', key='bgmap',
  302. subkey='value', internal=True))
  303. if len(bgmap) > 0:
  304. ret = self.digit.CopyLines(ids, bgmap)
  305. else:
  306. ret = self.digit.CopyLines(ids, None)
  307. if ret > 0:
  308. self.toolbar.EnableUndo()
  309. return ret
  310. def CopyCats(self, fromId, toId, copyAttrb=False):
  311. """!Copy given categories to objects with id listed in ids
  312. @param cats ids of 'from' feature
  313. @param ids ids of 'to' feature(s)
  314. @return number of modified features
  315. @return -1 on error
  316. """
  317. if len(fromId) == 0 or len(toId) == 0:
  318. return 0
  319. ret = self.digit.CopyCats(fromId, toId, copyAttrb)
  320. if ret > 0:
  321. self.toolbar.EnableUndo()
  322. return ret
  323. def SelectLinesByQuery(self, pos1, pos2):
  324. """!Select features by query
  325. @param pos1, pos2 bounding box definition
  326. """
  327. thresh = self.SelectLinesByQueryThresh()
  328. w, n = pos1
  329. e, s = pos2
  330. query = wxvdigit.QUERY_UNKNOWN
  331. if UserSettings.Get(group='vdigit', key='query', subkey='selection') == 0:
  332. query = wxvdigit.QUERY_LENGTH
  333. else:
  334. query = wxvdigit.QUERY_DANGLE
  335. type = wxvdigit.GV_POINTS | wxvdigit.GV_LINES # TODO: 3D
  336. ids = self.digit.SelectLinesByQuery(w, n, 0.0, e, s, 1000.0,
  337. UserSettings.Get(group='vdigit', key='query', subkey='box'),
  338. query, type, thresh)
  339. Debug.msg(4, "VDigit.SelectLinesByQuery(): %s" % \
  340. ",".join(["%d" % v for v in ids]))
  341. return ids
  342. def GetLineCats(self, line=-1):
  343. """!Get layer/category pairs from given (selected) line
  344. @param line feature id (-1 for first selected line)
  345. """
  346. return dict(self.digit.GetLineCats(line))
  347. def GetLineLength(self, line):
  348. """!Get line length
  349. @param line feature id
  350. @return line length
  351. @return -1 on error
  352. """
  353. return self.digit.GetLineLength(line)
  354. def GetAreaSize(self, centroid):
  355. """!Get area size
  356. @param centroid centroid id
  357. @return area size
  358. @return -1 on error
  359. """
  360. return self.digit.GetAreaSize(centroid)
  361. def GetAreaPerimeter(self, centroid):
  362. """!Get area perimeter
  363. @param centroid centroid id
  364. @return area size
  365. @return -1 on error
  366. """
  367. return self.digit.GetAreaPerimeter(centroid)
  368. def SetLineCats(self, line, layer, cats, add=True):
  369. """!Set categories for given line and layer
  370. @param line feature id
  371. @param layer layer number (-1 for first selected line)
  372. @param cats list of categories
  373. @param add if True to add, otherwise do delete categories
  374. @return new feature id (feature need to be rewritten)
  375. @return -1 on error
  376. """
  377. ret = self.digit.SetLineCats(line, layer, cats, add)
  378. if ret > 0:
  379. self.toolbar.EnableUndo()
  380. return ret
  381. def GetLayers(self):
  382. """!Get list of layers"""
  383. return self.digit.GetLayers()
  384. def TypeConvForSelectedLines(self):
  385. """!Feature type conversion for selected objects.
  386. Supported conversions:
  387. - point <-> centroid
  388. - line <-> boundary
  389. @return number of modified features
  390. @return -1 on error
  391. """
  392. ret = self.digit.TypeConvLines()
  393. if ret > 0:
  394. self.toolbar.EnableUndo()
  395. return ret
  396. def Undo(self, level=-1):
  397. """!Undo action
  398. @param level levels to undo (0 to revert all)
  399. @return id of current changeset
  400. """
  401. try:
  402. ret = self.digit.Undo(level)
  403. except SystemExit:
  404. ret = -2
  405. if ret == -2:
  406. raise gcmd.GException(_("Undo failed, data corrupted."))
  407. self.mapWindow.UpdateMap(render=False)
  408. if ret < 0: # disable undo tool
  409. self.toolbar.EnableUndo(False)
  410. def ZBulkLines(self, pos1, pos2, start, step):
  411. """!Z-bulk labeling
  412. @param pos1 reference line (start point)
  413. @param pos1 reference line (end point)
  414. @param start starting value
  415. @param step step value
  416. @return number of modified lines
  417. @return -1 on error
  418. """
  419. ret = self.digit.ZBulkLabeling(pos1[0], pos1[1], pos2[0], pos2[1],
  420. start, step)
  421. if ret > 0:
  422. self.toolbar.EnableUndo()
  423. return ret
  424. def GetDisplay(self):
  425. """!Get display driver instance"""
  426. return self._display
  427. def OpenMap(self, name):
  428. """!Open vector map for editing
  429. @param map name of vector map to be set up
  430. """
  431. Debug.msg (3, "AbstractDigit.SetMapName map=%s" % name)
  432. name, mapset = name.split('@')
  433. try:
  434. self.mapInfo = self._display.OpenMap(str(name), str(mapset), True)
  435. except SystemExit:
  436. pass
  437. # except StandardError, e:
  438. # raise gcmd.GException(_("Unable to initialize display driver of vector "
  439. # "digitizer. See 'Command output' for details.\n\n"
  440. # "Details: ") + repr(e))
  441. # if map and ret == -1:
  442. # raise gcmd.GException(_('Unable to open vector map <%s> for editing.\n\n'
  443. # 'Data are probably corrupted, '
  444. # 'try to run v.build to rebuild '
  445. # 'the topology (Vector->Develop vector map->'
  446. # 'Create/rebuild topology).') % map)
  447. # if not map and ret != 0:
  448. # raise gcmd.GException(_('Unable to open vector map <%s> for editing.\n\n'
  449. # 'Data are probably corrupted, '
  450. # 'try to run v.build to rebuild '
  451. # 'the topology (Vector->Develop vector map->'
  452. # 'Create/rebuild topology).') % map)
  453. self.InitCats()
  454. def CloseMap(self):
  455. """!Close currently open vector map
  456. """
  457. if not self.mapInfo:
  458. return
  459. self._display.CloseMap()
  460. def InitCats(self):
  461. """!Initialize categories information
  462. @return 0 on success
  463. @return -1 on error
  464. """
  465. self.cats.clear()
  466. if not self.mapInfo:
  467. return -1
  468. ndblinks = Vect_get_num_dblinks(self.mapInfo)
  469. for i in range(ndblinks):
  470. fi = Vect_get_dblink(self.mapInfo, i).contents
  471. if fi:
  472. self.cats[fi.number] = None
  473. # find max category
  474. nfields = Vect_cidx_get_num_fields(self.mapInfo)
  475. Debug.msg(2, "wxDigit.InitCats(): nfields=%d", nfields)
  476. for i in range(nfields):
  477. field = Vect_cidx_get_field_number(self.mapInfo, i)
  478. ncats = Vect_cidx_get_num_cats_by_index(self.mapInfo, i)
  479. if field <= 0:
  480. continue
  481. for j in range(ncats):
  482. cat = c_int()
  483. type = c_int()
  484. id = c_int()
  485. Vect_cidx_get_cat_by_index(self.mapInfo, i, j,
  486. byref(cat), byref(type), byref(id))
  487. if self.cats.has_key(field):
  488. if cat > self.cats[field]:
  489. self.cats[field] = cat.value
  490. else:
  491. self.cats[field] = cat.value
  492. Debug.msg(3, "wxDigit.InitCats(): layer=%d, cat=%d", field, self.cats[field])
  493. # set default values
  494. for field, cat in self.cats.iteritems():
  495. if cat == None:
  496. self.cats[field] = 0 # first category 1
  497. Debug.msg(3, "wxDigit.InitCats(): layer=%d, cat=%d", field, self.cats[field])
  498. def _errorWriteLine(self):
  499. """!Show error dialog
  500. """
  501. gcmd.GError(parent = self.mapwindow,
  502. message = _("Writing new feature failed"))
  503. def _addFeature(self, type, coords, layer, cat, bgmap, snap, threshold):
  504. """!Add new feature to the vector map
  505. @param type feature type (GV_POINT, GV_LINE, GV_BOUNDARY, ...)
  506. @coords tuple of coordinates ((x, y), (x, y), ...)
  507. @param layer layer number (-1 for no cat)
  508. @param cat category number
  509. @param bgmap name of background vector map (None for no background) to be used for snapping
  510. @param snap snap to node/vertex
  511. @param threshold threshold for snapping
  512. @return -1 on error
  513. @return feature id of new feature
  514. """
  515. if not self.mapInfo:
  516. return -1
  517. is3D = bool(Vect_is_3d(self.mapInfo))
  518. Debug.msg(2, "IVDigit._addFeature(): npoints=%d, layer=%d, cat=%d, snap=%d",
  519. len(coords), layer, cat, snap)
  520. if not (type & (GV_POINTS | GV_LINES)): # TODO: 3D
  521. return -1
  522. # try to open background map if asked
  523. bgMapInfo = None
  524. if bgmap:
  525. bgMapInfo = self._openBackgroundMap(bgmap)
  526. if not bgMapInfo:
  527. gcmd.GError(parent = self.mapwindow,
  528. message = _("Unable to open background vector map <%s>") % bgmap)
  529. return -1
  530. Points = Vect_new_line_struct()
  531. Cats = Vect_new_cats_struct()
  532. # set category
  533. if layer > 0 and \
  534. (type != GV_BOUNDARY or \
  535. (type == GV_BOUNDARY and self.settings['catBoundary'])):
  536. Vect_cat_set(Cats, layer, cat)
  537. self.cats[layer] = max(cat, self.cats.get(layer, 0))
  538. # append points
  539. for c in coords:
  540. Vect_append_point(Points, c[0], c[1], 0.0)
  541. if type & GV_BOUNDARY:
  542. # close boundary
  543. cPoints = Points.contents
  544. last = cPoints.n_points - 1
  545. if Vect_points_distance(cPoints.x[0], cPoints.x[0], cPoints.z[0],
  546. cPoints.x[last], cPoints.x[last], cPoints.z[last],
  547. is3D) <= threshold:
  548. cPoints.x[last] = cPoints.x[0]
  549. cPoints.y[last] = cPoints.y[0]
  550. cPoints.z[last] = cPoints.z[0]
  551. if snap != NO_SNAP and (type & (GV_POINT | GV_LINES)):
  552. # apply snapping (node or vertex)
  553. modeSnap = not (snap == SNAP)
  554. if bgMapInfo:
  555. Vedit_snap_line(self.mapInfo, byref(bgMapInfo), 1,
  556. -1, Points, threshold, modeSnap)
  557. else:
  558. # Vedit_snap_line(self.mapInfo, None, 0,
  559. # -1, Points, threshold, modeSnap)
  560. pass
  561. newline = Vect_write_line(self.mapInfo, type, Points, Cats)
  562. if newline < 0:
  563. self._errorWriteLine()
  564. return -1
  565. left = right = -1
  566. if type & GV_BOUNDARY and self.settings['addCentroid']:
  567. # add centroids for left/right area
  568. bpoints = Vect_new_line_struct()
  569. cleft = c_int()
  570. cright = c_int()
  571. Vect_get_line_areas(self.mapInfo, newline,
  572. byref(cleft), byref(cright))
  573. left = cleft.value
  574. right = cright.value
  575. # check if area exists and has no centroid inside
  576. if layer > 0 and (left > 0 or right > 0):
  577. Vect_cat_set(Cats, layer, cat)
  578. self.cats[layer] = max(cat, self.cats.get(layer, 0))
  579. x = c_double()
  580. y = c_double()
  581. if left > 0 and \
  582. Vect_get_area_centroid(self.mapInfo, left) == 0:
  583. if Vect_get_area_points(self.mapInfo, left, bpoints) > 0 and \
  584. Vect_find_poly_centroid(bpoints, byref(x), byref(y)) == 0:
  585. Vect_reset_line(bpoints)
  586. Vect_append_point(bpoints, x.value, y.value, 0.0)
  587. if Vect_write_line(self.mapInfo, GV_CENTROID,
  588. bpoints, Cats) < 0:
  589. self._errorWriteLine()
  590. return -1
  591. if right > 0 and \
  592. Vect_get_area_centroid(self.mapInfo, right) == 0:
  593. if Vect_get_area_points(byref(self.mapInfo), right, bpoints) > 0 and \
  594. Vect_find_poly_centroid(bpoints, byref(x), byref(y)) == 0:
  595. Vect_reset_line(bpoints)
  596. Vect_append_point(bpoints, x.value, y.value, 0.0)
  597. if Vect_write_line(byref(self.mapInfo), GV_CENTROID,
  598. bpoints, Cats) < 0:
  599. self._errorWriteLine()
  600. return -1
  601. Vect_destroy_line_struct(bpoints)
  602. # register changeset
  603. self._addActionToChangeset(len(self.changesets), True, newline)
  604. # break at intersection
  605. if self.settings['breakLines']:
  606. self._breakLineAtIntersection(newline, Points, changeset)
  607. Vect_destroy_line_struct(Points)
  608. Vect_destroy_cats_struct(Cats)
  609. # close background map if opened
  610. if bgMapInfo:
  611. Vect_close(byref(bgMapInfo))
  612. if type & GV_BOUNDARY and \
  613. not self.settings['catBoundary'] and \
  614. left < 1 and right < 1:
  615. newline = None # ?
  616. return newline
  617. def RewriteLine(self):
  618. pass
  619. def SplitLine(self):
  620. pass
  621. def DeleteLines(self):
  622. pass
  623. def MoveLines(self):
  624. pass
  625. def FlipLines(self):
  626. pass
  627. def MergeLines(self):
  628. pass
  629. def BreakLines(self):
  630. pass
  631. def SnapLines(self):
  632. pass
  633. def ConnectLines(self):
  634. pass
  635. def TypeConvLines(self):
  636. pass
  637. def ZBulkLabeling(self):
  638. pass
  639. def CopyLines(self):
  640. pass
  641. def MoveVertex(self):
  642. pass
  643. def ModifyLineVertex(self):
  644. pass
  645. def SelectLinesByQuery(self):
  646. pass
  647. def GetLineLength(self):
  648. pass
  649. def GetAreaSize(self):
  650. pass
  651. def GetAreaPerimeter(self):
  652. pass
  653. def CopyCats(self):
  654. pass
  655. def GetLineCats(self):
  656. pass
  657. def SetLineCats(self):
  658. pass
  659. def GetLayers(self):
  660. pass
  661. def Undo(self):
  662. pass
  663. def GetUndoLevel(self):
  664. pass
  665. def UpdateSettings(self, breakLines, addCentroid, catBoundary):
  666. """!Update digit settings
  667. @param breakLines break lines on intersection
  668. @param addCentroid add centroid to left/right area
  669. @param catBoundary attach category to boundary
  670. """
  671. self._settings['breakLines'] = breakLines
  672. self._settings['addCentroid'] = addCentroid
  673. self._settings['catBoundary'] = None # !catBoundary # do not attach
  674. def _getCategory(self):
  675. """!Get current category number to be use"""
  676. if not UserSettings.Get(group = 'vdigit', key = 'categoryMode', subkey = 'selection'):
  677. self.SetCategoryNextToUse()
  678. return UserSettings.Get(group = 'vdigit', key = 'category', subkey = 'value')
  679. def _setCategoryNextToUse(self):
  680. """!Find maximum category number for the given layer and
  681. update the settings
  682. """
  683. # reset 'category' to '1' (for maps with no attributes)
  684. UserSettings.Set(group = 'vdigit', key = 'category', subkey = 'value', value = 1)
  685. # get max category number for given layer and update the settings
  686. cat = self.cats.get(UserSettings.Get(group = 'vdigit', key = 'layer', subkey = 'value'), 0)
  687. cat += 1
  688. UserSettings.Set(group = 'vdigit', key = 'category', subkey = 'value',
  689. value = cat)