temporal_vector_algebra.py 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. """@package grass.temporal
  2. Temporal vector algebra
  3. (C) 2014 by the GRASS Development Team
  4. This program is free software under the GNU General Public
  5. License (>=v2). Read the file COPYING that comes with GRASS
  6. for details.
  7. :authors: Thomas Leppelt and Soeren Gebbert
  8. .. code-block:: python
  9. >>> import grass.temporal as tgis
  10. >>> tgis.init(True)
  11. >>> p = tgis.TemporalVectorAlgebraLexer()
  12. >>> p.build()
  13. >>> p.debug = True
  14. >>> expression = 'E = A : B ^ C : D'
  15. >>> p.test(expression)
  16. E = A : B ^ C : D
  17. LexToken(NAME,'E',1,0)
  18. LexToken(EQUALS,'=',1,2)
  19. LexToken(NAME,'A',1,4)
  20. LexToken(T_SELECT,':',1,6)
  21. LexToken(NAME,'B',1,8)
  22. LexToken(XOR,'^',1,10)
  23. LexToken(NAME,'C',1,12)
  24. LexToken(T_SELECT,':',1,14)
  25. LexToken(NAME,'D',1,16)
  26. >>> expression = 'E = buff_a(A, 10)'
  27. >>> p.test(expression)
  28. E = buff_a(A, 10)
  29. LexToken(NAME,'E',1,0)
  30. LexToken(EQUALS,'=',1,2)
  31. LexToken(BUFF_AREA,'buff_a',1,4)
  32. LexToken(LPAREN,'(',1,10)
  33. LexToken(NAME,'A',1,11)
  34. LexToken(COMMA,',',1,12)
  35. LexToken(INT,10,1,14)
  36. LexToken(RPAREN,')',1,16)
  37. """
  38. from __future__ import print_function
  39. try:
  40. import ply.lex as lex
  41. import ply.yacc as yacc
  42. except:
  43. pass
  44. import grass.pygrass.modules as pygrass
  45. import copy
  46. from .temporal_algebra import TemporalAlgebraLexer, TemporalAlgebraParser, GlobalTemporalVar
  47. from .core import init_dbif, get_current_mapset
  48. from .abstract_dataset import AbstractDatasetComparisonKeyStartTime
  49. from .open_stds import open_new_stds
  50. from .spatio_temporal_relationships import SpatioTemporalTopologyBuilder
  51. from .space_time_datasets import VectorDataset
  52. ##############################################################################
  53. class TemporalVectorAlgebraLexer(TemporalAlgebraLexer):
  54. """Lexical analyzer for the GRASS GIS temporal vector algebra"""
  55. def __init__(self):
  56. TemporalAlgebraLexer.__init__(self)
  57. # Buffer functions from v.buffer
  58. vector_buff_functions = {
  59. 'buff_p': 'BUFF_POINT',
  60. 'buff_l': 'BUFF_LINE',
  61. 'buff_a': 'BUFF_AREA',
  62. }
  63. # This is the list of token names.
  64. vector_tokens = (
  65. 'DISOR',
  66. 'XOR',
  67. 'NOT',
  68. 'T_OVERLAY_OPERATOR',
  69. )
  70. # Build the token list
  71. tokens = TemporalAlgebraLexer.tokens \
  72. + vector_tokens \
  73. + tuple(vector_buff_functions.values())
  74. # Regular expression rules for simple tokens
  75. t_DISOR = r'\+'
  76. t_XOR = r'\^'
  77. t_NOT = r'\~'
  78. #t_T_OVERLAY_OPERATOR = r'\{([a-zA-Z\|]+[,])?([\|&+=]?[\|&+=\^\~])\}'
  79. t_T_OVERLAY_OPERATOR = r'\{[\|&+\^\~][,]?[a-zA-Z\| ]*([,])?([lrudi]|left|right|union|disjoint|intersect)?\}'
  80. # Parse symbols
  81. def temporal_symbol(self, t):
  82. # Check for reserved words
  83. if t.value in TemporalVectorAlgebraLexer.time_functions.keys():
  84. t.type = TemporalVectorAlgebraLexer.time_functions.get(t.value)
  85. elif t.value in TemporalVectorAlgebraLexer.datetime_functions.keys():
  86. t.type = TemporalVectorAlgebraLexer.datetime_functions.get(t.value)
  87. elif t.value in TemporalVectorAlgebraLexer.conditional_functions.keys():
  88. t.type = TemporalVectorAlgebraLexer.conditional_functions.get(t.value)
  89. elif t.value in TemporalVectorAlgebraLexer.vector_buff_functions.keys():
  90. t.type = TemporalVectorAlgebraLexer.vector_buff_functions.get(t.value)
  91. else:
  92. t.type = 'NAME'
  93. return t
  94. ##############################################################################
  95. class TemporalVectorAlgebraParser(TemporalAlgebraParser):
  96. """The temporal algebra class"""
  97. # Get the tokens from the lexer class
  98. tokens = TemporalVectorAlgebraLexer.tokens
  99. # Setting equal precedence level for select and hash operations.
  100. precedence = (
  101. ('left', 'T_SELECT_OPERATOR', 'T_SELECT', 'T_NOT_SELECT', 'T_HASH_OPERATOR', 'HASH'), # 1
  102. ('left', 'AND', 'OR', 'T_COMP_OPERATOR', 'T_OVERLAY_OPERATOR', 'DISOR', \
  103. 'NOT', 'XOR'), # 2
  104. )
  105. def __init__(self, pid=None, run=False, debug=True, spatial = False):
  106. TemporalAlgebraParser.__init__(self, pid, run, debug, spatial)
  107. self.m_overlay = pygrass.Module('v.overlay', quiet=True, run_=False)
  108. self.m_rename = pygrass.Module('g.rename', quiet=True, run_=False)
  109. self.m_patch = pygrass.Module('v.patch', quiet=True, run_=False)
  110. self.m_mremove = pygrass.Module('g.remove', quiet=True, run_=False)
  111. self.m_buffer = pygrass.Module('v.buffer', quiet=True, run_=False)
  112. def parse(self, expression, basename = None, overwrite = False):
  113. # Check for space time dataset type definitions from temporal algebra
  114. l = TemporalVectorAlgebraLexer()
  115. l.build()
  116. l.lexer.input(expression)
  117. while True:
  118. tok = l.lexer.token()
  119. if not tok:
  120. break
  121. if tok.type == "STVDS" or tok.type == "STRDS" or tok.type == "STR3DS":
  122. raise SyntaxError("Syntax error near '%s'" % (tok.type))
  123. self.lexer = TemporalVectorAlgebraLexer()
  124. self.lexer.build()
  125. self.parser = yacc.yacc(module=self, debug=self.debug, write_tables=False)
  126. self.overwrite = overwrite
  127. self.count = 0
  128. self.stdstype = "stvds"
  129. self.maptype = "vector"
  130. self.mapclass = VectorDataset
  131. self.basename = basename
  132. self.expression = expression
  133. self.parser.parse(expression)
  134. ######################### Temporal functions ##############################
  135. def build_spatio_temporal_topology_list(self, maplistA, maplistB = None, topolist = ["EQUAL"],
  136. assign_val = False, count_map = False, compare_bool = False,
  137. compare_cmd = False, compop = None, aggregate = None,
  138. new = False, convert = False, overlay_cmd = False):
  139. """Build temporal topology for two space time data sets, copy map objects
  140. for given relation into map list.
  141. :param maplistA: List of maps.
  142. :param maplistB: List of maps.
  143. :param topolist: List of strings of temporal relations.
  144. :param assign_val: Boolean for assigning a boolean map value based on
  145. the map_values from the compared map list by
  146. topological relationships.
  147. :param count_map: Boolean if the number of topological related maps
  148. should be returned.
  149. :param compare_bool: Boolean for comparing boolean map values based on
  150. related map list and compariosn operator.
  151. :param compare_cmd: Boolean for comparing command list values based on
  152. related map list and compariosn operator.
  153. :param compop: Comparison operator, && or ||.
  154. :param aggregate: Aggregation operator for relation map list, & or |.
  155. :param new: Boolean if new temporary maps should be created.
  156. :param convert: Boolean if conditional values should be converted to
  157. r.mapcalc command strings.
  158. :param overlay_cmd: Boolean for aggregate overlay operators implicitly
  159. in command list values based on related map lists.
  160. :return: List of maps from maplistA that fulfil the topological relationships
  161. to maplistB specified in topolist.
  162. """
  163. topologylist = ["EQUAL", "FOLLOWS", "PRECEDES", "OVERLAPS", "OVERLAPPED",
  164. "DURING", "STARTS", "FINISHES", "CONTAINS", "STARTED",
  165. "FINISHED"]
  166. complementdict = {"EQUAL": "EQUAL", "FOLLOWS": "PRECEDES",
  167. "PRECEDES": "FOLLOWS", "OVERLAPS": "OVERLAPPED",
  168. "OVERLAPPED": "OVERLAPS", "DURING": "CONTAINS",
  169. "CONTAINS": "DURING", "STARTS": "STARTED",
  170. "STARTED": "STARTS", "FINISHES": "FINISHED",
  171. "FINISHED": "FINISHES"}
  172. resultdict = {}
  173. # Check if given temporal relation are valid.
  174. for topo in topolist:
  175. if topo.upper() not in topologylist:
  176. raise SyntaxError("Unpermitted temporal relation name '" + topo + "'")
  177. # Create temporal topology for maplistA to maplistB.
  178. tb = SpatioTemporalTopologyBuilder()
  179. # Dictionary with different spatial variables used for topology builder.
  180. spatialdict = {'strds': '2D', 'stvds': '2D', 'str3ds': '3D'}
  181. # Build spatial temporal topology
  182. if self.spatial:
  183. tb.build(maplistA, maplistB, spatial = spatialdict[self.stdstype])
  184. else:
  185. tb.build(maplistA, maplistB)
  186. # Iterate through maps in maplistA and search for relationships given
  187. # in topolist.
  188. for map_i in maplistA:
  189. tbrelations = map_i.get_temporal_relations()
  190. # Check for boolean parameters for further calculations.
  191. if assign_val:
  192. self.assign_bool_value(map_i, tbrelations, topolist)
  193. elif compare_bool:
  194. self.compare_bool_value(map_i, tbrelations, compop, aggregate, topolist)
  195. elif compare_cmd:
  196. self.compare_cmd_value(map_i, tbrelations, compop, aggregate, topolist, convert)
  197. elif overlay_cmd:
  198. self.overlay_cmd_value(map_i, tbrelations, compop, topolist)
  199. for topo in topolist:
  200. if topo.upper() in tbrelations.keys():
  201. if count_map:
  202. relationmaplist = tbrelations[topo.upper()]
  203. gvar = GlobalTemporalVar()
  204. gvar.td = len(relationmaplist)
  205. if "map_value" in dir(map_i):
  206. map_i.map_value.append(gvar)
  207. else:
  208. map_i.map_value = gvar
  209. # Use unique identifier, since map names may be equal
  210. resultdict[map_i.uid] = map_i
  211. resultlist = resultdict.values()
  212. # Sort list of maps chronological.
  213. resultlist = sorted(resultlist, key = AbstractDatasetComparisonKeyStartTime)
  214. return(resultlist)
  215. def overlay_cmd_value(self, map_i, tbrelations, function, topolist = ["EQUAL"]):
  216. """ Function to evaluate two map lists by given overlay operator.
  217. :param map_i: Map object with temporal extent.
  218. :param tbrelations: List of temporal relation to map_i.
  219. :param topolist: List of strings for given temporal relations.
  220. :param function: Overlay operator, &|+^~.
  221. :return: Map object with command list with operators that has been
  222. evaluated by implicit aggregration.
  223. """
  224. # Build comandlist list with elements from related maps and given relation operator.
  225. resultlist = []
  226. # Define overlay operation dictionary.
  227. overlaydict = {"&":"and", "|":"or", "^":"xor", "~":"not", "+":"disor"}
  228. operator = overlaydict[function]
  229. # Set first input for overlay module.
  230. mapainput = map_i.get_id()
  231. # Append command list of given map to result command list.
  232. if "cmd_list" in dir(map_i):
  233. resultlist = resultlist + map_i.cmd_list
  234. for topo in topolist:
  235. if topo.upper() in tbrelations.keys():
  236. relationmaplist = tbrelations[topo.upper()]
  237. for relationmap in relationmaplist:
  238. # Append command list of given map to result command list.
  239. if "cmd_list" in dir(relationmap):
  240. resultlist = resultlist + relationmap.cmd_list
  241. # Generate an intermediate name
  242. name = self.generate_map_name()
  243. # Put it into the removalbe map list
  244. self.removable_maps[name] = VectorDataset(name + "@%s" % (self.mapset))
  245. map_i.set_id(name + "@" + self.mapset)
  246. # Set second input for overlay module.
  247. mapbinput = relationmap.get_id()
  248. # Create module command in PyGRASS for v.overlay and v.patch.
  249. if operator != "disor":
  250. m = copy.deepcopy(self.m_overlay)
  251. m.run_ = False
  252. m.inputs["operator"].value = operator
  253. m.inputs["ainput"].value = str(mapainput)
  254. m.inputs["binput"].value = str(mapbinput)
  255. m.outputs["output"].value = name
  256. m.flags["overwrite"].value = self.overwrite
  257. else:
  258. patchinput = str(mapainput) + ',' + str(mapbinput)
  259. m = copy.deepcopy(self.m_patch)
  260. m.run_ = False
  261. m.inputs["input"].value = patchinput
  262. m.outputs["output"].value = name
  263. m.flags["overwrite"].value = self.overwrite
  264. # Conditional append of module command.
  265. resultlist.append(m)
  266. # Set new map name to temporary map name.
  267. mapainput = name
  268. # Add command list to result map.
  269. map_i.cmd_list = resultlist
  270. return(resultlist)
  271. def set_temporal_extent_list(self, maplist, topolist = ["EQUAL"], temporal = 'l' ):
  272. """ Change temporal extent of map list based on temporal relations to
  273. other map list and given temporal operator.
  274. :param maplist: List of map objects for which relations has been build
  275. correctely.
  276. :param topolist: List of strings of temporal relations.
  277. :param temporal: The temporal operator specifying the temporal
  278. extent operation (intersection, union, disjoint
  279. union, right reference, left reference).
  280. :return: Map list with specified temporal extent.
  281. """
  282. resultdict = {}
  283. for map_i in maplist:
  284. # Loop over temporal related maps and create overlay modules.
  285. tbrelations = map_i.get_temporal_relations()
  286. # Generate an intermediate map for the result map list.
  287. map_new = self.generate_new_map(base_map=map_i, bool_op = 'and',
  288. copy = True, rename = False,
  289. remove = True)
  290. # Combine temporal and spatial extents of intermediate map with related maps.
  291. for topo in topolist:
  292. if topo in tbrelations.keys():
  293. for map_j in (tbrelations[topo]):
  294. if temporal == 'r':
  295. # Generate an intermediate map for the result map list.
  296. map_new = self.generate_new_map(base_map=map_i, bool_op = 'and',
  297. copy = True, rename = False,
  298. remove = True)
  299. # Create overlaid map extent.
  300. returncode = self.overlay_map_extent(map_new, map_j, 'and',
  301. temp_op = temporal)
  302. # Stop the loop if no temporal or spatial relationship exist.
  303. if returncode == 0:
  304. break
  305. # Append map to result map list.
  306. elif returncode == 1:
  307. # resultlist.append(map_new)
  308. resultdict[map_new.get_id()] = map_new
  309. if returncode == 0:
  310. break
  311. # Append map to result map list.
  312. #if returncode == 1:
  313. # resultlist.append(map_new)
  314. # Get sorted map objects as values from result dictionoary.
  315. resultlist = resultdict.values()
  316. resultlist = sorted(resultlist, key = AbstractDatasetComparisonKeyStartTime)
  317. return(resultlist)
  318. ###########################################################################
  319. def p_statement_assign(self, t):
  320. # The expression should always return a list of maps.
  321. """
  322. statement : stds EQUALS expr
  323. """
  324. # Execute the command lists
  325. if self.run:
  326. # Open connection to temporal database.
  327. dbif, connected = init_dbif(dbif=self.dbif)
  328. if isinstance(t[3], list):
  329. num = len(t[3])
  330. count = 0
  331. returncode = 0
  332. register_list = []
  333. leadzero = len(str(num))
  334. for i in range(num):
  335. # Check if resultmap names exist in GRASS database.
  336. vectorname = self.basename + "_" + str(i).zfill(leadzero)
  337. vectormap = VectorDataset(vectorname + "@" + get_current_mapset())
  338. if vectormap.map_exists() and self.overwrite is False:
  339. self.msgr.fatal(_("Error vector maps with basename %s exist. "
  340. "Use --o flag to overwrite existing file")
  341. % (vectorname))
  342. for map_i in t[3]:
  343. if "cmd_list" in dir(map_i):
  344. # Execute command list.
  345. for cmd in map_i.cmd_list:
  346. try:
  347. # We need to check if the input maps have areas in case of v.overlay
  348. # otherwise v.overlay will break
  349. if cmd.name == "v.overlay":
  350. for name in (cmd.inputs["ainput"].value,
  351. cmd.inputs["binput"].value):
  352. #self.msgr.message("Check if map <" + name + "> exists")
  353. if name.find("@") < 0:
  354. name = name + "@" + get_current_mapset()
  355. tmp_map = map_i.get_new_instance(name)
  356. if not tmp_map.map_exists():
  357. raise Exception
  358. #self.msgr.message("Check if map <" + name + "> has areas")
  359. tmp_map.load()
  360. if tmp_map.metadata.get_number_of_areas() == 0:
  361. raise Exception
  362. except Exception:
  363. returncode = 1
  364. break
  365. # run the command
  366. # print the command that will be executed
  367. self.msgr.message("Run command:\n" + cmd.get_bash())
  368. cmd.run()
  369. if cmd.popen.returncode != 0:
  370. self.msgr.fatal(_("Error starting %s : \n%s")
  371. % (cmd.get_bash(),
  372. cmd.popen.stderr))
  373. mapname = cmd.outputs['output'].value
  374. if mapname.find("@") >= 0:
  375. map_test = map_i.get_new_instance(mapname)
  376. else:
  377. map_test = map_i.get_new_instance(mapname + "@" + self.mapset)
  378. if not map_test.map_exists():
  379. returncode = 1
  380. break
  381. if returncode == 0:
  382. # We remove the invalid vector name from the remove list.
  383. if map_i.get_name() in self.removable_maps:
  384. self.removable_maps.pop(map_i.get_name())
  385. mapset = map_i.get_mapset()
  386. # Change map name to given basename.
  387. newident = self.basename + "_" + str(count).zfill(leadzero)
  388. m = copy.deepcopy(self.m_rename)
  389. m.inputs["vector"].value = (map_i.get_name(),newident)
  390. m.flags["overwrite"].value = self.overwrite
  391. m.run()
  392. map_i.set_id(newident + "@" + mapset)
  393. count += 1
  394. register_list.append(map_i)
  395. else:
  396. # Test if temporal extents have been changed by temporal
  397. # relation operators (i|r). This is a code copy from temporal_algebra.py
  398. map_i_extent = map_i.get_temporal_extent_as_tuple()
  399. map_test = map_i.get_new_instance(map_i.get_id())
  400. map_test.select(dbif)
  401. map_test_extent = map_test.get_temporal_extent_as_tuple()
  402. if map_test_extent != map_i_extent:
  403. # Create new map with basename
  404. newident = self.basename + "_" + str(count).zfill(leadzero)
  405. map_result = map_i.get_new_instance(newident + "@" + self.mapset)
  406. if map_test.map_exists() and self.overwrite is False:
  407. self.msgr.fatal("Error raster maps with basename %s exist. "
  408. "Use --o flag to overwrite existing file"
  409. % (mapname))
  410. map_result.set_temporal_extent(map_i.get_temporal_extent())
  411. map_result.set_spatial_extent(map_i.get_spatial_extent())
  412. # Attention we attach a new attribute
  413. map_result.is_new = True
  414. count += 1
  415. register_list.append(map_result)
  416. # Copy the map
  417. m = copy.deepcopy(self.m_copy)
  418. m.inputs["vector"].value = map_i.get_id(), newident
  419. m.flags["overwrite"].value = self.overwrite
  420. m.run()
  421. else:
  422. register_list.append(map_i)
  423. if len(register_list) > 0:
  424. # Create result space time dataset.
  425. resultstds = open_new_stds(t[1], self.stdstype,
  426. 'absolute', t[1], t[1],
  427. "temporal vector algebra", self.dbif,
  428. overwrite=self.overwrite)
  429. for map_i in register_list:
  430. # Check if modules should be executed from command list.
  431. if hasattr(map_i, "cmd_list") or hasattr(map_i, "is_new"):
  432. # Get meta data from grass database.
  433. map_i.load()
  434. if map_i.is_in_db(dbif=dbif) and self.overwrite:
  435. # Update map in temporal database.
  436. map_i.update_all(dbif=dbif)
  437. elif map_i.is_in_db(dbif=dbif) and self.overwrite is False:
  438. # Raise error if map exists and no overwrite flag is given.
  439. self.msgr.fatal(_("Error vector map %s exist in temporal database. "
  440. "Use overwrite flag. : \n%s")
  441. % (map_i.get_map_id(), cmd.popen.stderr))
  442. else:
  443. # Insert map into temporal database.
  444. map_i.insert(dbif=dbif)
  445. else:
  446. # Map is original from an input STVDS
  447. map_i.load()
  448. # Register map in result space time dataset.
  449. print(map_i.get_temporal_extent_as_tuple())
  450. success = resultstds.register_map(map_i, dbif=dbif)
  451. resultstds.update_from_registered_maps(dbif)
  452. # Remove intermediate maps
  453. self.remove_maps()
  454. if connected:
  455. dbif.close()
  456. t[0] = t[3]
  457. def p_overlay_operation(self, t):
  458. """
  459. expr : stds AND stds
  460. | expr AND stds
  461. | stds AND expr
  462. | expr AND expr
  463. | stds OR stds
  464. | expr OR stds
  465. | stds OR expr
  466. | expr OR expr
  467. | stds XOR stds
  468. | expr XOR stds
  469. | stds XOR expr
  470. | expr XOR expr
  471. | stds NOT stds
  472. | expr NOT stds
  473. | stds NOT expr
  474. | expr NOT expr
  475. | stds DISOR stds
  476. | expr DISOR stds
  477. | stds DISOR expr
  478. | expr DISOR expr
  479. """
  480. if self.run:
  481. # Check input stds and operator.
  482. maplistA = self.check_stds(t[1])
  483. maplistB = self.check_stds(t[3])
  484. relations = ["EQUAL"]
  485. temporal = 'l'
  486. function = t[2]
  487. # Build command list for related maps.
  488. complist = self.build_spatio_temporal_topology_list(maplistA, maplistB, topolist = relations,
  489. compop = function, overlay_cmd = True)
  490. # Set temporal extent based on topological relationships.
  491. resultlist = self.set_temporal_extent_list(complist, topolist = relations,
  492. temporal = temporal)
  493. t[0] = resultlist
  494. if self.debug:
  495. str(t[1]) + t[2] + str(t[3])
  496. def p_overlay_operation_relation(self, t):
  497. """
  498. expr : stds T_OVERLAY_OPERATOR stds
  499. | expr T_OVERLAY_OPERATOR stds
  500. | stds T_OVERLAY_OPERATOR expr
  501. | expr T_OVERLAY_OPERATOR expr
  502. """
  503. if self.run:
  504. # Check input stds and operator.
  505. maplistA = self.check_stds(t[1])
  506. maplistB = self.check_stds(t[3])
  507. relations, temporal, function, aggregate = self.eval_toperator(t[2], optype = 'overlay')
  508. # Build command list for related maps.
  509. complist = self.build_spatio_temporal_topology_list(maplistA, maplistB, topolist = relations,
  510. compop = function, overlay_cmd = True)
  511. # Set temporal extent based on topological relationships.
  512. resultlist = self.set_temporal_extent_list(complist, topolist = relations,
  513. temporal = temporal)
  514. t[0] = resultlist
  515. if self.debug:
  516. str(t[1]) + t[2] + str(t[3])
  517. def p_buffer_operation(self,t):
  518. """
  519. expr : buff_function LPAREN stds COMMA number RPAREN
  520. | buff_function LPAREN expr COMMA number RPAREN
  521. """
  522. if self.run:
  523. # Check input stds.
  524. bufflist = self.check_stds(t[3])
  525. # Create empty result list.
  526. resultlist = []
  527. for map_i in bufflist:
  528. # Generate an intermediate name for the result map list.
  529. map_new = self.generate_new_map(base_map=map_i, bool_op=None,
  530. copy=True, remove = True)
  531. # Change spatial extent based on buffer size.
  532. map_new.spatial_buffer(float(t[5]))
  533. # Check buff type.
  534. if t[1] == "buff_p":
  535. buff_type = "point"
  536. elif t[1] == "buff_l":
  537. buff_type = "line"
  538. elif t[1] == "buff_a":
  539. buff_type = "area"
  540. m = copy.deepcopy(self.m_buffer)
  541. m.run_ = False
  542. m.inputs["type"].value = buff_type
  543. m.inputs["input"].value = str(map_i.get_id())
  544. m.inputs["distance"].value = float(t[5])
  545. m.outputs["output"].value = map_new.get_name()
  546. m.flags["overwrite"].value = self.overwrite
  547. # Conditional append of module command.
  548. if "cmd_list" in dir(map_new):
  549. map_new.cmd_list.append(m)
  550. else:
  551. map_new.cmd_list = [m]
  552. resultlist.append(map_new)
  553. t[0] = resultlist
  554. def p_buff_function(self, t):
  555. """buff_function : BUFF_POINT
  556. | BUFF_LINE
  557. | BUFF_AREA
  558. """
  559. t[0] = t[1]
  560. # Handle errors.
  561. def p_error(self, t):
  562. raise SyntaxError("syntax error on line %d near '%s' expression '%s'" %
  563. (t.lineno, t.value, self.expression))
  564. ###############################################################################
  565. if __name__ == "__main__":
  566. import doctest
  567. doctest.testmod()