vnet_data.py 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455
  1. """!
  2. @package vnet.vnet_data
  3. @brief Vector network analysis classes for data managment.
  4. Classes:
  5. - vnet_data::VNETData
  6. - vnet_data::VNETPointsData
  7. - vnet_data::VNETAnalysisParameters
  8. - vnet_data::VNETAnalysesProperties
  9. - vnet_data::VNETTmpVectMaps
  10. - vnet_data::VectMap
  11. - vnet_data::History
  12. - vnet_data::VNETGlobalTurnsData
  13. (C) 2013 by the GRASS Development Team
  14. This program is free software under the GNU General Public License
  15. (>=v2). Read the file COPYING that comes with GRASS for details.
  16. @author Stepan Turek <stepan.turek seznam.cz> (GSoC 2012, mentor: Martin Landa)
  17. @author Lukas Bocan <silent_bob centrum.cz> (turn costs support)
  18. @author Eliska Kyzlikova <eliska.kyzlikova gmail.com> (turn costs support)
  19. """
  20. import os
  21. import types
  22. from copy import deepcopy
  23. from grass.script import core as grass
  24. import wx
  25. from core import utils
  26. from core.gcmd import RunCommand, GMessage
  27. from core.settings import UserSettings
  28. from vnet.vnet_utils import ParseMapStr, SnapToNode
  29. from gui_core.gselect import VectorDBInfo
  30. from grass.pydispatch.signal import Signal
  31. from vnet.vnet_utils import DegreesToRadians, RadiansToDegrees
  32. class VNETData:
  33. def __init__(self, guiparent, mapWin):
  34. # setting initialization
  35. self._initSettings()
  36. self.guiparent = guiparent
  37. self.an_props = VNETAnalysesProperties()
  38. self.an_params = VNETAnalysisParameters(self.an_props)
  39. self.an_points = VNETPointsData(mapWin, self.an_props, self.an_params)
  40. self.global_turns = VNETGlobalTurnsData()
  41. self.pointsChanged = self.an_points.pointsChanged
  42. self.parametersChanged = self.an_params.parametersChanged
  43. def CleanUp(self):
  44. self.an_points.CleanUp()
  45. def GetAnalyses(self):
  46. return self.an_props.used_an
  47. def GetPointsData(self):
  48. return self.an_points
  49. def GetGlobalTurnsData(self):
  50. return self.global_turns
  51. def GetRelevantParams(self, analysis = None):
  52. if analysis:
  53. return self.an_props.GetRelevantParams(analysis)
  54. else:
  55. analysis, valid = self.an_params.GetParam("analysis")
  56. return self.an_props.GetRelevantParams(analysis)
  57. def GetAnalysisProperties(self, analysis = None):
  58. if analysis:
  59. return self.an_props[analysis]
  60. else:
  61. analysis, valid = self.an_params.GetParam("analysis")
  62. return self.an_props[analysis]
  63. def GetParam(self, param):
  64. return self.an_params.GetParam(param)
  65. def GetParams(self):
  66. return self.an_params.GetParams()
  67. def SetParams(self, params, flags):
  68. return self.an_params.SetParams(params, flags)
  69. def SetSnapping(self, activate):
  70. self.an_points.SetSnapping(activate)
  71. def GetSnapping(self):
  72. return self.an_points.GetSnapping()
  73. def GetLayerStyle(self):
  74. """!Returns cmd for d.vect, with set style for analysis result"""
  75. analysis, valid = self.an_params.GetParam("analysis")
  76. resProps = self.an_props[analysis]["resultProps"]
  77. width = UserSettings.Get(group='vnet', key='res_style', subkey= "line_width")
  78. layerStyleCmd = ["layer=1",'width=' + str(width)]
  79. if "catColor" in resProps:
  80. layerStyleCmd.append('flags=c')
  81. elif "singleColor" in resProps:
  82. col = UserSettings.Get(group='vnet', key='res_style', subkey= "line_color")
  83. layerStyleCmd.append('color=' + str(col[0]) + ':' + str(col[1]) + ':' + str(col[2]))
  84. layerStyleVnetColors = []
  85. if "attrColColor" in resProps:
  86. colorStyle = UserSettings.Get(group='vnet', key='res_style', subkey= "color_table")
  87. invert = UserSettings.Get(group='vnet', key='res_style', subkey= "invert_colors")
  88. layerStyleVnetColors = [
  89. "v.colors",
  90. "color=" + colorStyle,
  91. "column=" + resProps["attrColColor"],
  92. ]
  93. if invert:
  94. layerStyleVnetColors.append("-n")
  95. return layerStyleCmd, layerStyleVnetColors
  96. def InputsErrorMsgs(self, msg, analysis, params, flags, inv_params, relevant_params):
  97. """!Checks input data in Parameters tab and shows messages if some value is not valid
  98. @param msg (str) - message added to start of message string
  99. @return True - if checked inputs are OK
  100. @return False - if some of checked inputs is not ok
  101. """
  102. if flags["t"] and "tlayer" not in relevant_params:
  103. GMessage(parent = self.guiparent, message = _("Module <%s> does not support turns costs." % analysis))
  104. return False
  105. errMapStr = ""
  106. if 'input' in inv_params:
  107. if params['input']:
  108. errMapStr = _("Vector map '%s' does not exist.") % (params['input'])
  109. else:
  110. errMapStr = _("Vector map was not chosen.")
  111. if errMapStr:
  112. GMessage(parent = self.guiparent,
  113. message = msg + "\n" + errMapStr)
  114. return False
  115. errLayerStr = ""
  116. for layer, layerLabel in {'alayer' : _("arc layer"),
  117. 'nlayer' : _("node layer"),
  118. 'tlayer' : _("turntable layer"),
  119. 'tuclayer' : _("unique categories layer")}.iteritems():
  120. if layer in ["tlayer", "tuclayer"] and not flags["t"]:
  121. continue
  122. if layer in inv_params:
  123. if params[layer]:
  124. errLayerStr += _("Chosen %s '%s' does not exist in vector map '%s'.\n") % \
  125. (layerLabel, params[layer], params['input'])
  126. else:
  127. errLayerStr += _("Choose existing %s.\n") % \
  128. (layerLabel)
  129. if errLayerStr:
  130. GMessage(parent = self.guiparent,
  131. message = msg + "\n" + errLayerStr)
  132. return False
  133. errColStr = ""
  134. for col in ["afcol", "abcol", "ncol"]:
  135. if col and col in inv_params and col in relevant_params:
  136. errColStr += _("Chosen column '%s' does not exist in attribute table of layer '%s' of vector map '%s'.\n") % \
  137. (params[col], params[layer], params['input'])
  138. if errColStr:
  139. GMessage(parent = self.guiparent,
  140. message = msg + "\n" + errColStr)
  141. return False
  142. return True
  143. def _initSettings(self):
  144. """!Initialization of settings (if not already defined)"""
  145. # initializes default settings
  146. initSettings = [
  147. ['res_style', 'line_width', 5],
  148. ['res_style', 'line_color', (192,0,0)],
  149. ['res_style', 'color_table', 'byr'],
  150. ['res_style', 'invert_colors', False],
  151. ['point_symbol', 'point_size', 10],
  152. ['point_symbol', 'point_width', 2],
  153. ['point_colors', "unused", (131,139,139)],
  154. ['point_colors', "used1cat", (192,0,0)],
  155. ['point_colors', "used2cat", (0,0,255)],
  156. ['point_colors', "selected", (9,249,17)],
  157. ['other', "snap_tresh", 10],
  158. ['other', "max_hist_steps", 5]
  159. ]
  160. for init in initSettings:
  161. UserSettings.ReadSettingsFile()
  162. UserSettings.Append(dict = UserSettings.userSettings,
  163. group ='vnet',
  164. key = init[0],
  165. subkey =init[1],
  166. value = init[2],
  167. overwrite = False)
  168. class VNETPointsData:
  169. def __init__(self, mapWin, an_data, an_params):
  170. self.mapWin = mapWin
  171. self.an_data = an_data
  172. self.an_params = an_params
  173. # information, whether mouse event handler is registered in map window
  174. self.handlerRegistered = False
  175. self.pointsChanged = Signal('VNETPointsData.pointsChanged')
  176. self.an_params.parametersChanged.connect(self.ParametersChanged)
  177. self.snapping = False
  178. self.data = []
  179. self.cols = { "name" : ['use', 'type', 'topology', 'e', 'n'],
  180. "label" : [_('use'), _('type'), _('topology'), 'e', 'n'],
  181. "type" : [None, [_(""), _("Start point"), _("End Point")], None, float, float],#TDO
  182. "def_vals" : [False, 0, "new point", 0, 0]
  183. }
  184. # registration graphics for drawing
  185. self.pointsToDraw = self.mapWin.RegisterGraphicsToDraw(graphicsType = "point",
  186. setStatusFunc = self.SetPointStatus)
  187. self.SetPointDrawSettings()
  188. self.AddPoint()
  189. self.AddPoint()
  190. self.SetPointData(0, {'use' : True, 'type' : 1})
  191. self.SetPointData(1, {'use' : True, 'type' : 2})
  192. self.selected = 0
  193. def __del__(self):
  194. self.CleanUp()
  195. def CleanUp(self):
  196. self.mapWin.UnregisterGraphicsToDraw(self.pointsToDraw)
  197. if self.handlerRegistered:
  198. self.mapWin.UnregisterMouseEventHandler(wx.EVT_LEFT_DOWN,
  199. self.OnMapClickHandler)
  200. def SetSnapping(self, activate):
  201. self.snapping = activate
  202. def GetSnapping(self):
  203. return self.snapping
  204. def AddPoint(self):
  205. self.pointsToDraw.AddItem(coords = (self.cols["def_vals"][3], self.cols["def_vals"][4]))
  206. self.data.append(self.cols["def_vals"][:])
  207. self.pointsChanged.emit(method = "AddPoint", kwargs = {})
  208. def DeletePoint(self, pt_id):
  209. self.pointsToDraw.DeleteItem(pt_id)
  210. self.data.pop(pt_id)
  211. self.pointsChanged.emit(method = "DeletePoint", kwargs = {"pt_id" : pt_id})
  212. def SetPoints(self, pts_data):
  213. for item in self.pointsToDraw.GetAllItems():
  214. self.pointsToDraw.DeleteItem(item)
  215. self.data = []
  216. for pt_data in pts_data:
  217. pt_data_list = self._ptDataToList(pt_data)
  218. self.data.append(pt_data_list)
  219. self.pointsToDraw.AddItem(coords = (pt_data_list[3], pt_data_list[4]))
  220. self.pointsChanged.emit(method = "SetPoints", kwargs = {"pts_data" : pts_data})
  221. def SetPointData(self, pt_id, data):
  222. for col, v in data.iteritems():
  223. if col == 'use':
  224. continue
  225. idx = self.cols["name"].index(col)
  226. self.data[pt_id][idx] = v
  227. if data.has_key('use'):
  228. if self._usePoint(pt_id, data["use"]) == -1:
  229. data["use"] = False
  230. idx = self.cols["name"].index("use")
  231. self.data[pt_id][idx] = v
  232. self.pointsChanged.emit(method = "SetPointData", kwargs = {"pt_id" : pt_id, "data" : data})
  233. def GetPointData(self, pt_id):
  234. return self._ptListDataToPtData(self.data[pt_id])
  235. def GetPointsCount(self):
  236. return len(self.data)
  237. def SetPointStatus(self, item, itemIndex):
  238. """!Before point is drawn, decides properties of drawing style"""
  239. analysis, valid = self.an_params.GetParam("analysis")
  240. cats = self.an_data[analysis]["cmdParams"]["cats"]
  241. if itemIndex == self.selected:
  242. wxPen = "selected"
  243. elif not self.data[itemIndex][0]:
  244. wxPen = "unused"
  245. item.hide = False
  246. elif len(cats) > 1:
  247. idx = self.data[itemIndex][1]
  248. if idx == 2: #End/To/Sink point
  249. wxPen = "used2cat"
  250. else:
  251. wxPen = "used1cat"
  252. else:
  253. wxPen = "used1cat"
  254. item.SetPropertyVal('label', str(itemIndex + 1))
  255. item.SetPropertyVal('penName', wxPen)
  256. def SetSelected(self, pt_id):
  257. self.selected = pt_id
  258. self.pointsChanged.emit(method = "SetSelected", kwargs = {"pt_id" : pt_id})
  259. def GetSelected(self):
  260. return self.selected
  261. def SetPointDrawSettings(self):
  262. """!Set settings for drawing of points"""
  263. ptSize = int(UserSettings.Get(group='vnet', key='point_symbol', subkey = 'point_size'))
  264. self.pointsToDraw.SetPropertyVal("size", ptSize)
  265. colors = UserSettings.Get(group='vnet', key='point_colors')
  266. ptWidth = int(UserSettings.Get(group='vnet', key='point_symbol', subkey = 'point_width'))
  267. textProp = self.pointsToDraw.GetPropertyVal("text")
  268. textProp["font"].SetPointSize(ptSize + 2)
  269. for colKey, col in colors.iteritems():
  270. pen = self.pointsToDraw.GetPen(colKey)
  271. if pen:
  272. pen.SetColour(wx.Colour(col[0], col[1], col[2], 255))
  273. pen.SetWidth(ptWidth)
  274. else:
  275. self.pointsToDraw.AddPen(colKey, wx.Pen(colour = wx.Colour(col[0], col[1], col[2], 255), width = ptWidth))
  276. def ParametersChanged(self, method, kwargs):
  277. if "analysis" in kwargs["changed_params"].keys():
  278. self._updateTypeCol()
  279. def _updateTypeCol(self):
  280. """Rename category values when module is changed. Expample: Start point -> Sink point"""
  281. colValues = [""]
  282. analysis, valid = self.an_params.GetParam("analysis")
  283. anParamsCats = self.an_data[analysis]["cmdParams"]["cats"]
  284. for ptCat in anParamsCats:
  285. colValues.append(ptCat[1])
  286. type_idx = self.cols["name"].index("type")
  287. self.cols['type'][type_idx] = colValues
  288. def _ptDataToList(self, pt_data):
  289. pt_list_data = [None] * len(self.cols['name'])
  290. for k, val in pt_data.iteritems():
  291. pt_list_data[self.cols["name"].index(k)] = val
  292. return pt_list_data
  293. def _ptListDataToPtData(self, pt_list_data):
  294. pt_data = {}
  295. for i, val in enumerate(pt_list_data):
  296. pt_data[self.cols["name"][i]] = val
  297. return pt_data
  298. def _usePoint(self, pt_id, use):
  299. """!Item is checked/unchecked"""
  300. analysis, valid = self.an_params.GetParam("analysis")
  301. cats = self.an_data[analysis]["cmdParams"]["cats"]
  302. ##TODO move
  303. #if self.updateMap:
  304. # up_map_evt = gUpdateMap(render = False, renderVector = False)
  305. # wx.PostEvent(self.dialog.mapWin, up_map_evt)
  306. if len(cats) <= 1:
  307. return 0
  308. type_idx = self.cols["name"].index("type")
  309. use_idx = self.cols["name"].index("use")
  310. checkedVal = self.data[pt_id][1]
  311. if checkedVal == 0:
  312. self.data[pt_id][use_idx] = False
  313. self.pointsChanged.emit(method = "SetPointData", kwargs = {"pt_id" : pt_id, "data" : {"use" : False}})
  314. return -1
  315. if analysis == "v.net.path" and use:
  316. alreadyChecked = []
  317. if pt_id:
  318. checkedKey = pt_id
  319. alreadyChecked.append(self.data[pt_id][type_idx])
  320. else:
  321. checkedKey = -1
  322. for iKey, dt in enumerate(self.data):
  323. pt_type = dt[type_idx]
  324. if ((pt_type in alreadyChecked and checkedKey != iKey) \
  325. or pt_type == 0) and self.data[iKey][use_idx]:
  326. self.data[iKey][use_idx] = False
  327. self.pointsChanged.emit(method = "SetPointData", kwargs = {"pt_id" : iKey, "data": {"use" : False}})
  328. elif self.data[iKey][use_idx]:
  329. alreadyChecked.append(pt_type)
  330. def EditPointMode(self, activate):
  331. """!Registers/unregisters mouse handler into map window"""
  332. if activate == self.handlerRegistered:
  333. return
  334. if activate:
  335. self.mapWin.RegisterMouseEventHandler(wx.EVT_LEFT_DOWN,
  336. self.OnMapClickHandler,
  337. wx.StockCursor(wx.CURSOR_CROSS))
  338. self.handlerRegistered = True
  339. else:
  340. self.mapWin.UnregisterMouseEventHandler(wx.EVT_LEFT_DOWN,
  341. self.OnMapClickHandler)
  342. self.handlerRegistered = False
  343. self.pointsChanged.emit(method = "EditMode", kwargs = {"activated" : activate})
  344. def IsEditPointModeActive(self):
  345. return self.handlerRegistered
  346. def OnMapClickHandler(self, event):
  347. """!Take coordinates from map window"""
  348. #TODO update snapping after input change
  349. if event == 'unregistered':
  350. self.handlerRegistered = False
  351. return
  352. if not self.data:
  353. self.AddPoint()
  354. e, n = self.mapWin.GetLastEN()
  355. if self.snapping:
  356. # compute threshold
  357. snapTreshPix = int(UserSettings.Get(group ='vnet',
  358. key = 'other',
  359. subkey = 'snap_tresh'))
  360. res = max(self.mapWin.Map.region['nsres'], self.mapWin.Map.region['ewres'])
  361. snapTreshDist = snapTreshPix * res
  362. params, err_params, flags = self.an_params.GetParams()
  363. vectMap = params["input"]
  364. if "input" in err_params:
  365. msg = _("new point")
  366. coords = SnapToNode(e, n, snapTreshDist, vectMap)
  367. if coords:
  368. e = coords[0]
  369. n = coords[1]
  370. msg = ("snapped to node")
  371. else:
  372. msg = _("new point")
  373. else:
  374. msg = _("new point")
  375. if self.selected == len(self.data) - 1:
  376. self.SetSelected(0)
  377. else:
  378. self.SetSelected(self.GetSelected() + 1)
  379. self.SetPointData(self.selected,
  380. {'topology' : msg,
  381. 'e' : e,
  382. 'n' : n})
  383. self.pointsToDraw.GetItem(self.selected).SetCoords([e, n])
  384. def GetColumns(self, only_relevant = True):
  385. cols_data = deepcopy(self.cols)
  386. hidden_cols = []
  387. hidden_cols.append(self.cols["name"].index("e"))
  388. hidden_cols.append(self.cols["name"].index("n"))
  389. analysis, valid = self.an_params.GetParam("analysis")
  390. if only_relevant and len(self.an_data[analysis]["cmdParams"]["cats"]) <= 1:
  391. hidden_cols.append(self.cols["name"].index("type"))
  392. i_red = 0
  393. hidden_cols.sort()
  394. for idx in hidden_cols:
  395. for dt in cols_data.itervalues():
  396. dt.pop(idx - i_red)
  397. i_red +=1
  398. return cols_data
  399. class VNETAnalysisParameters:
  400. def __init__(self, an_props):
  401. self.an_props = an_props
  402. self.params = {"analysis" : self.an_props.used_an[0],
  403. "input" : "",
  404. "alayer" : "",
  405. "nlayer" : "",
  406. "afcolumn" : "",
  407. "abcolumn" : "",
  408. "ncolumn" : "",
  409. "tlayer" : "",
  410. "tuclayer" : "",
  411. "iso_lines" : "", #TODO check validity
  412. "max_dist" : 0} #TODO check validity
  413. self.flags = {"t" : False}
  414. self.parametersChanged = Signal('VNETAnalysisParameters.parametersChanged')
  415. def SetParams(self, params, flags):
  416. changed_params = {}
  417. for p, v in params.iteritems():
  418. if p == "analysis" and v not in self.an_props.used_an:
  419. continue
  420. if p == "input":
  421. mapName, mapSet = ParseMapStr(v)
  422. v = mapName + "@" + mapSet
  423. if self.params.has_key(p):
  424. if isinstance(v, str):
  425. v = v.strip()
  426. self.params[p] = v
  427. changed_params[p] = v
  428. changed_flags = {}
  429. for p, v in flags.iteritems():
  430. if self.flags.has_key(p):
  431. self.flags[p] = v
  432. changed_flags[p] = v
  433. self.parametersChanged.emit(method = "SetParams",
  434. kwargs = {"changed_params" : changed_params , "changed_flags" : changed_flags})
  435. return changed_params, changed_flags
  436. def GetParam(self, param):
  437. invParams = []
  438. if param in ["input", "alayer", "nlayer", "afcolumn",
  439. "abcolumn", "ncolumn", "tlayer", "tuclayer"]:
  440. invParams = self._getInvalidParams(self.params)
  441. if invParams:
  442. return self.params[param], False
  443. return self.params[param], True
  444. def GetParams(self):
  445. invParams = self._getInvalidParams(self.params)
  446. return self.params, invParams, self.flags
  447. def _getInvalidParams(self, params):
  448. """!Check of analysis input data for invalid values (Parameters tab)"""
  449. # dict of invalid values {key from self.itemData (comboboxes from Parameters tab) : invalid value}
  450. invParams = []
  451. # check vector map
  452. if params["input"]:
  453. mapName, mapSet = params["input"].split("@")
  454. if grass.list_grouped('vect').has_key(mapSet):
  455. vectMaps = grass.list_grouped('vect')[mapSet]
  456. if not params["input"] or mapName not in vectMaps:
  457. invParams = params.keys()[:]
  458. return invParams
  459. # check arc/node layer
  460. layers = utils.GetVectorNumberOfLayers(params["input"])
  461. for l in ['alayer', 'nlayer', 'tlayer', 'tuclayer']:
  462. if not layers or params[l] not in layers:
  463. invParams.append(l)
  464. dbInfo = VectorDBInfo(params["input"])
  465. try:
  466. table = dbInfo.GetTable(int(params["alayer"]))
  467. columnchoices = dbInfo.GetTableDesc(table)
  468. except (KeyError, ValueError):
  469. table = None
  470. # check costs columns
  471. for col in ["afcolumn", "abcolumn", "ncolumn"]:
  472. if col == "ncolumn":
  473. try:
  474. table = dbInfo.GetTable(int(params["nlayer"]))
  475. columnchoices = dbInfo.GetTableDesc(table)
  476. except (KeyError, ValueError):
  477. table = None
  478. if not table or not params[col] in columnchoices.keys():
  479. invParams.append(col)
  480. continue
  481. if not columnchoices[col].value['type'] not in ['integer', 'double precision']:
  482. invParams.append(col)
  483. continue
  484. return invParams
  485. class VNETAnalysesProperties:
  486. def __init__(self):
  487. """!Initializes parameters for different v.net.* modules """
  488. # initialization of v.net.* analysis parameters (data which characterizes particular analysis)
  489. self.attrCols = {
  490. 'afcolumn' : {
  491. "label" : _("Arc forward/both direction(s) cost column:"),
  492. "name" : _("arc forward/both")
  493. },
  494. 'abcolumn' : {
  495. "label" : _("Arc backward direction cost column:"),
  496. "name" : _("arc backward")
  497. },
  498. 'acolumn' : {
  499. "label" : _("Arcs' cost column (for both directions):"),
  500. "name" : _("arc"),
  501. "inputField" : 'afcolumn',
  502. },
  503. 'ncolumn' : {
  504. "label" : _("Node cost column:"),
  505. "name" : _("node")
  506. }
  507. }
  508. self.vnetProperties = {
  509. "v.net.path" : {
  510. "label" : _("Shortest path %s") % "(v.net.path)",
  511. "cmdParams" : {
  512. "cats" : [
  513. ["st_pt", _("Start point")],
  514. ["end_pt", _("End point")]
  515. ],
  516. "cols" : [
  517. 'afcolumn',
  518. 'abcolumn',
  519. 'ncolumn'
  520. ],
  521. },
  522. "resultProps" : {
  523. "singleColor" : None,
  524. "dbMgr" : True #TODO delete this property, this information can be get from result
  525. },
  526. "turns_support" : True
  527. },
  528. "v.net.salesman" : {
  529. "label" : _("Traveling salesman %s") % "(v.net.salesman)",
  530. "cmdParams" : {
  531. "cats" : [["ccats", None]],
  532. "cols" : [
  533. 'afcolumn',
  534. 'abcolumn'
  535. ],
  536. },
  537. "resultProps" : {
  538. "singleColor" : None,
  539. "dbMgr" : False
  540. },
  541. "turns_support" : True
  542. },
  543. "v.net.flow" : {
  544. "label" : _("Maximum flow %s") % "(v.net.flow)",
  545. "cmdParams" : {
  546. "cats" : [
  547. ["source_cats", _("Source point")],
  548. ["sink_cats", _("Sink point")]
  549. ],
  550. "cols" : [
  551. 'afcolumn',
  552. 'abcolumn',
  553. 'ncolumn'
  554. ]
  555. },
  556. "resultProps" : {
  557. "attrColColor": "flow",
  558. "dbMgr" : True
  559. },
  560. "turns_support" : False
  561. },
  562. "v.net.alloc" : {
  563. "label" : _("Subnets for nearest centers %s") % "(v.net.alloc)",
  564. "cmdParams" : {
  565. "cats" : [["ccats", None]],
  566. "cols" : [
  567. 'afcolumn',
  568. 'abcolumn',
  569. 'ncolumn'
  570. ]
  571. },
  572. "resultProps" : {
  573. "catColor" : None,
  574. "dbMgr" : False
  575. },
  576. "turns_support" : True
  577. },
  578. "v.net.steiner" : {
  579. "label" : _("Steiner tree for the network and given terminals %s") % "(v.net.steiner)",
  580. "cmdParams" : {
  581. "cats" : [["tcats", None]],
  582. "cols" : [
  583. 'acolumn',
  584. ]
  585. },
  586. "resultProps" : {
  587. "singleColor" : None,
  588. "dbMgr" : False
  589. },
  590. "turns_support" : True
  591. },
  592. "v.net.distance" : {
  593. "label" : _("Shortest distance via the network %s") % "(v.net.distance)",
  594. "cmdParams" : {
  595. "cats" : [
  596. ["from_cats", "From point"],
  597. ["to_cats", "To point"]
  598. ],
  599. "cols" : [
  600. 'afcolumn',
  601. 'abcolumn',
  602. 'ncolumn'
  603. ],
  604. },
  605. "resultProps" : {
  606. "catColor" : None,
  607. "dbMgr" : True
  608. },
  609. "turns_support" : False
  610. },
  611. "v.net.iso" : {
  612. "label" : _("Cost isolines %s") % "(v.net.iso)",
  613. "cmdParams" : {
  614. "cats" : [["ccats", None]],
  615. "cols" : [
  616. 'afcolumn',
  617. 'abcolumn',
  618. 'ncolumn'
  619. ]
  620. },
  621. "resultProps" : {
  622. "catColor" : None,
  623. "dbMgr" : False
  624. },
  625. "turns_support" : True
  626. }
  627. }
  628. self.used_an = ["v.net.path",
  629. "v.net.salesman",
  630. "v.net.flow",
  631. "v.net.alloc",
  632. "v.net.distance",
  633. "v.net.iso",
  634. #"v.net.steiner"
  635. ]
  636. for an in self.vnetProperties.keys():
  637. if an not in self.used_an:
  638. del self.vnetProperties[an]
  639. continue
  640. cols = self.vnetProperties[an]["cmdParams"]["cols"]
  641. self.vnetProperties[an]["cmdParams"]["cols"] = {}
  642. for c in cols:
  643. self.vnetProperties[an]["cmdParams"]["cols"][c] = self.attrCols[c]
  644. def has_key(self, key):
  645. return self.vnetProperties.has_key(key)
  646. def __getitem__(self, key):
  647. return self.vnetProperties[key]
  648. def GetRelevantParams(self, analysis):
  649. if not self.vnetProperties.has_key(analysis):
  650. return None
  651. relevant_params = ["input", "alayer", "nlayer"]
  652. if self.vnetProperties[analysis]["turns_support"]:
  653. relevant_params += ["tlayer", "tuclayer"]
  654. cols = self.vnetProperties[analysis]["cmdParams"]["cols"]
  655. for col, v in cols.iteritems():
  656. if "inputField" in col:
  657. colInptF = v["inputField"]
  658. else:
  659. colInptF = col
  660. relevant_params.append(colInptF)
  661. return relevant_params
  662. class VNETTmpVectMaps:
  663. """!Class which creates, stores and destroys all tmp maps created during analysis"""
  664. def __init__(self, parent, mapWin):
  665. self.tmpMaps = [] # temporary maps
  666. self.parent = parent
  667. self.mapWin = mapWin
  668. def AddTmpVectMap(self, mapName, msg):
  669. """!New temporary map
  670. @return instance of VectMap representing temporary map
  671. """
  672. currMapSet = grass.gisenv()['MAPSET']
  673. tmpMap = grass.find_file(name = mapName,
  674. element = 'vector',
  675. mapset = currMapSet)
  676. fullName = tmpMap["fullname"]
  677. # map already exists
  678. if fullName:
  679. #TODO move dialog out of class, AddTmpVectMap(self, mapName, overvrite = False)
  680. dlg = wx.MessageDialog(parent = self.parent,
  681. message = msg,
  682. caption = _("Overwrite map layer"),
  683. style = wx.YES_NO | wx.NO_DEFAULT |
  684. wx.ICON_QUESTION | wx.CENTRE)
  685. ret = dlg.ShowModal()
  686. dlg.Destroy()
  687. if ret == wx.ID_NO:
  688. return None
  689. else:
  690. fullName = mapName + "@" + currMapSet
  691. newVectMap = VectMap(self.mapWin, fullName)
  692. self.tmpMaps.append(newVectMap)
  693. return newVectMap
  694. def HasTmpVectMap(self, vectMapName):
  695. """
  696. @param vectMapName name of vector map
  697. @return True if it contains the map
  698. @return False if not
  699. """
  700. mapValSpl = vectMapName.strip().split("@")
  701. if len(mapValSpl) > 1:
  702. mapSet = mapValSpl[1]
  703. else:
  704. mapSet = grass.gisenv()['MAPSET']
  705. mapName = mapValSpl[0]
  706. fullName = mapName + "@" + mapSet
  707. for vectTmpMap in self.tmpMaps:
  708. if vectTmpMap.GetVectMapName() == fullName:
  709. return True
  710. return False
  711. def GetTmpVectMap(self, vectMapName):
  712. """ Get instance of VectMap with name vectMapName"""
  713. for vectMap in self.tmpMaps:
  714. if vectMap.GetVectMapName() == vectMapName.strip():
  715. return vectMap
  716. return None
  717. def RemoveFromTmpMaps(self, vectMap):
  718. """!Temporary map is removed from the class instance however it is not deleted
  719. @param vectMap instance of VectMap class to be removed
  720. @return True if was removed
  721. @return False if does not contain the map
  722. """
  723. try:
  724. self.tmpMaps.remove(vectMap)
  725. return True
  726. except ValueError:
  727. return False
  728. def DeleteTmpMap(self, vectMap):
  729. """!Temporary map is removed from the class and it is deleted
  730. @param vectMap instance of VectMap class to be deleted
  731. @return True if was removed
  732. @return False if does not contain the map
  733. """
  734. if vectMap:
  735. vectMap.DeleteRenderLayer()
  736. RunCommand('g.remove',
  737. vect = vectMap.GetVectMapName())
  738. self.RemoveFromTmpMaps(vectMap)
  739. return True
  740. return False
  741. def DeleteAllTmpMaps(self):
  742. """Delete all temporary maps in the class"""
  743. update = False
  744. for tmpMap in self.tmpMaps:
  745. RunCommand('g.remove',
  746. vect = tmpMap.GetVectMapName())
  747. if tmpMap.DeleteRenderLayer():
  748. update = True
  749. return update
  750. class VectMap:
  751. """!Represents map
  752. It can check if it was modified or render it
  753. """
  754. def __init__(self, mapWin, fullName):
  755. self.fullName = fullName
  756. self.mapWin = mapWin
  757. self.renderLayer = None
  758. self.modifTime = None # time, for modification check
  759. def __del__(self):
  760. self.DeleteRenderLayer()
  761. def AddRenderLayer(self, cmd = None, colorsCmd = None):
  762. """!Add map from map window layers to render """
  763. if not self.mapWin:
  764. return False
  765. existsMap = grass.find_file(name = self.fullName,
  766. element = 'vector',
  767. mapset = grass.gisenv()['MAPSET'])
  768. if not existsMap["name"]:
  769. self.DeleteRenderLayer()
  770. return False
  771. if not cmd:
  772. cmd = []
  773. cmd.insert(0, 'd.vect')
  774. cmd.append('map=%s' % self.fullName)
  775. if self.renderLayer:
  776. self.DeleteRenderLayer()
  777. if colorsCmd:
  778. colorsCmd.append('map=%s' % self.fullName)
  779. layerStyleVnetColors = utils.CmdToTuple(colorsCmd)
  780. RunCommand(layerStyleVnetColors[0],
  781. **layerStyleVnetColors[1])
  782. self.renderLayer = self.mapWin.Map.AddLayer(ltype = "vector", command = cmd,
  783. name = self.fullName, active = True,
  784. opacity = 1.0, render = True,
  785. pos = -1)
  786. return True
  787. def DeleteRenderLayer(self):
  788. """!Remove map from map window layers to render"""
  789. if not self.mapWin:
  790. return False
  791. if self.renderLayer:
  792. self.mapWin.Map.DeleteLayer(self.renderLayer)
  793. self.renderLayer = None
  794. return True
  795. return False
  796. def GetRenderLayer(self):
  797. return self.renderLayer
  798. def GetVectMapName(self):
  799. return self.fullName
  800. def SaveVectMapState(self):
  801. """!Save modification time for vector map"""
  802. self.modifTime = self.GetLastModified()
  803. def VectMapState(self):
  804. """!Checks if map was modified
  805. @return -1 - if no modification time was saved
  806. @return 0 - if map was modified
  807. @return 1 - if map was not modified
  808. """
  809. if self.modifTime is None:
  810. return -1
  811. if self.modifTime != self.GetLastModified():
  812. return 0
  813. return 1
  814. def GetLastModified(self):
  815. """!Get modification time
  816. @return MAP DATE time string from vector map head file
  817. """
  818. mapValSpl = self.fullName.split("@")
  819. mapSet = mapValSpl[1]
  820. mapName = mapValSpl[0]
  821. headPath = os.path.join(grass.gisenv()['GISDBASE'],
  822. grass.gisenv()['LOCATION_NAME'],
  823. mapSet,
  824. "vector",
  825. mapName,
  826. "head")
  827. try:
  828. head = open(headPath, 'r')
  829. for line in head.readlines():
  830. i = line.find('MAP DATE:', )
  831. if i == 0:
  832. head.close()
  833. return line.split(':', 1)[1].strip()
  834. head.close()
  835. return ""
  836. except IOError:
  837. return ""
  838. class History:
  839. """!Class which reads and saves history data (based on gui.core.settings Settings class file save/load)
  840. @todo Maybe it could be useful for other GRASS wxGUI tools.
  841. """
  842. def __init__(self):
  843. # max number of steps in history (zero based)
  844. self.maxHistSteps = 3
  845. # current history step
  846. self.currHistStep = 0
  847. # number of steps saved in history
  848. self.histStepsNum = 0
  849. # dict contains data saved in history for current history step
  850. self.currHistStepData = {}
  851. # buffer for data to be saved into history
  852. self.newHistStepData = {}
  853. self.histFile = grass.tempfile()
  854. # key/value separator
  855. self.sep = ';'
  856. def __del__(self):
  857. grass.try_remove(self.histFile)
  858. def GetNext(self):
  859. """!Go one step forward in history"""
  860. self.currHistStep -= 1
  861. self.currHistStepData.clear()
  862. self.currHistStepData = self._getHistStepData(self.currHistStep)
  863. return self.currHistStepData
  864. def GetPrev(self):
  865. """!Go one step back in history"""
  866. self.currHistStep += 1
  867. self.currHistStepData.clear()
  868. self.currHistStepData = self._getHistStepData(self.currHistStep)
  869. return self.currHistStepData
  870. def GetStepsNum(self):
  871. """!Get number of steps saved in history"""
  872. return self.histStepsNum
  873. def GetCurrHistStep(self):
  874. """!Get current history step"""
  875. return self.currHistStep
  876. def Add(self, key, subkey, value):
  877. """!Add new data into buffer"""
  878. if key not in self.newHistStepData:
  879. self.newHistStepData[key] = {}
  880. if type(subkey) == types.ListType:
  881. if subkey[0] not in self.newHistStepData[key]:
  882. self.newHistStepData[key][subkey[0]] = {}
  883. self.newHistStepData[key][subkey[0]][subkey[1]] = value
  884. else:
  885. self.newHistStepData[key][subkey] = value
  886. def SaveHistStep(self):
  887. """!Create new history step with data in buffer"""
  888. self.maxHistSteps = UserSettings.Get(group ='vnet',
  889. key = 'other',
  890. subkey = 'max_hist_steps')
  891. self.currHistStep = 0
  892. newHistFile = grass.tempfile()
  893. newHist = open(newHistFile, "w")
  894. self._saveNewHistStep(newHist)
  895. oldHist = open(self.histFile)
  896. removedHistData = self._savePreviousHist(newHist, oldHist)
  897. oldHist.close()
  898. newHist.close()
  899. grass.try_remove(self.histFile)
  900. self.histFile = newHistFile
  901. self.newHistStepData.clear()
  902. return removedHistData
  903. def _savePreviousHist(self, newHist, oldHist):
  904. """!Save previous history into new file"""
  905. newHistStep = False
  906. removedHistData = {}
  907. newHistStepsNum = self.histStepsNum
  908. for line in oldHist.readlines():
  909. if not line.strip():
  910. newHistStep = True
  911. newHistStepsNum += 1
  912. continue
  913. if newHistStep:
  914. newHistStep = False
  915. line = line.split("=")
  916. line[1] = str(newHistStepsNum)
  917. line = "=".join(line)
  918. if newHistStepsNum >= self.maxHistSteps:
  919. removedHistStep = removedHistData[line] = {}
  920. continue
  921. else:
  922. newHist.write('%s%s%s' % (os.linesep, line, os.linesep))
  923. self.histStepsNum = newHistStepsNum
  924. else:
  925. if newHistStepsNum >= self.maxHistSteps:
  926. self._parseLine(line, removedHistStep)
  927. else:
  928. newHist.write('%s' % line)
  929. return removedHistData
  930. def _saveNewHistStep(self, newHist):
  931. """!Save buffer (new step) data into file"""
  932. newHist.write('%s%s%s' % (os.linesep, "history step=0", os.linesep))
  933. for key in self.newHistStepData.keys():
  934. subkeys = self.newHistStepData[key].keys()
  935. newHist.write('%s%s' % (key, self.sep))
  936. for idx in range(len(subkeys)):
  937. value = self.newHistStepData[key][subkeys[idx]]
  938. if type(value) == types.DictType:
  939. if idx > 0:
  940. newHist.write('%s%s%s' % (os.linesep, key, self.sep))
  941. newHist.write('%s%s' % (subkeys[idx], self.sep))
  942. kvalues = self.newHistStepData[key][subkeys[idx]].keys()
  943. srange = range(len(kvalues))
  944. for sidx in srange:
  945. svalue = self._parseValue(self.newHistStepData[key][subkeys[idx]][kvalues[sidx]])
  946. newHist.write('%s%s%s' % (kvalues[sidx], self.sep, svalue))
  947. if sidx < len(kvalues) - 1:
  948. newHist.write('%s' % self.sep)
  949. else:
  950. if idx > 0 and \
  951. type( self.newHistStepData[key][subkeys[idx - 1]]) == types.DictType:
  952. newHist.write('%s%s%s' % (os.linesep, key, self.sep))
  953. value = self._parseValue(self.newHistStepData[key][subkeys[idx]])
  954. newHist.write('%s%s%s' % (subkeys[idx], self.sep, value))
  955. if idx < len(subkeys) - 1 and \
  956. type(self.newHistStepData[key][subkeys[idx + 1]]) != types.DictType:
  957. newHist.write('%s' % self.sep)
  958. newHist.write(os.linesep)
  959. self.histStepsNum = 0
  960. def _parseValue(self, value, read = False):
  961. """!Parse value"""
  962. if read: # -> read data (cast values)
  963. if value:
  964. if value[0] == '[' and value[-1] == ']':# TODO, possible wrong interpretation
  965. value = value[1:-1].split(',')
  966. value = map(self._castValue, value)
  967. return value
  968. if value == 'True':
  969. value = True
  970. elif value == 'False':
  971. value = False
  972. elif value == 'None':
  973. value = None
  974. elif ':' in value: # -> color
  975. try:
  976. value = tuple(map(int, value.split(':')))
  977. except ValueError: # -> string
  978. pass
  979. else:
  980. try:
  981. value = int(value)
  982. except ValueError:
  983. try:
  984. value = float(value)
  985. except ValueError:
  986. pass
  987. else: # -> write data
  988. if type(value) == type(()): # -> color
  989. value = str(value[0]) + ':' +\
  990. str(value[1]) + ':' + \
  991. str(value[2])
  992. return value
  993. def _castValue(self, value):
  994. """!Cast value"""
  995. try:
  996. value = int(value)
  997. except ValueError:
  998. try:
  999. value = float(value)
  1000. except ValueError:
  1001. value = value[1:-1]
  1002. return value
  1003. def _getHistStepData(self, histStep):
  1004. """!Load data saved in history step"""
  1005. hist = open(self.histFile)
  1006. histStepData = {}
  1007. newHistStep = False
  1008. isSearchedHistStep = False
  1009. for line in hist.readlines():
  1010. if not line.strip() and isSearchedHistStep:
  1011. break
  1012. elif not line.strip():
  1013. newHistStep = True
  1014. continue
  1015. elif isSearchedHistStep:
  1016. self._parseLine(line, histStepData)
  1017. if newHistStep:
  1018. line = line.split("=")
  1019. if int(line[1]) == histStep:
  1020. isSearchedHistStep = True
  1021. newHistStep = False
  1022. hist.close()
  1023. return histStepData
  1024. def _parseLine(self, line, histStepData):
  1025. """!Parse line in file with history"""
  1026. line = line.rstrip('%s' % os.linesep).split(self.sep)
  1027. key = line[0]
  1028. kv = line[1:]
  1029. idx = 0
  1030. subkeyMaster = None
  1031. if len(kv) % 2 != 0: # multiple (e.g. nviz)
  1032. subkeyMaster = kv[0]
  1033. del kv[0]
  1034. idx = 0
  1035. while idx < len(kv):
  1036. if subkeyMaster:
  1037. subkey = [subkeyMaster, kv[idx]]
  1038. else:
  1039. subkey = kv[idx]
  1040. value = kv[idx+1]
  1041. value = self._parseValue(value, read = True)
  1042. if key not in histStepData:
  1043. histStepData[key] = {}
  1044. if type(subkey) == types.ListType:
  1045. if subkey[0] not in histStepData[key]:
  1046. histStepData[key][subkey[0]] = {}
  1047. histStepData[key][subkey[0]][subkey[1]] = value
  1048. else:
  1049. histStepData[key][subkey] = value
  1050. idx += 2
  1051. def DeleteNewHistStepData(self):
  1052. """!Delete buffer data for new history step"""
  1053. self.newHistStepData.clear()
  1054. class VNETGlobalTurnsData:
  1055. """!Turn Data"""
  1056. def __init__(self):
  1057. # Definition of four basic directions
  1058. self.turn_data = [
  1059. ["Straight", DegreesToRadians(-30), DegreesToRadians(+30), 0.0],
  1060. ["Right Turn", DegreesToRadians(+30), DegreesToRadians(+150), 0.0],
  1061. ["Reverse", DegreesToRadians(+150), DegreesToRadians(-150), 0.0],
  1062. ["Left Turn", DegreesToRadians(-150), DegreesToRadians(-30), 0.0]
  1063. ]
  1064. def GetData(self):
  1065. data = []
  1066. for ival in self.turn_data:
  1067. data.append(ival[1:])
  1068. return data
  1069. def GetValue(self, line, col):
  1070. return self.turn_data[line][col]
  1071. def GetLinesCount(self):
  1072. return len(self.turn_data)
  1073. def SetValue(self, value, line, col):
  1074. self.DataValidator(line, col, value)
  1075. self.turn_data[line][col] = value
  1076. def SetUTurns(self, value):
  1077. """!Checked if checeBox is checed"""
  1078. useUTurns = value
  1079. def AppendRow(self, values):
  1080. self.turn_data.append(values)
  1081. def InsertRow(self,line,values):
  1082. self.turn_data.insert(line,values)
  1083. def PopRow(self, values):
  1084. self.RemoveDataValidator(values)
  1085. self.turn_data.pop(values)
  1086. def DataValidator(self, row, col, value):
  1087. """!Angle recalculation due to value changing"""
  1088. if col not in [1,2]:
  1089. return
  1090. if col == 1:
  1091. new_from_angle = value
  1092. old_from_angle = self.turn_data[row][1]
  1093. new_to_angle = self.turn_data[row][2]
  1094. if self.IsInInterval(old_from_angle, new_to_angle, new_from_angle):
  1095. prev_row = row - 1
  1096. if prev_row == -1:
  1097. prev_row = len(self.turn_data) - 1
  1098. self.turn_data[prev_row][2] = new_from_angle
  1099. return
  1100. if col ==2:
  1101. new_to_angle = value
  1102. old_to_angle = self.turn_data[row][2]
  1103. new_from_angle = self.turn_data[row][1]
  1104. if self.IsInInterval(new_from_angle, old_to_angle, new_to_angle):
  1105. next_row = row + 1
  1106. if len(self.turn_data) == next_row:
  1107. next_row = 0
  1108. self.turn_data[next_row][1] = new_to_angle
  1109. return
  1110. inside_new = []
  1111. overlap_new_from = []
  1112. overlap_new_to = []
  1113. for i in range(self.GetLinesCount()):
  1114. if i == row:
  1115. continue
  1116. from_angle = self.turn_data[i][1]
  1117. is_in_from = self.IsInInterval(new_from_angle, new_to_angle, from_angle)
  1118. to_angle = self.turn_data[i][2]
  1119. is_in_to = self.IsInInterval(new_from_angle, new_to_angle, to_angle)
  1120. if is_in_from and is_in_to:
  1121. inside_new.append(i)
  1122. if is_in_from:
  1123. overlap_new_to.append(i)
  1124. if is_in_to:
  1125. overlap_new_from.append(i)
  1126. for i_row in overlap_new_from:
  1127. self.turn_data[i_row][2] = new_from_angle
  1128. for i_row in overlap_new_to:
  1129. self.turn_data[i_row][1] = new_to_angle
  1130. for i_row in inside_new:
  1131. if col == 1:
  1132. angle = new_from_angle
  1133. else:
  1134. angle = new_to_angle
  1135. self.turn_data[i_row][1] = angle
  1136. self.turn_data[i_row][2] = angle
  1137. def RemoveDataValidator(self, row):
  1138. """!Angle recalculation due to direction remove"""
  1139. if row == 0:
  1140. prev_row = self.GetLinesCount() - 1
  1141. else:
  1142. prev_row = row - 1
  1143. remove_to_angle = self.turn_data[row][2]
  1144. self.turn_data[prev_row][2] = remove_to_angle
  1145. def IsInInterval(self, from_angle, to_angle, angle):
  1146. """!Test if a direction includes or not includes a value"""
  1147. if to_angle < from_angle:
  1148. to_angle = math.pi * 2 + to_angle
  1149. if angle < from_angle:
  1150. angle = math.pi * 2 + angle
  1151. if angle > from_angle and angle < to_angle:
  1152. return True
  1153. return False