12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562 |
- """
- @package vnet.vnet_data
- @brief Vector network analysis classes for data managment.
- Classes:
- - vnet_data::VNETData
- - vnet_data::VNETPointsData
- - vnet_data::VNETAnalysisParameters
- - vnet_data::VNETAnalysesProperties
- - vnet_data::VNETTmpVectMaps
- - vnet_data::VectMap
- - vnet_data::History
- - vnet_data::VNETGlobalTurnsData
- (C) 2013-2014 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 Stepan Turek <stepan.turek seznam.cz> (GSoC 2012, mentor: Martin Landa)
- @author Lukas Bocan <silent_bob centrum.cz> (turn costs support)
- @author Eliska Kyzlikova <eliska.kyzlikova gmail.com> (turn costs support)
- """
- import os
- import six
- from copy import deepcopy
- from grass.script.utils import try_remove
- from grass.script import core as grass
- from grass.script.task import cmdlist_to_tuple
- import wx
- from core import utils
- from core.gcmd import RunCommand, GMessage
- from core.settings import UserSettings
- from vnet.vnet_utils import ParseMapStr, SnapToNode
- from gui_core.gselect import VectorDBInfo
- from grass.pydispatch.signal import Signal
- from vnet.vnet_utils import DegreesToRadians, RadiansToDegrees
- class VNETData:
- def __init__(self, guiparent, mapWin):
- # setting initialization
- self._initSettings()
- self.guiparent = guiparent
- self.an_props = VNETAnalysesProperties()
- self.an_params = VNETAnalysisParameters(self.an_props)
- self.an_points = VNETPointsData(mapWin, self.an_props, self.an_params)
- self.global_turns = VNETGlobalTurnsData()
- self.pointsChanged = self.an_points.pointsChanged
- self.parametersChanged = self.an_params.parametersChanged
- def CleanUp(self):
- self.an_points.CleanUp()
- def GetAnalyses(self):
- return self.an_props.used_an
- def GetPointsData(self):
- return self.an_points
- def GetGlobalTurnsData(self):
- return self.global_turns
- def GetRelevantParams(self, analysis=None):
- if analysis:
- return self.an_props.GetRelevantParams(analysis)
- else:
- analysis, valid = self.an_params.GetParam("analysis")
- return self.an_props.GetRelevantParams(analysis)
- def GetAnalysisProperties(self, analysis=None):
- if analysis:
- return self.an_props[analysis]
- else:
- analysis, valid = self.an_params.GetParam("analysis")
- return self.an_props[analysis]
- def GetParam(self, param):
- return self.an_params.GetParam(param)
- def GetParams(self):
- return self.an_params.GetParams()
- def SetParams(self, params, flags):
- return self.an_params.SetParams(params, flags)
- def SetSnapping(self, activate):
- self.an_points.SetSnapping(activate)
- def GetSnapping(self):
- return self.an_points.GetSnapping()
- def GetLayerStyle(self):
- """Returns cmd for d.vect, with set style for analysis result"""
- analysis, valid = self.an_params.GetParam("analysis")
- resProps = self.an_props[analysis]["resultProps"]
- width = UserSettings.Get(
- group='vnet',
- key='res_style',
- subkey="line_width")
- layerStyleCmd = ["layer=1", 'width=' + str(width)]
- if "catColor" in resProps:
- layerStyleCmd.append('flags=c')
- elif "singleColor" in resProps:
- col = UserSettings.Get(
- group='vnet',
- key='res_style',
- subkey="line_color")
- layerStyleCmd.append(
- 'color=' + str(col[0]) + ':' + str(col[1]) + ':' + str(col[2]))
- layerStyleVnetColors = []
- if "attrColColor" in resProps:
- colorStyle = UserSettings.Get(
- group='vnet', key='res_style', subkey="color_table")
- invert = UserSettings.Get(
- group='vnet',
- key='res_style',
- subkey="invert_colors")
- layerStyleVnetColors = [
- "v.colors",
- "color=" + colorStyle,
- "column=" + resProps["attrColColor"],
- ]
- if invert:
- layerStyleVnetColors.append("-n")
- return layerStyleCmd, layerStyleVnetColors
- def InputsErrorMsgs(self, msg, analysis, params, flags,
- inv_params, relevant_params):
- """Checks input data in Parameters tab and shows messages if some value is not valid
- :param str msg: message added to start of message string
- :return: True if checked inputs are OK
- :return: False if some of checked inputs is not ok
- """
- if flags["t"] and "turn_layer" not in relevant_params:
- GMessage(
- parent=self.guiparent, message=_(
- "Module <%s> does not support turns costs." %
- analysis))
- return False
- errMapStr = ""
- if 'input' in inv_params:
- if params['input']:
- errMapStr = _("Vector map '%s' does not exist.") % (
- params['input'])
- else:
- errMapStr = _("Vector map was not chosen.")
- if errMapStr:
- GMessage(parent=self.guiparent,
- message=msg + "\n" + errMapStr)
- return False
- errLayerStr = ""
- vals = {
- 'arc_layer': _("arc layer"),
- 'node_layer': _("node layer"),
- 'turn_layer': _("turntable layer"),
- 'turn_cat_layer': _("unique categories layer")
- }
- for layer, layerLabel in six.iteritems(vals):
- if layer in ["turn_layer", "turn_cat_layer"] and not flags["t"]:
- continue
- if layer in inv_params:
- if params[layer]:
- errLayerStr += _("Chosen %s '%s' does not exist in vector map '%s'.\n") % (
- layerLabel, params[layer], params['input'])
- else:
- errLayerStr += _("Choose existing %s.\n") % \
- (layerLabel)
- if errLayerStr:
- GMessage(parent=self.guiparent,
- message=msg + "\n" + errLayerStr)
- return False
- errColStr = ""
- for col in ["arc_column", "arc_backward_column", "node_column"]:
- if params[col] and col in inv_params and col in relevant_params:
- errColStr += _("Chosen column '%s' does not exist in attribute table of layer '%s' of vector map '%s'.\n") % (
- params[col], params[layer], params['input'])
- if errColStr:
- GMessage(parent=self.guiparent,
- message=msg + "\n" + errColStr)
- return False
- return True
- def _initSettings(self):
- """Initialization of settings (if not already defined)"""
- # initializes default settings
- initSettings = [
- ['res_style', 'line_width', 5],
- ['res_style', 'line_color', (192, 0, 0)],
- ['res_style', 'color_table', 'byr'],
- ['res_style', 'invert_colors', False],
- ['point_symbol', 'point_size', 10],
- ['point_symbol', 'point_width', 2],
- ['point_colors', "unused", (131, 139, 139)],
- ['point_colors', "used1cat", (192, 0, 0)],
- ['point_colors', "used2cat", (0, 0, 255)],
- ['point_colors', "selected", (9, 249, 17)],
- ['other', "snap_tresh", 10],
- ['other', "max_hist_steps", 5]
- ]
- for init in initSettings:
- UserSettings.ReadSettingsFile()
- UserSettings.Append(dict=UserSettings.userSettings,
- group='vnet',
- key=init[0],
- subkey=init[1],
- value=init[2],
- overwrite=False)
- class VNETPointsData:
- def __init__(self, mapWin, an_data, an_params):
- self.mapWin = mapWin
- self.an_data = an_data
- self.an_params = an_params
- # information, whether mouse event handler is registered in map window
- self.handlerRegistered = False
- self.pointsChanged = Signal('VNETPointsData.pointsChanged')
- self.an_params.parametersChanged.connect(self.ParametersChanged)
- self.snapping = False
- self.data = []
- self.cols = {"name": ['use', 'type', 'topology', 'e', 'n'],
- "label": [_('use'), _('type'), _('topology'), 'e', 'n'],
- # TDO
- "type": [None, ["", _("Start point"), _("End Point")], None, float, float],
- "def_vals": [False, 0, "new point", 0, 0]
- }
- # registration graphics for drawing
- self.pointsToDraw = self.mapWin.RegisterGraphicsToDraw(
- graphicsType="point", setStatusFunc=self.SetPointStatus)
- self.SetPointDrawSettings()
- self.AddPoint()
- self.AddPoint()
- self.SetPointData(0, {'use': True, 'type': 1})
- self.SetPointData(1, {'use': True, 'type': 2})
- self.selected = 0
- def __del__(self):
- self.CleanUp()
- def CleanUp(self):
- self.mapWin.UnregisterGraphicsToDraw(self.pointsToDraw)
- if self.handlerRegistered:
- self.mapWin.UnregisterMouseEventHandler(wx.EVT_LEFT_DOWN,
- self.OnMapClickHandler)
- def SetSnapping(self, activate):
- self.snapping = activate
- def GetSnapping(self):
- return self.snapping
- def AddPoint(self):
- self.pointsToDraw.AddItem(
- coords=(
- self.cols["def_vals"][3],
- self.cols["def_vals"][4]))
- self.data.append(self.cols["def_vals"][:])
- self.pointsChanged.emit(method="AddPoint", kwargs={})
- def DeletePoint(self, pt_id):
- item = self.pointsToDraw.GetItem(pt_id)
- if item:
- self.pointsToDraw.DeleteItem(item)
- self.data.pop(pt_id)
- self.pointsChanged.emit(method="DeletePoint", kwargs={"pt_id": pt_id})
- def SetPoints(self, pts_data):
- for item in self.pointsToDraw.GetAllItems():
- self.pointsToDraw.DeleteItem(item)
- self.data = []
- for pt_data in pts_data:
- pt_data_list = self._ptDataToList(pt_data)
- self.data.append(pt_data_list)
- self.pointsToDraw.AddItem(
- coords=(pt_data_list[3], pt_data_list[4]))
- self.pointsChanged.emit(
- method="SetPoints", kwargs={
- "pts_data": pts_data})
- def SetPointData(self, pt_id, data):
- for col, v in six.iteritems(data):
- if col == 'use':
- continue
- idx = self.cols["name"].index(col)
- self.data[pt_id][idx] = v
- # if type is changed checked columns must be recalculated by _usePoint
- if 'type' in data and 'use' not in data:
- data["use"] = self.GetPointData(pt_id)['use']
- if 'use' in data:
- if self._usePoint(pt_id, data["use"]) == -1:
- data["use"] = False
- idx = self.cols["name"].index("use")
- self.data[pt_id][idx] = data["use"]
- self.pointsChanged.emit(
- method="SetPointData", kwargs={
- "pt_id": pt_id, "data": data})
- def GetPointData(self, pt_id):
- return self._ptListDataToPtData(self.data[pt_id])
- def GetPointsCount(self):
- return len(self.data)
- def SetPointStatus(self, item, itemIndex):
- """Before point is drawn, decides properties of drawing style"""
- analysis, valid = self.an_params.GetParam("analysis")
- cats = self.an_data[analysis]["cmdParams"]["cats"]
- if itemIndex == self.selected:
- wxPen = "selected"
- elif not self.data[itemIndex][0]:
- wxPen = "unused"
- item.hide = False
- elif len(cats) > 1:
- idx = self.data[itemIndex][1]
- if idx == 2: # End/To/Sink point
- wxPen = "used2cat"
- else:
- wxPen = "used1cat"
- else:
- wxPen = "used1cat"
- item.SetPropertyVal('label', str(itemIndex + 1))
- item.SetPropertyVal('penName', wxPen)
- def SetSelected(self, pt_id):
- self.selected = pt_id
- self.pointsChanged.emit(method="SetSelected", kwargs={"pt_id": pt_id})
- def GetSelected(self):
- return self.selected
- def SetPointDrawSettings(self):
- """Set settings for drawing of points"""
- ptSize = int(
- UserSettings.Get(
- group='vnet',
- key='point_symbol',
- subkey='point_size'))
- self.pointsToDraw.SetPropertyVal("size", ptSize)
- colors = UserSettings.Get(group='vnet', key='point_colors')
- ptWidth = int(
- UserSettings.Get(
- group='vnet',
- key='point_symbol',
- subkey='point_width'))
- textProp = self.pointsToDraw.GetPropertyVal("text")
- textProp["font"].SetPointSize(ptSize + 2)
- for colKey, col in six.iteritems(colors):
- pen = self.pointsToDraw.GetPen(colKey)
- if pen:
- pen.SetColour(wx.Colour(col[0], col[1], col[2], 255))
- pen.SetWidth(ptWidth)
- else:
- self.pointsToDraw.AddPen(
- colKey,
- wx.Pen(
- colour=wx.Colour(
- col[0],
- col[1],
- col[2],
- 255),
- width=ptWidth))
- def ParametersChanged(self, method, kwargs):
- if "analysis" in list(kwargs["changed_params"].keys()):
- self._updateTypeCol()
- if self.an_params.GetParam("analysis")[0] == "v.net.path":
- self._vnetPathUpdateUsePoints(None)
- def _updateTypeCol(self):
- """Rename category values when module is changed. Expample: Start point -> Sink point"""
- colValues = [""]
- analysis, valid = self.an_params.GetParam("analysis")
- anParamsCats = self.an_data[analysis]["cmdParams"]["cats"]
- for ptCat in anParamsCats:
- colValues.append(ptCat[1])
- type_idx = self.cols["name"].index("type")
- self.cols['type'][type_idx] = colValues
- def _ptDataToList(self, pt_data):
- pt_list_data = [None] * len(self.cols['name'])
- for k, val in six.iteritems(pt_data):
- pt_list_data[self.cols["name"].index(k)] = val
- return pt_list_data
- def _ptListDataToPtData(self, pt_list_data):
- pt_data = {}
- for i, val in enumerate(pt_list_data):
- pt_data[self.cols["name"][i]] = val
- return pt_data
- def _usePoint(self, pt_id, use):
- """Item is checked/unchecked"""
- analysis, valid = self.an_params.GetParam("analysis")
- cats = self.an_data[analysis]["cmdParams"]["cats"]
- # TODO move
- # if self.updateMap:
- # up_map_evt = gUpdateMap(render = False, renderVector = False)
- # wx.PostEvent(self.dialog.mapWin, up_map_evt)
- if len(cats) <= 1:
- return 0
- use_idx = self.cols["name"].index("use")
- checkedVal = self.data[pt_id][1]
- # point without given type cannot be selected
- if checkedVal == 0:
- self.data[pt_id][use_idx] = False
- self.pointsChanged.emit(
- method="SetPointData", kwargs={
- "pt_id": pt_id, "data": {
- "use": False}})
- return -1
- if analysis == "v.net.path" and use:
- self._vnetPathUpdateUsePoints(pt_id)
- def _vnetPathUpdateUsePoints(self, checked_pt_id):
- alreadyChecked = []
- type_idx = self.cols["name"].index("type")
- use_idx = self.cols["name"].index("use")
- if checked_pt_id is not None:
- checkedKey = checked_pt_id
- alreadyChecked.append(self.data[checked_pt_id][type_idx])
- else:
- checkedKey = -1
- for iKey, dt in enumerate(self.data):
- pt_type = dt[type_idx]
- if ((pt_type in alreadyChecked and checkedKey != iKey)
- or pt_type == 0) and self.data[iKey][use_idx]:
- self.data[iKey][use_idx] = False
- self.pointsChanged.emit(
- method="SetPointData", kwargs={
- "pt_id": iKey, "data": {
- "use": False}})
- elif self.data[iKey][use_idx]:
- alreadyChecked.append(pt_type)
- def EditPointMode(self, activate):
- """Registers/unregisters mouse handler into map window"""
- if activate == self.handlerRegistered:
- return
- if activate:
- self.mapWin.RegisterMouseEventHandler(wx.EVT_LEFT_DOWN,
- self.OnMapClickHandler,
- 'cross')
- self.handlerRegistered = True
- else:
- self.mapWin.UnregisterMouseEventHandler(wx.EVT_LEFT_DOWN,
- self.OnMapClickHandler)
- self.handlerRegistered = False
- self.pointsChanged.emit(
- method="EditMode", kwargs={
- "activated": activate})
- def IsEditPointModeActive(self):
- return self.handlerRegistered
- def OnMapClickHandler(self, event):
- """Take coordinates from map window"""
- # TODO update snapping after input change
- if event == 'unregistered':
- self.handlerRegistered = False
- return
- if not self.data:
- self.AddPoint()
- e, n = self.mapWin.GetLastEN()
- if self.snapping:
- # compute threshold
- snapTreshPix = int(UserSettings.Get(group='vnet',
- key='other',
- subkey='snap_tresh'))
- res = max(
- self.mapWin.Map.region['nsres'],
- self.mapWin.Map.region['ewres'])
- snapTreshDist = snapTreshPix * res
- params, err_params, flags = self.an_params.GetParams()
- vectMap = params["input"]
- if "input" in err_params:
- msg = _("new point")
- coords = SnapToNode(e, n, snapTreshDist, vectMap)
- if coords:
- e = coords[0]
- n = coords[1]
- msg = ("snapped to node")
- else:
- msg = _("new point")
- else:
- msg = _("new point")
- self.SetPointData(self.selected,
- {'topology': msg,
- 'e': e,
- 'n': n})
- self.pointsToDraw.GetItem(self.selected).SetCoords([e, n])
- if self.selected == len(self.data) - 1:
- self.SetSelected(0)
- else:
- self.SetSelected(self.GetSelected() + 1)
- def GetColumns(self, only_relevant=True):
- cols_data = deepcopy(self.cols)
- hidden_cols = []
- hidden_cols.append(self.cols["name"].index("e"))
- hidden_cols.append(self.cols["name"].index("n"))
- analysis, valid = self.an_params.GetParam("analysis")
- if only_relevant and len(self.an_data[analysis][
- "cmdParams"]["cats"]) <= 1:
- hidden_cols.append(self.cols["name"].index("type"))
- i_red = 0
- hidden_cols.sort()
- for idx in hidden_cols:
- for dt in six.itervalues(cols_data):
- dt.pop(idx - i_red)
- i_red += 1
- return cols_data
- class VNETAnalysisParameters:
- def __init__(self, an_props):
- self.an_props = an_props
- self.params = {"analysis": self.an_props.used_an[0],
- "input": "",
- "arc_layer": "",
- "node_layer": "",
- "arc_column": "",
- "arc_backward_column": "",
- "node_column": "",
- "turn_layer": "",
- "turn_cat_layer": "",
- "iso_lines": "", # TODO check validity
- "max_dist": 0} # TODO check validity
- self.flags = {"t": False}
- self.parametersChanged = Signal(
- 'VNETAnalysisParameters.parametersChanged')
- def SetParams(self, params, flags):
- changed_params = {}
- for p, v in six.iteritems(params):
- if p == "analysis" and v not in self.an_props.used_an:
- continue
- if p == "input":
- mapName, mapSet = ParseMapStr(v)
- v = mapName + "@" + mapSet
- if p in self.params:
- if isinstance(v, str):
- v = v.strip()
- self.params[p] = v
- changed_params[p] = v
- changed_flags = {}
- for p, v in six.iteritems(flags):
- if p in self.flags:
- self.flags[p] = v
- changed_flags[p] = v
- self.parametersChanged.emit(
- method="SetParams",
- kwargs={
- "changed_params": changed_params,
- "changed_flags": changed_flags})
- return changed_params, changed_flags
- def GetParam(self, param):
- invParams = []
- if param in [
- "input", "arc_layer", "node_layer", "arc_column",
- "arc_backward_column", "node_column", "turn_layer",
- "turn_cat_layer"]:
- invParams = self._getInvalidParams(self.params)
- if invParams:
- return self.params[param], False
- return self.params[param], True
- def GetParams(self):
- invParams = self._getInvalidParams(self.params)
- return self.params, invParams, self.flags
- def _getInvalidParams(self, params):
- """Check of analysis input data for invalid values (Parameters tab)"""
- # dict of invalid values {key from self.itemData (comboboxes from
- # Parameters tab) : invalid value}
- invParams = []
- # check vector map
- if params["input"]:
- mapName, mapSet = params["input"].split("@")
- if mapSet in grass.list_grouped('vector'):
- vectMaps = grass.list_grouped('vector')[mapSet]
- if not params["input"] or mapName not in vectMaps:
- invParams = params.keys()[:]
- return invParams
- # check arc/node layer
- layers = utils.GetVectorNumberOfLayers(params["input"])
- for l in ['arc_layer', 'node_layer', 'turn_layer', 'turn_cat_layer']:
- if not layers or params[l] not in layers:
- invParams.append(l)
- dbInfo = VectorDBInfo(params["input"])
- try:
- table = dbInfo.GetTable(int(params["arc_layer"]))
- columnchoices = dbInfo.GetTableDesc(table)
- except (KeyError, ValueError):
- table = None
- # check costs columns
- for col in ["arc_column", "arc_backward_column", "node_column"]:
- if col == "node_column":
- try:
- table = dbInfo.GetTable(int(params["node_layer"]))
- columnchoices = dbInfo.GetTableDesc(table)
- except (KeyError, ValueError):
- table = None
- if not table or not params[col] in list(columnchoices.keys()):
- invParams.append(col)
- continue
- if columnchoices[
- params[col]]['type'] not in [
- 'integer', 'double precision']:
- invParams.append(col)
- continue
- return invParams
- class VNETAnalysesProperties:
- def __init__(self):
- """Initializes parameters for different v.net.* modules """
- # initialization of v.net.* analysis parameters (data which
- # characterizes particular analysis)
- self.attrCols = {
- 'arc_column': {
- "label": _("Arc forward/both direction(s) cost column:"),
- "name": _("arc forward/both")
- },
- 'arc_backward_column': {
- "label": _("Arc backward direction cost column:"),
- "name": _("arc backward")
- },
- 'acolumn': {
- "label": _("Arcs' cost column (for both directions):"),
- "name": _("arc"),
- "inputField": 'arc_column',
- },
- 'node_column': {
- "label": _("Node cost column:"),
- "name": _("node")
- }
- }
- self.vnetProperties = {
- "v.net.path": {
- "label": _("Shortest path %s") % "(v.net.path)",
- "cmdParams": {
- "cats": [
- ["st_pt", _("Start point")],
- ["end_pt", _("End point")]
- ],
- "cols": [
- 'arc_column',
- 'arc_backward_column',
- 'node_column'
- ],
- },
- "resultProps": {
- "singleColor": None,
- "dbMgr": True # TODO delete this property, this information can be get from result
- },
- "turns_support": True
- },
- "v.net.salesman": {
- "label": _("Traveling salesman %s") % "(v.net.salesman)",
- "cmdParams": {
- "cats": [["center_cats", None]],
- "cols": [
- 'arc_column',
- 'arc_backward_column'
- ],
- },
- "resultProps": {
- "singleColor": None,
- "dbMgr": False
- },
- "turns_support": True
- },
- "v.net.flow": {
- "label": _("Maximum flow %s") % "(v.net.flow)",
- "cmdParams": {
- "cats": [
- ["source_cats", _("Source point")],
- ["sink_cats", _("Sink point")]
- ],
- "cols": [
- 'arc_column',
- 'arc_backward_column',
- 'node_column'
- ]
- },
- "resultProps": {
- "attrColColor": "flow",
- "dbMgr": True
- },
- "turns_support": False
- },
- "v.net.alloc": {
- "label": _("Subnets for nearest centers %s") % "(v.net.alloc)",
- "cmdParams": {
- "cats": [["center_cats", None]],
- "cols": [
- 'arc_column',
- 'arc_backward_column',
- 'node_column'
- ]
- },
- "resultProps": {
- "catColor": None,
- "dbMgr": False
- },
- "turns_support": True
- },
- "v.net.steiner": {
- "label": _("Steiner tree for the network and given terminals %s") % "(v.net.steiner)",
- "cmdParams": {
- "cats": [["terminal_cats", None]],
- "cols": [
- 'acolumn',
- ]
- },
- "resultProps": {
- "singleColor": None,
- "dbMgr": False
- },
- "turns_support": True
- },
- "v.net.distance": {
- "label": _("Shortest distance via the network %s") % "(v.net.distance)",
- "cmdParams": {
- "cats": [
- ["from_cats", "From point"],
- ["to_cats", "To point"]
- ],
- "cols": [
- 'arc_column',
- 'arc_backward_column',
- 'node_column'
- ],
- },
- "resultProps": {
- "catColor": None,
- "dbMgr": True
- },
- "turns_support": False
- },
- "v.net.iso": {
- "label": _("Cost isolines %s") % "(v.net.iso)",
- "cmdParams": {
- "cats": [["center_cats", None]],
- "cols": [
- 'arc_column',
- 'arc_backward_column',
- 'node_column'
- ]
- },
- "resultProps": {
- "catColor": None,
- "dbMgr": False
- },
- "turns_support": True
- }
- }
- self.used_an = ["v.net.path",
- "v.net.salesman",
- "v.net.flow",
- "v.net.alloc",
- "v.net.distance",
- "v.net.iso",
- #"v.net.steiner"
- ]
- for an in list(self.vnetProperties.keys()):
- if an not in self.used_an:
- del self.vnetProperties[an]
- continue
- cols = self.vnetProperties[an]["cmdParams"]["cols"]
- self.vnetProperties[an]["cmdParams"]["cols"] = {}
- for c in cols:
- self.vnetProperties[an]["cmdParams"][
- "cols"][c] = self.attrCols[c]
- def has_key(self, key):
- return key in self.vnetProperties
- def __getitem__(self, key):
- return self.vnetProperties[key]
- def GetRelevantParams(self, analysis):
- if analysis not in self.vnetProperties:
- return None
- relevant_params = ["input", "arc_layer", "node_layer"]
- if self.vnetProperties[analysis]["turns_support"]:
- relevant_params += ["turn_layer", "turn_cat_layer"]
- cols = self.vnetProperties[analysis]["cmdParams"]["cols"]
- for col, v in six.iteritems(cols):
- if "inputField" in col:
- colInptF = v["inputField"]
- else:
- colInptF = col
- relevant_params.append(colInptF)
- return relevant_params
- class VNETTmpVectMaps:
- """Class which creates, stores and destroys all tmp maps created during analysis"""
- def __init__(self, parent, mapWin):
- self.tmpMaps = [] # temporary maps
- self.parent = parent
- self.mapWin = mapWin
- def AddTmpVectMap(self, mapName, msg):
- """New temporary map
- :return: instance of VectMap representing temporary map
- """
- currMapSet = grass.gisenv()['MAPSET']
- tmpMap = grass.find_file(name=mapName,
- element='vector',
- mapset=currMapSet)
- fullName = tmpMap["fullname"]
- # map already exists
- if fullName:
- # TODO move dialog out of class, AddTmpVectMap(self, mapName,
- # overvrite = False)
- dlg = wx.MessageDialog(parent=self.parent,
- message=msg,
- caption=_("Overwrite map layer"),
- style=wx.YES_NO | wx.NO_DEFAULT |
- wx.ICON_QUESTION | wx.CENTRE)
- ret = dlg.ShowModal()
- dlg.Destroy()
- if ret == wx.ID_NO:
- return None
- else:
- fullName = mapName + "@" + currMapSet
- newVectMap = VectMap(self.mapWin, fullName)
- self.tmpMaps.append(newVectMap)
- return newVectMap
- def HasTmpVectMap(self, vectMapName):
- """
- :param: vectMapName name of vector map
- :return: True if it contains the map
- :return: False if not
- """
- mapValSpl = vectMapName.strip().split("@")
- if len(mapValSpl) > 1:
- mapSet = mapValSpl[1]
- else:
- mapSet = grass.gisenv()['MAPSET']
- mapName = mapValSpl[0]
- fullName = mapName + "@" + mapSet
- for vectTmpMap in self.tmpMaps:
- if vectTmpMap.GetVectMapName() == fullName:
- return True
- return False
- def GetTmpVectMap(self, vectMapName):
- """Get instance of VectMap with name vectMapName"""
- for vectMap in self.tmpMaps:
- if vectMap.GetVectMapName() == vectMapName.strip():
- return vectMap
- return None
- def RemoveFromTmpMaps(self, vectMap):
- """Temporary map is removed from the class instance however it is not deleted
- :param vectMap: instance of VectMap class to be removed
- :return: True if was removed
- :return: False if does not contain the map
- """
- try:
- self.tmpMaps.remove(vectMap)
- return True
- except ValueError:
- return False
- def DeleteTmpMap(self, vectMap):
- """Temporary map is removed from the class and it is deleted
- :param vectMap: instance of VectMap class to be deleted
- :return: True if was removed
- :return: False if does not contain the map
- """
- if vectMap:
- vectMap.DeleteRenderLayer()
- RunCommand('g.remove', flags='f', type='vector',
- name=vectMap.GetVectMapName())
- self.RemoveFromTmpMaps(vectMap)
- return True
- return False
- def DeleteAllTmpMaps(self):
- """Delete all temporary maps in the class"""
- update = False
- for tmpMap in self.tmpMaps:
- RunCommand('g.remove', flags='f', type='vector',
- name=tmpMap.GetVectMapName())
- if tmpMap.DeleteRenderLayer():
- update = True
- return update
- class VectMap:
- """Represents map
- It can check if it was modified or render it
- """
- def __init__(self, mapWin, fullName):
- self.fullName = fullName
- self.mapWin = mapWin
- self.renderLayer = None
- self.modifTime = None # time, for modification check
- def __del__(self):
- self.DeleteRenderLayer()
- def AddRenderLayer(self, cmd=None, colorsCmd=None):
- """Add map from map window layers to render """
- if not self.mapWin:
- return False
- existsMap = grass.find_file(name=self.fullName,
- element='vector',
- mapset=grass.gisenv()['MAPSET'])
- if not existsMap["name"]:
- self.DeleteRenderLayer()
- return False
- if not cmd:
- cmd = []
- cmd.insert(0, 'd.vect')
- cmd.append('map=%s' % self.fullName)
- if self.renderLayer:
- self.DeleteRenderLayer()
- if colorsCmd:
- colorsCmd.append('map=%s' % self.fullName)
- layerStyleVnetColors = cmdlist_to_tuple(colorsCmd)
- RunCommand(layerStyleVnetColors[0],
- **layerStyleVnetColors[1])
- self.renderLayer = self.mapWin.Map.AddLayer(
- ltype="vector", command=cmd, name=self.fullName, active=True,
- opacity=1.0, render=False, pos=-1)
- return True
- def DeleteRenderLayer(self):
- """Remove map from map window layers to render"""
- if not self.mapWin:
- return False
- if self.renderLayer:
- self.mapWin.Map.DeleteLayer(self.renderLayer)
- self.renderLayer = None
- return True
- return False
- def GetRenderLayer(self):
- return self.renderLayer
- def GetVectMapName(self):
- return self.fullName
- def SaveVectMapState(self):
- """Save modification time for vector map"""
- self.modifTime = self.GetLastModified()
- def VectMapState(self):
- """Checks if map was modified
- :return: -1 - if no modification time was saved
- :return: 0 - if map was modified
- :return: 1 - if map was not modified
- """
- if self.modifTime is None:
- return -1
- if self.modifTime != self.GetLastModified():
- return 0
- return 1
- def GetLastModified(self):
- """Get modification time
- :return: MAP DATE time string from vector map head file
- """
- mapValSpl = self.fullName.split("@")
- mapSet = mapValSpl[1]
- mapName = mapValSpl[0]
- headPath = os.path.join(grass.gisenv()['GISDBASE'],
- grass.gisenv()['LOCATION_NAME'],
- mapSet,
- "vector",
- mapName,
- "head")
- try:
- head = open(headPath, 'r')
- for line in head.readlines():
- i = line.find('MAP DATE:', )
- if i == 0:
- head.close()
- return line.split(':', 1)[1].strip()
- head.close()
- return ""
- except IOError:
- return ""
- class History:
- """Class which reads and saves history data (based on gui.core.settings Settings class file save/load)
- .. todo::
- Maybe it could be useful for other GRASS wxGUI tools.
- """
- def __init__(self):
- # max number of steps in history (zero based)
- self.maxHistSteps = 3
- # current history step
- self.currHistStep = 0
- # number of steps saved in history
- self.histStepsNum = 0
- # dict contains data saved in history for current history step
- self.currHistStepData = {}
- # buffer for data to be saved into history
- self.newHistStepData = {}
- self.histFile = grass.tempfile()
- # key/value separator
- self.sep = ';'
- def __del__(self):
- try_remove(self.histFile)
- def GetNext(self):
- """Go one step forward in history"""
- self.currHistStep -= 1
- self.currHistStepData.clear()
- self.currHistStepData = self._getHistStepData(self.currHistStep)
- return self.currHistStepData
- def GetPrev(self):
- """Go one step back in history"""
- self.currHistStep += 1
- self.currHistStepData.clear()
- self.currHistStepData = self._getHistStepData(self.currHistStep)
- return self.currHistStepData
- def GetStepsNum(self):
- """Get number of steps saved in history"""
- return self.histStepsNum
- def GetCurrHistStep(self):
- """Get current history step"""
- return self.currHistStep
- def Add(self, key, subkey, value):
- """Add new data into buffer"""
- if key not in self.newHistStepData:
- self.newHistStepData[key] = {}
- if isinstance(subkey, list):
- if subkey[0] not in self.newHistStepData[key]:
- self.newHistStepData[key][subkey[0]] = {}
- self.newHistStepData[key][subkey[0]][subkey[1]] = value
- else:
- self.newHistStepData[key][subkey] = value
- def SaveHistStep(self):
- """Create new history step with data in buffer"""
- self.maxHistSteps = UserSettings.Get(group='vnet',
- key='other',
- subkey='max_hist_steps')
- self.currHistStep = 0
- newHistFile = grass.tempfile()
- newHist = open(newHistFile, "w")
- self._saveNewHistStep(newHist)
- oldHist = open(self.histFile)
- removedHistData = self._savePreviousHist(newHist, oldHist)
- oldHist.close()
- newHist.close()
- try_remove(self.histFile)
- self.histFile = newHistFile
- self.newHistStepData.clear()
- return removedHistData
- def _savePreviousHist(self, newHist, oldHist):
- """Save previous history into new file"""
- newHistStep = False
- removedHistData = {}
- newHistStepsNum = self.histStepsNum
- for line in oldHist.readlines():
- if not line.strip():
- newHistStep = True
- newHistStepsNum += 1
- continue
- if newHistStep:
- newHistStep = False
- line = line.split("=")
- line[1] = str(newHistStepsNum)
- line = "=".join(line)
- if newHistStepsNum >= self.maxHistSteps:
- removedHistStep = removedHistData[line] = {}
- continue
- else:
- newHist.write('%s%s%s' % (os.linesep, line, os.linesep))
- self.histStepsNum = newHistStepsNum
- else:
- if newHistStepsNum >= self.maxHistSteps:
- self._parseLine(line, removedHistStep)
- else:
- newHist.write('%s' % line)
- return removedHistData
- def _saveNewHistStep(self, newHist):
- """Save buffer (new step) data into file"""
- newHist.write('%s%s%s' % (os.linesep, "history step=0", os.linesep))
- for key in list(self.newHistStepData.keys()):
- subkeys = list(self.newHistStepData[key].keys())
- newHist.write('%s%s' % (key, self.sep))
- for idx in range(len(subkeys)):
- value = self.newHistStepData[key][subkeys[idx]]
- if isinstance(value, dict):
- if idx > 0:
- newHist.write('%s%s%s' % (os.linesep, key, self.sep))
- newHist.write('%s%s' % (subkeys[idx], self.sep))
- kvalues = list(self.newHistStepData[key][subkeys[idx]].keys())
- srange = range(len(kvalues))
- for sidx in srange:
- svalue = self._parseValue(
- self.newHistStepData[key][
- subkeys[idx]][
- kvalues[sidx]])
- newHist.write(
- '%s%s%s' %
- (kvalues[sidx], self.sep, svalue))
- if sidx < len(kvalues) - 1:
- newHist.write('%s' % self.sep)
- else:
- if idx > 0 and isinstance(
- self.newHistStepData[key][subkeys[idx - 1]],
- dict):
- newHist.write('%s%s%s' % (os.linesep, key, self.sep))
- value = self._parseValue(
- self.newHistStepData[key][subkeys[idx]])
- newHist.write('%s%s%s' % (subkeys[idx], self.sep, value))
- if idx < len(subkeys) - 1 and not isinstance(
- self.newHistStepData[key][subkeys[idx + 1]],
- dict):
- newHist.write('%s' % self.sep)
- newHist.write(os.linesep)
- self.histStepsNum = 0
- def _parseValue(self, value, read=False):
- """Parse value"""
- if read: # -> read data (cast values)
- if value:
- if value[
- 0] == '[' and value[-1] == ']': # TODO, possible wrong interpretation
- value = value[1:-1].split(',')
- value = map(self._castValue, value)
- return value
- if value == 'True':
- value = True
- elif value == 'False':
- value = False
- elif value == 'None':
- value = None
- elif ':' in value: # -> color
- try:
- value = tuple(map(int, value.split(':')))
- except ValueError: # -> string
- pass
- else:
- try:
- value = int(value)
- except ValueError:
- try:
- value = float(value)
- except ValueError:
- pass
- else: # -> write data
- if isinstance(value, type(())): # -> color
- value = str(value[0]) + ':' +\
- str(value[1]) + ':' + \
- str(value[2])
- return value
- def _castValue(self, value):
- """Cast value"""
- try:
- value = int(value)
- except ValueError:
- try:
- value = float(value)
- except ValueError:
- value = value[1:-1]
- return value
- def _getHistStepData(self, histStep):
- """Load data saved in history step"""
- hist = open(self.histFile)
- histStepData = {}
- newHistStep = False
- isSearchedHistStep = False
- for line in hist.readlines():
- if not line.strip() and isSearchedHistStep:
- break
- elif not line.strip():
- newHistStep = True
- continue
- elif isSearchedHistStep:
- self._parseLine(line, histStepData)
- if newHistStep:
- line = line.split("=")
- if int(line[1]) == histStep:
- isSearchedHistStep = True
- newHistStep = False
- hist.close()
- return histStepData
- def _parseLine(self, line, histStepData):
- """Parse line in file with history"""
- line = line.rstrip('%s' % os.linesep).split(self.sep)
- key = line[0]
- kv = line[1:]
- idx = 0
- subkeyMaster = None
- if len(kv) % 2 != 0: # multiple (e.g. nviz)
- subkeyMaster = kv[0]
- del kv[0]
- idx = 0
- while idx < len(kv):
- if subkeyMaster:
- subkey = [subkeyMaster, kv[idx]]
- else:
- subkey = kv[idx]
- value = kv[idx + 1]
- value = self._parseValue(value, read=True)
- if key not in histStepData:
- histStepData[key] = {}
- if isinstance(subkey, list):
- if subkey[0] not in histStepData[key]:
- histStepData[key][subkey[0]] = {}
- histStepData[key][subkey[0]][subkey[1]] = value
- else:
- histStepData[key][subkey] = value
- idx += 2
- def DeleteNewHistStepData(self):
- """Delete buffer data for new history step"""
- self.newHistStepData.clear()
- class VNETGlobalTurnsData:
- """Turn Data"""
- def __init__(self):
- # Definition of four basic directions
- self.turn_data = [
- ["Straight", DegreesToRadians(-30), DegreesToRadians(+30), 0.0],
- ["Right Turn", DegreesToRadians(+30), DegreesToRadians(+150), 0.0],
- ["Reverse", DegreesToRadians(+150), DegreesToRadians(-150), 0.0],
- ["Left Turn", DegreesToRadians(-150), DegreesToRadians(-30), 0.0]
- ]
- def GetData(self):
- data = []
- for ival in self.turn_data:
- data.append(ival[1:])
- return data
- def GetValue(self, line, col):
- return self.turn_data[line][col]
- def GetLinesCount(self):
- return len(self.turn_data)
- def SetValue(self, value, line, col):
- self.DataValidator(line, col, value)
- self.turn_data[line][col] = value
- def SetUTurns(self, value):
- """Checked if checeBox is checed"""
- useUTurns = value
- def AppendRow(self, values):
- self.turn_data.append(values)
- def InsertRow(self, line, values):
- self.turn_data.insert(line, values)
- def PopRow(self, values):
- self.RemoveDataValidator(values)
- self.turn_data.pop(values)
- def DataValidator(self, row, col, value):
- """Angle recalculation due to value changing"""
- if col not in [1, 2]:
- return
- if col == 1:
- new_from_angle = value
- old_from_angle = self.turn_data[row][1]
- new_to_angle = self.turn_data[row][2]
- if self.IsInInterval(old_from_angle, new_to_angle, new_from_angle):
- prev_row = row - 1
- if prev_row == -1:
- prev_row = len(self.turn_data) - 1
- self.turn_data[prev_row][2] = new_from_angle
- return
- if col == 2:
- new_to_angle = value
- old_to_angle = self.turn_data[row][2]
- new_from_angle = self.turn_data[row][1]
- if self.IsInInterval(new_from_angle, old_to_angle, new_to_angle):
- next_row = row + 1
- if len(self.turn_data) == next_row:
- next_row = 0
- self.turn_data[next_row][1] = new_to_angle
- return
- inside_new = []
- overlap_new_from = []
- overlap_new_to = []
- for i in range(self.GetLinesCount()):
- if i == row:
- continue
- from_angle = self.turn_data[i][1]
- is_in_from = self.IsInInterval(
- new_from_angle, new_to_angle, from_angle)
- to_angle = self.turn_data[i][2]
- is_in_to = self.IsInInterval(
- new_from_angle, new_to_angle, to_angle)
- if is_in_from and is_in_to:
- inside_new.append(i)
- if is_in_from:
- overlap_new_to.append(i)
- if is_in_to:
- overlap_new_from.append(i)
- for i_row in overlap_new_from:
- self.turn_data[i_row][2] = new_from_angle
- for i_row in overlap_new_to:
- self.turn_data[i_row][1] = new_to_angle
- for i_row in inside_new:
- if col == 1:
- angle = new_from_angle
- else:
- angle = new_to_angle
- self.turn_data[i_row][1] = angle
- self.turn_data[i_row][2] = angle
- def RemoveDataValidator(self, row):
- """Angle recalculation due to direction remove"""
- if row == 0:
- prev_row = self.GetLinesCount() - 1
- else:
- prev_row = row - 1
- remove_to_angle = self.turn_data[row][2]
- self.turn_data[prev_row][2] = remove_to_angle
- def IsInInterval(self, from_angle, to_angle, angle):
- """Test if a direction includes or not includes a value"""
- if to_angle < from_angle:
- to_angle = math.pi * 2 + to_angle
- if angle < from_angle:
- angle = math.pi * 2 + angle
- if angle > from_angle and angle < to_angle:
- return True
- return False
|