[GRASS-SVN] r56736 - grass/trunk/gui/wxpython/vnet
svn_grass at osgeo.org
svn_grass at osgeo.org
Sun Jun 16 14:36:51 PDT 2013
Author: turek
Date: 2013-06-16 14:36:51 -0700 (Sun, 16 Jun 2013)
New Revision: 56736
Added:
grass/trunk/gui/wxpython/vnet/vnet_core.py
grass/trunk/gui/wxpython/vnet/vnet_data.py
grass/trunk/gui/wxpython/vnet/vnet_utils.py
Modified:
grass/trunk/gui/wxpython/vnet/__init__.py
grass/trunk/gui/wxpython/vnet/dialogs.py
grass/trunk/gui/wxpython/vnet/toolbars.py
grass/trunk/gui/wxpython/vnet/widgets.py
Log:
wx.vnet: basic refactoring (work in progress), added code for turns support (curently hidden until turns backend will be in GRASS)
Modified: grass/trunk/gui/wxpython/vnet/__init__.py
===================================================================
--- grass/trunk/gui/wxpython/vnet/__init__.py 2013-06-16 18:05:10 UTC (rev 56735)
+++ grass/trunk/gui/wxpython/vnet/__init__.py 2013-06-16 21:36:51 UTC (rev 56736)
@@ -2,4 +2,7 @@
'widgets',
'dialogs',
'toolbars',
+ 'vnet_core',
+ 'vnet_data',
+ 'vnet_utils'
]
Modified: grass/trunk/gui/wxpython/vnet/dialogs.py
===================================================================
--- grass/trunk/gui/wxpython/vnet/dialogs.py 2013-06-16 18:05:10 UTC (rev 56735)
+++ grass/trunk/gui/wxpython/vnet/dialogs.py 2013-06-16 21:36:51 UTC (rev 56736)
@@ -1,35 +1,32 @@
"""!
@package vnet.dialogs
- at brief Dialog for vector network analysis front-end
+ at brief Dialogs for vector network analysis front-end
Classes:
- dialogs::VNETDialog
- dialogs::PtsList
- dialogs::SettingsDialog
- - dialogs::AddLayerDialog
- - dialogs::VnetTmpVectMaps
- - dialogs::VectMap
- - dialogs::History
+ - dialogs::CreateTtbDialog
+ - dialogs::OutputVectorDialog
- dialogs::VnetStatusbar
+ - dialogs::DefIntesectionTurnCostDialog
+ - dialogs::DefGlobalTurnsDialog
+ - dialogs::TurnAnglesList
-(C) 2012 by the GRASS Development Team
+(C) 2012-2013 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)
+ at author Lukas Bocan <silent_bob centrum.cz> (turn costs support)
+ at author Eliska Kyzlikova <eliska.kyzlikova gmail.com> (turn costs support)
"""
import os
import sys
import types
-try:
- import grass.lib.vector as vectlib
- from ctypes import pointer, byref, c_char_p, c_int, c_double
- haveCtypes = True
-except ImportError:
- haveCtypes = False
from copy import copy
from grass.script import core as grass
@@ -38,6 +35,8 @@
import wx.aui
import wx.lib.flatnotebook as FN
import wx.lib.colourselect as csel
+import wx.lib.mixins.listctrl as listmix
+import wx.lib.scrolledpanel as scrolled
from core import globalvar, utils
from core.gcmd import RunCommand, GMessage
@@ -45,14 +44,16 @@
from core.settings import UserSettings
from dbmgr.base import DbMgrBase
+from dbmgr.vinfo import VectorDBInfo
from gui_core.widgets import GNotebook
from gui_core.goutput import GConsoleWindow
-from core.gconsole import CmdThread, EVT_CMD_DONE, GConsole
from gui_core.gselect import Select, LayerSelect, ColumnSelect
from vnet.widgets import PointsList
from vnet.toolbars import MainToolbar, PointListToolbar, AnalysisToolbar
+from vnet.vnet_core import VNETManager
+from vnet.vnet_utils import DegreesToRadians, RadiansToDegrees, GetNearestNodeCat, ParseMapStr
#Main TODOs
# - when layer tree of is changed, tmp result map is removed from render list
@@ -70,60 +71,38 @@
wx.Dialog.__init__(self, parent, id, style=style, title = title, **kwargs)
self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
- self.parent = parent # mapdisp.frame MapFrame class
- self.mapWin = parent.MapWindow
+ self.parent = parent
+ self.mapDisp = giface.GetMapDisplay()
+ self.mapWin = giface.GetMapWindow().GetMapWindow()
self._giface = giface
# contains current analysis result (do not have to be last one, when history is browsed),
# it is instance of VectMap class
self.tmp_result = None
- # initialization of History class used for saving and reading data from file
- # it is used for browsing analysis results
- self.history = History(self)
-
- # variable, which appends unique number to every name of map, which is saved into history
- self.histTmpVectMapNum = 0
-
- # list of maps, which will be saved into history
- self.tmpVectMapsToHist = []
-
- # this class instance manages all temporary vector maps created during life of VNETDialog
- self.tmpMaps = VnetTmpVectMaps(parent = self)
-
- # setting initialization
- self._initSettings()
-
- # registration graphics for drawing
- self.pointsToDraw = self.mapWin.RegisterGraphicsToDraw(graphicsType = "point",
- setStatusFunc = self.SetPointStatus)
- self.SetPointDrawSettings()
-
- # information, whether mouse event handler is registered in map window
- self.handlerRegistered = False
-
+ self.defIsecTurnsHndlrReg = False
+
# get attribute table columns only with numbers (for cost columns in vnet analysis)
self.columnTypes = ['integer', 'double precision']
- # initialization of v.net.* analysis parameters (data which characterizes particular analysis)
- self._initVnetParams()
+ self.vnet_mgr = VNETManager(self, giface)
+ self.vnet_mgr.analysisDone.connect(self.AnalysisDone)
+ self.vnet_mgr.ttbCreated.connect(self.TtbCreated)
+ self.vnet_mgr.snapping.connect(self.Snapping)
+ self.vnet_mgr.pointsChanged.connect(self.PointsChanged)
+
+ self.currAnModule, valid = self.vnet_mgr.GetParam("analysis")
+
# toobars
self.toolbars = {}
- self.toolbars['mainToolbar'] = MainToolbar(parent = self)
- self.toolbars['analysisToolbar'] = AnalysisToolbar(parent = self)
+ self.toolbars['mainToolbar'] = MainToolbar(parent = self, vnet_mgr = self.vnet_mgr)
+ self.toolbars['analysisToolbar'] = AnalysisToolbar(parent = self, vnet_mgr = self.vnet_mgr)
#
# Fancy gui
#
self._mgr = wx.aui.AuiManager(self)
- # Columns in points list
- # TODO init dynamically, not hard typed v.net.path
- self.cols = [
- ['type', _('type'), [_(""), _("Start point"), _("End point")], 0],
- ['topology', _('topology'), None, ""]
- ]
-
self.mainPanel = wx.Panel(parent=self)
self.notebook = GNotebook(parent = self.mainPanel,
style = FN.FNB_FANCY_TABS | FN.FNB_BOTTOM |
@@ -134,14 +113,13 @@
self.stBar = VnetStatusbar(parent = self.mainPanel, style = 0)
self.stBar.SetFieldsCount(number = 1)
-
+ self.def_isec_turns = None
+
# Create tabs
- # Stores all data related to snapping
- self.snapData = {}
- self.snapData['snap_mode'] = False
# Stores widgets which sets some of analysis parameters (e. g. v.ne.iso -> iso lines)
self.anSettings = {}
+
self._createPointsPage()
# stores widgets which are shown on parameters page
@@ -167,20 +145,9 @@
self._doVnetDialogLayout()
self._mgr.Update()
- # adds 2 points into list
- for i in range(2):
- self.list.AddItem()
- self.list.EditCellIndex(i, 'type', i + 1)
- self.list.CheckItem(i, True)
+ self.SetSize((370, 550))
+ self.SetMinSize((370, 420))
- # selects first point
- self.list.selected = 0
- self.list.Select(self.list.selected)
-
- dlgSize = (420, 560)
- self.SetMinSize(dlgSize)
- self.SetInitialSize(dlgSize)
-
#fix goutput's pane size (required for Mac OSX)
if self.gwindow:
self.gwindow.SetSashPosition(int(self.GetSize()[1] * .75))
@@ -189,23 +156,13 @@
self.notebook.SetSelectionByName("parameters")
self.toolbars['analysisToolbar'].SetMinSize((-1, self.toolbars['mainToolbar'].GetSize()[1]))
+ self.toolbars['mainToolbar'].UpdateUndoRedo(0, 0)
+
def __del__(self):
"""!Removes temp layers, unregisters handlers and graphics"""
- update = self.tmpMaps.DeleteAllTmpMaps()
+ #TODO onclose
+ pass
- self.mapWin.UnregisterGraphicsToDraw(self.pointsToDraw)
-
- if self.handlerRegistered:
- self.mapWin.UnregisterMouseEventHandler(wx.EVT_LEFT_DOWN,
- self.OnMapClickHandler)
- if update:
- up_map_evt = gUpdateMap(render = True, renderVector = True)
- wx.PostEvent(self.mapWin, up_map_evt)
- else:
- up_map_evt = gUpdateMap(render = True, renderVector = True)
- wx.PostEvent(self.mapWin, up_map_evt)
-
-
def _addPanes(self):
"""!Adds toolbar pane and pane with tabs"""
self._mgr.AddPane(self.toolbars['mainToolbar'],
@@ -254,8 +211,10 @@
text=_('Points'),
name = 'points')
- self.list = PtsList(parent = pointsPanel, dialog = self, cols = self.cols)
- self.toolbars['pointsList'] = PointListToolbar(parent = pointsPanel, list = self.list)
+ self.list = PtsList(parent = pointsPanel, vnet_mgr = self.vnet_mgr)
+ self.toolbars['pointsList'] = PointListToolbar(parent = pointsPanel,
+ dialog = self,
+ vnet_mgr = self.vnet_mgr)
anSettingsPanel = wx.Panel(parent = pointsPanel)
@@ -265,7 +224,9 @@
maxDistPanel = wx.Panel(parent = anSettingsPanel)
maxDistLabel = wx.StaticText(parent = maxDistPanel, id = wx.ID_ANY, label = _("Maximum distance of point to the network:"))
self.anSettings["max_dist"] = wx.SpinCtrl(parent = maxDistPanel, id = wx.ID_ANY, min = 0, max = maxValue)
+ self.anSettings["max_dist"].Bind(wx.EVT_SPINCTRL, lambda event : self.MaxDist())
self.anSettings["max_dist"].SetValue(100000) #TODO init val
+ self.MaxDist()
#showCutPanel = wx.Panel(parent = anSettingsPanel)
#self.anSettings["show_cut"] = wx.CheckBox(parent = showCutPanel, id=wx.ID_ANY,
@@ -275,7 +236,9 @@
isoLinesPanel = wx.Panel(parent = anSettingsPanel)
isoLineslabel = wx.StaticText(parent = isoLinesPanel, id = wx.ID_ANY, label = _("Iso lines:"))
self.anSettings["iso_lines"] = wx.TextCtrl(parent = isoLinesPanel, id = wx.ID_ANY)
+ self.anSettings["iso_lines"].Bind(wx.EVT_TEXT, lambda event : self.IsoLines())
self.anSettings["iso_lines"].SetValue("1000,2000,3000")
+ self.IsoLines()
# Layout
AnalysisSizer = wx.BoxSizer(wx.VERTICAL)
@@ -313,6 +276,14 @@
anSettingsPanel.SetSizer(anSettingsSizer)
pointsPanel.SetSizer(AnalysisSizer)
+ def MaxDist(self):
+ val = self.anSettings["max_dist"].GetValue()
+ self.vnet_mgr.SetParams({"max_dist" : val}, {})
+
+ def IsoLines(self):
+ val = self.anSettings["iso_lines"].GetValue()
+ self.vnet_mgr.SetParams({"iso_lines" : val}, {})
+
def OnShowCut(self, event):
"""!Shows vector map with minimal cut (v.net.flow) - not yet implemented"""
val = event.IsChecked()
@@ -335,8 +306,8 @@
text = _("Output"),
name = 'output')
- self.goutput = GConsole(guiparent = self)
- self.gwindow = GConsoleWindow(parent = outputPanel, gconsole = self.goutput)
+ goutput = self.vnet_mgr.goutput #TODO make interface
+ self.gwindow = GConsoleWindow(parent = outputPanel, gconsole = goutput)
#Layout
outputSizer = wx.BoxSizer(wx.VERTICAL)
@@ -347,7 +318,7 @@
def _createParametersPage(self):
"""!Tab for selection of data for analysis"""
- dataPanel = wx.Panel(parent=self)
+ dataPanel = scrolled.ScrolledPanel(parent=self)
self.notebook.AddPage(page = dataPanel,
text=_('Parameters'),
name = 'parameters')
@@ -356,12 +327,18 @@
['input', "Choose vector map for analysis:", Select],
['alayer', "Arc layer number or name:", LayerSelect],
['nlayer', "Node layer number or name:", LayerSelect],
- ['afcolumn', self.attrCols['afcolumn']['label'], ColumnSelect],
- ['abcolumn', self.attrCols['abcolumn']['label'], ColumnSelect],
- ['ncolumn', self.attrCols['ncolumn']['label'], ColumnSelect],
+ #['tlayer', "Layer with turntable:", LayerSelect],
+ #['tuclayer', "Layer with unique categories for turntable:", LayerSelect],
+ ['afcolumn', "", ColumnSelect],
+ ['abcolumn', "", ColumnSelect],
+ ['ncolumn', "", ColumnSelect],
]
+ #self.useTurns = wx.CheckBox(parent = dataPanel, id=wx.ID_ANY,
+ # label = _('Use turns'))
+
selPanels = {}
+
for dataSel in dataSelects:
selPanels[dataSel[0]] = wx.Panel(parent = dataPanel)
if dataSel[0] == 'input':
@@ -378,6 +355,11 @@
self.addToTreeBtn.Disable()
self.addToTreeBtn.Bind(wx.EVT_BUTTON, self.OnToTreeBtn)
elif dataSel[0] != 'input':
+ #if dataSel[0] == "tlayer":
+ # self.createTtbBtn = wx.Button(parent = selPanels[dataSel[0]],
+ # label = _("Create turntable"))
+ # self.createTtbBtn.Bind(wx.EVT_BUTTON, self.OnCreateTtbBtn)
+
self.inputData[dataSel[0]] = dataSel[2](parent = selPanels[dataSel[0]],
size = (-1, -1))
label[dataSel[0]] = wx.StaticText(parent = selPanels[dataSel[0]],
@@ -388,6 +370,13 @@
self.inputData['alayer'].Bind(wx.EVT_TEXT, self.OnALayerSel)
self.inputData['nlayer'].Bind(wx.EVT_TEXT, self.OnNLayerSel)
+ for params in ["afcolumn", "abcolumn", "ncolumn"]:#, "tlayer", "tuclayer"]:
+ self.inputData[params].Bind(wx.EVT_TEXT, lambda event : self._setInputData())
+
+ #self.useTurns.Bind(wx.EVT_CHECKBOX,
+ # lambda event: self.UseTurns())
+ #self.UseTurns()
+
# Layout
mainSizer = wx.BoxSizer(wx.VERTICAL)
box = wx.StaticBox(dataPanel, -1, "Vector map and layers for analysis")
@@ -396,15 +385,21 @@
mainSizer.Add(item = bsizer, proportion = 0,
flag = wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, border = 5)
- for sel in ['input', 'alayer', 'nlayer']:
- if sel== 'input':
+ for sel in ['input', 'alayer', 'nlayer']:#, 'tlayer', 'tuclayer']:
+ if sel == 'input':
btn = self.addToTreeBtn
+ #elif sel == "tlayer":
+ # btn = self.createTtbBtn
else:
btn = None
+ #if sel == 'tlayer':
+ # bsizer.Add(item = self.useTurns, proportion = 0,
+ # flag = wx.TOP | wx.LEFT | wx.RIGHT, border = 5)
+
selPanels[sel].SetSizer(self._doSelLayout(title = label[sel],
sel = self.inputData[sel],
btn = btn))
- bsizer.Add(item = selPanels[sel], proportion = 1,
+ bsizer.Add(item = selPanels[sel], proportion = 0,
flag = wx.EXPAND)
box = wx.StaticBox(dataPanel, -1, "Costs")
@@ -418,8 +413,12 @@
bsizer.Add(item = selPanels[sel], proportion = 0,
flag = wx.EXPAND)
+
dataPanel.SetSizer(mainSizer)
+ dataPanel.SetupScrolling()
+ dataPanel.SetAutoLayout(1)
+
def _doSelLayout(self, title, sel, btn = None):
# helper function for layout of self.inputData widgets initialized in _createParametersPage
selSizer = wx.BoxSizer(orient = wx.VERTICAL)
@@ -494,7 +493,7 @@
# analysis, which created result
analysis = self.resultDbMgrData['analysis']
#TODO maybe no need to store this information, just check it has attribute table, if so show it
- haveDbMgr = self.vnetParams[analysis]["resultProps"]["dbMgr"]
+ haveDbMgr = self.vnet_mgr.GetAnalysisProperties(analysis)["resultProps"]["dbMgr"]
if haveDbMgr and self.notebook.GetPageIndexByName('resultDbMgr') == -1:
self.notebook.AddPage(page = self.resultDbMgrData['browse'],
@@ -587,7 +586,7 @@
def OnToTreeBtn(self, event):
"""!Add vector map into layer tree"""
vectorMap = self.inputData['input'].GetValue()
- vectMapName, mapSet = self._parseMapStr(vectorMap)
+ vectMapName, mapSet = ParseMapStr(vectorMap)
vectorMap = vectMapName + '@' + mapSet
existsMap = grass.find_file(name = vectMapName,
element = 'vector',
@@ -614,20 +613,72 @@
up_map_evt = gUpdateMap(render = True, renderVector = True)
wx.PostEvent(self.mapWin, up_map_evt)
+ def UseTurns(self):
+ if self.useTurns.IsChecked():
+ self.inputData["tlayer"].GetParent().Show()
+ self.inputData["tuclayer"].GetParent().Show()
+
+ self.vnet_mgr.SetParams(params = {}, flags = {"t" : True})
+ else:
+ self.inputData["tlayer"].GetParent().Hide()
+ self.inputData["tuclayer"].GetParent().Hide()
+
+ self.vnet_mgr.SetParams(params = {}, flags = {"t" : False})
+
+ self.Layout()
+
+ def PointsChanged(self, method, kwargs):
+
+ if method == "EditMode" and not kwargs["activated"]:
+ ptListToolbar = self.toolbars['pointsList']
+ if ptListToolbar:
+ ptListToolbar.ToggleTool(id = ptListToolbar.GetToolId("insertPoint"),
+ toggle = False)
+
+ if method == "EditMode" and kwargs["activated"]:
+ ptListToolbar = self.toolbars['pointsList']
+ if ptListToolbar:
+ ptListToolbar.ToggleTool(id = ptListToolbar.GetToolId("insertPoint"),
+ toggle = True)
+
+ if method == "SetPointData" and ("e" in kwargs.keys() or "n" in kwargs.keys()):
+ self.notebook.SetSelectionByName("points")
+
+
+ def OnCreateTtbBtn(self, event):
+
+ params, err_params, flags = self.vnet_mgr.GetParams()
+ dlg = CreateTtbDialog(parent = self, init_data = params)
+
+ if dlg.ShowModal() == wx.ID_OK:
+ self.stBar.AddStatusItem(text = _('Creating turntable...'),
+ key = 'ttb',
+ priority = self.stPriorities['important'])
+
+ params = dlg.GetData()
+ if not self.vnet_mgr.CreateTttb(params):
+ self.stBar.RemoveStatusItem('ttb')
+ dlg.Destroy()
+
+ def TtbCreated(self):
+
+ params, err_params, flags = self.vnet_mgr.GetParams()
+ self._updateParamsTab(params, flags)
+
+ self.stBar.RemoveStatusItem('ttb')
+
def OnVectSel(self, event):
"""!When vector map is selected it populates other comboboxes in Parameters tab (layer selects, columns selects)"""
- if self.snapData['snap_mode']:
- self.OnSnapping(event = None)
+ if self.vnet_mgr.IsSnappingActive(): #TODO should be in vnet_mgr
+ self.vnet_mgr.Snapping(activate = True)
vectMapName, mapSet = self._parseMapStr(self.inputData['input'].GetValue())
vectorMap = vectMapName + '@' + mapSet
- self.inputData['alayer'].Clear()
- self.inputData['nlayer'].Clear()
+ for sel in ['alayer', 'nlayer']:#, 'tlayer', 'tuclayer']:
+ self.inputData[sel].Clear()
+ self.inputData[sel].InsertLayers(vector = vectorMap)
- self.inputData['alayer'].InsertLayers(vector = vectorMap)
- self.inputData['nlayer'].InsertLayers(vector = vectorMap)
-
items = self.inputData['alayer'].GetItems()
itemsLen = len(items)
if itemsLen < 1:
@@ -657,6 +708,15 @@
self.OnALayerSel(event)
self.OnNLayerSel(event)
+ self._setInputData()
+
+ def _updateParamsTab(self, params, flags):
+ #TODO flag
+
+ #'tlayer', 'tuclayer',
+ for k in ['input', 'alayer', 'nlayer', 'afcolumn', 'abcolumn', 'ncolumn']:
+ self.inputData[k].SetValue(params[k])
+
def OnALayerSel(self, event):
"""!When arc layer from vector map is selected, populates corespondent columns selects"""
self.inputData['afcolumn'].InsertColumns(vector = self.inputData['input'].GetValue(),
@@ -666,63 +726,26 @@
layer = self.inputData['alayer'].GetValue(),
type = self.columnTypes)
+ self._setInputData()
def OnNLayerSel(self, event):
"""!When node layer from vector map is selected, populates corespondent column select"""
- if self.snapData['snap_mode']:
- self.OnSnapping(event = None)
+ if self.vnet_mgr.IsSnappingActive():
+ self.vnet_mgr.Snapping(activate = True)
self.inputData['ncolumn'].InsertColumns(vector = self.inputData['input'].GetValue(),
layer = self.inputData['nlayer'].GetValue(),
type = self.columnTypes)
- def _getInvalidInputs(self, inpToTest):
- """!Check of analysis input data for invalid values (Parameters tab)"""
- # dict of invalid values {key from self.itemData (comboboxes from Parameters tab) : invalid value}
- errInput = {}
+ self._setInputData()
- mapVal = self.inputData['input'].GetValue()
- mapName, mapSet = self._parseMapStr(mapVal)
- vectMaps = grass.list_grouped('vect')[mapSet]
+ def _setInputData(self):
+ params = {}
+ for k, v in self.inputData.iteritems():
+ params[k] = v.GetValue()
+ flags = {}
+ self.vnet_mgr.SetParams(params, flags)
- # check of vector map
- if not inpToTest or "input" in inpToTest:
- if mapName not in vectMaps:
- errInput['input'] = mapVal
-
- # check of arc/node layer
- for layerSelName in ['alayer', 'nlayer'] :
- if not inpToTest or layerSelName in inpToTest:
-
- layerItems = self.inputData[layerSelName].GetItems()
- layerVal = self.inputData[layerSelName].GetValue().strip()
- if layerVal not in layerItems:
- errInput[layerSelName] = layerVal
-
- # check of costs columns
- currModCols = self.vnetParams[self.currAnModule]["cmdParams"]["cols"]
- for col, colData in self.attrCols.iteritems():
- if not inpToTest or col in inpToTest:
-
- if col not in currModCols:
- continue
-
- if "inputField" in self.attrCols[col]:
- colInptF = self.attrCols[col]["inputField"]
- else:
- colInptF = col
-
- if not self.inputData[colInptF].IsShown():
- continue
- colVal = self.inputData[colInptF].GetValue().strip()
-
- if not colVal:
- continue
- if colVal != self.inputData[colInptF].GetValue():
- errInput[col] = colVal
-
- return errInput
-
def _parseMapStr(self, vectMapStr):
"""!Create full map name (add current mapset if it is not present in name)"""
mapValSpl = vectMapStr.strip().split("@")
@@ -734,137 +757,41 @@
return mapName, mapSet
- def InputsErrorMsgs(self, msg, inpToTest = None):
- """!Checks input data in Parameters tab and shows messages if some value is not valid
-
- @param msg (str) - message added to start of message string
- @param inpToTest (list) - list of keys from self.itemData map, which says which input data should be checked,
- if is empty or None, all input data are checked
- @return True - if checked inputs are OK
- @return False - if some of checked inputs is not ok
- """
- errInput = self._getInvalidInputs(inpToTest)
-
- errMapStr = ""
- if errInput.has_key('input'):
- self.notebook.SetSelectionByName("parameters")
- if errInput['input']:
- errMapStr = _("Vector map '%s' does not exist.") % (errInput['input'])
- else:
- errMapStr = _("Vector map was not chosen.")
-
-
- if errMapStr:
- GMessage(parent = self,
- message = msg + "\n" + errMapStr)
- return False
-
- errLayerStr = ""
- for layer, layerLabel in {'alayer' : _("arc layer"),
- 'nlayer' : _("node layer")}.iteritems():
-
- if errInput.has_key(layer):
- if errInput[layer]:
- errLayerStr += _("Chosen %s '%s' does not exist in vector map '%s'.\n") % \
- (layerLabel, self.inputData[layer].GetValue(), self.inputData['input'].GetValue())
- else:
- errLayerStr += _("Choose existing %s.\n") % \
- (layerLabel)
- if errLayerStr:
- GMessage(parent = self,
- message = msg + "\n" + errLayerStr)
- return False
-
- errColStr = ""
- for col, colData in self.attrCols.iteritems():
- if col in errInput.iterkeys():
- errColStr += _("Chosen column '%s' does not exist in attribute table of layer '%s' of vector map '%s'.\n") % \
- (errInput[col], self.inputData[layer].GetValue(), self.inputData['input'].GetValue())
-
- if errColStr:
- self.notebook.SetSelectionByName("parameters")
- GMessage(parent = self,
- message = msg + "\n" + errColStr)
- return False
-
- return True
-
def OnCloseDialog(self, event):
"""!Cancel dialog"""
self.parent.dialogs['vnet'] = None
self.Destroy()
- def SetPointStatus(self, item, itemIndex):
- """!Before point is drawn, decides properties of drawing style"""
- key = self.list.GetItemData(itemIndex)
- cats = self.vnetParams[self.currAnModule]["cmdParams"]["cats"]
-
- if key == self.list.selected:
- wxPen = "selected"
- elif not self.list.IsChecked(key):
- wxPen = "unused"
- item.hide = False
- elif len(cats) > 1:
- idx = self.list.GetCellSelIdx(key, 'type')
- if idx == 2: #End/To/Sink point
- wxPen = "used2cat"
- else:
- wxPen = "used1cat"
+ def OnDefIsecTurnCosts(self, event):
+ """!Registers/unregisters mouse handler into map window"""
+ if self.defIsecTurnsHndlrReg == False:
+ self.mapWin.RegisterMouseEventHandler(wx.EVT_LEFT_DOWN,
+ self.OnDefIsecTurnCost,
+ wx.StockCursor(wx.CURSOR_CROSS))
+ self.defIsecTurnsHndlrReg = True
else:
- wxPen = "used1cat"
+ self.mapWin.UnregisterMouseEventHandler(wx.EVT_LEFT_DOWN,
+ self.OnDefIsecTurnCost)
- item.SetPropertyVal('label', str(itemIndex + 1))
- item.SetPropertyVal('penName', wxPen)
+ self.defIsecTurnsHndlrReg = False
- def OnMapClickHandler(self, event):
+ def OnDefGlobalTurnCosts(self, event):
+
+ dialog = DefGlobalTurnsDialog(self, data = self.vnet_mgr.GetGlobalTurnsData())
+ dialog.Show()
+
+ def OnDefIsecTurnCost(self, event): #TODO move to vnet mgr?
"""!Take coordinates from map window"""
if event == 'unregistered':
ptListToolbar = self.toolbars['pointsList']
if ptListToolbar:
- ptListToolbar.ToggleTool( id = ptListToolbar.GetToolId("insertPoint"),
+ ptListToolbar.ToggleTool( id = ptListToolbar.GetToolId("isec_turn_edit"),
toggle = False)
self.handlerRegistered = False
return
- self.notebook.SetSelectionByName("points")
- if not self.list.itemDataMap:
- self.list.AddItem(None)
-
e, n = self.mapWin.GetLastEN()
- index = self.list.selected
- key = self.list.GetItemData(index)
-
- if self.snapData['snap_mode']:
- coords = [e, n]
- if self._snapPoint(coords):
- msg = ("snapped to node")
- else:
- msg = _("new point")
-
- e = coords[0]
- n = coords[1]
-
- else:
- msg = _("new point")
-
- self.list.EditCellKey(key = self.list.selected ,
- colName = 'topology',
- cellData = msg)
-
- self.pointsToDraw.GetItem(key).SetCoords([e, n])
-
- if self.list.selected == self.list.GetItemCount() - 1:
- self.list.selected = 0
- else:
- self.list.selected += 1
- self.list.Select(self.list.selected)
-
- def _snapPoint(self, coords):
- """!Find nearest node to click coordinates (within given threshold)"""
- e = coords[0]
- n = coords[1]
-
# compute threshold
snapTreshPix = int(UserSettings.Get(group ='vnet',
key = 'other',
@@ -872,143 +799,49 @@
res = max(self.mapWin.Map.region['nsres'], self.mapWin.Map.region['ewres'])
snapTreshDist = snapTreshPix * res
- vectorMap = self.inputData['input'].GetValue()
- vectMapName, mapSet = self._parseMapStr(vectorMap)
- inpMapExists = grass.find_file(name = vectMapName,
- element = 'vector',
- mapset = mapSet)
- if not inpMapExists['name']:
- return False
+ params, err_params, flags = self.vnet_mgr.GetParams()
- openedMap = pointer(vectlib.Map_info())
- ret = vectlib.Vect_open_old2(openedMap,
- c_char_p(vectMapName),
- c_char_p(mapSet),
- c_char_p(self.inputData['alayer'].GetValue()))
- if ret == 1:
- vectlib.Vect_close(openedMap)
- if ret != 2:
- return False
+ if "input" in err_params:
+ GMessage(parent = self,
+ message = _("Input vector map does not exists."))
- nodeNum = vectlib.Vect_find_node(openedMap,
- c_double(e),
- c_double(n),
- c_double(0),
- c_double(snapTreshDist),
- vectlib.WITHOUT_Z)
+ if ["tlayer", "tuclayer"] in err_params:
+ GMessage(parent = self, message = "Please choose existing turntable layer and unique categories layer in Parameters tab.")
- if nodeNum > 0:
- e = c_double(0)
- n = c_double(0)
- vectlib.Vect_get_node_coor(openedMap,
- nodeNum,
- byref(e),
- byref(n),
- None); # z
- e = e.value
- n = n.value
- else:
- vectlib.Vect_close(openedMap)
- return False
+ cat = GetNearestNodeCat(e, n, int(params['tuclayer']), snapTreshDist, params["input"])
- coords[0] = e
- coords[1] = n
- return True
+ if not self.def_isec_turns:
+ self.def_isec_turns = DefIntesectionTurnCostDialog(self, self.parent)
+ self.def_isec_turns.SetSize((500, 400))
+ self.def_isec_turns.SetData(params["input"], params["tlayer"])
+ self.def_isec_turns.SetIntersection(cat)
+ self.def_isec_turns.Show()
+
def OnAnalyze(self, event):
"""!Called when network analysis is started"""
- # Check of parameters for analysis
- if not self.InputsErrorMsgs(msg = _("Analysis can not be done.")):
- return
- if self.tmp_result:
- self.tmp_result.DeleteRenderLayer()
-
- # history - delete data in buffer for hist step
- self.history.DeleteNewHistStepData()
- # empty list for maps to be saved to history
- self.tmpVectMapsToHist= []
- # create new map (included to history) for result of analysis
- self.tmp_result = self.NewTmpVectMapToHist('vnet_tmp_result')
-
- if not self.tmp_result:
- return
-
self.stBar.AddStatusItem(text = _('Analysing...'),
key = 'analyze',
priority = self.stPriorities['important'])
- # for case there is some map with same name
- # (when analysis does not produce any map, this map would have been shown as result)
- RunCommand('g.remove',
- vect = self.tmp_result.GetVectMapName())
+ ret = self.vnet_mgr.RunAnalysis()
- # save data from
- self._saveAnInputToHist()
-
+ #TODO
self.resultDbMgrData['analysis'] = self.currAnModule
- # Creates part of cmd fro analysis
- cmdParams = [self.currAnModule]
- cmdParams.extend(self._getInputParams())
- cmdParams.append("output=" + self.tmp_result.GetVectMapName())
+ if ret < 0:
+ self.stBar.RemoveStatusItem(key = 'analyze')
+ if ret == -2:
+ self.notebook.SetSelectionByName("parameters")
- catPts = self._getPtByCat()
+ def AnalysisDone(self):
- if self.currAnModule == "v.net.path":
- self._vnetPathRunAn(cmdParams, catPts)
- else:
- self._runAn(cmdParams, catPts)
+ curr_step, steps_num = self.vnet_mgr.GetHistStep()
+ self.toolbars['mainToolbar'].UpdateUndoRedo(curr_step, steps_num)
- def _vnetPathRunAn(self, cmdParams, catPts):
- """!Called when analysis is run for v.net.path module"""
- if len(self.pointsToDraw.GetAllItems()) < 1:
- return
- cats = self.vnetParams[self.currAnModule]["cmdParams"]["cats"]
+ self.tmp_result = self.vnet_mgr.GetResults()
- cmdPts = []
- for cat in cats:
- if len(catPts[cat[0]]) < 1:
- GMessage(parent = self,
- message=_("Please choose '%s' and '%s' point.") % (cats[0][1], cats[1][1]))
- return
- cmdPts.append(catPts[cat[0]][0])
-
- resId = 1
- inpPoints = str(resId) + " " + str(cmdPts[0][0]) + " " + str(cmdPts[0][1]) + \
- " " + str(cmdPts[1][0]) + " " + str(cmdPts[1][1])
-
- self.coordsTmpFile = grass.tempfile()
- coordsTmpFileOpened = open(self.coordsTmpFile, 'w')
- coordsTmpFileOpened.write(inpPoints)
- coordsTmpFileOpened.close()
-
- cmdParams.append("file=" + self.coordsTmpFile)
-
- cmdParams.append("dmax=" + str(self.anSettings["max_dist"].GetValue()))
- cmdParams.append("input=" + self.inputData['input'].GetValue())
-
- cmdParams.append("--overwrite")
- self._prepareCmd(cmd = cmdParams)
-
- self.goutput.RunCmd(command = cmdParams, onDone = self._vnetPathRunAnDone)
-
- def _vnetPathRunAnDone(self, cmd, returncode):
- """!Called when v.net.path analysis is done"""
- grass.try_remove(self.coordsTmpFile)
-
- self._saveHistStep()
- self.tmp_result.SaveVectMapState()
-
- self._updateResultDbMgrPage()
- self._updateDbMgrData()
-
- cmd = self.GetLayerStyle()
- self.tmp_result.AddRenderLayer(cmd)
-
- up_map_evt = gUpdateMap(render = True, renderVector = True)
- wx.PostEvent(self.mapWin, up_map_evt)
-
mainToolbar = self.toolbars['mainToolbar']
id = vars(mainToolbar)['showResult']
mainToolbar.ToggleTool(id =id,
@@ -1016,236 +849,12 @@
self.stBar.RemoveStatusItem(key = 'analyze')
- def _runAn(self, cmdParams, catPts):
- """!Called for all v.net.* analysis (except v.net.path)"""
-
- cats = self.vnetParams[self.currAnModule]["cmdParams"]["cats"]
-
- if len(cats) > 1:
- for cat in cats:
- if len(catPts[cat[0]]) < 1:
- GMessage(parent = self,
- message = _("Please choose '%s' and '%s' point.") \
- % (cats[0][1], cats[1][1]))
- return
- else:
- for cat in cats:
- if len(catPts[cat[0]]) < 2:
- GMessage(parent = self,
- message = _("Please choose at least two points."))
- return
-
- # TODO add also to thread for analysis?
- vcatResult = RunCommand("v.category",
- input = self.inputData['input'].GetValue(),
- option = "report",
- flags = "g",
- read = True)
-
- vcatResult = vcatResult.splitlines()
- for cat in vcatResult:#TODO
- cat = cat.split()
- if "all" in cat:
- maxCat = int(cat[4])
- break
-
- layerNum = self.inputData["nlayer"].GetValue().strip()
-
- pt_ascii, catsNums = self._getAsciiPts (catPts = catPts,
- maxCat = maxCat,
- layerNum = layerNum)
-
- self.tmpPtsAsciiFile = grass.tempfile()#TODO better tmp files cleanup (make class for managing tmp files)
- tmpPtsAsciiFileOpened = open(self.tmpPtsAsciiFile, 'w')
- tmpPtsAsciiFileOpened.write(pt_ascii)
- tmpPtsAsciiFileOpened.close()
-
- self.tmpInPts = self._addTmpMapAnalysisMsg("vnet_tmp_in_pts")
- if not self.tmpInPts:
- return
-
- self.tmpInPtsConnected = self._addTmpMapAnalysisMsg("vnet_tmp_in_pts_connected")
- if not self.tmpInPtsConnected:
- return
-
- cmdParams.append("input=" + self.tmpInPtsConnected.GetVectMapName())
- cmdParams.append("--overwrite")
-
- # append parameters needed for particular analysis
- if self.currAnModule == "v.net.distance":
- cmdParams.append("from_layer=1")
- cmdParams.append("to_layer=1")
- elif self.currAnModule == "v.net.flow":
- self.vnetFlowTmpCut = self.NewTmpVectMapToHist('vnet_tmp_flow_cut')
- if not self.vnetFlowTmpCut:
- return
- cmdParams.append("cut=" + self.vnetFlowTmpCut.GetVectMapName())
- elif self.currAnModule == "v.net.iso":
- costs = self.anSettings["iso_lines"].GetValue()
- cmdParams.append("costs=" + costs)
- for catName, catNum in catsNums.iteritems():
- if catNum[0] == catNum[1]:
- cmdParams.append(catName + "=" + str(catNum[0]))
- else:
- cmdParams.append(catName + "=" + str(catNum[0]) + "-" + str(catNum[1]))
-
- # create and run commands which goes to analysis thread
- cmdVEdit = [
- "v.edit",
- "map=" + self.tmpInPts.GetVectMapName(),
- "input=" + self.tmpPtsAsciiFile,
- "tool=create",
- "--overwrite",
- "-n"
- ]
- self._prepareCmd(cmdVEdit)
- self.goutput.RunCmd(command = cmdVEdit)
-
- cmdVNet = [
- "v.net",
- "points=" + self.tmpInPts.GetVectMapName(),
- "input=" + self.inputData['input'].GetValue(),
- "output=" + self.tmpInPtsConnected.GetVectMapName(),
- "alayer=" + self.inputData["alayer"].GetValue().strip(),
- "nlayer=" + self.inputData["nlayer"].GetValue().strip(),
- "operation=connect",
- "thresh=" + str(self.anSettings["max_dist"].GetValue()),
- "--overwrite"
- ] #TODO snapping to nodes optimization
- self._prepareCmd(cmdVNet)
- self.goutput.RunCmd(command = cmdVNet)
-
- self._prepareCmd(cmdParams)
- self.goutput.RunCmd(command = cmdParams, onDone = self._runAnDone)
-
- def _runAnDone(self, cmd, returncode):
- """!Called when analysis is done"""
- self.tmpMaps.DeleteTmpMap(self.tmpInPts) #TODO remove earlier (OnDone lambda?)
- self.tmpMaps.DeleteTmpMap(self.tmpInPtsConnected)
- grass.try_remove(self.tmpPtsAsciiFile)
-
- self._saveHistStep()
- self.tmp_result.SaveVectMapState()
- if self.currAnModule == "v.net.flow":
- self.vnetFlowTmpCut.SaveVectMapState()
self._updateResultDbMgrPage()
self._updateDbMgrData()
- cmd = self.GetLayerStyle()
- self.tmp_result.AddRenderLayer(cmd)
-
up_map_evt = gUpdateMap(render = True, renderVector = True)
wx.PostEvent(self.mapWin, up_map_evt)
- mainToolbar = self.toolbars['mainToolbar']
- id = vars(mainToolbar)['showResult']
- mainToolbar.ToggleTool(id =id,
- toggle = True)
-
- self.stBar.RemoveStatusItem(key = 'analyze')
-
- def _getInputParams(self):
- """!Return list of chosen values (vector map, layers) from Parameters tab.
-
- The list items are in form to be used in command for analysis e.g. 'alayer=1'.
- """
-
- inParams = []
- for col in self.vnetParams[self.currAnModule]["cmdParams"]["cols"]:
-
- if "inputField" in self.attrCols[col]:
- colInptF = self.attrCols[col]["inputField"]
- else:
- colInptF = col
-
- inParams.append(col + '=' + self.inputData[colInptF].GetValue())
-
- for layer in ['alayer', 'nlayer']:
- inParams.append(layer + "=" + self.inputData[layer].GetValue().strip())
-
- return inParams
-
- def _getPtByCat(self):
- """!Return points separated by theirs categories"""
- cats = self.vnetParams[self.currAnModule]["cmdParams"]["cats"]
-
- ptByCats = {}
- for cat in self.vnetParams[self.currAnModule]["cmdParams"]["cats"]:
- ptByCats[cat[0]] = []
-
- for i in range(len(self.list.itemDataMap)):
- key = self.list.GetItemData(i)
- if self.list.IsChecked(key):
- for cat in cats:
- if cat[1] == self.list.itemDataMap[key][1] or len(ptByCats) == 1:
- ptByCats[cat[0]].append(self.pointsToDraw.GetItem(key).GetCoords())
- continue
-
- return ptByCats
-
- def _getAsciiPts (self, catPts, maxCat, layerNum):
- """!Return points separated by categories in GRASS ASCII vector representation"""
- catsNums = {}
- pt_ascii = ""
- catNum = maxCat
-
- for catName, pts in catPts.iteritems():
-
- catsNums[catName] = [catNum + 1]
- for pt in pts:
- catNum += 1
- pt_ascii += "P 1 1\n"
- pt_ascii += str(pt[0]) + " " + str(pt[1]) + "\n"
- pt_ascii += str(layerNum) + " " + str(catNum) + "\n"
-
- catsNums[catName].append(catNum)
-
- return pt_ascii, catsNums
-
- def _prepareCmd(self, cmd):
- """!Helper function for preparation of cmd list into form for RunCmd method"""
- for c in cmd[:]:
- if c.find("=") == -1:
- continue
- v = c.split("=")
- if len(v) != 2:
- cmd.remove(c)
- elif not v[1].strip():
- cmd.remove(c)
-
- def GetLayerStyle(self):
- """!Returns cmd for d.vect, with set style for analysis result"""
- resProps = self.vnetParams[self.currAnModule]["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]))
-
- 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",
- "map=" + self.tmp_result.GetVectMapName(),
- "color=" + colorStyle,
- "column=" + resProps["attrColColor"],
- ]
- if invert:
- layerStyleVnetColors.append("-n")
-
- layerStyleVnetColors = utils.CmdToTuple(layerStyleVnetColors)
-
- RunCommand( layerStyleVnetColors[0],
- **layerStyleVnetColors[1])
-
- return layerStyleCmd
-
def OnShowResult(self, event):
"""!Show/hide analysis result"""
mainToolbar = self.toolbars['mainToolbar']
@@ -1256,109 +865,30 @@
mainToolbar.ToggleTool(id =id,
toggle = False)
elif toggleState:
- self._checkResultMapChanged(self.tmp_result)
- cmd = self.GetLayerStyle()
- self.tmp_result.AddRenderLayer(cmd)
+ self.vnet_mgr.ShowResult(True)
else:
- cmd = self.GetLayerStyle()
- self.tmp_result.DeleteRenderLayer()
+ self.vnet_mgr.ShowResult(False)
- up_map_evt = gUpdateMap(render = True, renderVector = True)
- wx.PostEvent(self.mapWin, up_map_evt)
-
- def OnInsertPoint(self, event):
- """!Registers/unregisters mouse handler into map window"""
- if self.handlerRegistered == False:
- self.mapWin.RegisterMouseEventHandler(wx.EVT_LEFT_DOWN,
- self.OnMapClickHandler,
- wx.StockCursor(wx.CURSOR_CROSS))
- self.handlerRegistered = True
- else:
- self.mapWin.UnregisterMouseEventHandler(wx.EVT_LEFT_DOWN,
- self.OnMapClickHandler)
- self.handlerRegistered = False
-
def OnSaveTmpLayer(self, event):
- """!Permanently saves temporary map of analysis result"""
- dlg = AddLayerDialog(parent = self)
+ dlg = OutputVectorDialog(parent = self)
+ dlg.ShowModal()
+ self.vnet_mgr.SaveTmpLayer(dlg.vectSel.GetValue())
+ dlg.Destroy()
- msg = _("Vector map with analysis result does not exist.")
- if dlg.ShowModal() == wx.ID_OK:
-
- if not hasattr(self.tmp_result, "GetVectMapName"):
- GMessage(parent = self,
- message = msg)
- return
-
- mapToAdd = self.tmp_result.GetVectMapName()
- mapToAddEx = grass.find_file(name = mapToAdd,
- element = 'vector',
- mapset = grass.gisenv()['MAPSET'])
-
- if not mapToAddEx["name"]:
- GMessage(parent = self,
- message = msg)
- dlg.Destroy()
- return
-
- addedMap = dlg.vectSel.GetValue()
- mapName, mapSet = self._parseMapStr(addedMap)
- if mapSet != grass.gisenv()['MAPSET']:
- GMessage(parent = self,
- message = _("Map can be saved only to currently set mapset"))
- return
- existsMap = grass.find_file(name = mapName,
- element = 'vector',
- mapset = grass.gisenv()['MAPSET'])
- dlg.Destroy()
- if existsMap["name"]:
- dlg = wx.MessageDialog(parent = self.parent.parent,
- message = _("Vector map %s already exists. " +
- "Do you want to overwrite it?") %
- (existsMap["fullname"]),
- caption = _("Overwrite map layer"),
- style = wx.YES_NO | wx.NO_DEFAULT |
- wx.ICON_QUESTION | wx.CENTRE)
- ret = dlg.ShowModal()
- if ret == wx.ID_NO:
- dlg.Destroy()
- return
- dlg.Destroy()
-
- RunCommand("g.copy",
- overwrite = True,
- vect = [self.tmp_result.GetVectMapName(), mapName])
-
- cmd = self.GetLayerStyle()#TODO get rid of insert
- cmd.insert(0, 'd.vect')
- cmd.append('map=%s' % mapName)
-
- if not self.mapWin.tree:
- return
-
- if self.mapWin.tree.FindItemByData(key = 'name', value = mapName) is None:
- self.mapWin.tree.AddLayer(ltype = "vector",
- lname = mapName,
- lcmd = cmd,
- lchecked = True)
- else:
- up_map_evt = gUpdateMap(render = True, renderVector = True)
- wx.PostEvent(self.mapWin, up_map_evt)
-
def OnSettings(self, event):
"""!Displays vnet settings dialog"""
- dlg = SettingsDialog(parent=self, id=wx.ID_ANY, title=_('Settings'))
+ dlg = SettingsDialog(parent=self, id=wx.ID_ANY,
+ title=_('Settings'), vnet_mgr = self.vnet_mgr)
- if dlg.ShowModal() == wx.ID_OK:
- pass
-
+ dlg.ShowModal()
dlg.Destroy()
def OnAnalysisChanged(self, event):
"""!Updates dialog when analysis is changed"""
# set chosen analysis
iAn = self.toolbars['analysisToolbar'].anChoice.GetSelection()
- self.currAnModule = self.vnetModulesOrder[iAn]
+ self.currAnModule = self.vnet_mgr.GetAnalyses()[iAn]
+ self.vnet_mgr.SetParams({"analysis" : self.currAnModule}, {})
# update dialog for particular analysis
if self.currAnModule == "v.net.iso":
@@ -1373,9 +903,17 @@
# show only corresponding selects for chosen v.net module
skip = []
- for col in self.attrCols.iterkeys():
- if "inputField" in self.attrCols[col]:
- colInptF = self.attrCols[col]["inputField"]
+
+ an_props = self.vnet_mgr.GetAnalysisProperties()
+
+ used_cols = []
+ attrCols = an_props["cmdParams"]["cols"]
+
+
+ for col in attrCols.iterkeys():
+
+ if "inputField" in attrCols[col]:
+ colInptF = attrCols[col]["inputField"]
else:
colInptF = col
@@ -1383,690 +921,214 @@
continue
inputPanel = self.inputData[colInptF].GetParent()
- if col in self.vnetParams[self.currAnModule]["cmdParams"]["cols"]:
- inputPanel.Show()
- inputPanel.FindWindowByName(colInptF).SetLabel(self.attrCols[col]["label"])
- inputPanel.Layout()
- if col != colInptF:
- skip.append(colInptF)
- else:
- self.inputData[colInptF].GetParent().Hide()
- self.Layout()
+ inputPanel.Show()
+ inputPanel.FindWindowByName(colInptF).SetLabel(attrCols[col]["label"])
- # if module has only one category -> hide type column in points list otherwise show it
- if len(self.vnetParams[self.currAnModule]["cmdParams"]["cats"]) > 1:
- if not self.list.IsShown('type'):
- self.list.ShowColumn('type', 1)
+ if col != colInptF:
+ skip.append(colInptF)
+ used_cols.append(colInptF)
- currParamsCats = self.vnetParams[self.currAnModule]["cmdParams"]["cats"]
- self.list.AdaptPointsList(currParamsCats)
- else:
- if self.list.IsShown('type'):
- self.list.HideColumn('type')
+ for col in ["abcolumn", "afcolumn", "ncolumn"]:
+ if col not in used_cols:
+ inputPanel = self.inputData[colInptF].GetParent()
+ inputPanel.Hide()
- # for v.net.path just one 'Start point' and one 'End point' can be checked
- if self.currAnModule == "v.net.path":
- self.list.UpdateCheckedItems(index = None)
+ self.Layout()
- def OnSnapping(self, event):
+ def Snapping(self, evt):
"""!Start/stop snapping mode"""
- ptListToolbar = self.toolbars['pointsList']
- if not haveCtypes:
+ if evt == "deactivated":
+ self.stBar.RemoveStatusItem(key = 'snap')
+ ptListToolbar = self.toolbars['pointsList']
ptListToolbar.ToggleTool(id = ptListToolbar.GetToolId("snapping"),
toggle = False)
- GMessage(parent = self,
- message = _("Unable to use ctypes. \n") + \
- _("Snapping mode can not be activated."))
- return
- if not event or not event.IsChecked():
- if not event:
- ptListToolbar.ToggleTool(id = ptListToolbar.GetToolId("snapping"),
- toggle = False)
- if self.tmpMaps.HasTmpVectMap("vnet_snap_points"):
- self.snapPts.DeleteRenderLayer()
-
- up_map_evt = gUpdateMap(render = False, renderVector = False)
- wx.PostEvent(self.mapWin, up_map_evt)
-
- if self.snapData.has_key('cmdThread'):
- self.snapData['cmdThread'].abort()
-
- self.snapData['snap_mode'] = False
- return
-
- if not self.InputsErrorMsgs(msg = _("Snapping mode can not be activated."),
- inpToTest = ["input", "nlayer"]):
-
- ptListToolbar.ToggleTool(id = ptListToolbar.GetToolId("snapping"),
- toggle = False)
- return
-
- if not self.tmpMaps.HasTmpVectMap("vnet_snap_points"):
- endStr = _("Do you really want to activate snapping and overwrite it?")
- self.snapPts = self.tmpMaps.AddTmpVectMap("vnet_snap_points", endStr)
-
- if not self.snapPts:
- ptListToolbar.ToggleTool(id = ptListToolbar.GetToolId("snapping"),
- toggle = False)
- return
- elif self.snapPts.VectMapState() == 0:
- dlg = wx.MessageDialog(parent = self.parent,
- message = _("Temporary map '%s' was changed outside " +
- "vector analysis tool.\n"
- "Do you really want to activate " +
- "snapping and overwrite it? ") % \
- self.snapPts.GetVectMapName(),
- caption = _("Overwrite map"),
- style = wx.YES_NO | wx.NO_DEFAULT |
- wx.ICON_QUESTION | wx.CENTRE)
-
- ret = dlg.ShowModal()
- dlg.Destroy()
-
- if ret == wx.ID_NO:
- self.tmpMaps.DeleteTmpMap(self.snapPts)
- ptListToolbar.ToggleTool(id = ptListToolbar.GetToolId("snapping"),
- toggle = False)
- return
-
- self.snapData['snap_mode'] = True
-
- inpName = self.inputData['input'].GetValue()
- inpName, mapSet = self._parseMapStr(inpName)
- inpFullName = inpName + '@' + mapSet
- computeNodes = True
-
- if not self.snapData.has_key("inputMap"):
- pass
- elif inpFullName != self.snapData["inputMap"].GetVectMapName():
- self.snapData["inputMap"] = VectMap(self, inpFullName)
- elif self.snapData["inputMapNlayer"] == self.inputData["nlayer"].GetValue():
- if self.snapData["inputMap"].VectMapState() == 1:
- computeNodes = False
-
- # new map need
- if computeNodes:
+ elif evt == "computing_points":
self.stBar.AddStatusItem(text = _('Computing nodes...'),
key = 'snap',
priority = self.stPriorities['important'])
- if not self.snapData.has_key('cmdThread'):
- self.snapData['cmdThread'] = CmdThread(self)
- cmd = ["v.to.points", "input=" + self.inputData['input'].GetValue(),
- "output=" + self.snapPts.GetVectMapName(),
- "llayer=" + self.inputData["nlayer"].GetValue(),
- "-n", "--overwrite"]
- # process GRASS command with argument
- self.snapData["inputMap"] = VectMap(self, inpFullName)
- self.snapData["inputMap"].SaveVectMapState()
+ elif evt == "computing_points_done":
+ self.stBar.RemoveStatusItem(key = 'snap')
- self.Bind(EVT_CMD_DONE, self._onToPointsDone)
- self.snapData['cmdThread'].RunCmd(cmd)
-
- self.snapData["inputMapNlayer"] = self.inputData["nlayer"].GetValue()
- # map is already created and up to date for input data
- else:
- self.snapPts.AddRenderLayer()
-
- up_map_evt = gUpdateMap(render = True, renderVector = True)
- wx.PostEvent(self.mapWin, up_map_evt)
-
- def _onToPointsDone(self, event):
+ def SnapPointsDone(self):
"""!Update map window, when map with nodes to snap is created"""
self.stBar.RemoveStatusItem(key = 'snap')
- if not event.aborted:
- self.snapPts.SaveVectMapState()
- self.snapPts.AddRenderLayer()
- up_map_evt = gUpdateMap(render = True, renderVector = True)
- wx.PostEvent(self.mapWin, up_map_evt)
-
def OnUndo(self, event):
"""!Step back in history"""
- histStepData = self.history.GetPrev()
- self.toolbars['mainToolbar'].UpdateUndoRedo()
- if histStepData:
- self._updateHistStepData(histStepData)
+ curr_step, steps_num = self.vnet_mgr.Undo()
+ self._updateDialog()
+ self.toolbars['mainToolbar'].UpdateUndoRedo(curr_step, steps_num)
def OnRedo(self, event):
"""!Step forward in history"""
- histStepData = self.history.GetNext()
- self.toolbars['mainToolbar'].UpdateUndoRedo()
- if histStepData:
- self._updateHistStepData(histStepData)
+ curr_step, steps_num = self.vnet_mgr.Redo()
+ self._updateDialog()
+ self.toolbars['mainToolbar'].UpdateUndoRedo(curr_step, steps_num)
- def _saveAnInputToHist(self):
- """!Save all data needed for analysis into history buffer"""
- pts = self.pointsToDraw.GetAllItems()
+ def _updateDialog(self):
+ params, err_params, flags = self.vnet_mgr.GetParams()
+ self._updateParamsTab(params, flags)
- for iPt, pt in enumerate(pts):
- ptName = "pt" + str(iPt)
+ anChoice = self.toolbars['analysisToolbar'].anChoice
+ anChoice.SetSelection(self.vnet_mgr.GetAnalyses().index(params["analysis"]))
+ self.currAnModule = params["analysis"]
+ self.resultDbMgrData['analysis'] = params["analysis"]
- coords = pt.GetCoords()
- self.history.Add(key = "points",
- subkey = [ptName, "coords"],
- value = coords)
- # save type column
- # if is shown
- if len(self.vnetParams[self.currAnModule]["cmdParams"]["cats"]) > 1:
- cat = self.list.GetCellSelIdx(iPt, 'type')
- self.history.Add(key = "points",
- subkey = [ptName, "catIdx"],
- value = cat)
- # if is hidden
- else:
- self.history.Add(key = 'points_hidden_cols',
- subkey = 'type',
- value = self.list.GetHiddenColSelIdxs('type'))
+ # set analysis combobox
+ anChoice = self.toolbars['analysisToolbar'].anChoice
+ anChoice.SetSelection(self.vnet_mgr.GetAnalyses().index(params["analysis"]))
- topology = self.list.GetCellValue(iPt, 'topology')
- self.history.Add(key = "points",
- subkey = [ptName, "topology"],
- value = topology)
+ self._updateResultDbMgrPage()
+ self._updateDbMgrData()
+ self.OnAnalysisChanged(None)
- self.history.Add(key = "points",
- subkey = [ptName, "checked"],
- value = self.list.IsChecked(iPt))
+class PtsList(PointsList):
+ def __init__(self, parent, vnet_mgr, id=wx.ID_ANY):
+ """! List with points for analysis"""
+ self.updateMap = True
+ self.vnet_mgr = vnet_mgr
+ self.pts_data = self.vnet_mgr.GetPointsManager()
- for inpName, inp in self.inputData.iteritems():
+ pts_data_cols = self.pts_data.GetColumns(only_relevant = False)
- if inpName == "input":
- vectMapName, mapSet = self._parseMapStr(inp.GetValue())
- inpMapFullName = vectMapName + '@' + mapSet
- inpMap = VectMap(self, inpMapFullName)
- self.history.Add(key = "other",
- subkey = "input_modified",
- value = inpMap.GetLastModified())
- inpVal = inpMapFullName
- else:
- inpVal = inp.GetValue()
-
- self.history.Add(key = "input_data",
- subkey = inpName,
- value = inpVal)
-
- self.history.Add(key = "vnet_modules",
- subkey = "curr_module",
- value = self.currAnModule)
+ cols = []
+ for i_col, name in enumerate(pts_data_cols["name"]):
+ if i_col == 0:
+ continue
+ cols.append([name, pts_data_cols["label"][i_col],
+ pts_data_cols["type"][i_col], pts_data_cols["def_vals"][i_col]])
- for settName, sett in self.anSettings.iteritems():
- self.history.Add(key = "an_settings",
- subkey = settName,
- value = sett.GetValue())
+ PointsList.__init__(self, parent = parent, cols = cols, id = id)
+ self.vnet_mgr.pointsChanged.connect(self.PointsChanged)
+ self.vnet_mgr.parametersChanged.connect(self.ParametersChanged)
- def _saveHistStep(self):
- """!Save new step into history"""
- removedHistData = self.history.SaveHistStep()
- self.toolbars['mainToolbar'].UpdateUndoRedo()
+ analysis, valid = self.vnet_mgr.GetParam("analysis")
- if not removedHistData:
- return
+ self.AnalysisChanged(analysis)
- # delete temporary maps in history steps which were deleted
- for removedStep in removedHistData.itervalues():
- mapsNames = removedStep["tmp_data"]["maps"]
- for vectMapName in mapsNames:
- tmpMap = self.tmpMaps.GetTmpVectMap(vectMapName)
- self.tmpMaps.DeleteTmpMap(tmpMap)
+ for iPt in range(self.pts_data.GetPointsCount()):
+ self.AddItem()
+ pt_dt = self.pts_data.GetPointData(iPt)
+ self.SetData(iPt, pt_dt)
+ self.Select(self.pts_data.GetSelected())
- def _updateHistStepData(self, histStepData):
- """!Updates dialog according to chosen history step"""
+ def AnalysisChanged(self, analysis):
+ active_cols = self.pts_data.GetColumns()
+ if 'type' in active_cols["name"]:
+ if not self.IsShown('type'):
+ self.ShowColumn('type', 1)
- # set analysis module
- self.currAnModule = histStepData["vnet_modules"]["curr_module"]
+ type_idx = active_cols["name"].index("type")
+ type_labels = active_cols["type"][type_idx]
- # optimization -map is not re-rendered when change in points list is done
- self.list.SetUpdateMap(updateMap = False)
+ self.ChangeColEditable('type', type_labels)
+ colNum = self._getColumnNum('type')
- # delete points list items
- while self.list.GetSelected() != wx.NOT_FOUND:
- self.list.DeleteItem()
+ for iItem, item in enumerate(self.itemDataMap):
+ self.EditCellKey(iItem, 'type', self.selIdxs[iItem][colNum])
- # show/hide 'type' column according to particular analysis
- if len(self.vnetParams[self.currAnModule]["cmdParams"]["cats"]) > 1:
- hasType = True
- self.list.ShowColumn('type', 1)
- else:
- hasType = False
- self.list.HideColumn('type')
+ if not item[1]:
+ self.CheckItem(iItem, False)
- # add points to list
- for iPt in range(len(histStepData["points"])):
- ptData = histStepData["points"]["pt" + str(iPt)]
- coords = ptData["coords"]
- self.list.AddItem()
- item = self.pointsToDraw.GetItem(iPt)
- item.SetCoords(coords)
-
- if hasType:
- self.list.EditCellKey(iPt, 'type', int(ptData["catIdx"]))
-
- self.list.EditCellKey(iPt, 'topology', ptData["topology"])
-
- if ptData["checked"]:
- self.list.CheckItem(iPt, True)
-
- if hasType:
- currParamsCats = self.vnetParams[self.currAnModule]["cmdParams"]["cats"]
- self.list.AdaptPointsList(currParamsCats)
else:
- self.list.SetHiddenSelIdxs('type', histStepData["points_hidden_cols"]["type"])
+ if self.IsShown('type'):
+ self.HideColumn('type')
- # set analysis combobox
- anChoice = self.toolbars['analysisToolbar'].anChoice
- anChoice.SetSelection(self.vnetModulesOrder.index(self.currAnModule))
+ def ParametersChanged(self, method, kwargs):
+ if "analysis" in kwargs["changed_params"].keys():
+ self.AnalysisChanged(analysis = kwargs["changed_params"]["analysis"])
- # update analysis result maps
- mapsNames = histStepData["tmp_data"]["maps"]
- for vectMapName in mapsNames:
- if "vnet_tmp_result" in vectMapName:
- self.tmp_result.DeleteRenderLayer()
- self.tmp_result = self.tmpMaps.GetTmpVectMap(vectMapName)
- self._checkResultMapChanged(self.tmp_result)
+ def OnItemActivated(self, event):
+ changed, key = PointsList.OnItemActivated(self, event)
+
+ if not changed:
+ return
- cmd = self.GetLayerStyle()
- self.tmp_result.AddRenderLayer(cmd)
+ dt_dict = {}
+ active_cols = self.pts_data.GetColumns()
+ for col in active_cols["name"]:
+ if col == "use":
+ continue
+ dt_dict[col] = self.GetCellValue(key, col)
- # update Parameters tab
- histInputData = histStepData["input_data"]
- for inpName, inp in histInputData.iteritems():
- self.inputData[inpName].SetValue(str(inp))
- if inpName == "input":
- inpMap = inp
+ self.pts_data.SetPointData(key, dt_dict)
- prevInpModTime = str(histStepData["other"]["input_modified"])
- currInpModTime = VectMap(self, inpMap).GetLastModified()
+ def PointsChanged(self, method, kwargs):
+ if method == "AddPoint":
+ self.AddItem()
- if currInpModTime.strip()!= prevInpModTime.strip():
- dlg = wx.MessageDialog(parent = self,
- message = _("Input map '%s' for analysis was changed outside " +
- "vector network analysis tool.\n" +
- "Topology column may not " +
- "correspond to changed situation.") %\
- inpMap,
- caption = _("Input changed outside"),
- style = wx.ICON_INFORMATION| wx.CENTRE)
- dlg.ShowModal()
- dlg.Destroy()
+ elif method == "DeletePoint":
+ self.DeleteItem()
- # update Points tab (analysis settings)
- histAnSettData = histStepData["an_settings"]
- for settName, sett in histAnSettData.iteritems():
- if settName == 'iso_lines':
- sett = str(sett)
- self.anSettings[settName].SetValue(sett)
+ elif method == "SetPointData":
+ self.SetData(kwargs["pt_id"], kwargs["data"])
- self.resultDbMgrData['analysis'] = self.currAnModule
- self._updateResultDbMgrPage()
- self._updateDbMgrData()
+ elif method == "SetPoints":
+ while self.GetSelected() != wx.NOT_FOUND:
+ self.DeleteItem()
- self.OnAnalysisChanged(None)
- self.list.SetUpdateMap(updateMap = True)
+ for iPt, pt_dt in enumerate(kwargs["pts_data"]):
+ self.AddItem()
+ self.SetData(iPt, pt_dt)
- up_map_evt = gUpdateMap(render = True, renderVector = True)
- wx.PostEvent(self.mapWin, up_map_evt)
-
- def _checkResultMapChanged(self, resultVectMap):
- """!Check if map was modified outside"""
- if resultVectMap.VectMapState() == 0:
- dlg = wx.MessageDialog(parent = self,
- message = _("Temporary map '%s' with result " +
- "was changed outside vector network analysis tool.\n" +
- "Showed result may not correspond " +
- "original analysis result.") %\
- resultVectMap.GetVectMapName(),
- caption = _("Result changed outside"),
- style = wx.ICON_INFORMATION| wx.CENTRE)
- dlg.ShowModal()
- dlg.Destroy()
+ elif method == "SetSelected":
+ self.Select(self._findIndex(kwargs["pt_id"]))
- def NewTmpVectMapToHist(self, prefMapName):
- """!Add new vector map, which will be saved into history step"""
+ def SetData(self, key, data):
- mapName = prefMapName + str(self.histTmpVectMapNum)
- self.histTmpVectMapNum += 1
-
- tmpMap = self._addTmpMapAnalysisMsg(mapName)
- if not tmpMap:
- return tmpMap
-
- self.tmpVectMapsToHist.append(tmpMap.GetVectMapName())
- self.history.Add(key = "tmp_data",
- subkey = "maps",
- value = self.tmpVectMapsToHist)
-
- return tmpMap
-
- def _addTmpMapAnalysisMsg(self, mapName):
- """!Wraped AddTmpVectMap"""
- msg = _("Temporary map %s already exists.\n" +
- "Do you want to continue in analysis and overwrite it?") \
- % (mapName +'@' + grass.gisenv()['MAPSET'])
- tmpMap = self.tmpMaps.AddTmpVectMap(mapName, msg)
- return tmpMap
-
-
- def _initVnetParams(self):
- """!Initializes parameters for different v.net.* modules """
-
- self.attrCols = {
- 'afcolumn' : {
- "label" : _("Arc forward/both direction(s) cost column:"),
- "name" : _("arc forward/both")
- },
- 'abcolumn' : {
- "label" : _("Arc backward direction cost column:"),
- "name" : _("arc backward")
- },
- 'acolumn' : {
- "label" : _("Arcs' cost column (for both directions):"),
- "name" : _("arc"),
- "inputField" : 'afcolumn',
- },
- 'ncolumn' : {
- "label" : _("Node cost column:"),
- "name" : _("node")
- }
- }
-
- self.vnetParams = {
- "v.net.path" : {
- "label" : _("Shortest path %s") % "(v.net.path)",
- "cmdParams" : {
- "cats" : [
- ["st_pt", _("Start point")],
- ["end_pt", _("End point")]
- ],
- "cols" : [
- 'afcolumn',
- 'abcolumn',
- 'ncolumn'
- ],
- },
- "resultProps" : {
- "singleColor" : None,
- "dbMgr" : True
- }
- },
-
- "v.net.salesman" : {
- "label" : _("Traveling salesman %s") % "(v.net.salesman)",
- "cmdParams" : {
- "cats" : [["ccats", None]],
- "cols" : [
- 'afcolumn',
- 'abcolumn'
- ],
- },
- "resultProps" : {
- "singleColor" : None,
- "dbMgr" : False
- }
- },
- "v.net.flow" : {
- "label" : _("Maximum flow %s") % "(v.net.flow)",
- "cmdParams" : {
- "cats" : [
- ["source_cats", _("Source point")],
- ["sink_cats", _("Sink point")]
- ],
- "cols" : [
- 'afcolumn',
- 'abcolumn',
- 'ncolumn'
- ]
- },
- "resultProps" : {
- "attrColColor": "flow",
- "dbMgr" : True
- }
- },
- "v.net.alloc" : {
- "label" : _("Subnets for nearest centers %s") % "(v.net.alloc)",
- "cmdParams" : {
- "cats" : [["ccats", None]],
- "cols" : [
- 'afcolumn',
- 'abcolumn',
- 'ncolumn'
- ]
- },
- "resultProps" : {
- "catColor" : None,
- "dbMgr" : False
- }
- },
- "v.net.steiner" : {
- "label" : _("Steiner tree for the network and given terminals %s") % "(v.net.steiner)",
- "cmdParams" : {
- "cats" : [["tcats", None]],
- "cols" : [
- 'acolumn',
- ]
- },
- "resultProps" : {
- "singleColor" : None,
- "dbMgr" : False
- }
- },
- "v.net.distance" : {
- "label" : _("Shortest distance via the network %s") % "(v.net.distance)",
- "cmdParams" : {
- "cats" : [
- ["from_cats", "From point"],
- ["to_cats", "To point"]
- ],
- "cols" : [
- 'afcolumn',
- 'abcolumn',
- 'ncolumn'
- ],
- },
- "resultProps" : {
- "catColor" : None,
- "dbMgr" : True
- }
- },
- "v.net.iso" : {
- "label" : _("Cost isolines %s") % "(v.net.iso)",
- "cmdParams" : {
- "cats" : [["ccats", None]],
- "cols" : [
- 'afcolumn',
- 'abcolumn',
- 'ncolumn'
- ]
- },
- "resultProps" : {
- "catColor" : None,
- "dbMgr" : False
- }
- }
- }
- # order in combobox for choose of analysis
- self.vnetModulesOrder = ["v.net.path",
- "v.net.salesman",
- "v.net.flow",
- "v.net.alloc",
- "v.net.distance",
- "v.net.iso",
- #"v.net.steiner"
- ]
- self.currAnModule = self.vnetModulesOrder[0]
-
- 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)
-
-
- 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 colors.iteritems():
- pen = self.pointsToDraw.GetPen(colKey)
- if pen:
- pen.SetColour(wx.Colour(col[0], col[1], col[2], 255))
- pen.SetWidth(ptWidth)
+ idx = self._findIndex(key)
+ for k, v in data.iteritems():
+ if k == "use":
+
+ if v and not self.IsChecked(idx):
+ self.CheckItem(idx, True)
+ elif not v and self.IsChecked(idx):
+ self.CheckItem(idx, False)
else:
- self.pointsToDraw.AddPen(colKey, wx.Pen(colour = wx.Colour(col[0], col[1], col[2], 255), width = ptWidth))
+ found = 0
+ for col in self.colsData:
+ if k == col[0]:
+ found = 1
+ break
-class PtsList(PointsList):
- def __init__(self, parent, dialog, cols, id=wx.ID_ANY):
- """! List with points for analysis"""
- self.updateMap = True
- self.dialog = dialog # VNETDialog class
+ if found:
+ self.EditCellKey(key, k, v)
- PointsList.__init__(self, parent = parent, cols = cols, id = id)
- def AddItem(self, event = None, updateMap = True):
- """!Append point to list"""
- self.dialog.pointsToDraw.AddItem(coords = [0,0])
-
- PointsList.AddItem(self, event)
-
- self.EditCellKey(key = self.selected ,
- colName = 'topology',
- cellData = _("new point"))
-
- def DeleteItem(self, event = None):
- """!Delete selected point in list"""
- key = self.GetItemData(self.selected)
- if self.selected != wx.NOT_FOUND:
- item = self.dialog.pointsToDraw.GetItem(key)
- self.dialog.pointsToDraw.DeleteItem(item)
-
- PointsList.DeleteItem(self, event)
-
def OnItemSelected(self, event):
"""!Item selected"""
PointsList.OnItemSelected(self, event)
+ self.selectedkey = self.GetItemData(self.selected)
- if self.updateMap:
- up_map_evt = gUpdateMap(render = False, renderVector = False)
- wx.PostEvent(self.dialog.mapWin, up_map_evt)
+ if self.selectedkey == self.pts_data.GetSelected():
+ return
- def AdaptPointsList(self, currParamsCats):
- """Rename category values when module is changed. Expample: Start point -> Sink point"""
- colValues = [""]
+ if self.selectedkey == wx.NOT_FOUND:
+ self.pts_data.SetSelected(None)
+ else:
+ self.pts_data.SetSelected(self.selectedkey)
- for ptCat in currParamsCats:
- colValues.append(ptCat[1])
- colNum = self._getColumnNum('type')
- self.ChangeColEditable('type', colValues)
-
- for iItem, item in enumerate(self.itemDataMap):
- self.EditCellKey(iItem, 'type', self.selIdxs[iItem][colNum])
-
- if not item[1]:
- self.CheckItem(iItem, False)
-
def OnCheckItem(self, index, flag):
- """!Item is checked/unchecked"""
- key = self.GetItemData(index)
- checkedVal = self.itemDataMap[key][1]
+ "flag is True if the item was checked, False if unchecked"
+ key = self.GetItemData(index)
+ if self.pts_data.GetPointData(key)["use"]!= flag:
+ self.pts_data.SetPointData(key, {"use" : flag})
- currModule = self.dialog.currAnModule #TODO public func
- cats = self.dialog.vnetParams[currModule]["cmdParams"]["cats"]
-
- if self.updateMap:
- up_map_evt = gUpdateMap(render = False, renderVector = False)
- wx.PostEvent(self.dialog.mapWin, up_map_evt)
-
- if len(cats) <= 1:
- return
-
- if checkedVal == "":
- self.CheckItem(key, False)
- return
-
- if currModule == "v.net.path" and flag:
- self.UpdateCheckedItems(index)
-
- def UpdateCheckedItems(self, index):
- """!For v.net.path - max. just one checked 'Start point' and 'End point'"""
- alreadyChecked = []
- colNum = self._getColumnNum('type')
- if colNum == -1:
- return
- if index:
- checkedKey = self.GetItemData(index)
- checkedVal = self.selIdxs[checkedKey][colNum]
- alreadyChecked.append(checkedVal)
- else:
- checkedKey = -1
-
- for iKey, idx in enumerate(self.selIdxs):
- index = self._findIndex(iKey)
- if (idx[colNum] in alreadyChecked and checkedKey != iKey) \
- or idx[colNum] == 0:
- self.CheckItem(index, False)
- elif self.IsChecked(index):
- alreadyChecked.append(idx[colNum])
-
- def SetUpdateMap(self, updateMap):
- """!Update/Not update map window when some change in list is made"""
- self.updateMap = updateMap
-
- def GetHiddenColSelIdxs(self, colName):
- """!Get indexes of chosen values in hidden 'type' column"""
- if self.hiddenCols.has_key(colName):
- return self.hiddenCols[colName]['selIdxs']
- return None
-
- def SetHiddenSelIdxs(self, colName, selIdxs):
- """!Set indexes of chosen values in hidden 'type' column and update text in it's cells"""
- if self.hiddenCols.has_key(colName):
- self.hiddenCols[colName]['selIdxs'] = map(int, selIdxs)
- self.hiddenCols[colName]['itemDataMap'] = []
- # update text in hidden column cells
- for idx in self.hiddenCols[colName]['selIdxs']:
- self.hiddenCols[colName]['itemDataMap'].append(self.hiddenCols[colName]['colsData'][2][idx])
- return True
- return False
-
class SettingsDialog(wx.Dialog):
- def __init__(self, parent, id, title, pos=wx.DefaultPosition, size=wx.DefaultSize,
+ def __init__(self, parent, id, title, vnet_mgr, pos=wx.DefaultPosition, size=wx.DefaultSize,
style=wx.DEFAULT_DIALOG_STYLE):
"""!Settings dialog"""
wx.Dialog.__init__(self, parent, id, title, pos, size, style)
+ self.vnet_mgr = vnet_mgr
+
maxValue = 1e8
self.parent = parent
self.settings = {}
@@ -2260,20 +1322,7 @@
UserSettings.Set(group = 'vnet', key = 'res_style', subkey = 'invert_colors',
value = self.settings['invert_colors'].IsChecked())
- self.parent.SetPointDrawSettings()
- if not self.parent.tmp_result or \
- not self.parent.tmpMaps.HasTmpVectMap(self.parent.tmp_result.GetVectMapName()):
- up_map_evt = gUpdateMap(render = False, renderVector = False)
- wx.PostEvent(self.parent.mapWin, up_map_evt)
- elif self.parent.tmp_result.GetRenderLayer():
- cmd = self.parent.GetLayerStyle()
- self.parent.tmp_result.AddRenderLayer(cmd)
-
- up_map_evt = gUpdateMap(render = True, renderVector = True)
- wx.PostEvent(self.parent.mapWin, up_map_evt)#TODO optimization
- else:
- up_map_evt = gUpdateMap(render = False, renderVector = False)
- wx.PostEvent(self.parent.mapWin, up_map_evt)
+ self.vnet_mgr.SettingsUpdated()
def OnApply(self, event):
"""!Button 'Apply' pressed"""
@@ -2284,7 +1333,147 @@
"""!Button 'Cancel' pressed"""
self.Close()
-class AddLayerDialog(wx.Dialog):
+class CreateTtbDialog(wx.Dialog):
+
+ def __init__(self, parent, init_data, id=wx.ID_ANY,
+ title = _("New vector map with turntable"), style=wx.DEFAULT_DIALOG_STYLE):
+ """!Create turntable dialog."""
+ wx.Dialog.__init__(self, parent, id, title = _(title), style = style)
+
+ label = {}
+ dataSelects = [
+ ['input', "Choose vector map for analysis:", Select],
+ ['output', "Name of vector map with turntable:", Select],
+ ['alayer', "Arc layer which will be expanded by turntable:", LayerSelect],
+ ['tlayer', "Layer with turntable:", LayerSelect],
+ ['tuclayer', "Layer with unique categories for turntable:", LayerSelect],
+ ]
+
+ self.inputData = {}
+
+ selPanels = {}
+
+ for dataSel in dataSelects:
+ selPanels[dataSel[0]] = wx.Panel(parent = self)
+ if dataSel[0] in ['input', 'output']:
+ self.inputData[dataSel[0]] = dataSel[2](parent = selPanels[dataSel[0]],
+ size = (-1, -1),
+ type = 'vector')
+ elif dataSel[0] != 'input':
+ self.inputData[dataSel[0]] = dataSel[2](parent = selPanels[dataSel[0]],
+ size = (-1, -1))
+
+ label[dataSel[0]] = wx.StaticText(parent = selPanels[dataSel[0]],
+ name = dataSel[0])
+ label[dataSel[0]].SetLabel(dataSel[1])
+
+ self.inputData['input'].Bind(wx.EVT_TEXT, lambda event : self.InputSel)
+
+ # buttons
+ self.btnCancel = wx.Button(self, wx.ID_CANCEL)
+ self.btnOk = wx.Button(self, wx.ID_OK)
+ self.btnOk.SetDefault()
+
+ # Layout
+ mainSizer = wx.BoxSizer(wx.VERTICAL)
+ box = wx.StaticBox(self, -1, "Vector map and layers for analysis")
+ bsizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+ mainSizer.Add(item = bsizer, proportion = 0,
+ flag = wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, border = 5)
+
+ btn = None
+ for sel in ['input', 'output', 'alayer', 'tlayer', 'tuclayer']:
+
+ selPanels[sel].SetSizer(self._doSelLayout(title = label[sel],
+ sel = self.inputData[sel],
+ btn = btn))
+ bsizer.Add(item = selPanels[sel], proportion = 0,
+ flag = wx.EXPAND)
+
+ for k, v in init_data.iteritems():
+ if self.inputData.has_key(k):
+ self.inputData[k].SetValue(v)
+
+ inp_vect_map = self.inputData["input"].GetValue().split("@")[0]
+ self.inputData['output'].SetValue(inp_vect_map + "_ttb")
+
+ btnSizer = wx.StdDialogButtonSizer()
+ btnSizer.AddButton(self.btnCancel)
+ btnSizer.AddButton(self.btnOk)
+ btnSizer.Realize()
+
+ mainSizer.Add(item = btnSizer, proportion = 0,
+ flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
+
+
+ self.SetSizer(mainSizer)
+ self.Fit()
+
+ def _doSelLayout(self, title, sel, btn = None):
+ # helper function for layout of self.inputData widgets initialized in _createParametersPage
+ selSizer = wx.BoxSizer(orient = wx.VERTICAL)
+
+ selTitleSizer = wx.BoxSizer(wx.HORIZONTAL)
+ selTitleSizer.Add(item = title, proportion = 1,
+ flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5)
+
+ selSizer.Add(item = selTitleSizer, proportion = 0,
+ flag = wx.EXPAND)
+
+ if btn:
+ selFiledSizer = wx.BoxSizer(orient = wx.HORIZONTAL)
+ selFiledSizer.Add(item = sel, proportion = 1,
+ flag = wx.EXPAND | wx.ALL)
+
+ selFiledSizer.Add(item = btn, proportion = 0,
+ flag = wx.EXPAND | wx.ALL)
+
+ selSizer.Add(item = selFiledSizer, proportion = 0,
+ flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL,
+ border = 5)
+ else:
+ selSizer.Add(item = sel, proportion = 1,
+ flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL,
+ border = 5)
+ return selSizer
+
+ def InputSel(self):
+ """!When vector map is selected it populates other comboboxes in Parameters tab (layer selects, columns selects)"""
+ vectMapName, mapSet = self._parseMapStr(self.inputData['input'].GetValue())
+ vectorMap = vectMapName + '@' + mapSet
+
+ for sel in ['alayer', 'tlayer', 'tuclayer']:
+ self.inputData[sel].Clear()
+ self.inputData[sel].InsertLayers(vector = vectorMap)
+
+ items = self.inputData['alayer'].GetItems()
+ itemsLen = len(items)
+ if itemsLen < 1:
+ self.addToTreeBtn.Disable()
+ if hasattr(self, 'inpDbMgrData'):
+ self._updateInputDbMgrPage(show = False)
+ self.inputData['alayer'].SetValue("")
+ return
+ elif itemsLen == 1:
+ self.inputData['alayer'].SetSelection(0)
+ elif itemsLen >= 1:
+ if unicode("1") in items:
+ iItem = items.index(unicode("1"))
+ self.inputData['alayer'].SetSelection(iItem)
+ self.addToTreeBtn.Enable()
+ if hasattr(self, 'inpDbMgrData'):
+ self._updateInputDbMgrPage(show = True)
+
+ def GetData(self):
+
+ params = {}
+ for param, sel in self.inputData.iteritems():
+ params[param] = sel.GetValue()
+
+ return params
+
+class OutputVectorDialog(wx.Dialog):
def __init__(self, parent,id=wx.ID_ANY,
title =_("Save analysis result"), style=wx.DEFAULT_DIALOG_STYLE):
"""!Save analysis result"""
@@ -2336,469 +1525,6 @@
self.panel.SetSizer(sizer)
sizer.Fit(self)
-class VnetTmpVectMaps:
- """!Class which creates, stores and destroys all tmp maps created during analysis"""
- def __init__(self, parent):
- self.tmpMaps = [] # temporary maps
- self.parent = parent
- self.mapWin = self.parent.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, 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',
- vect = 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',
- vect = 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, parent, fullName):
- self.fullName = fullName
- self.parent = parent
- self.renderLayer = None
- self.modifTime = None # time, for modification check
-
- def __del__(self):
-
- self.DeleteRenderLayer()
-
- def AddRenderLayer(self, cmd = None):
- """!Add map from map window layers to render """
- 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()
-
- self.renderLayer = self.parent.mapWin.Map.AddLayer(ltype = "vector", command = cmd,
- name = self.fullName, active = True,
- opacity = 1.0, render = True,
- pos = -1)
- return True
-
- def DeleteRenderLayer(self):
- """!Remove map from map window layers to render"""
- if self.renderLayer:
- self.parent.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)"""
- def __init__(self, parent):
-
- # 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):
- grass.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 type(subkey) == types.ListType:
- 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()
- grass.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 self.newHistStepData.keys():
- subkeys = self.newHistStepData[key].keys()
- newHist.write('%s%s' % (key, self.sep))
- for idx in range(len(subkeys)):
- value = self.newHistStepData[key][subkeys[idx]]
- if type(value) == types.DictType:
- if idx > 0:
- newHist.write('%s%s%s' % (os.linesep, key, self.sep))
- newHist.write('%s%s' % (subkeys[idx], self.sep))
- kvalues = 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 \
- type( self.newHistStepData[key][subkeys[idx - 1]]) == types.DictType:
- 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 \
- type(self.newHistStepData[key][subkeys[idx + 1]]) != types.DictType:
- 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 type(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 type(subkey) == types.ListType:
- 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 VnetStatusbar(wx.StatusBar):
"""!Extends wx.StatusBar class with functionality to show multiple messages with the highest priority"""
def __init__(self, parent, style, id = wx.ID_ANY, **kwargs):
@@ -2857,3 +1583,207 @@
if self.maxPriority < item['priority']:
self.maxPriority = item['priority']
self._updateStatus()
+
+class DefIntesectionTurnCostDialog(wx.Dialog):
+
+ def __init__(self, parent, mapWin, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, id = wx.ID_ANY, title = _("Edit intersection turns costs"), **kwargs):
+ wx.Dialog.__init__(self, parent, id, style=style, title = title, **kwargs)
+
+ self.dbMgr = DbMgrBase(mapdisplay = mapWin)
+ self.browsePage = self.dbMgr.CreateDbMgrPage(parent = self, pageName = 'browse')
+
+ def layout(self):
+ sizer = wx.BoxSizer(wx.VERTICAL)
+
+ sizer.Add(item = self.browsePage, proportion = 1,
+ flag = wx.EXPAND)
+
+ self.SetSizer(sizer)
+
+ def SetData(self, vectMapName, layer):
+ if vectMapName != self.dbMgr.GetVectorName():
+ self.dbMgr.ChangeVectorMap(vectorName = vectMapName)
+ else:
+ self.browsePage.DeleteAllPages()
+
+ self.browsePage.AddLayer(int(layer))
+ self.layer = int(layer)
+
+ # TODO HACK!!!
+ self.browsePage.FindWindowById(self.browsePage.layerPage[int(layer)]['sqlNtb']).GetParent().Hide()
+
+ def SetIntersection(self, isec):
+
+ self.browsePage.LoadData(self.layer, where = "isec = %d" % (isec))
+
+class DefGlobalTurnsDialog(wx.Dialog):
+ def __init__(self, parent, data, style= wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
+ id= wx.ID_ANY, title= _("Define Global Turn Costs"), **kwargs): # v Gassu dopln preklad
+
+ wx.Dialog.__init__(self, parent, id, title, style = style, **kwargs)
+
+ self.data = data
+
+ self.angle_list = TurnAnglesList(parent= self, data= self.data)
+
+ self.btnAdd = wx.Button(parent=self, id=wx.ID_ANY, label = "Add" )
+ self.btnRemove = wx.Button(parent=self, id=wx.ID_ANY, label = "Remove" )
+ self.btnClose = wx.Button(parent = self, id = wx.ID_CLOSE)
+ self.useUTurns = wx.CheckBox(parent = self, id = wx.ID_ANY, label = "Use U-turns")
+
+ self.btnAdd.Bind(wx.EVT_BUTTON, self.OnAddButtonClick)
+ self.btnRemove.Bind(wx.EVT_BUTTON, self.OnRemoveButtonClick)
+ self.btnClose.Bind(wx.EVT_BUTTON, self.OnCloseDialog)
+ self.useUTurns.Bind(wx.EVT_CHECKBOX, self.OnCheckedUTurns)
+
+ self.btnClose.SetDefault()
+ self.useUTurns.SetValue(True)
+ self.OnCheckedUTurns(None)
+ self.layout()
+ self.SetInitialSize((500, 200))
+
+
+
+ def layout(self):
+ sizer = wx.BoxSizer(wx.VERTICAL)
+ labelSizer = wx.BoxSizer(wx.HORIZONTAL)
+ addRemoveSizer = wx.BoxSizer(wx.VERTICAL)
+ closeSizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ addRemoveSizer.Add(item= self.btnAdd, proportion= 0, flag= wx.ALIGN_RIGHT, border = 10)
+ addRemoveSizer.Add(item= self.btnRemove, proportion= 0, flag= wx.ALIGN_RIGHT, border = 10)
+
+ labelSizer.Add(item= self.angle_list, proportion= 1, flag= wx.EXPAND, border = 10)
+ labelSizer.Add(item=addRemoveSizer, proportion = 0, flag = wx.ALIGN_RIGHT, border = 10)
+
+ closeSizer.Add(item=self.useUTurns, proportion = 1, flag = wx.ALIGN_LEFT, border = 10 )
+ closeSizer.Add(item=self.btnClose, proportion = 0, flag = wx.ALIGN_RIGHT, border = 10)
+
+ sizer.Add(item=labelSizer, proportion = 1, flag = wx.EXPAND)
+ sizer.Add(item=closeSizer, proportion = 0, flag = wx.EXPAND)
+
+ self.SetSizer(sizer)
+
+
+ def OnAddButtonClick(self, event):
+ """!Add new direction over selected row"""
+ selected_indices = self.angle_list.GetSelectedIndices()
+
+ if not selected_indices:
+ from_value = self.turn_data.GetValue(self.turn_data.GetLinesCount()-1,2)
+ to_value = self.turn_data.GetValue(0,1)
+ default_row = ["new", from_value, to_value, 0.0]
+ self.angle_list.AppendRow(default_row)
+
+ # If no row is selected, new direction is added to the end of table
+ i_addition = 0
+ for i in selected_indices:
+ i += i_addition
+ from_value = self.turn_data.GetValue(i-1,2)
+ to_value = self.turn_data.GetValue(i,1)
+ default_row = ["new", from_value, to_value, 0.0]
+ self.angle_list.InsertRow(i,default_row)
+ i_addition += 1
+
+
+ def OnRemoveButtonClick(self, event):
+ """!Delete one or more selected directions"""
+ selected_indices = self.angle_list.GetSelectedIndices()
+
+ i_reduction = 0
+ for i in selected_indices:
+ i -= i_reduction
+ self.angle_list.DeleteRow(i)
+ i_reduction += 1
+
+ def OnCloseDialog(self, event):
+ """!Close dialog"""
+ self.Close()
+
+ def OnCheckedUTurns(self, event):
+ """!Use U-turns in analyse"""
+ self.data.SetUTurns(self.useUTurns.GetValue())
+
+ def SetData(self, data):
+ self.angle_list.SetData(data)
+ self.data = data
+
+
+
+class TurnAnglesList(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.TextEditMixin):
+ """!Virtual editable table with global turns"""
+ def __init__(self, parent, data, id= wx.ID_ANY, style= wx.LC_REPORT | wx.LC_VIRTUAL, **kwargs):
+ wx.ListCtrl.__init__(self, parent, id,style= style, **kwargs)
+ listmix.ListCtrlAutoWidthMixin.__init__(self)
+ listmix.TextEditMixin.__init__(self)
+
+ self.Populate()
+ self.data = data
+ self.SetItemCount(self.data.GetLinesCount())
+
+
+ def Populate(self):
+ """!Columns definition"""
+ self.InsertColumn(col= 0, heading= "Direction", format= wx.LIST_FORMAT_LEFT) # v Gassu dopln preklad
+ self.InsertColumn(col= 1, heading= "From Angle", format= wx.LIST_FORMAT_RIGHT)
+ self.InsertColumn(col= 2, heading= "To Angle", format= wx.LIST_FORMAT_RIGHT)
+ self.InsertColumn(col= 3, heading= "Cost", format= wx.LIST_FORMAT_RIGHT)
+
+ def OnGetItemText(self, item, col):
+ val = self.data.GetValue(item, col)
+ if col in [1,2]:
+ val = RadiansToDegrees(val)
+ return str(val)
+
+ def SetVirtualData(self, row, column, text):
+ """!Set data to table"""
+ if column in [1,2,3]:
+ try:
+ text = float(text)
+ except:
+ return
+ if column in [1,2]:
+ text = DegreesToRadians(text)
+
+ # Tested allowed range of values
+ if text > math.pi:
+ text = 0.0
+ elif text < -math.pi:
+ text = 0.0
+
+ self.data.SetValue(text, row, column)
+
+ self.edited_row = row
+ self.RefreshItems(0,self.data.GetLinesCount()-1)
+
+
+ def AppendRow(self, values):
+ self.data.AppendRow(values)
+ self.SetItemCount(self.data.GetLinesCount())
+
+ def InsertRow(self, line, values):
+ self.data.InsertRow(line,values)
+ self.SetItemCount(self.data.GetLinesCount())
+
+ def DeleteRow(self, row):
+ self.data.PopRow(row)
+ self.SetItemCount(self.data.GetLinesCount())
+
+ def SetData(self, data):
+ self.data = data
+ self.SetItemCount(self.data.GetLinesCount())
+ self.RefreshItems(0, self.data.GetLinesCount()-1)
+
+
+ def GetSelectedIndices(self, state = wx.LIST_STATE_SELECTED):
+ """!Get numbers of selected rows"""
+ indices = []
+ lastFound = -1
+ while True:
+ index = self.GetNextItem(lastFound, wx.LIST_NEXT_ALL, state)
+ if index == -1:
+ break
+ else:
+ lastFound = index
+ indices.append(index)
+ return indices
\ No newline at end of file
Modified: grass/trunk/gui/wxpython/vnet/toolbars.py
===================================================================
--- grass/trunk/gui/wxpython/vnet/toolbars.py 2013-06-16 18:05:10 UTC (rev 56735)
+++ grass/trunk/gui/wxpython/vnet/toolbars.py 2013-06-16 21:36:51 UTC (rev 56736)
@@ -13,6 +13,8 @@
(>=v2). Read the file COPYING that comes with GRASS for details.
@author Stepan Turek <stepan.turek seznam.cz> (GSoC 2012, mentor: Martin Landa)
+ at author Lukas Bocan <silent_bob centrum.cz> (turn costs support)
+ at author Eliska Kyzlikova <eliska.kyzlikova gmail.com> (turn costs support)
"""
import wx
@@ -25,9 +27,13 @@
@param parent reference to VNETDialog
"""
- def __init__(self, parent, list):
+ def __init__(self, parent, dialog, vnet_mgr):
BaseToolbar.__init__(self, parent)
- self.list = list
+ self.vnet_mgr = vnet_mgr
+ self.vnet_pts_mgr = self.vnet_mgr.GetPointsManager()
+
+ self.dialog = dialog
+
self.InitToolbar(self._toolbarData())
# realize the toolbar
@@ -41,6 +47,10 @@
label = _('Insert points from Map Display')),
'snapping' : MetaIcon(img = 'move',
label = _('Activate snapping to nodes')),
+ 'isec_turn_edit' : MetaIcon(img = 'line-edit',
+ label = _('Activate mode for turns editing')),
+ 'global_turn_edit' : MetaIcon(img = 'vector-tools',
+ label = _('Activate mode for global turns editing')),
'pointAdd' : MetaIcon(img = 'point-create',
label = _('Add new point')),
'pointDelete' : MetaIcon(img = 'gcp-delete',
@@ -48,35 +58,45 @@
}
return self._getToolbarData((('insertPoint', icons['insertPoint'],
- self.list.dialog.OnInsertPoint,#TODO self.list.dialog
+ self.OnEditPointMode,#TODO self.list.dialog
wx.ITEM_CHECK),
('snapping', icons['snapping'],
- self.list.dialog.OnSnapping,
+ lambda event : self.vnet_mgr.Snapping(event.IsChecked()),
wx.ITEM_CHECK),
(None, ),
('pointAdd', icons["pointAdd"],
- self.list.AddItem),
+ lambda event : self.vnet_pts_mgr.AddPoint()),
('pointDelete', icons["pointDelete"],
- self.list.DeleteItem)))
+ self.OnDeletePoint),
+ (None, )#,
+ #('isec_turn_edit', icons['isec_turn_edit'],
+ #self.dialog.OnDefIsecTurnCosts,
+ #wx.ITEM_CHECK),
+ #('global_turn_edit', icons['global_turn_edit'],
+ #self.dialog.OnDefGlobalTurnCosts)
+ ))
def GetToolId(self, toolName): #TODO can be useful in base
-
return vars(self)[toolName]
+ def OnEditPointMode(self, event):
+ self.vnet_pts_mgr.EditPointMode(not self.vnet_pts_mgr.IsEditPointModeActive())
+
+ def OnDeletePoint(self, event):
+ pt_id = self.vnet_pts_mgr.GetSelected()
+ self.vnet_pts_mgr.DeletePoint(pt_id)
+
+
class MainToolbar(BaseToolbar):
"""!Main toolbar
"""
- def __init__(self, parent):
+ def __init__(self, parent, vnet_mgr):
BaseToolbar.__init__(self, parent)
self.InitToolbar(self._toolbarData())
- choices = []
+ self.vnet_mgr = vnet_mgr
- for moduleName in self.parent.vnetModulesOrder:
- choices.append(self.parent.vnetParams[moduleName]['label'])
-
- self.UpdateUndoRedo()
# realize the toolbar
self.Realize()
@@ -121,18 +141,18 @@
))
- def UpdateUndoRedo(self):
+ def UpdateUndoRedo(self, curr_step, steps_num):
id = vars(self)['showResult']
self.ToggleTool(id =id,
toggle = True)
- if self.parent.history.GetCurrHistStep() >= self.parent.history.GetStepsNum():
+ if curr_step >= steps_num:
self.Enable("undo", False)
else:
self.Enable("undo", True)
- if self.parent.history.GetCurrHistStep() <= 0:
+ if curr_step <= 0:
self.Enable("redo", False)
else:
self.Enable("redo", True)
@@ -144,15 +164,16 @@
class AnalysisToolbar(BaseToolbar):
"""!Main toolbar
"""
- def __init__(self, parent):
+ def __init__(self, parent, vnet_mgr):
BaseToolbar.__init__(self, parent)
+ self.vnet_mgr = vnet_mgr
self.InitToolbar(self._toolbarData())
choices = []
- for moduleName in self.parent.vnetModulesOrder:
- choices.append(self.parent.vnetParams[moduleName]['label'])
+ for moduleName in self.vnet_mgr.GetAnalyses():
+ choices.append(self.vnet_mgr.GetAnalysisProperties(moduleName)['label'])
self.anChoice = wx.ComboBox(parent = self, id = wx.ID_ANY,
choices = choices,
Added: grass/trunk/gui/wxpython/vnet/vnet_core.py
===================================================================
--- grass/trunk/gui/wxpython/vnet/vnet_core.py (rev 0)
+++ grass/trunk/gui/wxpython/vnet/vnet_core.py 2013-06-16 21:36:51 UTC (rev 56736)
@@ -0,0 +1,1120 @@
+"""!
+ at package vnet.vnet_core
+
+ at brief Vector network analysis logic.
+
+Classes:
+ - vnet_core::VNETManager
+ - vnet_core::VNETAnalyses
+ - vnet_core::VNETHistory
+ - vnet_core::SnappingNodes
+
+(C) 2013 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.
+
+ at author Stepan Turek <stepan.turek seznam.cz> (GSoC 2012, mentor: Martin Landa)
+ at author Lukas Bocan <silent_bob centrum.cz> (turn costs support)
+ at author Eliska Kyzlikova <eliska.kyzlikova gmail.com> (turn costs support)
+"""
+
+import os
+from grass.script import core as grass
+
+import wx
+
+from core import utils
+from core.gcmd import RunCommand, GMessage
+from core.events import gUpdateMap
+from core.gconsole import CmdThread, EVT_CMD_DONE, GConsole
+
+from gui_core.gselect import VectorDBInfo
+
+from vnet.vnet_data import VNETData, VNETTmpVectMaps, VectMap, History
+from vnet.vnet_utils import ParseMapStr, haveCtypes, GetNearestNodeCat
+
+from grass.pydispatch.signal import Signal
+
+class VNETManager:
+ def __init__(self, guiparent, giface):
+
+ self.data = {}
+
+ self.guiparent = guiparent
+ self.mapDisp = giface.GetMapDisplay()
+ self.mapWin = giface.GetMapWindow().GetMapWindow()
+
+ self.goutput = GConsole(guiparent = guiparent)
+
+ self.vnet_data = VNETData(guiparent = guiparent, mapWin = self.mapWin)
+
+ self.results = {"analysis" : None,
+ "vect_map" : None} #TODO more results
+
+ # this class instance manages all temporary vector maps created during life of VNETDialog
+ self.tmp_maps = VNETTmpVectMaps(parent = guiparent, mapWin = self.mapWin)
+
+ # initialization of History class used for saving and reading data from file
+ # it is used for browsing analysis results
+ self.history = VNETHistory(self.guiparent, self.vnet_data, self.tmp_maps)
+ self.analyses = VNETAnalyses(self.vnet_data, self.RunAnDone, self.goutput, self.tmp_maps)
+
+ # information, whether mouse event handler is registered in map window
+ self.handlerRegistered = False
+
+ self.snap_nodes = SnappingNodes(self.vnet_data, self.tmp_maps, self.mapWin)
+
+ self.ttbCreated = Signal('VNETManager.ttbCreated')
+ self.analysisDone = Signal('VNETManager.analysisDone')
+ self.pointsChanged = self.vnet_data.pointsChanged
+ self.parametersChanged = self.vnet_data.parametersChanged
+
+ self.snapping = self.snap_nodes.snapping
+ self.pointsChanged.connect(self.PointsChanged)
+
+
+ def __del__(self):
+ """!Removes temp layers, unregisters handlers and graphics"""
+ update = self.tmp_maps.DeleteAllTmpMaps()
+
+ if update:
+ up_map_evt = gUpdateMap(render = True, renderVector = True)
+ wx.PostEvent(self.mapWin, up_map_evt)
+ else:
+ up_map_evt = gUpdateMap(render = True, renderVector = True)
+ wx.PostEvent(self.mapWin, up_map_evt)
+
+ def GetPointsManager(self):
+ return self.vnet_data.GetPointsData()
+
+ def GetGlobalTurnsData(self):
+ return self.vnet_data.GetGlobalTurnsData()
+
+ def RunAnalysis(self):
+
+ analysis, valid = self.vnet_data.GetParam("analysis")
+
+ params, err_params, flags = self.vnet_data.GetParams()
+ relevant_params = self.vnet_data.GetRelevantParams(analysis)
+
+ if not relevant_params:
+ return -1
+
+ if not self.vnet_data.InputsErrorMsgs(_("Unable to perform analysis."),
+ analysis, params, flags, err_params, relevant_params):
+ return -2
+
+ if self.results["vect_map"]:
+ self.results["vect_map"].DeleteRenderLayer()
+
+ # history - delete data in buffer for hist step
+ self.history.DeleteNewHistStepData()
+
+ # create new map (included to history) for result of analysis
+ self.results["vect_map"] = self.history.NewTmpVectMapToHist('vnet_tmp_result')
+
+ if not self.results["vect_map"]:
+ return False
+
+ # for case there is some map with same name
+ # (when analysis does not produce any map, this map would have been shown as result)
+ RunCommand('g.remove',
+ vect = self.results["vect_map"].GetVectMapName())
+
+ # save data from
+ self.history._saveAnInputToHist(analysis, params, flags)
+
+ ret = self.analyses.RunAnalysis(self.results["vect_map"].GetVectMapName(), params, flags)
+ if not ret:
+ return -3
+ else:
+ return 1
+
+ def RunAnDone(self, cmd, returncode, results):
+
+ self.results["analysis"] = cmd[0]
+
+ self.results["vect_map"].SaveVectMapState()
+
+ cmd, cmd_colors = self.vnet_data.GetLayerStyle()
+ self.results["vect_map"].AddRenderLayer(cmd, cmd_colors)
+
+ self.history.SaveHistStep()
+
+ self.analysisDone.emit()
+
+ def ShowResult(self, show):
+ #TODO can be more results e. g. smallest cut
+
+ if show:
+ self._checkResultMapChanged(self.results["vect_map"])
+ cmd, cmd_colors = self.vnet_data.GetLayerStyle()
+ self.results["vect_map"].AddRenderLayer(cmd, cmd_colors)
+ else:
+ self.results["vect_map"].DeleteRenderLayer()
+
+ up_map_evt = gUpdateMap(render = True, renderVector = True)
+ wx.PostEvent(self.mapWin, up_map_evt)
+
+ def GetAnalysisProperties(self, analysis = None):
+ return self.vnet_data.GetAnalysisProperties(analysis = analysis)
+
+ def GetResults(self):
+ return self.results["vect_map"]
+
+ def Undo(self):
+ self._updateDataForHistStep(self.history.Undo())
+ #SetUpdateMap TODO
+ return self.history.GetHistStep()
+ def Redo(self):
+ self._updateDataForHistStep(self.history.Redo())
+ #SetUpdateMap
+ return self.history.GetHistStep()
+
+ def _updateDataForHistStep(self, data):
+ if not data:
+ return
+
+ analysis, resultMapName, params, flags = data
+
+ self.results["analysis"] = analysis
+ self.vnet_data.SetParams(params, flags)
+
+ self.results["vect_map"].DeleteRenderLayer()
+ self.results["vect_map"] = self.tmp_maps.GetTmpVectMap(resultMapName)
+ self._checkResultMapChanged(self.results["vect_map"])
+
+ cmd, cmd_colors = self.vnet_data.GetLayerStyle()
+ self.results["vect_map"].AddRenderLayer(cmd, cmd_colors)
+
+ up_map_evt = gUpdateMap(render = True, renderVector = True)
+ wx.PostEvent(self.mapWin, up_map_evt)
+
+ def GetHistStep(self):
+ return self.history.GetHistStep()
+
+ def SetParams(self, params, flags):
+ self.vnet_data.SetParams(params, flags)
+
+ def GetParams(self):
+ params, inv_params, flags = self.vnet_data.GetParams()
+ return params, inv_params, flags
+
+ def GetParam(self, param):
+ return self.vnet_data.GetParam(param)
+
+ def _checkResultMapChanged(self, resultVectMap):
+ """!Check if map was modified outside"""
+ if resultVectMap.VectMapState() == 0:
+ dlg = wx.MessageDialog(parent = self,
+ message = _("Temporary map '%s' with result " +
+ "was changed outside vector network analysis tool.\n" +
+ "Showed result may not correspond " +
+ "original analysis result.") %\
+ resultVectMap.GetVectMapName(),
+ caption = _("Result changed outside"),
+ style = wx.ICON_INFORMATION| wx.CENTRE)
+ dlg.ShowModal()
+ dlg.Destroy()
+
+ def IsSnappingActive(self):
+ return self.vnet_data.GetSnapping()
+
+ def Snapping(self, activate):
+ self.snap_nodes.ComputeNodes(activate)
+
+ def GetAnalyses(self):
+ return self.vnet_data.GetAnalyses()
+
+ def SettingsUpdated(self):
+ self.vnet_data.GetPointsData().SetPointDrawSettings()
+ if not self.results["vect_map"] or \
+ not self.tmp_maps.HasTmpVectMap(self.results["vect_map"].GetVectMapName()):
+ up_map_evt = gUpdateMap(render = False, renderVector = False)
+ wx.PostEvent(self.mapWin, up_map_evt)
+ elif self.results["vect_map"].GetRenderLayer():
+ cmd, cmd_colors = self.vnet_data.GetLayerStyle()
+ self.results["vect_map"].AddRenderLayer(cmd, cmd_colors)
+
+ up_map_evt = gUpdateMap(render = True, renderVector = True)
+ wx.PostEvent(self.mapWin, up_map_evt)#TODO optimization
+ else:
+ up_map_evt = gUpdateMap(render = False, renderVector = False)
+ wx.PostEvent(self.mapWin, up_map_evt)
+
+ def PointsChanged(self, method, kwargs):
+
+ up_map_evt = gUpdateMap(render = False, renderVector = False)
+ wx.PostEvent(self.mapWin, up_map_evt)
+
+ def CreateTttb(self, params):
+
+ outputMap = params["output"]
+ mapName, mapSet = ParseMapStr(outputMap)
+ if mapSet != grass.gisenv()['MAPSET']:
+ GMessage(parent = self,
+ message = _("Map can be created only in current mapset"))
+ return False
+ existsMap = grass.find_file(name = mapName,
+ element = 'vector',
+ mapset = grass.gisenv()['MAPSET'])
+ if existsMap["name"]:
+ dlg = wx.MessageDialog(parent = self.guiparent,
+ message = _("Vector map %s already exists. " +
+ "Do you want to overwrite it?") %
+ (existsMap["fullname"]),
+ caption = _("Overwrite vector map"),
+ style = wx.YES_NO | wx.NO_DEFAULT |
+ wx.ICON_QUESTION | wx.CENTRE)
+ ret = dlg.ShowModal()
+ dlg.Destroy()
+ if ret == wx.ID_NO:
+ return False
+
+ cmdTtb = [
+ "v.net.turntable",
+ "input=" + params["input"],
+ "output=" + params["output"],
+ "alayer=" + params["alayer"],
+ "tlayer=" + params["tlayer"],
+ "tuclayer=" + params["tuclayer"],
+ "--overwrite",
+ ]
+
+ self.goutput.RunCmd(command = cmdTtb, onDone = self._createTtbDone)
+
+ return True
+
+ def _createTtbDone(self, cmd, returncode):
+
+ if returncode != 0:
+ GMessage(parent = self.guiparent,
+ message = _("Creation of turntable failed."))
+ return
+ else:
+ params = {}
+ for c in cmd:
+ spl_c = c.split("=")
+ if len(spl_c) != 2:
+ continue
+
+ if spl_c[0] and spl_c != "input":
+ params[spl_c[0]] = spl_c[1]
+ if spl_c[0] == "output":
+ params["input"] = spl_c[1]
+
+ self.vnet_data.SetParams(params, {})
+
+ self.ttbCreated.emit(returncode = returncode)
+
+ def SaveTmpLayer(self, layer_name):
+ """!Permanently saves temporary map of analysis result"""
+ msg = _("Vector map with analysis result does not exist.")
+
+ if not hasattr(self.results["vect_map"], "GetVectMapName"):
+ GMessage(parent = self.guiparent,
+ message = msg)
+ return
+
+ mapToAdd = self.results["vect_map"].GetVectMapName()
+ mapToAddEx = grass.find_file(name = mapToAdd,
+ element = 'vector',
+ mapset = grass.gisenv()['MAPSET'])
+
+ if not mapToAddEx["name"]:
+ GMessage(parent = self.guiparent,
+ message = msg)
+ return
+
+ addedMap = layer_name
+ mapName, mapSet = ParseMapStr(addedMap)
+ if mapSet != grass.gisenv()['MAPSET']:
+ GMessage(parent = self.guiparent,
+ message = _("Map can be saved only to currently set mapset"))
+ return
+ existsMap = grass.find_file(name = mapName,
+ element = 'vector',
+ mapset = grass.gisenv()['MAPSET'])
+ if existsMap["name"]:
+ dlg = wx.MessageDialog(parent = self.guiparent,
+ message = _("Vector map %s already exists. " +
+ "Do you want to overwrite it?") %
+ (existsMap["fullname"]),
+ caption = _("Overwrite vector map"),
+ style = wx.YES_NO | wx.NO_DEFAULT |
+ wx.ICON_QUESTION | wx.CENTRE)
+ ret = dlg.ShowModal()
+ if ret == wx.ID_NO:
+ dlg.Destroy()
+ return
+ dlg.Destroy()
+
+ RunCommand("g.copy",
+ overwrite = True,
+ vect = [self.results["vect_map"].GetVectMapName(), mapName])
+
+
+ if not self.mapWin.tree:
+ return
+
+ if self.mapWin.tree.FindItemByData(key = 'name', value = mapName) is None:
+
+ cmd, cmd_colors = self.vnet_data.GetLayerStyle()#TODO get rid of insert
+ cmd.insert(0, 'd.vect')
+ cmd.append('map=%s' % mapName)
+
+ self.mapWin.tree.AddLayer(ltype = "vector",
+ lname = mapName,
+ lcmd = cmd,
+ lchecked = True)
+ if cmd_colors:
+ layerStyleVnetColors = utils.CmdToTuple(cmd_colors)
+
+ RunCommand(layerStyleVnetColors[0],
+ **layerStyleVnetColors[1])
+ else:
+ up_map_evt = gUpdateMap(render = True, renderVector = True)
+ wx.PostEvent(self.mapWin, up_map_evt)
+
+class VNETAnalyses:
+ def __init__(self, data, onAnDone, goutput, tmp_maps):
+ self.data = data
+
+ self.pts_data = self.data.GetPointsData()
+ self.tmp_maps = tmp_maps
+
+ self.onAnDone = onAnDone
+ self.goutput = goutput
+
+ def RunAnalysis(self, output, params, flags):
+ """!Perform network analysis"""
+
+ analysis, valid = self.data.GetParam("analysis")
+
+ catPts = self._getPtByCat(analysis)
+
+ if analysis == "v.net.path":
+ self._vnetPathRunAn(analysis, output, params, flags, catPts)
+ elif flags["t"]:
+ self._runTurnsAn(analysis, output, params, flags, catPts)
+ else:
+ self._runAn(analysis, output, params, flags, catPts)
+
+ def _vnetPathRunAn(self, analysis, output, params, flags, catPts):
+ """!Called when analysis is run for v.net.path module"""
+ if self.pts_data.GetPointsCount() < 1:
+ return False
+ cats = self.data.GetAnalysisProperties()["cmdParams"]["cats"]
+
+ # Creates part of cmd fro analysis
+ cmdParams = [analysis]
+ cmdParams.extend(self._setInputParams(analysis, params, flags))
+ cmdParams.append("output=" + output)
+
+ cmdPts = []
+ for cat in cats:
+ if len(catPts[cat[0]]) < 1:#TODO
+ GMessage(parent = self.guiparent,
+ message=_("Please choose '%s' and '%s' point.") % (cats[0][1], cats[1][1]))
+ return False
+ cmdPts.append(catPts[cat[0]][0])
+
+ resId = 1
+ inpPoints = str(resId) + " " + str(cmdPts[0][0]) + " " + str(cmdPts[0][1]) + \
+ " " + str(cmdPts[1][0]) + " " + str(cmdPts[1][1])
+
+ self.coordsTmpFile = grass.tempfile()
+ coordsTmpFileOpened = open(self.coordsTmpFile, 'w')
+ coordsTmpFileOpened.write(inpPoints)
+ coordsTmpFileOpened.close()
+
+ if flags["t"]:
+ cmdParams.append("-t")
+
+ self.tmpTurnAn = AddTmpMapAnalysisMsg("vnet_tunr_an_tmp", self.tmp_maps)
+ if not self.tmpTurnAn:
+ return False
+
+ mapName, mapSet = ParseMapStr(self.tmpTurnAn.GetVectMapName())
+ cmdCopy = [
+ "g.copy",
+ "vect=%s,%s" % (params["input"], mapName),
+ "--overwrite",
+ ]
+ cmdParams.append("input=" + self.tmpTurnAn.GetVectMapName())
+
+ ret, msg, err = RunCommand('g.copy',
+ getErrorMsg = True,
+ vect = "%s,%s" % (params['input'], mapName),
+ read = True,
+ overwrite = True)
+
+ self._updateTtbByGlobalCosts(self.tmpTurnAn.GetVectMapName(),
+ int(params["tlayer"]))
+
+ #self._prepareCmd(cmdCopy)
+ #self.goutput.RunCmd(command = cmdCopy)
+ else:
+ cmdParams.append("input=" + params["input"])
+
+ cmdParams.append("file=" + self.coordsTmpFile)
+
+ cmdParams.append("dmax=" + str(params["max_dist"]))
+
+ cmdParams.append("--overwrite")
+ self._prepareCmd(cmd = cmdParams)
+
+ if flags["t"]:
+ self.goutput.RunCmd(command = cmdParams, onDone = self._vnetPathRunTurnsAnDone)
+ else:
+ self.goutput.RunCmd(command = cmdParams, onDone = self._vnetPathRunAnDone)
+
+ def _vnetPathRunTurnsAnDone(self, cmd, returncode):
+ #TODO
+ #self.tmp_maps.DeleteTmpMap(self.tmpTurnAn)
+ self._vnetPathRunAnDone(cmd, returncode)
+
+ def _vnetPathRunAnDone(self, cmd, returncode):
+ """!Called when v.net.path analysis is done"""
+ grass.try_remove(self.coordsTmpFile)
+
+ self._onDone(cmd, returncode)
+
+ def _onDone(self, cmd, returncode):
+ for c in cmd:
+ if "output=" in c:
+ output = c.split("=")[1]
+ break
+
+ self.onAnDone(cmd, returncode, output)
+
+ def _runTurnsAn(self, analysis, output, params, flags, catPts):
+
+ # Creates part of cmd fro analysis
+ cmdParams = [analysis]
+ cmdParams.extend(self._setInputParams(analysis, params, flags))
+ cmdParams.append("output=" + output)
+
+ cats = {}
+ for cat_name, pts_coor in catPts.iteritems():
+
+ for coor in pts_coor:
+ cat_num = str(GetNearestNodeCat(e = coor[0],
+ n = coor[1],
+ field = int(params["tuclayer"],
+ tresh = params["max_dist"]),
+ vectMap = params["input"]))
+ if cat_num < 0:
+ continue
+ if cats.has_key(cat_name):
+ cats[cat_name].append(cat_num)
+ else:
+ cats[cat_name] = [cat_num]
+
+ for cat_name, cat_nums in cats.iteritems():
+ cmdParams.append(cat_name + "=" + ",".join(cat_nums))
+
+ self.tmpTurnAn = AddTmpMapAnalysisMsg("vnet_tunr_an_tmp", self.tmp_maps)
+ if not self.tmpTurnAn:
+ return False
+
+ # create and run commands which goes to analysis thread
+
+ mapName, mapSet = ParseMapStr(self.tmpTurnAn.GetVectMapName())
+ cmdCopy = [
+ "g.copy",
+ "vect=%s,%s" % (params['input'], mapName),
+ "--overwrite",
+ ]
+ cmdParams.append("input=" + self.tmpTurnAn.GetVectMapName())
+
+ ret, msg, err = RunCommand('g.copy',
+ getErrorMsg = True,
+ vect = "%s,%s" % (params['input'], mapName),
+ read = True,
+ overwrite = True)
+
+ self._updateTtbByGlobalCosts(self.tmpTurnAn.GetVectMapName(),
+ int(params["tlayer"]))
+
+
+ self._setCmdForSpecificAn(cmdParams)
+
+ cmdParams.append("-t")
+
+ self._prepareCmd(cmdParams)
+ self.goutput.RunCmd(command = cmdParams, onDone = self._runTurnsAnDone)
+
+ def _updateTtbByGlobalCosts(self, vectMapName, tlayer):
+ #TODO get layer number do not use it directly
+ intervals = self.turnsData["global"].GetData()
+
+ cmdUpdGlob = [
+ "v.db.update",
+ "map=", self.inputData["input"].GetValue(),
+ "layer=%d" % tlayer,
+ "column=cost",
+ ]
+
+ dbInfo = VectorDBInfo(vectMapName)
+ table = dbInfo.GetTable(tlayer)
+ driver, database = dbInfo.GetDbSettings(tlayer)
+
+
+ sqlFile = grass.tempfile()
+ sqlFile_f = open(sqlFile, 'w')
+
+ for ival in intervals:
+ from_angle = ival[0]
+ to_angle = ival[1]
+ cost = ival[2]
+
+ if to_angle < from_angle:
+ to_angle = math.pi * 2 + to_angle
+ #if angle < from_angle:
+ # angle = math.pi * 2 + angle
+
+ where = " WHERE (((angle < {0}) AND ({2} + angle >= {0} AND {2} + angle < {1})) OR \
+ ((angle >= {0}) AND (angle >= {0} AND angle < {1}))) AND cost==0.0 ".format(str(from_angle), str(to_angle), str(math.pi * 2))
+
+ stm = ("UPDATE %s SET cost=%f " % (table, cost)) + where + ";\n";
+ sqlFile_f.write(stm)
+
+ sqlFile_f.close()
+
+ #TODO imporve parser and run in thread
+
+
+ ret, msg, err = RunCommand('db.execute',
+ getErrorMsg = True,
+ input = sqlFile,
+ read = True,
+ driver = driver,
+ database = database)
+
+ grass.try_remove(sqlFile)
+
+ def _runTurnsAnDone(self, cmd, returncode):
+ """!Called when analysis is done"""
+ #self.tmp_maps.DeleteTmpMap(self.tmpTurnAn) #TODO remove earlier (OnDone lambda?)
+
+ self._onDone(cmd, returncode)
+
+
+ def _runAn(self, analysis, output, params, flags, catPts):
+ """!Called for all v.net.* analysis (except v.net.path)"""
+
+ # Creates part of cmd fro analysis
+ cmdParams = [analysis]
+ cmdParams.extend(self._setInputParams(analysis, params, flags))
+ cmdParams.append("output=" + output)
+
+ cats = self.data.GetAnalysisProperties()["cmdParams"]["cats"]
+
+ if len(cats) > 1:
+ for cat in cats:
+ if len(catPts[cat[0]]) < 1:
+ GMessage(parent = self,
+ message = _("Please choose '%s' and '%s' point.") \
+ % (cats[0][1], cats[1][1]))
+ return False
+ else:
+ for cat in cats:
+ if len(catPts[cat[0]]) < 2:
+ GMessage(parent = self,
+ message = _("Please choose at least two points."))
+ return False
+
+ # TODO add also to thread for analysis?
+ vcatResult = RunCommand("v.category",
+ input = params['input'],
+ option = "report",
+ flags = "g",
+ read = True)
+
+ vcatResult = vcatResult.splitlines()
+ for cat in vcatResult:#TODO
+ cat = cat.split()
+ if "all" in cat:
+ maxCat = int(cat[4])
+ break
+
+ layerNum = params["nlayer"]
+
+ pt_ascii, catsNums = self._getAsciiPts (catPts = catPts,
+ maxCat = maxCat,
+ layerNum = layerNum)
+
+ self.tmpPtsAsciiFile = grass.tempfile()#TODO better tmp files cleanup (make class for managing tmp files)
+ tmpPtsAsciiFileOpened = open(self.tmpPtsAsciiFile, 'w')
+ tmpPtsAsciiFileOpened.write(pt_ascii)
+ tmpPtsAsciiFileOpened.close()
+
+ self.tmpInPts = AddTmpMapAnalysisMsg("vnet_tmp_in_pts", self.tmp_maps)
+ if not self.tmpInPts:
+ return False
+
+ self.tmpInPtsConnected = AddTmpMapAnalysisMsg("vnet_tmp_in_pts_connected", self.tmp_maps)
+ if not self.tmpInPtsConnected:
+ return False
+
+ cmdParams.append("input=" + self.tmpInPtsConnected.GetVectMapName())
+ cmdParams.append("--overwrite")
+
+ self._setCmdForSpecificAn(cmdParams)
+
+ for catName, catNum in catsNums.iteritems():
+ if catNum[0] == catNum[1]:
+ cmdParams.append(catName + "=" + str(catNum[0]))
+ else:
+ cmdParams.append(catName + "=" + str(catNum[0]) + "-" + str(catNum[1]))
+
+ # create and run commands which goes to analysis thread
+ cmdVEdit = [
+ "v.edit",
+ "map=" + self.tmpInPts.GetVectMapName(),
+ "input=" + self.tmpPtsAsciiFile,
+ "tool=create",
+ "--overwrite",
+ "-n"
+ ]
+
+ self._prepareCmd(cmdVEdit)
+ self.goutput.RunCmd(command = cmdVEdit)
+
+ cmdVNet = [
+ "v.net",
+ "points=" + self.tmpInPts.GetVectMapName(),
+ "input=" + params['input'],
+ "output=" + self.tmpInPtsConnected.GetVectMapName(),
+ "alayer=" + params["alayer"],
+ "nlayer=" + params["nlayer"],
+ "operation=connect",
+ "thresh=" + str(params["max_dist"]),
+ "--overwrite"
+ ] #TODO snapping to nodes optimization
+
+ self._prepareCmd(cmdVNet)
+ self.goutput.RunCmd(command = cmdVNet)
+
+ self._prepareCmd(cmdParams)
+ self.goutput.RunCmd(command = cmdParams, onDone = self._runAnDone)
+
+ def _runAnDone(self, cmd, returncode):
+ """!Called when analysis is done"""
+ self.tmp_maps.DeleteTmpMap(self.tmpInPts) #TODO remove earlier (OnDone lambda?)
+ self.tmp_maps.DeleteTmpMap(self.tmpInPtsConnected)
+ grass.try_remove(self.tmpPtsAsciiFile)
+
+ if cmd[0] == "v.net.flow":
+ self.tmp_maps.DeleteTmpMap(self.vnetFlowTmpCut)
+
+ self._onDone(cmd, returncode)
+
+ def _setInputParams(self, analysis, params, flags):
+ """!Return list of chosen values (vector map, layers).
+
+ The list items are in form to be used in command for analysis e.g. 'alayer=1'.
+ """
+
+ inParams = []
+ for col, v in self.data.GetAnalysisProperties()["cmdParams"]["cols"].iteritems():
+
+ if "inputField" in v:
+ colInptF = v["inputField"]
+ else:
+ colInptF = col
+
+ inParams.append(col + '=' + params[colInptF])
+
+ for layer in ['alayer', 'nlayer', 'tlayer', 'tuclayer']:
+ if not flags["t"] and layer in ['tlayer', 'tuclayer']:
+ continue
+ # TODO
+ if flags["t"] and layer == 'nlayer':
+ inParams.append(layer + "=" + params['tuclayer'])
+ continue
+
+ inParams.append(layer + "=" + params[layer])
+
+ return inParams
+
+ def _getPtByCat(self, analysis):
+ """!Return points separated by theirs categories"""
+ anProps = self.data.GetAnalysisProperties()
+ cats = anProps["cmdParams"]["cats"]
+
+ ptByCats = {}
+ for cat in anProps["cmdParams"]["cats"]:
+ ptByCats[cat[0]] = []
+
+ for i in range(self.pts_data.GetPointsCount()):
+ pt_data = self.pts_data.GetPointData(i)
+ if pt_data["use"]:
+ for i_cat, cat in enumerate(cats):
+ #i_cat + 1 - we ave to increment it because pt_data["type"] includes "" in first place
+ if (i_cat + 1) == pt_data["type"] or len(ptByCats) == 1:
+ coords = (pt_data['e'], pt_data['n'])
+ ptByCats[cat[0]].append(coords)
+
+ return ptByCats
+
+ def _getAsciiPts (self, catPts, maxCat, layerNum):
+ """!Return points separated by categories in GRASS ASCII vector representation"""
+ catsNums = {}
+ pt_ascii = ""
+ catNum = maxCat
+
+ for catName, pts in catPts.iteritems():
+
+ catsNums[catName] = [catNum + 1]
+ for pt in pts:
+ catNum += 1
+ pt_ascii += "P 1 1\n"
+ pt_ascii += str(pt[0]) + " " + str(pt[1]) + "\n"
+ pt_ascii += str(layerNum) + " " + str(catNum) + "\n"
+
+ catsNums[catName].append(catNum)
+
+ return pt_ascii, catsNums
+
+ def _prepareCmd(self, cmd):
+ """!Helper function for preparation of cmd list into form for RunCmd method"""
+ for c in cmd[:]:
+ if c.find("=") == -1:
+ continue
+ v = c.split("=")
+ if len(v) != 2:
+ cmd.remove(c)
+ elif not v[1].strip():
+ cmd.remove(c)
+
+ def _setCmdForSpecificAn(self, cmdParams):
+ # append parameters needed for particular analysis
+ if cmdParams[0] == "v.net.distance":
+ cmdParams.append("from_layer=1")
+ cmdParams.append("to_layer=1")
+ elif cmdParams[0] == "v.net.flow":
+ #self.vnetFlowTmpCut = self.NewTmpVectMapToHist('vnet_tmp_flow_cut') TODO
+ self.vnetFlowTmpCut = AddTmpMapAnalysisMsg('vnet_tmp_flow_cut', self.tmp_maps)
+ if not self.vnetFlowTmpCut:
+ return
+ cmdParams.append("cut=" + self.vnetFlowTmpCut.GetVectMapName())
+ elif cmdParams[0] == "v.net.iso":
+ costs, valid = self.data.GetParam("iso_lines") #TODO valid
+ cmdParams.append("costs=" + costs)
+
+class VNETHistory():
+ def __init__(self, guiparent, data, tmp_maps):
+ self.history = History()
+ self.guiparent = guiparent
+
+ self.tmp_maps = tmp_maps
+
+ # variable, which appends unique number to every name of map, which is saved into history
+ self.histTmpVectMapNum = 0
+
+ self.data = data
+
+ def Undo(self):
+ """!Step back in history"""
+ histStepData = self.history.GetPrev()
+
+ if histStepData:
+ return self._updateHistStepData(histStepData)
+
+ return None
+
+ def Redo(self):
+ """!Step forward in history"""
+ histStepData = self.history.GetNext()
+
+ if histStepData:
+ return self._updateHistStepData(histStepData)
+
+ return None
+
+ def GetHistStep(self):
+ return self.history.GetCurrHistStep(), self.history.GetStepsNum()
+
+ def SaveHistStep(self):
+ """!Save new step into history"""
+ removedHistData = self.history.SaveHistStep()
+
+ if not removedHistData:
+ return
+
+ # delete temporary maps in history steps which were deleted
+ for removedStep in removedHistData.itervalues():
+ mapsNames = removedStep["tmp_data"]["maps"]
+ for vectMapName in mapsNames:
+ tmpMap = self.tmp_maps.GetTmpVectMap(vectMapName)
+ self.tmp_maps.DeleteTmpMap(tmpMap)
+
+ def DeleteNewHistStepData(self):
+ # history - delete data in buffer for hist step
+ self.history.DeleteNewHistStepData()
+ # empty list for maps to be saved to history
+ self.tmpVectMapsToHist= []
+
+ def _updateHistStepData(self, histStepData):
+ """!Updates dialog according to chosen history step"""
+ # set analysis module
+ analysis = histStepData["vnet_modules"]["curr_module"]
+ self.data.SetParams({"analysis" : analysis}, {})
+
+ pts = []
+ # add points to list
+ for iPt in range(len(histStepData["points"])):
+ ptDataHist = histStepData["points"]["pt" + str(iPt)]
+
+ e, n = ptDataHist["coords"]
+ pt_data = {"e" : e, "n" : n}
+
+ pt_data['type'] = int(ptDataHist["catIdx"])
+
+ pt_data['topology'] = ptDataHist["topology"]
+
+ pt_data['use'] = ptDataHist["checked"]
+
+ pts.append(pt_data)
+
+ self.data.GetPointsData().SetPoints(pts)
+
+ # update analysis result maps
+ mapsNames = histStepData["tmp_data"]["maps"]
+ for m in mapsNames:
+ if "vnet_tmp_result" in m:
+ resultMapName = m
+ break
+
+ # update parameters
+ params = {}
+ histInputData = histStepData["an_params"]
+ for inpName, inp in histInputData.iteritems():
+ params[inpName] = str(inp)
+ if inpName == "input":
+ inpMap = inp
+
+ prevInpModTime = str(histStepData["other"]["input_modified"])
+ currInpModTime = VectMap(None, inpMap).GetLastModified()
+
+ if currInpModTime.strip()!= prevInpModTime.strip():
+ dlg = wx.MessageDialog(parent = self.guiparent,
+ message = _("Input map '%s' for analysis was changed outside " +
+ "vector network analysis tool.\n" +
+ "Topology column may not " +
+ "correspond to changed situation.") %\
+ inpMap,
+ caption = _("Input changed outside"),
+ style = wx.ICON_INFORMATION| wx.CENTRE)
+ dlg.ShowModal()
+ dlg.Destroy()
+
+ #TODO
+ flags = {}
+ return analysis, resultMapName, params, flags
+
+ def _saveAnInputToHist(self, analysis, params, flags):
+ """!Save all data needed for analysis into history buffer"""
+ pts_num = self.data.GetPointsData().GetPointsCount()
+
+ for pt_id in range(pts_num):
+ data = self.data.GetPointsData().GetPointData(pt_id)
+
+ ptName = "pt" + str(pt_id)
+
+ coords = [data["e"], data["n"]]
+ self.history.Add(key = "points",
+ subkey = [ptName, "coords"],
+ value = coords)
+
+ self.history.Add(key = "points",
+ subkey = [ptName, "catIdx"],
+ value = data['type'])
+
+ self.history.Add(key = "points",
+ subkey = [ptName, "topology"],
+ value = data['topology'])
+
+
+ self.history.Add(key = "points",
+ subkey = [ptName, "checked"],
+ value = data["use"])
+
+ for param, value in params.iteritems():
+
+ if param == "input":
+ inpMap = VectMap(self, value)
+ self.history.Add(key = "other",
+ subkey = "input_modified",
+ value = inpMap.GetLastModified())
+ param_val = value
+ else:
+ param_val = value
+
+ self.history.Add(key = "an_params",
+ subkey = param,
+ value = param_val)
+
+ self.history.Add(key = "vnet_modules",
+ subkey = "curr_module",
+ value = analysis)
+
+
+ def NewTmpVectMapToHist(self, prefMapName):
+ """!Add new vector map, which will be saved into history step"""
+
+ mapName = prefMapName + str(self.histTmpVectMapNum)
+ self.histTmpVectMapNum += 1
+
+ tmpMap = AddTmpMapAnalysisMsg(mapName, self.tmp_maps)
+ if not tmpMap:
+ return tmpMap
+
+ self.tmpVectMapsToHist.append(tmpMap.GetVectMapName())
+ self.history.Add(key = "tmp_data",
+ subkey = "maps",
+ value = self.tmpVectMapsToHist)
+
+ return tmpMap
+
+def AddTmpMapAnalysisMsg(mapName, tmp_maps): #TODO
+ """!Wraped AddTmpVectMap"""
+ msg = _("Temporary map %s already exists.\n" +
+ "Do you want to continue in analysis and overwrite it?") \
+ % (mapName +'@' + grass.gisenv()['MAPSET'])
+ tmpMap = tmp_maps.AddTmpVectMap(mapName, msg)
+ return tmpMap
+
+
+class SnappingNodes(wx.EvtHandler):
+ def __init__(self, data, tmp_maps, mapWin):
+
+ self.data = data
+ self.tmp_maps = tmp_maps
+ self.mapWin = mapWin
+
+ wx.EvtHandler.__init__(self)
+ self.snapping= Signal('VNETManager.snapping')
+
+ # Stores all data related to snapping
+ self.snapData = {}
+
+ def ComputeNodes(self, activate):
+ """!Start/stop snapping mode"""
+
+ if not haveCtypes:
+ GMessage(parent = self,
+ message = _("Unable to use ctypes. \n") + \
+ _("Snapping mode can not be activated."))
+ return -1
+
+ if not activate:
+
+ if self.tmp_maps.HasTmpVectMap("vnet_snap_points"):
+ self.snapPts.DeleteRenderLayer()
+
+ up_map_evt = gUpdateMap(render = False, renderVector = False)
+ wx.PostEvent(self.mapWin, up_map_evt)
+
+ if self.snapData.has_key('cmdThread'):
+ self.snapData['cmdThread'].abort()
+
+ self.data.SetSnapping(False)
+
+ self.snapping.emit(evt = "deactivated")
+
+ return -1
+
+ self.data.SetSnapping(activate)
+
+ params, inv_params, flags = self.data.GetParams()
+ if not self.data.InputsErrorMsgs(msg = _("Snapping mode can not be activated."),
+ analysis = None,
+ params = params,
+ inv_params = inv_params,
+ flags = flags,
+ relevant_params = ["input", "nlayer"]):
+ return -1
+
+ if not self.tmp_maps.HasTmpVectMap("vnet_snap_points"):
+ endStr = _("Do you really want to activate snapping and overwrite it?")
+ self.snapPts = self.tmp_maps.AddTmpVectMap("vnet_snap_points", endStr)
+
+ if not self.snapPts:
+ return -1
+
+ elif self.snapPts.VectMapState() == 0:
+ dlg = wx.MessageDialog(parent = self.parent,
+ message = _("Temporary map '%s' was changed outside " +
+ "vector analysis tool.\n"
+ "Do you really want to activate " +
+ "snapping and overwrite it? ") % \
+ self.snapPts.GetVectMapName(),
+ caption = _("Overwrite map"),
+ style = wx.YES_NO | wx.NO_DEFAULT |
+ wx.ICON_QUESTION | wx.CENTRE)
+
+ ret = dlg.ShowModal()
+ dlg.Destroy()
+
+ if ret == wx.ID_NO:
+ self.tmp_maps.DeleteTmpMap(self.snapPts)
+ return -1
+
+ self.data.SetSnapping(True)
+
+ inpFullName = params["input"]
+ inpName, mapSet = inpFullName.split("@")
+ computeNodes = True
+
+ if not self.snapData.has_key("inputMap"):
+ pass
+ elif inpFullName != self.snapData["inputMap"].GetVectMapName():
+ self.snapData["inputMap"] = VectMap(None, inpFullName)
+ elif self.snapData["inputMap"].VectMapState() == 1:
+ computeNodes = False
+
+ # new map needed
+ if computeNodes:
+ if not self.snapData.has_key('cmdThread'):
+ self.snapData['cmdThread'] = CmdThread(self)
+ else:
+ self.snapData['cmdThread'].abort()
+
+ cmd = ["v.to.points", "input=" + params['input'],
+ "output=" + self.snapPts.GetVectMapName(),
+ "use=node", "--overwrite"]
+ # process GRASS command with argument
+ self.snapData["inputMap"] = VectMap(None, inpFullName)
+ self.snapData["inputMap"].SaveVectMapState()
+
+ self.Bind(EVT_CMD_DONE, self._onNodesDone)
+ self.snapData['cmdThread'].RunCmd(cmd)
+
+ self.snapping.emit(evt = "computing_points")
+
+ return 0
+ # map is already created and up to date for input data
+ else:
+ self.snapPts.AddRenderLayer()
+
+ up_map_evt = gUpdateMap(render = True, renderVector = True)
+ wx.PostEvent(self.mapWin, up_map_evt)
+
+ self.snapping.emit(evt = "computing_points_done")
+
+ return 1
+
+ def _onNodesDone(self, event):
+ """!Update map window, when map with nodes to snap is created"""
+ if not event.aborted:
+ self.snapPts.SaveVectMapState()
+ self.snapPts.AddRenderLayer()
+
+ up_map_evt = gUpdateMap(render = True, renderVector = True)
+ wx.PostEvent(self.mapWin, up_map_evt)
+
+ self.snapping.emit(evt = "computing_points_done")
Added: grass/trunk/gui/wxpython/vnet/vnet_data.py
===================================================================
--- grass/trunk/gui/wxpython/vnet/vnet_data.py (rev 0)
+++ grass/trunk/gui/wxpython/vnet/vnet_data.py 2013-06-16 21:36:51 UTC (rev 56736)
@@ -0,0 +1,1449 @@
+"""!
+ at package vnet.vnet_data
+
+ at 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 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.
+
+ at author Stepan Turek <stepan.turek seznam.cz> (GSoC 2012, mentor: Martin Landa)
+ at author Lukas Bocan <silent_bob centrum.cz> (turn costs support)
+ at author Eliska Kyzlikova <eliska.kyzlikova gmail.com> (turn costs support)
+"""
+import os
+import types
+from copy import deepcopy
+
+from grass.script import core as grass
+
+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 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 msg (str) - 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 "tlayer" 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 = ""
+ for layer, layerLabel in {'alayer' : _("arc layer"),
+ 'nlayer' : _("node layer"),
+ 'tlayer' : _("turntable layer"),
+ 'tuclayer' : _("unique categories layer")}.iteritems():
+
+ if layer in ["tlayer", "tuclayer"] 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 ["afcol", "abcol", "ncol"]:
+ if 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
+
+ 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'],
+ "type" : [None, [_(""), _("Start point"), _("End Point")], None, float, float],#TDO
+ "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.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):
+ self.pointsToDraw.DeleteItem(pt_id)
+ 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 data.iteritems():
+ if col == 'use':
+ continue
+
+ idx = self.cols["name"].index(col)
+ self.data[pt_id][idx] = v
+
+ if data.has_key('use'):
+ if self._usePoint(pt_id, data["use"]) == -1:
+ data["use"] = False
+ idx = self.cols["name"].index("use")
+ self.data[pt_id][idx] = v
+
+ 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 colors.iteritems():
+ 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 kwargs["changed_params"].keys():
+ self._updateTypeCol()
+
+ 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 pt_data.iteritems():
+ 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
+
+ type_idx = self.cols["name"].index("type")
+ use_idx = self.cols["name"].index("use")
+ checkedVal = self.data[pt_id][1]
+
+ 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:
+ alreadyChecked = []
+
+ if pt_id:
+ checkedKey = pt_id
+ alreadyChecked.append(self.data[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,
+ wx.StockCursor(wx.CURSOR_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")
+
+ if self.selected == len(self.data) - 1:
+ self.SetSelected(0)
+ else:
+ self.SetSelected(self.GetSelected() + 1)
+
+ self.SetPointData(self.selected,
+ {'topology' : msg,
+ 'e' : e,
+ 'n' : n})
+
+ self.pointsToDraw.GetItem(self.selected).SetCoords([e, n])
+
+ 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 cols_data.itervalues():
+ 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" : "",
+ "alayer" : "",
+ "nlayer" : "",
+ "afcolumn" : "",
+ "abcolumn" : "",
+ "ncolumn" : "",
+ "tlayer" : "",
+ "tuclayer" : "",
+ "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 params.iteritems():
+ if p == "analysis" and v not in self.an_props.used_an:
+ continue
+
+ if p == "input":
+ mapName, mapSet = ParseMapStr(v)
+ v = mapName + "@" + mapSet
+
+ if self.params.has_key(p):
+ if isinstance(v, str):
+ v = v.strip()
+
+ self.params[p] = v
+ changed_params[p] = v
+
+ changed_flags = {}
+ for p, v in flags.iteritems():
+ if self.flags.has_key(p):
+ 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", "alayer", "nlayer", "afcolumn",
+ "abcolumn", "ncolumn", "tlayer", "tuclayer"]:
+ 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 grass.list_grouped('vect').has_key(mapSet):
+ vectMaps = grass.list_grouped('vect')[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 ['alayer', 'nlayer', 'tlayer', 'tuclayer']:
+ if not layers or params[l] not in layers:
+ invParams.append(l)
+
+ dbInfo = VectorDBInfo(params["input"])
+
+ try:
+ table = dbInfo.GetTable(int(params["alayer"]))
+ columnchoices = dbInfo.GetTableDesc(table)
+ except (KeyError, ValueError):
+ table = None
+
+ # check costs columns
+ for col in ["afcolumn", "abcolumn", "ncolumn"]:
+ if col == "ncolumn":
+ try:
+ table = dbInfo.GetTable(int(params["nlayer"]))
+ columnchoices = dbInfo.GetTableDesc(table)
+ except (KeyError, ValueError):
+ table = None
+
+ if not table or not params[col] in columnchoices.keys():
+ invParams.append(col)
+ continue
+
+ if not columnchoices[col].value['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 = {
+ 'afcolumn' : {
+ "label" : _("Arc forward/both direction(s) cost column:"),
+ "name" : _("arc forward/both")
+ },
+ 'abcolumn' : {
+ "label" : _("Arc backward direction cost column:"),
+ "name" : _("arc backward")
+ },
+ 'acolumn' : {
+ "label" : _("Arcs' cost column (for both directions):"),
+ "name" : _("arc"),
+ "inputField" : 'afcolumn',
+ },
+ 'ncolumn' : {
+ "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" : [
+ 'afcolumn',
+ 'abcolumn',
+ 'ncolumn'
+ ],
+ },
+ "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" : [["ccats", None]],
+ "cols" : [
+ 'afcolumn',
+ 'abcolumn'
+ ],
+ },
+ "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" : [
+ 'afcolumn',
+ 'abcolumn',
+ 'ncolumn'
+ ]
+ },
+ "resultProps" : {
+ "attrColColor": "flow",
+ "dbMgr" : True
+ },
+ "turns_support" : False
+ },
+ "v.net.alloc" : {
+ "label" : _("Subnets for nearest centers %s") % "(v.net.alloc)",
+ "cmdParams" : {
+ "cats" : [["ccats", None]],
+ "cols" : [
+ 'afcolumn',
+ 'abcolumn',
+ 'ncolumn'
+ ]
+ },
+ "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" : [["tcats", 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" : [
+ 'afcolumn',
+ 'abcolumn',
+ 'ncolumn'
+ ],
+ },
+ "resultProps" : {
+ "catColor" : None,
+ "dbMgr" : True
+ },
+ "turns_support" : False
+ },
+ "v.net.iso" : {
+ "label" : _("Cost isolines %s") % "(v.net.iso)",
+ "cmdParams" : {
+ "cats" : [["ccats", None]],
+ "cols" : [
+ 'afcolumn',
+ 'abcolumn',
+ 'ncolumn'
+ ]
+ },
+ "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 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 self.vnetProperties.has_key(key)
+
+ def __getitem__(self, key):
+ return self.vnetProperties[key]
+
+ def GetRelevantParams(self, analysis):
+
+ if not self.vnetProperties.has_key(analysis):
+ return None
+
+ relevant_params = ["input", "alayer", "nlayer"]
+
+ if self.vnetProperties[analysis]["turns_support"]:
+ relevant_params += ["tlayer", "tuclayer"]
+
+ cols = self.vnetProperties[analysis]["cmdParams"]["cols"]
+
+ for col, v in cols.iteritems():
+ 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',
+ vect = 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',
+ vect = 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 = utils.CmdToTuple(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 = True,
+ 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):
+ grass.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 type(subkey) == types.ListType:
+ 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()
+ grass.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 self.newHistStepData.keys():
+ subkeys = self.newHistStepData[key].keys()
+ newHist.write('%s%s' % (key, self.sep))
+ for idx in range(len(subkeys)):
+ value = self.newHistStepData[key][subkeys[idx]]
+ if type(value) == types.DictType:
+ if idx > 0:
+ newHist.write('%s%s%s' % (os.linesep, key, self.sep))
+ newHist.write('%s%s' % (subkeys[idx], self.sep))
+ kvalues = 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 \
+ type( self.newHistStepData[key][subkeys[idx - 1]]) == types.DictType:
+ 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 \
+ type(self.newHistStepData[key][subkeys[idx + 1]]) != types.DictType:
+ 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 type(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 type(subkey) == types.ListType:
+ 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
\ No newline at end of file
Added: grass/trunk/gui/wxpython/vnet/vnet_utils.py
===================================================================
--- grass/trunk/gui/wxpython/vnet/vnet_utils.py (rev 0)
+++ grass/trunk/gui/wxpython/vnet/vnet_utils.py 2013-06-16 21:36:51 UTC (rev 56736)
@@ -0,0 +1,153 @@
+"""!
+ at package vnet.vnet_utils
+
+ at brief Vector network analysis utilities.
+
+Classes:
+ - vnet_core::VNETTmpVectMaps
+ - vnet_core::VectMap
+ - vnet_core::History
+
+(C) 2013 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.
+
+ at author Stepan Turek <stepan.turek seznam.cz> (GSoC 2012, mentor: Martin Landa)
+ at author Lukas Bocan <silent_bob centrum.cz> (turn costs support)
+ at author Eliska Kyzlikova <eliska.kyzlikova gmail.com> (turn costs support)
+"""
+
+import math
+from grass.script import core as grass
+
+try:
+ import grass.lib.vector as vectlib
+ from ctypes import pointer, byref, c_char_p, c_int, c_double, POINTER
+ haveCtypes = True
+except ImportError:
+ haveCtypes = False
+
+def ParseMapStr(mapStr):
+ """!Create full map name (add current mapset if it is not present in name)"""
+ mapValSpl = mapStr.strip().split("@")
+ if len(mapValSpl) > 1:
+ mapSet = mapValSpl[1]
+ else:
+ mapSet = grass.gisenv()['MAPSET']
+ mapName = mapValSpl[0]
+
+ return mapName, mapSet
+
+def DegreesToRadians(degrees):
+ return degrees * math.pi / 180
+
+def RadiansToDegrees(radians):
+ return radians * 180 / math.pi
+
+def SnapToNode(e, n, tresh, vectMap):
+ """!Find nearest node to click coordinates (within given threshold)"""
+ if not haveCtypes:
+ return None
+
+ vectMap, mapSet = ParseMapStr(vectMap)
+
+ openedMap = pointer(vectlib.Map_info())
+ ret = vectlib.Vect_open_old(openedMap,
+ c_char_p(vectMap),
+ c_char_p(mapSet))
+ if ret == 1:
+ vectlib.Vect_close(openedMap)
+ if ret != 2:
+ return None
+
+ nodeNum = vectlib.Vect_find_node(openedMap,
+ c_double(e),
+ c_double(n),
+ c_double(0),
+ c_double(tresh),
+ vectlib.WITHOUT_Z)
+
+ if nodeNum > 0:
+ e = c_double(0)
+ n = c_double(0)
+ vectlib.Vect_get_node_coor(openedMap,
+ nodeNum,
+ byref(e),
+ byref(n),
+ None); # z
+ e = e.value
+ n = n.value
+ else:
+ vectlib.Vect_close(openedMap)
+ return False
+
+ return e, n
+
+def GetNearestNodeCat(e, n, layer, tresh, vectMap):
+
+ if not haveCtypes:
+ return -2
+
+ vectMapName, mapSet = ParseMapStr(vectMap)
+
+ openedMap = pointer(vectlib.Map_info())
+ ret = vectlib.Vect_open_old(openedMap,
+ c_char_p(vectMapName),
+ c_char_p(mapSet))
+ if ret == 1:
+ vectlib.Vect_close(openedMap)
+ if ret != 2:
+ return -1
+
+ nodeNum = vectlib.Vect_find_node(openedMap,
+ c_double(e),
+ c_double(n),
+ c_double(0),
+ c_double(tresh),
+ vectlib.WITHOUT_Z)
+
+ if nodeNum > 0:
+ e = c_double(0)
+ n = c_double(0)
+ vectlib.Vect_get_node_coor(openedMap,
+ nodeNum,
+ byref(e),
+ byref(n),
+ None); # z
+ e = e.value
+ n = n.value
+ else:
+ vectlib.Vect_close(openedMap)
+ return -1
+
+ box = vectlib.bound_box();
+ List = POINTER(vectlib.boxlist);
+ List = vectlib.Vect_new_boxlist(c_int(0));
+
+ box.E = box.W = e;
+ box.N = box.S = n;
+ box.T = box.B = 0;
+ vectlib.Vect_select_lines_by_box(openedMap, byref(box), vectlib.GV_POINT, List);
+
+ found = 0;
+ dcost = 0;
+
+ Cats = POINTER(vectlib.line_cats)
+ Cats = vectlib.Vect_new_cats_struct()
+
+ cat = c_int(0)
+
+ for j in range(List.contents.n_values):
+ line = List.contents.id[j]
+ type = vectlib.Vect_read_line(openedMap, None, Cats, line)
+ if type != vectlib.GV_POINT:
+ continue
+
+ if vectlib.Vect_cat_get(Cats, c_int(layer), byref(cat)):
+ found = 1
+ break
+ if found:
+ return cat.value
+
+ return -1
\ No newline at end of file
Modified: grass/trunk/gui/wxpython/vnet/widgets.py
===================================================================
--- grass/trunk/gui/wxpython/vnet/widgets.py 2013-06-16 18:05:10 UTC (rev 56735)
+++ grass/trunk/gui/wxpython/vnet/widgets.py 2013-06-16 21:36:51 UTC (rev 56736)
@@ -146,7 +146,7 @@
info.SetText(col[1][iLabel])
self.InsertColumnInfo(col[0], info)
- def AddItem(self, event):
+ def AddItem(self):
"""!Appends an item to list with default values"""
iDefVal = self.dataTypes["itemDefaultValue"]
iColEd = self.dataTypes["colEditable"]
@@ -192,7 +192,14 @@
def GetCellValue(self, key, colName):
"""!Get value in cell of list using key (same regardless of sorting)"""
colNum = self._getColumnNum(colName)
- iColEd = self.dataTypes["colEditable"]
+
+ if colNum < 0:
+ return None
+
+ iColEd = self.dataTypes["colEditable"]
+ if self.selIdxs[key][colNum] != -1:
+ return self.selIdxs[key][colNum]
+
return self.itemDataMap[key][colNum]
def GetCellSelIdx(self, key, colName):
@@ -256,7 +263,7 @@
iColEd = self.dataTypes["colEditable"]
self.colsData[colNum][iColEd] = colType
- def DeleteItem(self, event = None):
+ def DeleteItem(self):
"""!Delete selected item in list"""
if self.selected == wx.NOT_FOUND:
return
@@ -373,7 +380,7 @@
self.selIdxs[key] = dlg.GetSelectionIndexes()
dlg.Destroy()
- return changed
+ return changed, key
def CreateEditDialog(self, data, pointNo):
"""!Helper function
More information about the grass-commit
mailing list