1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759 |
- """!
- @package wxvdigit.py
- @brief wxGUI vector digitizer (base class)
- Code based on wxVdigit C++ component from GRASS 6.4.0
- (gui/wxpython/vdigit). Converted to Python in 2010/12-2011/01.
- List of classes:
- - VDigitError
- - IVDigit
- @todo Read large amounts of data from Vlib into arrays, which could
- then be processed using NumPy and rendered using glDrawArrays or
- glDrawElements, so no per-line/per-vertex processing in Python. Bulk
- data processing with NumPy is much faster than iterating in Python
- (and NumPy would be an excellent candidate for acceleration via
- e.g. OpenCL or CUDA; I'm surprised it hasn't happened already).
- (C) 2007-2011 by the GRASS Development Team
- This program is free software under the GNU General Public License
- (>=v2). Read the file COPYING that comes with GRASS for details.
- @author Martin Landa <landa.martin gmail.com>
- """
- from gcmd import GError
- from debug import Debug
- from preferences import globalSettings as UserSettings
- from wxvdriver import DisplayDriver, GetLastError
- from grass.lib.gis import *
- from grass.lib.vector import *
- from grass.lib.vedit import *
- from grass.lib.dbmi import *
- import grass.script.core as grass
- class VDigitError:
- def __init__(self, parent):
- """!Class for managing error messages of vector digitizer
- @param parent parent window for dialogs
- """
- self.parent = parent
- self.caption = _('Digitization Error')
-
- def NoMap(self, name = None):
- """!No map for editing"""
- if name:
- message = _('Unable to open vector map <%s>.') % name
- else:
- message = _('No vector map open for editing.')
- GError(message + ' ' + _('Operation cancelled.'),
- parent = self.parent,
- caption = self.caption)
- def WriteLine(self):
- """!Writing line failed
- """
- GError(message = _('Writing new feature failed. '
- 'Operation cancelled.\n\n'
- 'Reason: %s') % GetLastError(),
- parent = self.parent,
- caption = self.caption)
- def ReadLine(self, line):
- """!Reading line failed
- """
- GError(message = _('Reading feature id %d failed. '
- 'Operation cancelled.') % line,
- parent = self.parent,
- caption = self.caption)
- def DbLink(self, dblink):
- """!No dblink available
- """
- GError(message = _('Database link %d not available. '
- 'Operation cancelled.') % dblink,
- parent = self.parent,
- caption = self.caption)
- def Driver(self, driver):
- """!Staring driver failed
- """
- GError(message = _('Unable to start database driver <%s>. '
- 'Operation cancelled.') % driver,
- parent = self.parent,
- caption = self.caption)
- def Database(self, driver, database):
- """!Opening database failed
- """
- GError(message = _('Unable to open database <%(db)s> by driver <%(driver)s>. '
- 'Operation cancelled.') % { 'db' : database, 'driver' : driver},
- parent = self.parent,
- caption = self.caption)
- def DbExecute(self, sql):
- """!Sql query failed
- """
- GError(message = _("Unable to execute SQL query '%s'. "
- "Operation cancelled.") % sql,
- parent = self.parent,
- caption = self.caption)
- def DeadLine(self, line):
- """!Dead line
- """
- GError(message = _("Feature id %d is marked as dead. "
- "Operation cancelled.") % line,
- parent = self.parent,
- caption = self.caption)
- def FeatureType(self, ftype):
- """!Unknown feature type
- """
- GError(message = _("Unsupported feature type %d. "
- "Operation cancelled.") % ftype,
- parent = self.parent,
- caption = self.caption)
-
- class IVDigit:
- def __init__(self, mapwindow):
- """!Base class for vector digitizer (ctypes interface)
-
- @parem mapwindow reference for map window (BufferedWindow)
- """
- self.poMapInfo = None # pointer to Map_info
- self.mapWindow = mapwindow
- # background map
- self.bgMapInfo = Map_info()
- self.poBgMapInfo = self.popoBgMapInfo = None
-
- if not mapwindow.parent.IsStandalone():
- goutput = mapwindow.parent.GetLayerManager().GetLogWindow()
- log = goutput.GetLog(err = True)
- progress = goutput.GetProgressBar()
- else:
- log = sys.stderr
- progress = None
-
- self.toolbar = mapwindow.parent.toolbars['vdigit']
-
- self._error = VDigitError(parent = self.mapWindow)
-
- self._display = DisplayDriver(device = mapwindow.pdcVector,
- deviceTmp = mapwindow.pdcTmp,
- mapObj = mapwindow.Map,
- window = mapwindow,
- glog = log,
- gprogress = progress)
-
- # GRASS lib
- self.poPoints = Vect_new_line_struct()
- self.poCats = Vect_new_cats_struct()
-
- # self.SetCategory()
-
- # layer / max category
- self.cats = dict()
-
- self._settings = dict()
- self.UpdateSettings() # -> self._settings
-
- # undo/redo
- self.changesets = dict()
- self.changesetCurrent = -1 # first changeset to apply
- self.changesetEnd = -1 # last changeset to be applied
-
- if self.poMapInfo:
- self.InitCats()
-
- def __del__(self):
- Debug.msg(1, "IVDigit.__del__()")
- Vect_destroy_line_struct(self.poPoints)
- self.poPoints = None
- Vect_destroy_cats_struct(self.poCats)
- self.poCats = None
-
- if self.poBgMapInfo:
- Vect_close(self.poBgMapInfo)
- self.poBgMapInfo = self.popoBgMapInfo = None
- del self.bgMapInfo
-
- def CloseBackgroundMap(self):
- """!Close background vector map"""
- if not self.poBgMapInfo:
- return
-
- Vect_close(self.poBgMapInfo)
- self.poBgMapInfo = self.popoBgMapInfo = None
-
- def OpenBackgroundMap(self, bgmap):
- """!Open background vector map
- @todo support more background maps then only one
-
- @param bgmap name of vector map to be opened
- @return pointer to map_info
- @return None on error
- """
- name = create_string_buffer(GNAME_MAX)
- mapset = create_string_buffer(GMAPSET_MAX)
- if not G_name_is_fully_qualified(bgmap, name, mapset):
- name = str(bgmap)
- mapset = str(G_find_vector2(bgmap, ''))
- else:
- name = str(name.value)
- mapset = str(mapset.value)
-
- if (name == Vect_get_name(self.poMapInfo) and \
- mapset == Vect_get_mapset(self.poMapInfo)):
- self.poBgMapInfo = self.popoBgMapInfo = None
- self._error.NoMap(bgmap)
- return
-
- self.poBgMapInfo = pointer(self.bgMapInfo)
- self.popoBgMapInfo = pointer(self.poBgMapInfo)
- if Vect_open_old(self.poBgMapInfo, name, mapset) == -1:
- self.poBgMapInfo = self.popoBgMapInfo = None
- self._error.NoMap(bgmap)
- return
-
- def _getSnapMode(self):
- """!Get snapping mode
- - snap to vertex
- - snap to nodes
- - no snapping
-
- @return snap mode
- """
- threshold = self._display.GetThreshold()
- if threshold > 0.0:
- if UserSettings.Get(group = 'vdigit', key = 'snapToVertex', subkey = 'enabled'):
- return SNAPVERTEX
- else:
- return SNAP
- else:
- return NO_SNAP
-
- def _breakLineAtIntersection(self, line, pointsLine, changeset):
- """!Break given line at intersection
- \param line line id
- \param pointsLine line geometry
- \param changeset id
-
- \return number of modified lines
- """
- if not self._checkMap():
- return -1
-
- if not Vect_line_alive(self.poMapInfo, line):
- return 0
-
- if not pointsLine:
- if Vect_read_line(self.poMapInfo, self.poPoints, None, line) < 0:
- self._error.ReadLine(line)
- return -1
- points = self.poPoints
- else:
- points = pointsLine
-
- listLine = Vect_new_boxlist(0)
- listRef = Vect_new_list()
- listBreak = Vect_new_list()
-
- pointsCheck = Vect_new_line_struct()
-
- lineBox = bound_box()
- # find all relevant lines
- Vect_get_line_box(self.poMapInfo, line, byref(lineBox))
- Vect_select_lines_by_box(self.poMapInfo, byref(lineBox),
- GV_LINES, listLine)
-
- # check for intersection
- Vect_list_append(listBreak, line)
- Vect_list_append(listRef, line)
- for i in range(listLine.contents.n_values):
- lineBreak = listLine.contents.id[i]
- if lineBreak == line:
- continue
-
- ltype = Vect_read_line(self.poMapInfo, pointsCheck, None, lineBreak)
- if not (ltype & GV_LINES):
- continue
-
- if Vect_line_check_intersection(self.poPoints, pointsCheck,
- WITHOUT_Z):
- Vect_list_append(listBreak, lineBreak)
-
- nlines = Vect_get_num_lines(self.poMapInfo)
-
- for i in range(listBreak.contents.n_values):
- self._addActionToChangeset(changeset, listBreak.contents.value[i], add = False)
-
- ret = Vect_break_lines_list(self.poMapInfo, listBreak, listRef,
- GV_LINES, None)
-
- for i in range(listBreak.contents.n_values):
- if Vect_line_alive(self.poMapInfo, listBreak.contents.value[i]):
- self._removeActionFromChangeset(changeset, listBreak.contents.value[i],
- add = False)
-
- for line in range(nlines + 1, Vect_get_num_lines(self.poMapInfo) + 1):
- self._addActionToChangeset(changeset, line, add = True)
-
- Vect_destroy_line_struct(pointsCheck)
- Vect_destroy_boxlist(listLine)
- Vect_destroy_list(listBreak)
- Vect_destroy_list(listRef)
-
- return ret
-
- def _addActionsBefore(self):
- """!Register action before operation
-
- @return changeset id
- """
- changeset = len(self.changesets)
- for line in self._display.selected['ids']:
- if Vect_line_alive(self.poMapInfo, line):
- self._addActionToChangeset(changeset, line, add = False)
-
- return changeset
- def _applyChangeset(self, changeset, undo):
- """!Apply changeset (undo/redo changeset)
-
- @param changeset changeset id
- @param undo True for undo otherwise redo
- @return 1 changeset applied
- @return 0 changeset not applied
- @return -1 on error
- """
- if changeset < 0 or changeset > len(self.changesets.keys()):
- return -1
-
- if self.changesetEnd < 0:
- self.changesetEnd = changeset
-
- ret = 0
- actions = self.changesets[changeset]
- for action in actions:
- add = action['add']
- line = action['line']
- if (undo and add) or \
- (not undo and not add):
- if Vect_line_alive(self.poMapInfo, line):
- Debug.msg(3, "IVDigit._applyChangeset(): changeset=%d, action=add, line=%d -> deleted",
- changeset, line)
- Vect_delete_line(self.poMapInfo, line)
- ret = 1
- else:
- Debug.msg(3, "Digit.ApplyChangeset(): changeset=%d, action=add, line=%d dead",
- changeset, line)
- else: # delete
- offset = action['offset']
- if not Vect_line_alive(self.poMapInfo, line):
- Debug.msg(3, "Digit.ApplyChangeset(): changeset=%d, action=delete, line=%d -> added",
- changeset, line)
- if Vect_restore_line(self.poMapInfo, line, offset) < 0:
- return -1
- ret = 1
- else:
- Debug.msg(3, "Digit.ApplyChangeset(): changeset=%d, action=delete, line=%d alive",
- changeset, line)
-
- return ret
-
- def _addActionsAfter(self, changeset, nlines):
- """!Register action after operation
- @param changeset changeset id
- @param nline number of lines
- """
- for line in self._display.selected['ids']:
- if Vect_line_alive(self.poMapInfo, line):
- self._removeActionFromChangeset(changeset, line, add = False)
-
- for line in range(nlines + 1, Vect_get_num_lines(self.poMapInfo)):
- if Vect_line_alive(self.poMapInfo, line):
- self._addActionToChangeset(changeset, line, add = True)
-
- def _addActionToChangeset(self, changeset, line, add):
- """!Add action to changeset
-
- @param changeset id of changeset
- @param line feature id
- @param add True to add, otherwise delete
- """
- if not self._checkMap():
- return
-
- if not Vect_line_alive(self.poMapInfo, line):
- return
-
- offset = Vect_get_line_offset(self.poMapInfo, line)
-
- if changeset not in self.changesets:
- self.changesets[changeset] = list()
- self.changesetCurrent = changeset
-
- self.changesets[changeset].append({ 'add' : add,
- 'line' : line,
- 'offset' : offset })
-
- Debug.msg(3, "IVDigit._addActionToChangeset(): changeset=%d, add=%d, line=%d, offset=%d",
- changeset, add, line, offset)
-
- def _removeActionFromChangeset(self, changeset, line, add):
- """!Remove action from changeset
-
- @param changeset changeset id
- @param line line id
- @param add True for add, False for delete
-
- @return number of actions in changeset
- @return -1 on error
- """
- if changeset not in self.changesets.keys():
- return -1
-
- alist = self.changesets[changeset]
- for action in alist:
- if action['add'] == add and action['line'] == line:
- alist.remove(action)
-
- return len(alist)
- def AddFeature(self, ftype, points):
- """!Add new feature
-
- @param ftype feature type (point, line, centroid, boundary)
- @param points tuple of points ((x, y), (x, y), ...)
-
- @return tuple (number of added features, feature ids)
- """
- if UserSettings.Get(group = 'vdigit', key = "categoryMode", subkey = 'selection') == 2:
- layer = -1 # -> no category
- cat = -1
- else:
- layer = UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value')
- cat = self.SetCategory()
-
- if ftype == 'point':
- vtype = GV_POINT
- elif ftype == 'line':
- vtype = GV_LINE
- elif ftype == 'centroid':
- vtype = GV_CENTROID
- elif ftype == 'boundary':
- vtype = GV_BOUNDARY
- elif ftype == 'area':
- vtype = GV_AREA
- else:
- GError(parent = self.mapWindow,
- message = _("Unknown feature type '%s'") % ftype)
- return (-1, None)
-
- if vtype & GV_LINES and len(points) < 2:
- GError(parent = self.mapWindow,
- message = _("Not enough points for line"))
- return (-1, None)
-
- self.toolbar.EnableUndo()
-
- return self._addFeature(vtype, points, layer, cat,
- self._getSnapMode(), self._display.GetThreshold())
-
- def DeleteSelectedLines(self):
- """!Delete selected features
- @return number of deleted features
- """
- deleteRec = UserSettings.Get(group = 'vdigit', key = 'delRecord', subkey = 'enabled')
- if not self._checkMap():
- return -1
-
- n_dblinks = Vect_get_num_dblinks(self.poMapInfo)
- Cats_del = None
-
- # collect categories for delete if requested
- if deleteRec:
- poCats = Vect_new_cats_struct()
- poCatsDel = Vect_new_cats_struct()
- for i in self._display.selected['ids']:
- if Vect_read_line(self.poMapInfo, None, poCats, i) < 0:
- Vect_destroy_cats_struct(poCatsDel)
- self._error.ReadLine(i)
- return -1
-
- cats = poCats.contents
- for j in range(cats.n_cats):
- Vect_cat_set(poCatsDel, cats.field[j], cats.cat[j])
-
- Vect_destroy_cats_struct(poCats)
-
- # register changeset
- changeset = self._addActionsBefore()
-
- poList = self._display.GetSelectedIList()
- nlines = Vedit_delete_lines(self.poMapInfo, poList)
- Vect_destroy_list(poList)
- self._display.selected['ids'] = list()
-
- if nlines > 0 and deleteRec:
- handle = dbHandle()
- poHandle = pointer(handle)
- stmt = dbString()
- poStmt = pointer(stmt)
-
- for dblink in range(n_dblinks):
- poFi = Vect_get_dblink(self.poMapInfo, dblink)
- if poFi is None:
- self._error.DbLink(dblink)
- return -1
-
- Fi = poFi.contents
- poDriver = db_start_driver(Fi.driver)
- if poDriver is None:
- self._error.Driver(Fi.driver)
- return -1
-
- db_init_handle(poHandle)
- db_set_handle(poHandle, Fi.database, None)
- if db_open_database(poDriver, poHandle) != DB_OK:
- self._error.Database(Fi.driver, Fi.database)
- return -1
-
- db_init_string(poStmt)
- db_set_string(poStmt, "DELETE FROM %s WHERE" % Fi.table)
- n_cats = 0;
- catsDel = poCatsDel.contents
- for c in range(catsDel.n_cats):
- if catsDel.field[c] == Fi.number:
- if n_cats > 0:
- db_append_string(poStmt, " or")
-
- db_append_string(poStmt, " %s = %d" % (Fi.key, catsDel.cat[c]))
- n_cats += 1
-
- Vect_cat_del(poCatsDel, Fi.number)
-
- if n_cats and \
- db_execute_immediate(poDriver, poStmt) != DB_OK:
- self._error.DbExecute(db_get_string(poStmt))
- return -1
-
- db_close_database(poDriver)
- db_shutdown_driver(poDriver)
-
- if poCatsDel:
- Vect_destroy_cats_struct(poCatsDel)
-
- if nlines > 0:
- self.toolbar.EnableUndo()
-
- return nlines
- def MoveSelectedLines(self, move):
- """!Move selected features
- @param move direction (x, y)
- """
- if not self._checkMap():
- return -1
-
- thresh = self._display.GetThreshold()
- snap = self._getSnapMode()
-
- nlines = Vect_get_num_lines(self.poMapInfo)
-
- # register changeset
- changeset = self._addActionsBefore()
-
- poList = self._display.GetSelectedIList()
- nlines = Vedit_move_lines(self.poMapInfo, self.popoBgMapInfo, int(self.poBgMapInfo is not None),
- poList,
- move[0], move[1], 0,
- snap, thresh)
- Vect_destroy_list(poList)
-
- if nlines > 0:
- self._addActionsAfter(changeset, nlines)
- else:
- del self.changesets[changeset]
-
- if nlines > 0 and self._settings['breakLines']:
- for i in range(1, nlines):
- self._breakLineAtIntersection(nlines + i, None, changeset)
-
- if nlines > 0:
- self.toolbar.EnableUndo()
-
- return nlines
- def MoveSelectedVertex(self, point, move):
- """!Move selected vertex of the line
- @param point location point
- @param move x,y direction
-
- @return id of new feature
- @return 0 vertex not moved (not found, line is not selected)
- @return -1 on error
- """
- if not self._checkMap():
- return -1
-
- if len(self._display.selected['ids']) != 1:
- return -1
-
- Vect_reset_line(self.poPoints)
- Vect_append_point(self.poPoints, point[0], point[1], 0.0)
-
- nlines = Vect_get_num_lines(self.poMapInfo)
-
- changeset = self._addActionsBefore()
-
- # move only first found vertex in bbox
- poList = self._display.GetSelectedIList()
- moved = Vedit_move_vertex(self.poMapInfo, self.popoBgMapInfo, int(self.poBgMapInfo is not None),
- poList, self.poPoints,
- self._display.GetThreshold(type = 'selectThresh'),
- self._display.GetThreshold(),
- move[0], move[1], 0.0,
- 1, self._getSnapMode())
- Vect_destroy_list(poList)
-
- if moved > 0:
- self._addActionsAfter(changeset, nlines)
- else:
- del self.changesets[changeset]
-
- if moved > 0 and self._settings['breakLines']:
- self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
- None, changeset)
-
- if moved > 0:
- self.toolbar.EnableUndo()
-
- return moved
- def AddVertex(self, coords):
- """!Add new vertex to the selected line/boundary on position 'coords'
- @param coords coordinates to add vertex
- @return id of new feature
- @return 0 nothing changed
- @return -1 on failure
- """
- added = self._ModifyLineVertex(coords, add = True)
-
- if added > 0:
- self.toolbar.EnableUndo()
- return added
- def RemoveVertex(self, coords):
- """!Remove vertex from the selected line/boundary on position 'coords'
- @param coords coordinates to remove vertex
- @return id of new feature
- @return 0 nothing changed
- @return -1 on failure
- """
- deleted = self._ModifyLineVertex(coords, add = False)
-
- if deleted > 0:
- self.toolbar.EnableUndo()
- return deleted
- def SplitLine(self, point):
- """!Split/break selected line/boundary on given position
- @param point point where to split line
-
- @return 1 line modified
- @return 0 nothing changed
- @return -1 error
- """
- thresh = self._display.GetThreshold('selectThresh')
- if not self._checkMap():
- return -1
-
- poList = self._display.GetSelectedIList()
- Vect_reset_line(self.poPoints)
- Vect_append_point(self.poPoints, point[0], point[1], 0.0)
-
- nlines = Vect_get_num_lines(self.poMapInfo)
-
- changeset = self._addActionsBefore()
-
- ret = Vedit_split_lines(self.poMapInfo, poList,
- self.poPoints, thresh, None)
- Vect_destroy_list(poList)
-
- if ret > 0:
- self._addActionsAfter(changeset, nlines)
- self.toolbar.EnableUndo()
- else:
- del self.changesets[changeset]
-
- return ret
- def EditLine(self, line, coords):
- """!Edit existing line/boundary
- @param line feature id to be modified
- @param coords list of coordinates of modified line
- @return feature id of new line
- @return -1 on error
- """
- if not self._checkMap():
- return -1
-
- if len(coords) < 2:
- self.DeleteSelectedLines()
- return 0
-
- if not Vect_line_alive(self.poMapInfo, line):
- self._error.DeadLine(line)
- return -1
-
- # read original feature
- ltype = Vect_read_line(self.poMapInfo, None, self.poCats, line)
- if ltype < 0:
- self._error.ReadLine(line)
- return -1
-
- # build feature geometry
- Vect_reset_line(self.poPoints)
- for p in coords:
- Vect_append_point(self.poPoints, p[0], p[1], 0.0)
- # apply snapping (node or vertex)
- snap = self._getSnapMode()
- if snap != NO_SNAP:
- modeSnap = not (snap == SNAP)
- Vedit_snap_line(self.poMapInfo, self.popoBgMapInfo,
- int(self.poBgMapInfo is not None),
- -1, self.poPoints, self._display.GetThreshold(), modeSnap)
- nlines = Vect_get_num_lines(self.poMapInfo)
-
- changeset = self._addActionsBefore()
- newline = Vect_rewrite_line(self.poMapInfo, line, ltype,
- self.poPoints, self.poCats)
- if newline > 0:
- self._addActionsAfter(changeset, nlines)
- self.toolbar.EnableUndo()
- else:
- del self.changesets[changeset]
-
- if newline > 0 and self._settings['breakLines']:
- self._breakLineAtIntersection(newline, None, changeset)
-
- return newline
- def FlipLine(self):
- """!Flip selected lines/boundaries
- @return number of modified lines
- @return -1 on error
- """
- if not self._checkMap():
- return -1
-
- nlines = Vect_get_num_lines(self.poMapInfo)
-
- # register changeset
- changeset = self._addActionsBefore()
-
- poList = self._display.GetSelectedIList()
- ret = Vedit_flip_lines(self.poMapInfo, poList)
- Vect_destroy_list(poList)
-
- if ret > 0:
- self._addActionsAfter(changeset, nlines)
- self.toolbar.EnableUndo()
- else:
- del self.changesets[changeset]
-
- return ret
- def MergeLine(self):
- """!Merge selected lines/boundaries
- @return number of modified lines
- @return -1 on error
- """
- if not self._checkMap():
- return -1
-
- nlines = Vect_get_num_lines(self.poMapInfo)
-
- changeset = self._addActionsBefore()
-
- poList = self._display.GetSelectedIList()
- ret = Vedit_merge_lines(self.poMapInfo, poList)
- Vect_destroy_list(poList)
-
- if ret > 0:
- self._addActionsAfter(changeset, nlines)
- self.toolbar.EnableUndo()
- else:
- del self.changesets[changeset]
-
- return ret
- def BreakLine(self):
- """!Break selected lines/boundaries
- @return number of modified lines
- @return -1 on error
- """
- if not self._checkMap():
- return -1
-
- nlines = Vect_get_num_lines(self.poMapInfo)
-
- changeset = self._addActionsBefore()
-
- poList = self._display.GetSelectedIList()
- ret = Vect_break_lines_list(self.poMapInfo, poList, None,
- GV_LINES, None)
- Vect_destroy_list(poList)
-
- if ret > 0:
- self._addActionsAfter(changeset, nlines)
- self.toolbar.EnableUndo()
- else:
- del self.changesets[changeset]
-
- return ret
- def SnapLine(self):
- """!Snap selected lines/boundaries
- @return on success
- @return -1 on error
- """
- if not self._checkMap():
- return -1
-
- nlines = Vect_get_num_lines(self.poMapInfo)
-
- changeset = self._addActionsBefore()
-
- poList = self._display.GetSelectedIList()
- Vect_snap_lines_list(self.poMapInfo, poList,
- self._display.GetThreshold(), None)
- Vect_destroy_list(poList)
-
- if nlines < Vect_get_num_lines(self.poMapInfo):
- self._addActionsAfter(changeset, nlines)
- self.toolbar.EnableUndo()
- else:
- del self.changesets[changeset]
-
- def ConnectLine(self):
- """!Connect selected lines/boundaries
- @return 1 lines connected
- @return 0 lines not connected
- @return -1 on error
- """
- if not self._checkMap():
- return -1
-
- nlines = Vect_get_num_lines(self.poMapInfo)
-
- # register changeset
- changeset = self._addActionsBefore()
-
- poList = self._display.GetSelectedIList()
- ret = Vedit_connect_lines(self.poMapInfo, poList,
- self._display.GetThreshold())
- Vect_destroy_list(poList)
-
- if ret > 0:
- self._addActionsAfter(changeset, nlines)
- self.toolbar.EnableUndo()
- else:
- del self.changesets[changeset]
-
- return ret
-
- def CopyLine(self, ids = []):
- """!Copy features from (background) vector map
- @param ids list of line ids to be copied
- @return number of copied features
- @return -1 on error
- """
- if not self._checkMap():
- return -1
-
- nlines = Vect_get_num_lines(self.poMapInfo)
-
- poList = self._display.GetSelectedIList(ids)
- ret = Vedit_copy_lines(self.poMapInfo, self.poBgMapInfo,
- poList)
- Vect_destroy_list(poList)
-
- if ret > 0:
- changeset = len(self.changesets)
- for line in (range(nlines + 1, Vect_get_num_lines(self.poMapInfo))):
- self._addActionToChangeset(changeset, line, add = True)
- self.toolbar.EnableUndo()
- else:
- del self.changesets[changeset]
- if ret > 0 and self.poBgMapInfo and self._settings['breakLines']:
- for i in range(1, ret):
- self._breakLineAtIntersection(nlines + i, None, changeset)
-
- return ret
- def CopyCats(self, fromId, toId, copyAttrb = False):
- """!Copy given categories to objects with id listed in ids
- @param cats ids of 'from' feature
- @param ids ids of 'to' feature(s)
- @return number of modified features
- @return -1 on error
- """
- if len(fromId) < 1 or len(toId) < 1:
- return 0
-
- poCatsFrom = self.poCats
- poCatsTo = Vect_new_cats_struct();
-
- nlines = 0
-
- for fline in fromId:
- if not Vect_line_alive(self.poMapInfo, fline):
- continue
-
- if Vect_read_line(self.poMapInfo, None, poCatsFrom, fline) < 0:
- self._error.ReadLine(fline)
- return -1
-
- for tline in toId:
- if not Vect_line_alive(self.poMapInfo, tline):
- continue
-
- ltype = Vect_read_line(self.poMapInfo, self.poPoints, poCatsTo, tline)
- if ltype < 0:
- self._error.ReadLine(fline)
- return -1
-
- catsFrom = poCatsFrom.contents
- for i in range(catsFrom.n_cats):
- if not copyAttrb:
- # duplicate category
- cat = catsFrom.cat[i]
- else:
- # duplicate attributes
- cat = self.cats[catsFrom.field[i]] + 1
- self.cats[catsFrom.field[i]] = cat
- poFi = Vect_get_field(self.poMapInfo, catsFrom.field[i])
- if not poFi:
- self._error.DbLink(i)
- return -1
-
- fi = poFi.contents
- driver = db_start_driver(fi.driver)
- if not driver:
- self._error.Driver(fi.driver)
- return -1
-
- handle = dbHandle()
- db_init_handle(byref(handle))
- db_set_handle(byref(handle), fi.database, None)
- if db_open_database(driver, byref(handle)) != DB_OK:
- db_shutdown_driver(driver)
- self._error.Database(fi.driver, fi.database)
- return -1
-
- stmt = dbString()
- db_init_string(byref(stmt))
- db_set_string(byref(stmt),
- "SELECT * FROM %s WHERE %s=%d" % (fi.table, fi.key,
- catsFrom.cat[i]))
-
- cursor = dbCursor()
- if db_open_select_cursor(driver, byref(stmt), byref(cursor),
- DB_SEQUENTIAL) != DB_OK:
- db_close_database_shutdown_driver(driver)
- return -1
-
- table = db_get_cursor_table(byref(cursor))
- ncols = db_get_table_number_of_columns(table)
-
- sql = "INSERT INTO %s VALUES (" % fi.table
- # fetch the data
- more = c_int()
- while True:
- if db_fetch(byref(cursor), DB_NEXT, byref(more)) != DB_OK:
- db_close_database_shutdown_driver(driver)
- return -1
- if not more.value:
- break
-
- value_string = dbString()
- for col in range(ncols):
- if col > 0:
- sql += ","
-
- column = db_get_table_column(table, col)
- if db_get_column_name(column) == fi.key:
- sql += "%d" % cat
- continue
-
- value = db_get_column_value(column)
- db_convert_column_value_to_string(column, byref(value_string))
- if db_test_value_isnull(value):
- sql += "NULL"
- else:
- ctype = db_sqltype_to_Ctype(db_get_column_sqltype(column))
- if ctype != DB_C_TYPE_STRING:
- sql += db_get_string(byref(value_string))
- else:
- sql += "'%s'" % db_get_string(byref(value_string))
-
- sql += ")"
- db_set_string(byref(stmt), sql)
- if db_execute_immediate(driver, byref(stmt)) != DB_OK:
- db_close_database_shutdown_driver(driver)
- return -1
-
- db_close_database_shutdown_driver(driver)
- G_free(poFi)
-
- if Vect_cat_set(poCatsTo, catsFrom.field[i], cat) < 1:
- continue
-
- if Vect_rewrite_line(self.poMapInfo, tline, ltype, self.poPoints, poCatsTo) < 0:
- self._error.WriteLine()
- return -1
-
- nlines +=1
-
- Vect_destroy_cats_struct(poCatsTo)
-
- if nlines > 0:
- self.toolbar.EnableUndo()
-
- return nlines
- def _selectLinesByQueryThresh(self):
- """!Generic method used for SelectLinesByQuery() -- to get
- threshold value"""
- thresh = 0.0
- if UserSettings.Get(group = 'vdigit', key = 'query', subkey = 'selection') == 0:
- thresh = UserSettings.Get(group = 'vdigit', key = 'queryLength', subkey = 'thresh')
- if UserSettings.Get(group = 'vdigit', key = "queryLength", subkey = 'than-selection') == 0:
- thresh = -1 * thresh
- else:
- thresh = UserSettings.Get(group = 'vdigit', key = 'queryDangle', subkey = 'thresh')
- if UserSettings.Get(group = 'vdigit', key = "queryDangle", subkey = 'than-selection') == 0:
- thresh = -1 * thresh
-
- return thresh
- def SelectLinesByQuery(self, bbox):
- """!Select features by query
-
- @todo layer / 3D
-
- @param bbox bounding box definition
- """
- if not self._checkMap():
- return -1
-
- thresh = self._selectLinesByQueryThresh()
-
- query = QUERY_UNKNOWN
- if UserSettings.Get(group = 'vdigit', key = 'query', subkey = 'selection') == 0:
- query = QUERY_LENGTH
- else:
- query = QUERY_DANGLE
-
- ftype = GV_POINTS | GV_LINES # TODO: 3D
- layer = 1 # TODO
-
- ids = list()
- poList = Vect_new_list()
- coList = poList.contents
- if UserSettings.Get(group = 'vdigit', key = 'query', subkey = 'box'):
- Vect_reset_line(self.poPoints)
- x1, y1 = bbox[0]
- x2, y2 = bbox[1]
- z1 = z2 = 0.0
-
- Vect_append_point(self.poPoints, x1, y1, z1)
- Vect_append_point(self.poPoints, x2, y1, z2)
- Vect_append_point(self.poPoints, x2, y2, z1)
- Vect_append_point(self.poPoints, x1, y2, z2)
- Vect_append_point(self.poPoints, x1, y1, z1)
-
- Vect_select_lines_by_polygon(self.poMapInfo, self.poPoints, 0, None,
- ftype, poList)
-
- if coList.n_values == 0:
- return ids
-
- Vedit_select_by_query(self.poMapInfo,
- ftype, layer, thresh, query,
- poList)
-
- for i in range(coList.n_values):
- ids.append(int(coList.value[i]))
-
- Debug.msg(3, "IVDigit.SelectLinesByQuery(): lines=%d", coList.n_values)
- Vect_destroy_list(poList)
-
- return ids
- def IsVector3D(self):
- """!Check if open vector map is 3D
- """
- if not self._checkMap():
- return False
-
- return Vect_is_3d(self.poMapInfo)
-
- def GetLineLength(self, line):
- """!Get line length
- @param line feature id
- @return line length
- @return -1 on error
- """
- if not self._checkMap():
- return -1
-
- if not Vect_line_alive(self.poMapInfo, line):
- return -1
-
- ltype = Vect_read_line(self.poMapInfo, self.poPoints, None, line)
- if ltype < 0:
- self._error.ReadLine(line)
- return ret
-
- length = -1
- if ltype & GV_LINES: # lines & boundaries
- length = Vect_line_length(self.poPoints)
-
- return length
- def GetAreaSize(self, centroid):
- """!Get area size
- @param centroid centroid id
- @return area size
- @return -1 on error
- """
- if not self._checkMap():
- return -1
-
- ltype = Vect_read_line(self.poMapInfo, None, None, centroid)
- if ltype < 0:
- self._error.ReadLine(line)
- return ret
-
- if ltype != GV_CENTROID:
- return -1
-
- area = Vect_get_centroid_area(self.poMapInfo, centroid)
- size = -1
- if area > 0:
- if not Vect_area_alive(self.poMapInfo, area):
- return size
-
- size = Vect_get_area_area(self.poMapInfo, area)
-
- return size
-
- def GetAreaPerimeter(self, centroid):
- """!Get area perimeter
-
- @param centroid centroid id
-
- @return area size
- @return -1 on error
- """
- if not self._checkMap():
- return -1
-
- ltype = Vect_read_line(self.poMapInfo, None, None, centroid)
- if ltype < 0:
- self._error.ReadLine(line)
- return ret
-
- if ltype != GV_CENTROID:
- return -1
-
- area = Vect_get_centroid_area(self.poMapInfo, centroid)
- perimeter = -1
- if area > 0:
- if not Vect_area_alive(self.poMapInfo, area):
- return -1
-
- Vect_get_area_points(self.poMapInfo, area, self.poPoints)
- perimeter = Vect_area_perimeter(self.poPoints)
-
- return perimeter
-
- def SetLineCats(self, line, layer, cats, add = True):
- """!Set categories for given line and layer
- @param line feature id
- @param layer layer number (-1 for first selected line)
- @param cats list of categories
- @param add if True to add, otherwise do delete categories
- @return new feature id (feature need to be rewritten)
- @return -1 on error
- """
- if not self._checkMap():
- return -1
-
- if line < 1 and len(self._display.selected['ids']) < 1:
- return -1
-
- update = False
- if line == -1:
- update = True
- line = self._display.selected['ids'][0]
-
- if not Vect_line_alive(self.poMapInfo, line):
- return -1
-
- ltype = Vect_read_line(self.poMapInfo, self.poPoints, self.poCats, line)
- if ltype < 0:
- self._error.ReadLine(line)
- return -1
-
- for c in cats:
- if add:
- Vect_cat_set(self.poCats, layer, c)
- else:
- Vect_field_cat_del(self.poCats, layer, c)
-
- nlines = Vect_get_num_lines(self.poMapInfo)
- changeset = self._addActionsBefore()
- newline = Vect_rewrite_line(self.poMapInfo, line, ltype,
- self.poPoints, self.poCats)
-
- if newline > 0:
- self._addActionsAfter(changeset, nlines)
- self.toolbar.EnableUndo()
-
- if update:
- # update line id since the line was rewritten
- self._display.selected['ids'][0] = newline
-
- return newline
- def TypeConvForSelectedLines(self):
- """!Feature type conversion for selected objects.
- Supported conversions:
- - point <-> centroid
- - line <-> boundary
- @return number of modified features
- @return -1 on error
- """
- if not self._checkMap():
- return -1
-
- nlines = Vect_get_num_lines(self.poMapInfo)
-
- # register changeset
- changeset = self._addActionsBefore()
-
- poList = self._display.GetSelectedIList()
- ret = Vedit_chtype_lines(self.poMapInfo, poList)
- Vect_destroy_list(poList)
-
- if ret > 0:
- self._addActionsAfter(changeset, nlines)
- self.toolbar.EnableUndo()
- else:
- del self.changesets[changeset]
-
- return ret
- def Undo(self, level = -1):
- """!Undo action
- @param level levels to undo (0 to revert all)
- @return id of current changeset
- """
- changesetLast = len(self.changesets.keys()) - 1
- if changesetLast < 0:
- return changesetLast
-
- if self.changesetCurrent == -2: # value uninitialized
- self.changesetCurrent = changesetLast
-
- if level > 0 and self.changesetCurrent < 0:
- self.changesetCurrent = 0
-
- if level == 0:
- # 0 -> undo all
- level = -1 * changesetLast + 1
- Debug.msg(2, "Digit.Undo(): changeset_last=%d, changeset_current=%d, level=%d",
- changesetLast, self.changesetCurrent, level)
-
- if level < 0: # undo
- if self.changesetCurrent + level < -1:
- return changesetCurrent;
- for changeset in range(self.changesetCurrent, self.changesetCurrent + level, -1):
- self._applyChangeset(changeset, undo = True)
- elif level > 0: # redo
- if self.changesetCurrent + level > len(self.changesets.keys()):
- return self.changesetCurrent
- for changeset in range(self.changesetCurrent, self.changesetCurrent + level):
- self._applyChangeset(changeset, undo = False)
-
- self.changesetCurrent += level
- Debug.msg(2, "Digit.Undo(): changeset_current=%d, changeset_last=%d, changeset_end=%d",
- self.changesetCurrent, changesetLast, self.changesetEnd)
-
- if self.changesetCurrent == self.changesetEnd:
- self.changesetEnd = changesetLast
- return -1
-
- self.mapWindow.UpdateMap(render = False)
-
- if self.changesetCurrent < 0: # disable undo tool
- self.toolbar.EnableUndo(False)
- def ZBulkLines(self, pos1, pos2, start, step):
- """!Z-bulk labeling
- @param pos1 reference line (start point)
- @param pos1 reference line (end point)
- @param start starting value
- @param step step value
- @return number of modified lines
- @return -1 on error
- """
- if not self._checkMap():
- return -1
-
- nlines = Vect_get_num_lines(self.poMapInfo)
-
- # register changeset
- changeset = self._addActionsBefore()
-
- poList = self._display.GetSelectedIList()
- ret = Vedit_bulk_labeling(self.poMapInfo, poList,
- pos1[0], pos1[1], pos2[0], pos2[1],
- start, step)
- Vect_destroy_list(poList)
-
- if ret > 0:
- self._addActionsAfter(changeset, nlines)
- self.toolbar.EnableUndo()
- else:
- del self.changesets[changeset]
-
- return ret
-
- def GetDisplay(self):
- """!Get display driver instance"""
- return self._display
-
- def OpenMap(self, name):
- """!Open vector map for editing
-
- @param map name of vector map to be set up
- """
- Debug.msg (3, "AbstractDigit.SetMapName map=%s" % name)
- if '@' in name:
- name, mapset = name.split('@')
- else:
- mapset = grass.gisenv()['MAPSET']
-
- self.poMapInfo = self._display.OpenMap(str(name), str(mapset), True)
-
- if self.poMapInfo:
- self.InitCats()
-
- return self.poMapInfo
-
- def CloseMap(self):
- """!Close currently open vector map
- """
- if not self._checkMap():
- return
-
- self._display.CloseMap()
- def InitCats(self):
- """!Initialize categories information
-
- @return 0 on success
- @return -1 on error
- """
- self.cats.clear()
- if not self._checkMap():
- return -1
-
- ndblinks = Vect_get_num_dblinks(self.poMapInfo)
- for i in range(ndblinks):
- fi = Vect_get_dblink(self.poMapInfo, i).contents
- if fi:
- self.cats[fi.number] = None
-
- # find max category
- nfields = Vect_cidx_get_num_fields(self.poMapInfo)
- Debug.msg(2, "wxDigit.InitCats(): nfields=%d", nfields)
-
- for i in range(nfields):
- field = Vect_cidx_get_field_number(self.poMapInfo, i)
- ncats = Vect_cidx_get_num_cats_by_index(self.poMapInfo, i)
- if field <= 0:
- continue
- for j in range(ncats):
- cat = c_int()
- type = c_int()
- id = c_int()
- Vect_cidx_get_cat_by_index(self.poMapInfo, i, j,
- byref(cat), byref(type), byref(id))
- if field in self.cats:
- if cat > self.cats[field]:
- self.cats[field] = cat.value
- else:
- self.cats[field] = cat.value
- Debug.msg(3, "wxDigit.InitCats(): layer=%d, cat=%d", field, self.cats[field])
-
- # set default values
- for field, cat in self.cats.iteritems():
- if cat == None:
- self.cats[field] = 0 # first category 1
- Debug.msg(3, "wxDigit.InitCats(): layer=%d, cat=%d", field, self.cats[field])
-
- def _checkMap(self):
- """!Check if map is open
- """
- if not self.poMapInfo:
- self._error.NoMap()
- return False
-
- return True
- def _addFeature(self, ftype, coords, layer, cat, snap, threshold):
- """!Add new feature(s) to the vector map
- @param ftype feature type (GV_POINT, GV_LINE, GV_BOUNDARY, ...)
- @coords tuple of coordinates ((x, y), (x, y), ...)
- @param layer layer number (-1 for no cat)
- @param cat category number
- @param snap snap to node/vertex
- @param threshold threshold for snapping
-
- @return tuple (number of added features, list of fids)
- @return number of features -1 on error
- """
- fids = list()
- if not self._checkMap():
- return (-1, None)
-
- is3D = bool(Vect_is_3d(self.poMapInfo))
-
- Debug.msg(2, "IVDigit._addFeature(): npoints=%d, layer=%d, cat=%d, snap=%d",
- len(coords), layer, cat, snap)
-
- if not (ftype & (GV_POINTS | GV_LINES | GV_AREA)): # TODO: 3D
- self._error.FeatureType(ftype)
- return (-1, None)
-
- # set category
- Vect_reset_cats(self.poCats)
- if layer > 0 and ftype != GV_AREA:
- Vect_cat_set(self.poCats, layer, cat)
- self.cats[layer] = max(cat, self.cats.get(layer, 1))
-
- # append points
- Vect_reset_line(self.poPoints)
- for c in coords:
- Vect_append_point(self.poPoints, c[0], c[1], 0.0)
-
- if ftype & (GV_BOUNDARY | GV_AREA):
- # close boundary
- points = self.poPoints.contents
- last = points.n_points - 1
- if Vect_points_distance(points.x[0], points.x[0], points.z[0],
- points.x[last], points.x[last], points.z[last],
- is3D) <= threshold:
- points.x[last] = points.x[0]
- points.y[last] = points.y[0]
- points.z[last] = points.z[0]
-
- if snap != NO_SNAP:
- # apply snapping (node or vertex)
- modeSnap = not (snap == SNAP)
- Vedit_snap_line(self.poMapInfo, self.popoBgMapInfo, int(self.poBgMapInfo is not None),
- -1, self.poPoints, threshold, modeSnap)
-
- if ftype == GV_AREA:
- ltype = GV_BOUNDARY
- else:
- ltype = ftype
- newline = Vect_write_line(self.poMapInfo, ltype, self.poPoints, self.poCats)
- if newline < 0:
- self._error.WriteLine()
- return (-1, None)
- else:
- fids.append(newline)
-
- left = right = -1
- if ftype & GV_AREA:
- # add centroids for left/right area
- bpoints = Vect_new_line_struct()
- cleft = c_int()
- cright = c_int()
-
- Vect_get_line_areas(self.poMapInfo, newline,
- byref(cleft), byref(cright))
- left = cleft.value
- right = cright.value
-
- # check if area exists and has no centroid inside
- if layer > 0 and (left > 0 or right > 0):
- Vect_cat_set(self.poCats, layer, cat)
- self.cats[layer] = max(cat, self.cats.get(layer, 0))
-
- x = c_double()
- y = c_double()
- if left > 0 and \
- Vect_get_area_centroid(self.poMapInfo, left) == 0:
- # if Vect_get_area_points(self.poMapInfo, left, bpoints) > 0 and
- # Vect_find_poly_centroid(bpoints, byref(x), byref(y)) == 0:
- if Vect_get_point_in_area(self.poMapInfo, left, byref(x), byref(y)) == 0:
- Vect_reset_line(bpoints)
- Vect_append_point(bpoints, x.value, y.value, 0.0)
- newline = Vect_write_line(self.poMapInfo, GV_CENTROID,
- bpoints, self.poCats)
- if newline < 0:
- self._error.WriteLine()
- return (len(fids), fids)
- else:
- fids.append(newline)
-
- if right > 0 and \
- Vect_get_area_centroid(self.poMapInfo, right) == 0:
- # if Vect_get_area_points(byref(self.poMapInfo), right, bpoints) > 0 and
- # Vect_find_poly_centroid(bpoints, byref(x), byref(y)) == 0:
- if Vect_get_point_in_area(self.poMapInfo, left, byref(x), byref(y)) == 0:
- Vect_reset_line(bpoints)
- Vect_append_point(bpoints, x.value, y.value, 0.0)
- newline = Vect_write_line(self.poMapInfo, GV_CENTROID,
- bpoints, self.poCats)
- if newline < 0:
- self._error.WriteLine()
- return (len(fids, fids))
- else:
- fids.append(newline)
-
- Vect_destroy_line_struct(bpoints)
-
- # register changeset
- changeset = len(self.changesets)
- self._addActionToChangeset(changeset, newline, add = True)
-
- # break at intersection
- if self._settings['breakLines']:
- self._breakLineAtIntersection(newline, self.poPoints, changeset)
-
- return (len(fids), fids)
-
- def _ModifyLineVertex(self, coords, add = True):
- """!Add or remove vertex
-
- Shape of line/boundary is not changed when adding new vertex.
-
- @param coords coordinates of point
- @param add True to add, False to remove
-
- @return id id of the new feature
- @return 0 nothing changed
- @return -1 error
- """
- if not self._checkMap():
- return -1
-
- selected = self._display.selected
- if len(selected['ids']) != 1:
- return 0
-
- poList = self._display.GetSelectedIList()
- Vect_reset_line(self.poPoints)
- Vect_append_point(self.poPoints, coords[0], coords[1], 0.0)
-
- nlines = Vect_get_num_lines(self.poMapInfo)
- thresh = self._display.GetThreshold(type = 'selectThresh')
-
- changeset = self._addActionsBefore()
-
- if add:
- ret = Vedit_add_vertex(self.poMapInfo, poList,
- self.poPoints, thresh)
- else:
- ret = Vedit_remove_vertex(self.poMapInfo, poList,
- self.poPoints, thresh)
- Vect_destroy_list(poList)
-
- if ret > 0:
- self._addActionsAfter(changeset, nlines)
- else:
- del self.changesets[changeset]
-
- if not add and ret > 0 and self._settings['breakLines']:
- self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
- None, changeset)
-
- return nlines + 1 # feature is write at the end of the file
-
- def GetLineCats(self, line):
- """!Get list of layer/category(ies) for selected feature.
- @param line feature id (-1 for first selected feature)
- @return list of layer/cats
- """
- ret = dict()
- if not self._checkMap():
- return ret
-
- if line == -1 and len(self._display.selected['ids']) < 1:
- return ret
-
- if line == -1:
- line = self._display.selected['ids'][0]
-
- if not Vect_line_alive(self.poMapInfo, line):
- self._error.DeadLine(line)
- return ret
-
- if Vect_read_line(self.poMapInfo, None, self.poCats, line) < 0:
- self._error.ReadLine(line)
- return ret
-
- cats = self.poCats.contents
- for i in range(cats.n_cats):
- field = cats.field[i]
- if field not in ret:
- ret[field] = list()
- ret[field].append(cats.cat[i])
-
- return ret
- def GetLayers(self):
- """!Get list of layers
-
- Requires self.InitCats() to be called.
- @return list of layers
- """
- return self.cats.keys()
-
- def UpdateSettings(self):
- """!Update digit (and display) settings
- """
- self._display.UpdateSettings()
-
- self._settings['breakLines'] = bool(UserSettings.Get(group = 'vdigit', key = "breakLines",
- subkey = 'enabled'))
-
- def SetCategory(self):
- """!Update self.cats based on settings"""
- sel = UserSettings.Get(group = 'vdigit', key = 'categoryMode', subkey = 'selection')
- cat = None
- if sel == 0: # next to usep
- cat = self._setCategoryNextToUse()
- elif sel == 1:
- cat = UserSettings.Get(group = 'vdigit', key = 'category', subkey = 'value')
-
- if cat:
- layer = UserSettings.Get(group = 'vdigit', key = 'layer', subkey = 'value')
- self.cats[layer] = cat
-
- return cat
-
- def _setCategoryNextToUse(self):
- """!Find maximum category number for the given layer and
- update the settings
- @return category to be used
- """
- # get max category number for given layer and update the settings
- layer = UserSettings.Get(group = 'vdigit', key = 'layer', subkey = 'value')
- cat = self.cats.get(layer, 0) + 1
- UserSettings.Set(group = 'vdigit', key = 'category', subkey = 'value',
- value = cat)
- Debug.msg(1, "IVDigit._setCategoryNextToUse(): cat=%d", cat)
-
- return cat
- def SelectLinesFromBackgroundMap(self, bbox):
- """!Select features from background map
- @param bbox bounding box definition
-
- @return list of selected feature ids
- """
- # try select features by box first
- if self._display.SelectLinesByBox(bbox, poMapInfo = self.poBgMapInfo) < 1:
- self._display.SelectLineByPoint(bbox[0], poMapInfo = self.poBgMapInfo)['line']
-
- return self._display.selected['ids']
-
- def GetUndoLevel(self):
- """!Get undo level (number of active changesets)
-
- Note: Changesets starts wiht 0
- """
- return self.changesetCurrent
-
- def GetFeatureType(self):
- """!Get feature type for OGR layers
- @return feature type as string (Point, Line String, Polygon)
- @return None for native format
- """
- return Vect_get_ogr_geometry_type(self.poMapInfo)
-
|