space_time_datasets.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. """!@package grass.temporal
  2. @brief GRASS Python scripting module (temporal GIS functions)
  3. Temporal GIS related functions to be used in Python scripts.
  4. Usage:
  5. @code
  6. import grass.temporal as tgis
  7. strds = tgis.space_time_raster_dataset("soils_1950_2010")
  8. ...
  9. @endcode
  10. (C) 2008-2011 by the GRASS Development Team
  11. This program is free software under the GNU General Public
  12. License (>=v2). Read the file COPYING that comes with GRASS
  13. for details.
  14. @author Soeren Gebbert
  15. """
  16. import getpass
  17. import grass.script.raster as raster
  18. import grass.script.vector as vector
  19. import grass.script.raster3d as raster3d
  20. from ctypes import *
  21. import grass.lib.gis as libgis
  22. import grass.lib.raster as libraster
  23. from datetime_math import *
  24. from abstract_map_dataset import *
  25. from abstract_space_time_dataset import *
  26. ###############################################################################
  27. class raster_dataset(abstract_map_dataset):
  28. """!Raster dataset class
  29. This class provides functions to select, update, insert or delete raster
  30. map information and valid time stamps into the SQL temporal database.
  31. """
  32. def __init__(self, ident):
  33. self.reset(ident)
  34. def get_type(self):
  35. return "raster"
  36. def get_new_instance(self, ident):
  37. """!Return a new instance with the type of this class"""
  38. return raster_dataset(ident)
  39. def get_new_stds_instance(self, ident):
  40. """!Return a new space time dataset instance in which maps are stored with the type of this class"""
  41. return space_time_raster_dataset(ident)
  42. def get_stds_register(self):
  43. """!Return the space time dataset register table name in which stds are listed in which this map is registered"""
  44. return self.metadata.get_strds_register()
  45. def set_stds_register(self, name):
  46. """!Set the space time dataset register table name in which stds are listed in which this map is registered"""
  47. self.metadata.set_strds_register(name)
  48. def spatial_overlapping(self, dataset):
  49. """!Return True if the spatial extents 2d overlap"""
  50. return self.spatial_extent.overlapping_2d(dataset.spatial_extent)
  51. def spatial_relation(self, dataset):
  52. """Return the two dimensional spatial relation"""
  53. return self.spatial_extent.spatial_relation_2d(dataset.spatial_extent)
  54. def reset(self, ident):
  55. """!Reset the internal structure and set the identifier"""
  56. self.ident = ident
  57. self.base = raster_base(ident=ident)
  58. self.absolute_time = raster_absolute_time(ident=ident)
  59. self.relative_time = raster_relative_time(ident=ident)
  60. self.spatial_extent = raster_spatial_extent(ident=ident)
  61. self.metadata = raster_metadata(ident=ident)
  62. def has_grass_timestamp(self):
  63. """!Check if a grass file bsased time stamp exists for this map.
  64. """
  65. if G_has_raster_timestamp(self.get_name(), self.get_mapset()):
  66. return True
  67. else:
  68. return False
  69. def write_timestamp_to_grass(self):
  70. """!Write the timestamp of this map into the map metadata in the grass file system based spatial
  71. database.
  72. Internally the libgis API functions are used for writing
  73. """
  74. ts = libgis.TimeStamp()
  75. libgis.G_scan_timestamp(byref(ts), self._convert_timestamp())
  76. check = libgis.G_write_raster_timestamp(self.get_name(), byref(ts))
  77. if check == -1:
  78. core.error(_("Unable to create timestamp file for raster map <%s>"%(self.get_map_id())))
  79. if check == -2:
  80. core.error(_("Invalid datetime in timestamp for raster map <%s>"%(self.get_map_id())))
  81. def remove_timestamp_from_grass(self):
  82. """!Remove the timestamp from the grass file system based spatial database
  83. Internally the libgis API functions are used for removal
  84. """
  85. check = libgis.G_remove_raster_timestamp(self.get_name())
  86. if check == -1:
  87. core.error(_("Unable to remove timestamp for raster map <%s>"%(self.get_name())))
  88. def map_exists(self):
  89. """!Return True in case the map exists in the grass spatial database
  90. @return True if map exists, False otherwise
  91. """
  92. mapset = libgis.G_find_raster(self.get_name(), self.get_mapset())
  93. if not mapset:
  94. return False
  95. return True
  96. def read_info(self):
  97. """!Read the raster map info from the file system and store the content
  98. into a dictionary
  99. This method uses the ctypes interface to the gis and raster libraries
  100. to read the map metadata information
  101. """
  102. kvp = {}
  103. name = self.get_name()
  104. mapset = self.get_mapset()
  105. if not self.map_exists():
  106. core.fatal(_("Raster map <%s> not found" % name))
  107. # Read the region information
  108. region = libgis.Cell_head()
  109. libraster.Rast_get_cellhd(name, mapset, byref(region))
  110. kvp["north"] = region.north
  111. kvp["south"] = region.south
  112. kvp["east"] = region.east
  113. kvp["west"] = region.west
  114. kvp["nsres"] = region.ns_res
  115. kvp["ewres"] = region.ew_res
  116. kvp["rows"] = region.cols
  117. kvp["cols"] = region.rows
  118. maptype = libraster.Rast_map_type(name, mapset)
  119. if maptype == libraster.DCELL_TYPE:
  120. kvp["datatype"] = "DCELL"
  121. elif maptype == libraster.FCELL_TYPE:
  122. kvp["datatype"] = "FCELL"
  123. elif maptype == libraster.CELL_TYPE:
  124. kvp["datatype"] = "CELL"
  125. # Read range
  126. if libraster.Rast_map_is_fp(name, mapset):
  127. range = libraster.FPRange()
  128. libraster.Rast_init_fp_range (byref(range))
  129. libraster.Rast_read_fp_range(name, mapset, byref(range))
  130. min = libgis.DCELL()
  131. max = libgis.DCELL()
  132. libraster.Rast_get_fp_range_min_max(byref(range), byref(min), byref(max))
  133. kvp["min"] = float(min.value)
  134. kvp["max"] = float(max.value)
  135. else:
  136. range = libraster.Range()
  137. libraster.Rast_init_range (byref(range))
  138. libraster.Rast_read_range(name, mapset, byref(range))
  139. min = libgis.CELL()
  140. max = libgis.CELL()
  141. libraster.Rast_get_fp_range_min_max(byref(range), byref(min), byref(max))
  142. kvp["min"] = int(min.value)
  143. kvp["max"] = int(max.value)
  144. return kvp
  145. def load(self):
  146. """!Load all info from an existing raster map into the internal structure"""
  147. # Fill base information
  148. self.base.set_name(self.ident.split("@")[0])
  149. self.base.set_mapset(self.ident.split("@")[1])
  150. self.base.set_creator(str(getpass.getuser()))
  151. # Get the data from an existing raster map
  152. kvp = self.read_info()
  153. # Fill spatial extent
  154. self.set_spatial_extent(north=kvp["north"], south=kvp["south"], \
  155. east=kvp["east"], west=kvp["west"])
  156. # Fill metadata
  157. self.metadata.set_nsres(kvp["nsres"])
  158. self.metadata.set_ewres(kvp["ewres"])
  159. self.metadata.set_datatype(kvp["datatype"])
  160. self.metadata.set_min(kvp["min"])
  161. self.metadata.set_max(kvp["max"])
  162. rows = kvp["rows"]
  163. cols = kvp["cols"]
  164. ncells = cols * rows
  165. self.metadata.set_cols(cols)
  166. self.metadata.set_rows(rows)
  167. self.metadata.set_number_of_cells(ncells)
  168. ###############################################################################
  169. class raster3d_dataset(abstract_map_dataset):
  170. """!Raster3d dataset class
  171. This class provides functions to select, update, insert or delete raster3d
  172. map information and valid time stamps into the SQL temporal database.
  173. """
  174. def __init__(self, ident):
  175. self.reset(ident)
  176. def get_type(self):
  177. return "raster3d"
  178. def get_new_instance(self, ident):
  179. """!Return a new instance with the type of this class"""
  180. return raster3d_dataset(ident)
  181. def get_new_stds_instance(self, ident):
  182. """!Return a new space time dataset instance in which maps are stored with the type of this class"""
  183. return space_time_raster3d_dataset(ident)
  184. def get_stds_register(self):
  185. """!Return the space time dataset register table name in which stds are listed in which this map is registered"""
  186. return self.metadata.get_str3ds_register()
  187. def set_stds_register(self, name):
  188. """!Set the space time dataset register table name in which stds are listed in which this map is registered"""
  189. self.metadata.set_str3ds_register(name)
  190. def spatial_overlapping(self, dataset):
  191. """!Return True if the spatial extents overlap"""
  192. if self.get_type() == dataset.get_type() or dataset.get_type() == "str3ds":
  193. return self.spatial_extent.overlapping(dataset.spatial_extent)
  194. else:
  195. return self.spatial_extent.overlapping_2d(dataset.spatial_extent)
  196. def spatial_relation(self, dataset):
  197. """Return the two or three dimensional spatial relation"""
  198. if self.get_type() == dataset.get_type() or dataset.get_type() == "str3ds":
  199. return self.spatial_extent.spatial_relation(dataset.spatial_extent)
  200. else:
  201. return self.spatial_extent.spatial_relation_2d(dataset.spatial_extent)
  202. def reset(self, ident):
  203. """!Reset the internal structure and set the identifier"""
  204. self.ident = ident
  205. self.base = raster3d_base(ident=ident)
  206. self.absolute_time = raster3d_absolute_time(ident=ident)
  207. self.relative_time = raster3d_relative_time(ident=ident)
  208. self.spatial_extent = raster3d_spatial_extent(ident=ident)
  209. self.metadata = raster3d_metadata(ident=ident)
  210. def has_grass_timestamp(self):
  211. """!Check if a grass file bsased time stamp exists for this map.
  212. """
  213. if G_has_raster3d_timestamp(self.get_name(), self.get_mapset()):
  214. return True
  215. else:
  216. return False
  217. def write_timestamp_to_grass(self):
  218. """!Write the timestamp of this map into the map metadata in the grass file system based spatial
  219. database.
  220. Internally the libgis API functions are used for writing
  221. """
  222. ts = libgis.TimeStamp()
  223. libgis.G_scan_timestamp(byref(ts), self._convert_timestamp())
  224. check = libgis.G_write_raster3d_timestamp(self.get_name(), byref(ts))
  225. if check == -1:
  226. core.error(_("Unable to create timestamp file for raster3d map <%s>"%(self.get_map_id())))
  227. if check == -2:
  228. core.error(_("Invalid datetime in timestamp for raster3d map <%s>"%(self.get_map_id())))
  229. def remove_timestamp_from_grass(self):
  230. """!Remove the timestamp from the grass file system based spatial database
  231. Internally the libgis API functions are used for removal
  232. """
  233. check = libgis.G_remove_raster3d_timestamp(self.get_name())
  234. if check == -1:
  235. core.error(_("Unable to remove timestamp for raster3d map <%s>"%(self.get_name())))
  236. def map_exists(self):
  237. """!Return True in case the map exists in the grass spatial database
  238. @return True if map exists, False otherwise
  239. """
  240. mapset = libgis.G_find_raster3d(self.get_name(), self.get_mapset())
  241. if not mapset:
  242. return False
  243. return True
  244. def load(self):
  245. """!Load all info from an existing raster3d map into the internal structure"""
  246. # Get the data from an existing raster map
  247. kvp = raster3d.raster3d_info(self.get_map_id())
  248. # Fill base information
  249. self.base.set_name(self.ident.split("@")[0])
  250. self.base.set_mapset(self.ident.split("@")[1])
  251. self.base.set_creator(str(getpass.getuser()))
  252. # Fill spatial extent
  253. self.set_spatial_extent(north=kvp["north"], south=kvp["south"], \
  254. east=kvp["east"], west=kvp["west"],\
  255. top=kvp["top"], bottom=kvp["bottom"])
  256. # Fill metadata
  257. self.metadata.set_nsres(kvp["nsres"])
  258. self.metadata.set_ewres(kvp["ewres"])
  259. self.metadata.set_tbres(kvp["tbres"])
  260. self.metadata.set_datatype(kvp["datatype"])
  261. self.metadata.set_min(kvp["min"])
  262. self.metadata.set_max(kvp["max"])
  263. rows = int((kvp["north"] - kvp["south"])/kvp["nsres"] + 0.5)
  264. cols = int((kvp["east"] - kvp["west"])/kvp["ewres"] + 0.5)
  265. depths = int((kvp["top"] - kvp["bottom"])/kvp["tbres"] + 0.5)
  266. ncells = cols * rows * depths
  267. self.metadata.set_cols(cols)
  268. self.metadata.set_rows(rows)
  269. self.metadata.set_depths(depths)
  270. self.metadata.set_number_of_cells(ncells)
  271. ###############################################################################
  272. class vector_dataset(abstract_map_dataset):
  273. """!Vector dataset class
  274. This class provides functions to select, update, insert or delete vector
  275. map information and valid time stamps into the SQL temporal database.
  276. """
  277. def __init__(self, ident):
  278. self.reset(ident)
  279. def get_type(self):
  280. return "vector"
  281. def get_new_instance(self, ident):
  282. """!Return a new instance with the type of this class"""
  283. return vector_dataset(ident)
  284. def get_new_stds_instance(self, ident):
  285. """!Return a new space time dataset instance in which maps are stored with the type of this class"""
  286. return space_time_vector_dataset(ident)
  287. def get_stds_register(self):
  288. """!Return the space time dataset register table name in which stds are listed in which this map is registered"""
  289. return self.metadata.get_stvds_register()
  290. def set_stds_register(self, name):
  291. """!Set the space time dataset register table name in which stds are listed in which this map is registered"""
  292. self.metadata.set_stvds_register(name)
  293. def get_layer(self):
  294. """!Return the layer"""
  295. return self.base.get_layer()
  296. def spatial_overlapping(self, dataset):
  297. """!Return True if the spatial extents 2d overlap"""
  298. return self.spatial_extent.overlapping_2d(dataset.spatial_extent)
  299. def spatial_relation(self, dataset):
  300. """Return the two dimensional spatial relation"""
  301. return self.spatial_extent.spatial_relation_2d(dataset.spatial_extent)
  302. def reset(self, ident):
  303. """!Reset the internal structure and set the identifier"""
  304. self.ident = ident
  305. self.base = vector_base(ident=ident)
  306. self.absolute_time = vector_absolute_time(ident=ident)
  307. self.relative_time = vector_relative_time(ident=ident)
  308. self.spatial_extent = vector_spatial_extent(ident=ident)
  309. self.metadata = vector_metadata(ident=ident)
  310. def has_grass_timestamp(self):
  311. """!Check if a grass file bsased time stamp exists for this map.
  312. """
  313. if G_has_raster_timestamp(self.get_name(), self.get_layer(), self.get_mapset()):
  314. return True
  315. else:
  316. return False
  317. def write_timestamp_to_grass(self):
  318. """!Write the timestamp of this map into the map metadata in the grass file system based spatial
  319. database.
  320. Internally the libgis API functions are used for writing
  321. """
  322. ts = libgis.TimeStamp()
  323. libgis.G_scan_timestamp(byref(ts), self._convert_timestamp())
  324. check = libgis.G_write_vector_timestamp(self.get_name(), self.get_layer(), byref(ts))
  325. if check == -1:
  326. core.error(_("Unable to create timestamp file for vector map <%s>"%(self.get_map_id())))
  327. if check == -2:
  328. core.error(_("Invalid datetime in timestamp for vector map <%s>"%(self.get_map_id())))
  329. def remove_timestamp_from_grass(self):
  330. """!Remove the timestamp from the grass file system based spatial database
  331. Internally the libgis API functions are used for removal
  332. """
  333. check = libgis.G_remove_vector_timestamp(self.get_name(), self.get_layer())
  334. if check == -1:
  335. core.error(_("Unable to remove timestamp for vector map <%s>"%(self.get_name())))
  336. def map_exists(self):
  337. """!Return True in case the map exists in the grass spatial database
  338. @return True if map exists, False otherwise
  339. """
  340. mapset = libgis.G_find_vector(self.get_name(), self.get_mapset())
  341. if not mapset:
  342. return False
  343. return True
  344. def load(self):
  345. """!Load all info from an existing vector map into the internal structure"""
  346. # Get the data from an existing raster map
  347. kvp = vector.vector_info(self.get_map_id())
  348. # Fill base information
  349. if self.ident.find(":") >= 0:
  350. self.base.set_name(self.ident.split("@")[0].split(":")[0])
  351. self.base.set_layer(self.ident.split("@")[0].split(":")[1])
  352. else:
  353. self.base.set_name(self.ident.split("@")[0])
  354. self.base.set_mapset(self.ident.split("@")[1])
  355. self.base.set_creator(str(getpass.getuser()))
  356. # Fill spatial extent
  357. self.set_spatial_extent(north=kvp["north"], south=kvp["south"], \
  358. east=kvp["east"], west=kvp["west"],\
  359. top=kvp["top"], bottom=kvp["bottom"])
  360. # Fill metadata .. no metadata yet
  361. ###############################################################################
  362. class space_time_raster_dataset(abstract_space_time_dataset):
  363. """!Space time raster dataset class
  364. """
  365. def __init__(self, ident):
  366. abstract_space_time_dataset.__init__(self, ident)
  367. def get_type(self):
  368. return "strds"
  369. def get_new_instance(self, ident):
  370. """!Return a new instance with the type of this class"""
  371. return space_time_raster_dataset(ident)
  372. def get_new_map_instance(self, ident):
  373. """!Return a new instance of a map dataset which is associated with the type of this class"""
  374. return raster_dataset(ident)
  375. def get_map_register(self):
  376. """!Return the name of the map register table"""
  377. return self.metadata.get_raster_register()
  378. def set_map_register(self, name):
  379. """!Set the name of the map register table"""
  380. self.metadata.set_raster_register(name)
  381. def spatial_overlapping(self, dataset):
  382. """!Return True if the spatial extents 2d overlap"""
  383. return self.spatial_extent.overlapping_2d(dataset.spatial_extent)
  384. def spatial_relation(self, dataset):
  385. """Return the two dimensional spatial relation"""
  386. return self.spatial_extent.spatial_relation_2d(dataset.spatial_extent)
  387. def reset(self, ident):
  388. """!Reset the internal structure and set the identifier"""
  389. self.ident = ident
  390. self.base = strds_base(ident=ident)
  391. if ident != None:
  392. self.base.set_name(self.ident.split("@")[0])
  393. self.base.set_mapset(self.ident.split("@")[1])
  394. self.base.set_creator(str(getpass.getuser()))
  395. self.absolute_time = strds_absolute_time(ident=ident)
  396. self.relative_time = strds_relative_time(ident=ident)
  397. self.spatial_extent = strds_spatial_extent(ident=ident)
  398. self.metadata = strds_metadata(ident=ident)
  399. ###############################################################################
  400. class space_time_raster3d_dataset(abstract_space_time_dataset):
  401. """!Space time raster3d dataset class
  402. """
  403. def __init__(self, ident):
  404. abstract_space_time_dataset.__init__(self, ident)
  405. def get_type(self):
  406. return "str3ds"
  407. def get_new_instance(self, ident):
  408. """!Return a new instance with the type of this class"""
  409. return space_time_raster3d_dataset(ident)
  410. def get_new_map_instance(self, ident):
  411. """!Return a new instance of a map dataset which is associated with the type of this class"""
  412. return raster3d_dataset(ident)
  413. def get_map_register(self):
  414. """!Return the name of the map register table"""
  415. return self.metadata.get_raster3d_register()
  416. def set_map_register(self, name):
  417. """!Set the name of the map register table"""
  418. self.metadata.set_raster3d_register(name)
  419. def spatial_overlapping(self, dataset):
  420. """!Return True if the spatial extents overlap"""
  421. if self.get_type() == dataset.get_type() or dataset.get_type() == "str3ds":
  422. return self.spatial_extent.overlapping(dataset.spatial_extent)
  423. else:
  424. return self.spatial_extent.overlapping_2d(dataset.spatial_extent)
  425. def spatial_relation(self, dataset):
  426. """Return the two or three dimensional spatial relation"""
  427. if self.get_type() == dataset.get_type() or dataset.get_type() == "str3ds":
  428. return self.spatial_extent.spatial_relation(dataset.spatial_extent)
  429. else:
  430. return self.spatial_extent.spatial_relation_2d(dataset.spatial_extent)
  431. def reset(self, ident):
  432. """!Reset the internal structure and set the identifier"""
  433. self.ident = ident
  434. self.base = str3ds_base(ident=ident)
  435. if ident != None:
  436. self.base.set_name(self.ident.split("@")[0])
  437. self.base.set_mapset(self.ident.split("@")[1])
  438. self.base.set_creator(str(getpass.getuser()))
  439. self.absolute_time = str3ds_absolute_time(ident=ident)
  440. self.relative_time = str3ds_relative_time(ident=ident)
  441. self.spatial_extent = str3ds_spatial_extent(ident=ident)
  442. self.metadata = str3ds_metadata(ident=ident)
  443. ###############################################################################
  444. class space_time_vector_dataset(abstract_space_time_dataset):
  445. """!Space time vector dataset class
  446. """
  447. def __init__(self, ident):
  448. abstract_space_time_dataset.__init__(self, ident)
  449. def get_type(self):
  450. return "stvds"
  451. def get_new_instance(self, ident):
  452. """!Return a new instance with the type of this class"""
  453. return space_time_vector_dataset(ident)
  454. def get_new_map_instance(self, ident):
  455. """!Return a new instance of a map dataset which is associated with the type of this class"""
  456. return vector_dataset(ident)
  457. def get_map_register(self):
  458. """!Return the name of the map register table"""
  459. return self.metadata.get_vector_register()
  460. def set_map_register(self, name):
  461. """!Set the name of the map register table"""
  462. self.metadata.set_vector_register(name)
  463. def spatial_overlapping(self, dataset):
  464. """!Return True if the spatial extents 2d overlap"""
  465. return self.spatial_extent.overlapping_2d(dataset.spatial_extent)
  466. def spatial_relation(self, dataset):
  467. """Return the two dimensional spatial relation"""
  468. return self.spatial_extent.spatial_relation_2d(dataset.spatial_extent)
  469. def reset(self, ident):
  470. """!Reset the internal structure and set the identifier"""
  471. self.ident = ident
  472. self.base = stvds_base(ident=ident)
  473. if ident != None:
  474. self.base.set_name(self.ident.split("@")[0])
  475. self.base.set_mapset(self.ident.split("@")[1])
  476. self.base.set_creator(str(getpass.getuser()))
  477. self.absolute_time = stvds_absolute_time(ident=ident)
  478. self.relative_time = stvds_relative_time(ident=ident)
  479. self.spatial_extent = stvds_spatial_extent(ident=ident)
  480. self.metadata = stvds_metadata(ident=ident)