space_time_datasets.py 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432
  1. """
  2. Map layer and space time dataset classes
  3. (C) 2012-2013 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: Soeren Gebbert
  8. """
  9. import getpass
  10. from datetime import datetime
  11. from .core import get_current_mapset
  12. from .abstract_map_dataset import AbstractMapDataset
  13. from .abstract_space_time_dataset import AbstractSpaceTimeDataset
  14. from .base import Raster3DBase, RasterBase, VectorBase, STR3DSBase, STVDSBase, STRDSBase,\
  15. VectorSTDSRegister, Raster3DSTDSRegister, RasterSTDSRegister
  16. from .metadata import Raster3DMetadata, RasterMetadata, VectorMetadata, STRDSMetadata,\
  17. STR3DSMetadata, STVDSMetadata
  18. from .spatial_extent import RasterSpatialExtent, Raster3DSpatialExtent, VectorSpatialExtent,\
  19. STRDSSpatialExtent, STR3DSSpatialExtent, STVDSSpatialExtent
  20. from .temporal_extent import RasterAbsoluteTime, RasterRelativeTime, Raster3DAbsoluteTime, \
  21. Raster3DRelativeTime, VectorAbsoluteTime, VectorRelativeTime, STRDSAbsoluteTime,\
  22. STRDSRelativeTime, STR3DSAbsoluteTime, STR3DSRelativeTime, STVDSAbsoluteTime, STVDSRelativeTime
  23. import grass.script.array as garray
  24. from .core import init
  25. ###############################################################################
  26. class RasterDataset(AbstractMapDataset):
  27. """Raster dataset class
  28. This class provides functions to select, update, insert or delete raster
  29. map information and valid time stamps into the SQL temporal database.
  30. Usage:
  31. .. code-block:: python
  32. >>> import grass.script as gs
  33. >>> import grass.temporal as tgis
  34. >>> init()
  35. >>> gs.use_temp_region()
  36. >>> gs.run_command("g.region", n=80.0, s=0.0, e=120.0, w=0.0,
  37. ... t=1.0, b=0.0, res=10.0)
  38. 0
  39. >>> gs.run_command("r.mapcalc", overwrite=True, quiet=True,
  40. ... expression="strds_map_test_case = 1")
  41. 0
  42. >>> gs.run_command("r.timestamp", map="strds_map_test_case",
  43. ... date="15 jan 1999", quiet=True)
  44. 0
  45. >>> mapset = tgis.get_current_mapset()
  46. >>> name = "strds_map_test_case"
  47. >>> identifier = "%s@%s" % (name, mapset)
  48. >>> rmap = RasterDataset(identifier)
  49. >>> rmap.map_exists()
  50. True
  51. >>> rmap.read_timestamp_from_grass()
  52. True
  53. >>> rmap.get_temporal_extent_as_tuple()
  54. (datetime.datetime(1999, 1, 15, 0, 0), None)
  55. >>> rmap.load()
  56. True
  57. >>> rmap.spatial_extent.print_info()
  58. +-------------------- Spatial extent ----------------------------------------+
  59. | North:...................... 80.0
  60. | South:...................... 0.0
  61. | East:.. .................... 120.0
  62. | West:....................... 0.0
  63. | Top:........................ 0.0
  64. | Bottom:..................... 0.0
  65. >>> rmap.absolute_time.print_info()
  66. +-------------------- Absolute time -----------------------------------------+
  67. | Start time:................. 1999-01-15 00:00:00
  68. | End time:................... None
  69. >>> rmap.metadata.print_info()
  70. +-------------------- Metadata information ----------------------------------+
  71. | Datatype:................... CELL
  72. | Number of columns:.......... 8
  73. | Number of rows:............. 12
  74. | Number of cells:............ 96
  75. | North-South resolution:..... 10.0
  76. | East-west resolution:....... 10.0
  77. | Minimum value:.............. 1.0
  78. | Maximum value:.............. 1.0
  79. >>> gs.run_command("r.timestamp", map="strds_map_test_case",
  80. ... date="2 years", quiet=True)
  81. 0
  82. >>> rmap.read_timestamp_from_grass()
  83. True
  84. >>> rmap.get_temporal_extent_as_tuple()
  85. (2, None)
  86. >>> rmap.get_relative_time_unit()
  87. 'years'
  88. >>> rmap.is_in_db()
  89. False
  90. >>> rmap.is_stds()
  91. False
  92. >>> newmap = rmap.get_new_instance("new@PERMANENT")
  93. >>> isinstance(newmap, RasterDataset)
  94. True
  95. >>> newstrds = rmap.get_new_stds_instance("new@PERMANENT")
  96. >>> isinstance(newstrds, SpaceTimeRasterDataset)
  97. True
  98. >>> rmap.get_type()
  99. 'raster'
  100. >>> rmap.set_absolute_time(start_time=datetime(2001,1,1),
  101. ... end_time=datetime(2012,1,1))
  102. True
  103. >>> rmap.get_absolute_time()
  104. (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2012, 1, 1, 0, 0))
  105. >>> rmap.get_temporal_extent_as_tuple()
  106. (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2012, 1, 1, 0, 0))
  107. >>> rmap.get_name()
  108. 'strds_map_test_case'
  109. >>> rmap.get_mapset() == mapset
  110. True
  111. >>> rmap.get_temporal_type()
  112. 'absolute'
  113. >>> rmap.get_spatial_extent_as_tuple()
  114. (80.0, 0.0, 120.0, 0.0, 0.0, 0.0)
  115. >>> rmap.is_time_absolute()
  116. True
  117. >>> rmap.is_time_relative()
  118. False
  119. >>> gs.run_command("g.remove", flags="f", type="raster", name=name, quiet=True)
  120. 0
  121. >>> gs.del_temp_region()
  122. """
  123. def __init__(self, ident):
  124. AbstractMapDataset.__init__(self)
  125. self.reset(ident)
  126. def is_stds(self):
  127. """Return True if this class is a space time dataset
  128. :return: True if this class is a space time dataset, False otherwise
  129. """
  130. return False
  131. def get_type(self):
  132. return 'raster'
  133. def get_new_instance(self, ident):
  134. """Return a new instance with the type of this class"""
  135. return RasterDataset(ident)
  136. def get_new_stds_instance(self, ident):
  137. """Return a new space time dataset instance in which maps
  138. are stored with the type of this class"""
  139. return SpaceTimeRasterDataset(ident)
  140. def spatial_overlapping(self, dataset):
  141. """Return True if the spatial extents 2d overlap"""
  142. return self.spatial_extent.overlapping_2d(dataset.spatial_extent)
  143. def spatial_relation(self, dataset):
  144. """Return the two dimensional spatial relation"""
  145. return self.spatial_extent.spatial_relation_2d(dataset.spatial_extent)
  146. def spatial_intersection(self, dataset):
  147. """Return the two dimensional intersection as spatial_extent
  148. object or None in case no intersection was found.
  149. :param dataset: The abstract dataset to intersect with
  150. :return: The intersection spatial extent or None
  151. """
  152. return self.spatial_extent.intersect_2d(dataset.spatial_extent)
  153. def spatial_union(self, dataset):
  154. """Return the two dimensional union as spatial_extent
  155. object or None in case the extents does not overlap or meet.
  156. :param dataset :The abstract dataset to create a union with
  157. :return: The union spatial extent or None
  158. """
  159. return self.spatial_extent.union_2d(dataset.spatial_extent)
  160. def spatial_disjoint_union(self, dataset):
  161. """Return the two dimensional union as spatial_extent object.
  162. :param dataset: The abstract dataset to create a union with
  163. :return: The union spatial extent
  164. """
  165. return self.spatial_extent.disjoint_union_2d(dataset.spatial_extent)
  166. def get_np_array(self):
  167. """Return this raster map as memmap numpy style array to access the raster
  168. values in numpy style without loading the whole map in the RAM.
  169. In case this raster map does exists in the grass spatial database,
  170. the map will be exported using r.out.bin to a temporary location
  171. and assigned to the memmap object that is returned by this function.
  172. In case the raster map does not exist, an empty temporary
  173. binary file will be created and assigned to the memap object.
  174. You need to call the write function to write the memmap
  175. array back into grass.
  176. """
  177. a = garray.array()
  178. if self.map_exists():
  179. a.read(self.get_map_id())
  180. return a
  181. def reset(self, ident):
  182. """Reset the internal structure and set the identifier"""
  183. self.base = RasterBase(ident=ident)
  184. self.absolute_time = RasterAbsoluteTime(ident=ident)
  185. self.relative_time = RasterRelativeTime(ident=ident)
  186. self.spatial_extent = RasterSpatialExtent(ident=ident)
  187. self.metadata = RasterMetadata(ident=ident)
  188. self.stds_register = RasterSTDSRegister(ident=ident)
  189. def has_grass_timestamp(self):
  190. """Check if a grass file based time stamp exists for this map.
  191. :return: True if success, False on error
  192. """
  193. return self.ciface.has_raster_timestamp(self.get_name(),
  194. self.get_mapset())
  195. def read_timestamp_from_grass(self):
  196. """Read the timestamp of this map from the map metadata
  197. in the grass file system based spatial database and
  198. set the internal time stamp that should be insert/updated
  199. in the temporal database.
  200. :return: True if success, False on error
  201. """
  202. if not self.has_grass_timestamp():
  203. return False
  204. check, dates = self.ciface.read_raster_timestamp(self.get_name(),
  205. self.get_mapset(),)
  206. if check < 1:
  207. self.msgr.error(_("Unable to read timestamp file "
  208. "for raster map <%s>" % (self.get_map_id())))
  209. return False
  210. if len(dates) == 2:
  211. self.set_absolute_time(dates[0], dates[1])
  212. else:
  213. self.set_relative_time(dates[0], dates[1], dates[2])
  214. return True
  215. def write_timestamp_to_grass(self):
  216. """Write the timestamp of this map into the map metadata in
  217. the grass file system based spatial database.
  218. Internally the libgis API functions are used for writing
  219. :return: True if success, False on error
  220. """
  221. check = self.ciface.write_raster_timestamp(self.get_name(),
  222. self.get_mapset(),
  223. self._convert_timestamp())
  224. if check == -1:
  225. self.msgr.error(_("Unable to create timestamp file "
  226. "for raster map <%s>" % (self.get_map_id())))
  227. return False
  228. if check == -2:
  229. self.msgr.error(_("Invalid datetime in timestamp for raster map "
  230. "<%s>" % (self.get_map_id())))
  231. return False
  232. if check == -3:
  233. self.msgr.error(_("Internal error"))
  234. return False
  235. return True
  236. def remove_timestamp_from_grass(self):
  237. """Remove the timestamp from the grass file system based
  238. spatial database
  239. Internally the libgis API functions are used for removal
  240. :return: True if success, False on error
  241. """
  242. check = self.ciface.remove_raster_timestamp(self.get_name(),
  243. self.get_mapset())
  244. if check == -1:
  245. self.msgr.error(_("Unable to remove timestamp for raster map <%s>"
  246. % (self.get_name())))
  247. return False
  248. return True
  249. def read_band_reference_from_grass(self):
  250. """Read the band identifier of this map from the map metadata
  251. in the GRASS file system based spatial database and
  252. set the internal band identifier that should be insert/updated
  253. in the temporal database.
  254. :return: True if success, False on error
  255. """
  256. check, band_ref = self.ciface.read_raster_band_reference(self.get_name(),
  257. self.get_mapset())
  258. if check < 1:
  259. self.msgr.error(_("Unable to read band reference file "
  260. "for raster map <%s>" % (self.get_map_id())))
  261. return False
  262. self.metadata.set_band_reference(band_ref)
  263. return True
  264. def write_band_reference_to_grass(self):
  265. """Write the band identifier of this map into the map metadata in
  266. the GRASS file system based spatial database.
  267. Internally the libgis API functions are used for writing
  268. :return: True if success, False on error
  269. """
  270. check = self.ciface.write_raster_band_reference(self.get_name(),
  271. self.get_mapset(),
  272. self.metadata.get_band_reference())
  273. if check == -1:
  274. self.msgr.error(_("Unable to write band identifier for raster map <%s>"
  275. % (self.get_name())))
  276. return False
  277. return True
  278. def map_exists(self):
  279. """Return True in case the map exists in the grass spatial database
  280. :return: True if map exists, False otherwise
  281. """
  282. return self.ciface.raster_map_exists(self.get_name(),
  283. self.get_mapset())
  284. def load(self):
  285. """Load all info from an existing raster map into the internal structure
  286. This method checks first if the map exists, in case it exists
  287. the metadata of the map is put into this object and True is returned
  288. :return: True is the map exists and the metadata was filled
  289. successfully and getting the data was successful,
  290. False otherwise
  291. """
  292. if self.map_exists() is not True:
  293. return False
  294. # Fill base information
  295. self.base.set_creator(str(getpass.getuser()))
  296. kvp = self.ciface.read_raster_info(self.get_name(),
  297. self.get_mapset())
  298. if kvp:
  299. # Fill spatial extent
  300. self.set_spatial_extent_from_values(north=kvp["north"],
  301. south=kvp["south"],
  302. east=kvp["east"],
  303. west=kvp["west"])
  304. # Fill metadata
  305. self.metadata.set_nsres(kvp["nsres"])
  306. self.metadata.set_ewres(kvp["ewres"])
  307. self.metadata.set_datatype(kvp["datatype"])
  308. self.metadata.set_min(kvp["min"])
  309. self.metadata.set_max(kvp["max"])
  310. rows = int(kvp["rows"])
  311. cols = int(kvp["cols"])
  312. ncells = cols * rows
  313. self.metadata.set_cols(cols)
  314. self.metadata.set_rows(rows)
  315. self.metadata.set_number_of_cells(ncells)
  316. # Fill band reference if defined
  317. check, band_ref = self.ciface.read_raster_band_reference(self.get_name(),
  318. self.get_mapset())
  319. if check > 0:
  320. self.metadata.set_band_reference(band_ref)
  321. return True
  322. return False
  323. def set_band_reference(self, band_reference):
  324. """Set band reference identifier
  325. Metadata is updated in order to propagate band identifier into
  326. temporal DB.
  327. File-based band identifier stored in GRASS data base.
  328. :param str band_reference: band reference identifier (eg. S2_1)
  329. """
  330. self.metadata.set_band_reference(band_reference)
  331. self.write_band_reference_to_grass()
  332. ###############################################################################
  333. class Raster3DDataset(AbstractMapDataset):
  334. """Raster3d dataset class
  335. This class provides functions to select, update, insert or delete raster3d
  336. map information and valid time stamps into the SQL temporal database.
  337. Usage:
  338. .. code-block:: python
  339. >>> import grass.script as gs
  340. >>> init()
  341. >>> gs.use_temp_region()
  342. >>> gs.run_command("g.region", n=80.0, s=0.0, e=120.0, w=0.0,
  343. ... t=100.0, b=0.0, res=10.0, res3=10.0)
  344. 0
  345. >>> gs.run_command("r3.mapcalc", overwrite=True, quiet=True,
  346. ... expression="str3ds_map_test_case = 1")
  347. 0
  348. >>> gs.run_command("r3.timestamp", map="str3ds_map_test_case",
  349. ... date="15 jan 1999", quiet=True)
  350. 0
  351. >>> mapset = get_current_mapset()
  352. >>> name = "str3ds_map_test_case"
  353. >>> identifier = "%s@%s" % (name, mapset)
  354. >>> r3map = Raster3DDataset(identifier)
  355. >>> r3map.map_exists()
  356. True
  357. >>> r3map.read_timestamp_from_grass()
  358. True
  359. >>> r3map.get_temporal_extent_as_tuple()
  360. (datetime.datetime(1999, 1, 15, 0, 0), None)
  361. >>> r3map.load()
  362. True
  363. >>> r3map.spatial_extent.print_info()
  364. +-------------------- Spatial extent ----------------------------------------+
  365. | North:...................... 80.0
  366. | South:...................... 0.0
  367. | East:.. .................... 120.0
  368. | West:....................... 0.0
  369. | Top:........................ 100.0
  370. | Bottom:..................... 0.0
  371. >>> r3map.absolute_time.print_info()
  372. +-------------------- Absolute time -----------------------------------------+
  373. | Start time:................. 1999-01-15 00:00:00
  374. | End time:................... None
  375. >>> r3map.metadata.print_info()
  376. +-------------------- Metadata information ----------------------------------+
  377. | Datatype:................... DCELL
  378. | Number of columns:.......... 8
  379. | Number of rows:............. 12
  380. | Number of cells:............ 960
  381. | North-South resolution:..... 10.0
  382. | East-west resolution:....... 10.0
  383. | Minimum value:.............. 1.0
  384. | Maximum value:.............. 1.0
  385. | Number of depths:........... 10
  386. | Top-Bottom resolution:...... 10.0
  387. >>> gs.run_command("r3.timestamp", map="str3ds_map_test_case",
  388. ... date="2 years", quiet=True)
  389. 0
  390. >>> r3map.read_timestamp_from_grass()
  391. True
  392. >>> r3map.get_temporal_extent_as_tuple()
  393. (2, None)
  394. >>> r3map.get_relative_time_unit()
  395. 'years'
  396. >>> r3map.is_in_db()
  397. False
  398. >>> r3map.is_stds()
  399. False
  400. >>> newmap = r3map.get_new_instance("new@PERMANENT")
  401. >>> isinstance(newmap, Raster3DDataset)
  402. True
  403. >>> newstr3ds = r3map.get_new_stds_instance("new@PERMANENT")
  404. >>> isinstance(newstr3ds, SpaceTimeRaster3DDataset)
  405. True
  406. >>> r3map.get_type()
  407. 'raster3d'
  408. >>> r3map.set_absolute_time(start_time=datetime(2001,1,1),
  409. ... end_time=datetime(2012,1,1))
  410. True
  411. >>> r3map.get_absolute_time()
  412. (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2012, 1, 1, 0, 0))
  413. >>> r3map.get_temporal_extent_as_tuple()
  414. (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2012, 1, 1, 0, 0))
  415. >>> r3map.get_name()
  416. 'str3ds_map_test_case'
  417. >>> r3map.get_mapset() == mapset
  418. True
  419. >>> r3map.get_temporal_type()
  420. 'absolute'
  421. >>> r3map.get_spatial_extent_as_tuple()
  422. (80.0, 0.0, 120.0, 0.0, 100.0, 0.0)
  423. >>> r3map.is_time_absolute()
  424. True
  425. >>> r3map.is_time_relative()
  426. False
  427. >>> gs.run_command("g.remove", flags="f", type="raster_3d", name=name, quiet=True)
  428. 0
  429. >>> gs.del_temp_region()
  430. """
  431. def __init__(self, ident):
  432. AbstractMapDataset.__init__(self)
  433. self.reset(ident)
  434. def is_stds(self):
  435. """Return True if this class is a space time dataset
  436. :return: True if this class is a space time dataset, False otherwise
  437. """
  438. return False
  439. def get_type(self):
  440. return "raster3d"
  441. def get_new_instance(self, ident):
  442. """Return a new instance with the type of this class"""
  443. return Raster3DDataset(ident)
  444. def get_new_stds_instance(self, ident):
  445. """Return a new space time dataset instance in which maps
  446. are stored with the type of this class"""
  447. return SpaceTimeRaster3DDataset(ident)
  448. def spatial_overlapping(self, dataset):
  449. """Return True if the spatial extents overlap"""
  450. if self.get_type() == dataset.get_type() or dataset.get_type() == "str3ds":
  451. return self.spatial_extent.overlapping(dataset.spatial_extent)
  452. else:
  453. return self.spatial_extent.overlapping_2d(dataset.spatial_extent)
  454. def spatial_relation(self, dataset):
  455. """Return the two or three dimensional spatial relation"""
  456. if self.get_type() == dataset.get_type() or dataset.get_type() == "str3ds":
  457. return self.spatial_extent.spatial_relation(dataset.spatial_extent)
  458. else:
  459. return self.spatial_extent.spatial_relation_2d(dataset.spatial_extent)
  460. def spatial_intersection(self, dataset):
  461. """Return the three or two dimensional intersection as spatial_extent
  462. object or None in case no intersection was found.
  463. :param dataset: The abstract dataset to intersect with
  464. :return: The intersection spatial extent or None
  465. """
  466. if self.get_type() == dataset.get_type() or dataset.get_type() == "str3ds":
  467. return self.spatial_extent.intersect(dataset.spatial_extent)
  468. else:
  469. return self.spatial_extent.intersect_2d(dataset.spatial_extent)
  470. def spatial_union(self, dataset):
  471. """Return the three or two dimensional union as spatial_extent
  472. object or None in case the extents does not overlap or meet.
  473. :param dataset: The abstract dataset to create a union with
  474. :return: The union spatial extent or None
  475. """
  476. if self.get_type() == dataset.get_type() or dataset.get_type() == "str3ds":
  477. return self.spatial_extent.union(dataset.spatial_extent)
  478. else:
  479. return self.spatial_extent.union_2d(dataset.spatial_extent)
  480. def spatial_disjoint_union(self, dataset):
  481. """Return the three or two dimensional union as spatial_extent object.
  482. :param dataset: The abstract dataset to create a union with
  483. :return: The union spatial extent
  484. """
  485. if self.get_type() == dataset.get_type() or dataset.get_type() == "str3ds":
  486. return self.spatial_extent.disjoint_union(dataset.spatial_extent)
  487. else:
  488. return self.spatial_extent.disjoint_union_2d(dataset.spatial_extent)
  489. def get_np_array(self):
  490. """Return this 3D raster map as memmap numpy style array to access the
  491. 3D raster values in numpy style without loading the whole map in
  492. the RAM.
  493. In case this 3D raster map does exists in the grass spatial database,
  494. the map will be exported using r3.out.bin to a temporary location
  495. and assigned to the memmap object that is returned by this function.
  496. In case the 3D raster map does not exist, an empty temporary
  497. binary file will be created and assigned to the memap object.
  498. You need to call the write function to write the memmap
  499. array back into grass.
  500. """
  501. a = garray.array3d()
  502. if self.map_exists():
  503. a.read(self.get_map_id())
  504. return a
  505. def reset(self, ident):
  506. """Reset the internal structure and set the identifier"""
  507. self.base = Raster3DBase(ident=ident)
  508. self.absolute_time = Raster3DAbsoluteTime(ident=ident)
  509. self.relative_time = Raster3DRelativeTime(ident=ident)
  510. self.spatial_extent = Raster3DSpatialExtent(ident=ident)
  511. self.metadata = Raster3DMetadata(ident=ident)
  512. self.stds_register = Raster3DSTDSRegister(ident=ident)
  513. def has_grass_timestamp(self):
  514. """Check if a grass file bsased time stamp exists for this map.
  515. :return: True if success, False on error
  516. """
  517. return self.ciface.has_raster3d_timestamp(self.get_name(),
  518. self.get_mapset())
  519. def read_timestamp_from_grass(self):
  520. """Read the timestamp of this map from the map metadata
  521. in the grass file system based spatial database and
  522. set the internal time stamp that should be insert/updated
  523. in the temporal database.
  524. :return: True if success, False on error
  525. """
  526. if not self.has_grass_timestamp():
  527. return False
  528. check, dates = self.ciface.read_raster3d_timestamp(self.get_name(),
  529. self.get_mapset(),)
  530. if check < 1:
  531. self.msgr.error(_("Unable to read timestamp file "
  532. "for 3D raster map <%s>" % (self.get_map_id())))
  533. return False
  534. if len(dates) == 2:
  535. self.set_absolute_time(dates[0], dates[1])
  536. else:
  537. self.set_relative_time(dates[0], dates[1], dates[2])
  538. return True
  539. def write_timestamp_to_grass(self):
  540. """Write the timestamp of this map into the map metadata
  541. in the grass file system based spatial database.
  542. Internally the libgis API functions are used for writing
  543. :return: True if success, False on error
  544. """
  545. check = self.ciface.write_raster3d_timestamp(self.get_name(),
  546. self.get_mapset(),
  547. self._convert_timestamp())
  548. if check == -1:
  549. self.msgr.error(_("Unable to create timestamp file "
  550. "for 3D raster map <%s>" % (self.get_map_id())))
  551. return False
  552. if check == -2:
  553. self.msgr.error(_("Invalid datetime in timestamp for 3D raster "
  554. "map <%s>" % (self.get_map_id())))
  555. return False
  556. if check == -3:
  557. self.msgr.error(_("Internal error"))
  558. return False
  559. return True
  560. def remove_timestamp_from_grass(self):
  561. """Remove the timestamp from the grass file system based spatial database
  562. :return: True if success, False on error
  563. """
  564. check = self.ciface.remove_raster3d_timestamp(self.get_name(),
  565. self.get_mapset())
  566. if check == -1:
  567. self.msgr.error(_("Unable to remove timestamp for raster map "
  568. "<%s>" % (self.get_name())))
  569. return False
  570. return True
  571. def map_exists(self):
  572. """Return True in case the map exists in the grass spatial database
  573. :return: True if map exists, False otherwise
  574. """
  575. return self.ciface.raster3d_map_exists(self.get_name(),
  576. self.get_mapset())
  577. def load(self):
  578. """Load all info from an existing 3d raster map into the internal structure
  579. This method checks first if the map exists, in case it exists
  580. the metadata of the map is put into this object and True is returned
  581. :return: True is the map exists and the metadata was filled
  582. successfully and getting the data was successful,
  583. False otherwise
  584. """
  585. if self.map_exists() is not True:
  586. return False
  587. # Fill base information
  588. self.base.set_creator(str(getpass.getuser()))
  589. # Fill spatial extent
  590. kvp = self.ciface.read_raster3d_info(self.get_name(),
  591. self.get_mapset())
  592. if kvp:
  593. self.set_spatial_extent_from_values(north=kvp["north"],
  594. south=kvp["south"],
  595. east=kvp["east"],
  596. west=kvp["west"],
  597. top=kvp["top"],
  598. bottom=kvp["bottom"])
  599. # Fill metadata
  600. self.metadata.set_nsres(kvp["nsres"])
  601. self.metadata.set_ewres(kvp["ewres"])
  602. self.metadata.set_tbres(kvp["tbres"])
  603. self.metadata.set_datatype(kvp["datatype"])
  604. self.metadata.set_min(kvp["min"])
  605. self.metadata.set_max(kvp["max"])
  606. rows = int(kvp["rows"])
  607. cols = int(kvp["cols"])
  608. depths = int(kvp["depths"])
  609. ncells = cols * rows * depths
  610. self.metadata.set_cols(cols)
  611. self.metadata.set_rows(rows)
  612. self.metadata.set_depths(depths)
  613. self.metadata.set_number_of_cells(ncells)
  614. return True
  615. return False
  616. ###############################################################################
  617. class VectorDataset(AbstractMapDataset):
  618. """Vector dataset class
  619. This class provides functions to select, update, insert or delete vector
  620. map information and valid time stamps into the SQL temporal database.
  621. Usage:
  622. .. code-block:: python
  623. >>> import grass.script as gs
  624. >>> init()
  625. >>> gs.use_temp_region()
  626. >>> gs.run_command("g.region", n=80.0, s=0.0, e=120.0, w=0.0,
  627. ... t=1.0, b=0.0, res=10.0)
  628. 0
  629. >>> gs.run_command("v.random", overwrite=True, output="stvds_map_test_case",
  630. ... n=100, zmin=0, zmax=100, flags="z", column="elevation", quiet=True)
  631. 0
  632. >>> gs.run_command("v.timestamp", map="stvds_map_test_case",
  633. ... date="15 jan 1999", quiet=True)
  634. 0
  635. >>> mapset = get_current_mapset()
  636. >>> name = "stvds_map_test_case"
  637. >>> identifier = "%s@%s" % (name, mapset)
  638. >>> vmap = VectorDataset(identifier)
  639. >>> vmap.map_exists()
  640. True
  641. >>> vmap.read_timestamp_from_grass()
  642. True
  643. >>> vmap.get_temporal_extent_as_tuple()
  644. (datetime.datetime(1999, 1, 15, 0, 0), None)
  645. >>> vmap.load()
  646. True
  647. >>> vmap.absolute_time.print_info()
  648. +-------------------- Absolute time -----------------------------------------+
  649. | Start time:................. 1999-01-15 00:00:00
  650. | End time:................... None
  651. >>> vmap.metadata.print_info()
  652. +-------------------- Metadata information ----------------------------------+
  653. | Is map 3d .................. True
  654. | Number of points ........... 100
  655. | Number of lines ............ 0
  656. | Number of boundaries ....... 0
  657. | Number of centroids ........ 0
  658. | Number of faces ............ 0
  659. | Number of kernels .......... 0
  660. | Number of primitives ....... 100
  661. | Number of nodes ............ 0
  662. | Number of areas ............ 0
  663. | Number of islands .......... 0
  664. | Number of holes ............ 0
  665. | Number of volumes .......... 0
  666. >>> gs.run_command("v.timestamp", map="stvds_map_test_case",
  667. ... date="2 years", quiet=True)
  668. 0
  669. >>> vmap.read_timestamp_from_grass()
  670. True
  671. >>> vmap.get_temporal_extent_as_tuple()
  672. (2, None)
  673. >>> vmap.get_relative_time_unit()
  674. 'years'
  675. >>> vmap.is_in_db()
  676. False
  677. >>> vmap.is_stds()
  678. False
  679. >>> newmap = vmap.get_new_instance("new@PERMANENT")
  680. >>> isinstance(newmap, VectorDataset)
  681. True
  682. >>> newstvds = vmap.get_new_stds_instance("new@PERMANENT")
  683. >>> isinstance(newstvds, SpaceTimeVectorDataset)
  684. True
  685. >>> vmap.get_type()
  686. 'vector'
  687. >>> vmap.set_absolute_time(start_time=datetime(2001,1,1),
  688. ... end_time=datetime(2012,1,1))
  689. True
  690. >>> vmap.get_absolute_time()
  691. (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2012, 1, 1, 0, 0))
  692. >>> vmap.get_temporal_extent_as_tuple()
  693. (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2012, 1, 1, 0, 0))
  694. >>> vmap.get_name()
  695. 'stvds_map_test_case'
  696. >>> vmap.get_mapset() == mapset
  697. True
  698. >>> vmap.get_temporal_type()
  699. 'absolute'
  700. >>> vmap.is_time_absolute()
  701. True
  702. >>> vmap.is_time_relative()
  703. False
  704. >>> gs.run_command("g.remove", flags="f", type="vector", name=name, quiet=True)
  705. 0
  706. >>> gs.del_temp_region()
  707. """
  708. def __init__(self, ident):
  709. AbstractMapDataset.__init__(self)
  710. self.reset(ident)
  711. def is_stds(self):
  712. """Return True if this class is a space time dataset
  713. :return: True if this class is a space time dataset, False otherwise
  714. """
  715. return False
  716. def get_type(self):
  717. return "vector"
  718. def get_new_instance(self, ident):
  719. """Return a new instance with the type of this class"""
  720. return VectorDataset(ident)
  721. def get_new_stds_instance(self, ident):
  722. """Return a new space time dataset instance in which maps
  723. are stored with the type of this class"""
  724. return SpaceTimeVectorDataset(ident)
  725. def get_layer(self):
  726. """Return the layer"""
  727. return self.base.get_layer()
  728. def spatial_overlapping(self, dataset):
  729. """Return True if the spatial extents 2d overlap"""
  730. return self.spatial_extent.overlapping_2d(dataset.spatial_extent)
  731. def spatial_relation(self, dataset):
  732. """Return the two dimensional spatial relation"""
  733. return self.spatial_extent.spatial_relation_2d(dataset.spatial_extent)
  734. def spatial_intersection(self, dataset):
  735. """Return the two dimensional intersection as spatial_extent
  736. object or None in case no intersection was found.
  737. :param dataset: The abstract dataset to intersect with
  738. :return: The intersection spatial extent or None
  739. """
  740. return self.spatial_extent.intersect_2d(dataset.spatial_extent)
  741. def spatial_union(self, dataset):
  742. """Return the two dimensional union as spatial_extent
  743. object or None in case the extents does not overlap or meet.
  744. :param dataset: The abstract dataset to create a union with
  745. :return: The union spatial extent or None
  746. """
  747. return self.spatial_extent.union_2d(dataset.spatial_extent)
  748. def spatial_disjoint_union(self, dataset):
  749. """Return the two dimensional union as spatial_extent object.
  750. :param dataset: The abstract dataset to create a union with
  751. :return: The union spatial extent
  752. """
  753. return self.spatial_extent.disjoint_union_2d(dataset.spatial_extent)
  754. def reset(self, ident):
  755. """Reset the internal structure and set the identifier"""
  756. self.base = VectorBase(ident=ident)
  757. self.absolute_time = VectorAbsoluteTime(ident=ident)
  758. self.relative_time = VectorRelativeTime(ident=ident)
  759. self.spatial_extent = VectorSpatialExtent(ident=ident)
  760. self.metadata = VectorMetadata(ident=ident)
  761. self.stds_register = VectorSTDSRegister(ident=ident)
  762. def has_grass_timestamp(self):
  763. """Check if a grass file bsased time stamp exists for this map.
  764. """
  765. return self.ciface.has_vector_timestamp(self.get_name(),
  766. self.get_mapset(),
  767. self.get_layer())
  768. def read_timestamp_from_grass(self):
  769. """Read the timestamp of this map from the map metadata
  770. in the grass file system based spatial database and
  771. set the internal time stamp that should be insert/updated
  772. in the temporal database.
  773. """
  774. if not self.has_grass_timestamp():
  775. return False
  776. check, dates = self.ciface.read_vector_timestamp(self.get_name(),
  777. self.get_mapset(),)
  778. if check < 1:
  779. self.msgr.error(_("Unable to read timestamp file "
  780. "for vector map <%s>" % (self.get_map_id())))
  781. return False
  782. if len(dates) == 2:
  783. self.set_absolute_time(dates[0], dates[1])
  784. else:
  785. self.set_relative_time(dates[0], dates[1], dates[2])
  786. return True
  787. def write_timestamp_to_grass(self):
  788. """Write the timestamp of this map into the map metadata in
  789. the grass file system based spatial database.
  790. Internally the libgis API functions are used for writing
  791. """
  792. check = self.ciface.write_vector_timestamp(self.get_name(),
  793. self.get_mapset(),
  794. self._convert_timestamp(),
  795. self.get_layer())
  796. if check == -1:
  797. self.msgr.error(_("Unable to create timestamp file "
  798. "for vector map <%s>" % (self.get_map_id())))
  799. return False
  800. if check == -2:
  801. self.msgr.error(_("Invalid datetime in timestamp for vector "
  802. "map <%s>" % (self.get_map_id())))
  803. return False
  804. return True
  805. def remove_timestamp_from_grass(self):
  806. """Remove the timestamp from the grass file system based spatial
  807. database
  808. Internally the libgis API functions are used for removal
  809. """
  810. check = self.ciface.remove_vector_timestamp(self.get_name(),
  811. self.get_mapset())
  812. if check == -1:
  813. self.msgr.error(_("Unable to remove timestamp for vector "
  814. "map <%s>" % (self.get_name())))
  815. return False
  816. return True
  817. def map_exists(self):
  818. """Return True in case the map exists in the grass spatial database
  819. :return: True if map exists, False otherwise
  820. """
  821. return self.ciface.vector_map_exists(self.get_name(),
  822. self.get_mapset())
  823. def load(self):
  824. """Load all info from an existing vector map into the internal structure
  825. This method checks first if the map exists, in case it exists
  826. the metadata of the map is put into this object and True is returned
  827. :return: True is the map exists and the metadata was filled
  828. successfully and getting the data was successful,
  829. False otherwise
  830. """
  831. if self.map_exists() is not True:
  832. return False
  833. # Fill base information
  834. self.base.set_creator(str(getpass.getuser()))
  835. # Get the data from an existing vector map
  836. kvp = self.ciface.read_vector_info(self.get_name(),
  837. self.get_mapset())
  838. if kvp:
  839. # Fill spatial extent
  840. self.set_spatial_extent_from_values(north=kvp["north"],
  841. south=kvp["south"],
  842. east=kvp["east"],
  843. west=kvp["west"],
  844. top=kvp["top"],
  845. bottom=kvp["bottom"])
  846. # Fill metadata
  847. self.metadata.set_3d_info(kvp["map3d"])
  848. self.metadata.set_number_of_points(kvp["points"])
  849. self.metadata.set_number_of_lines(kvp["lines"])
  850. self.metadata.set_number_of_boundaries(kvp["boundaries"])
  851. self.metadata.set_number_of_centroids(kvp["centroids"])
  852. self.metadata.set_number_of_faces(kvp["faces"])
  853. self.metadata.set_number_of_kernels(kvp["kernels"])
  854. self.metadata.set_number_of_primitives(kvp["primitives"])
  855. self.metadata.set_number_of_nodes(kvp["nodes"])
  856. self.metadata.set_number_of_areas(kvp["areas"])
  857. self.metadata.set_number_of_islands(kvp["islands"])
  858. self.metadata.set_number_of_holes(kvp["holes"])
  859. self.metadata.set_number_of_volumes(kvp["volumes"])
  860. return True
  861. return False
  862. ###############################################################################
  863. class SpaceTimeRasterDataset(AbstractSpaceTimeDataset):
  864. """Space time raster dataset class
  865. .. code-block:: python
  866. >>> import grass.temporal as tgis
  867. >>> tgis.init()
  868. >>> mapset = tgis.get_current_mapset()
  869. >>> strds = tgis.SpaceTimeRasterDataset("old@%s"%mapset)
  870. >>> strds.is_in_db()
  871. False
  872. >>> strds.is_stds()
  873. True
  874. >>> strds.get_type()
  875. 'strds'
  876. >>> newstrds = strds.get_new_instance("newstrds@%s"%mapset)
  877. >>> isinstance(newstrds, SpaceTimeRasterDataset)
  878. True
  879. >>> newmap = strds.get_new_map_instance("newmap@%s"%mapset)
  880. >>> isinstance(newmap, RasterDataset)
  881. True
  882. >>> strds.reset("new@%s"%mapset)
  883. >>> strds.is_in_db()
  884. False
  885. >>> strds.reset(None)
  886. >>> strds.is_in_db()
  887. False
  888. >>> strds.get_id()
  889. ...
  890. """
  891. def __init__(self, ident):
  892. AbstractSpaceTimeDataset.__init__(self, ident)
  893. def set_band_reference(self, band_reference):
  894. """Set band reference identifier
  895. :param str band_reference: band reference identifier (eg. S2_1)
  896. """
  897. self.band_reference = band_reference
  898. def is_stds(self):
  899. """Return True if this class is a space time dataset
  900. :return: True if this class is a space time dataset, False otherwise
  901. """
  902. return True
  903. def get_type(self):
  904. return "strds"
  905. def get_new_instance(self, ident):
  906. """Return a new instance with the type of this class"""
  907. return SpaceTimeRasterDataset(ident)
  908. def get_new_map_instance(self, ident):
  909. """Return a new instance of a map dataset which is associated "
  910. "with the type of this class"""
  911. return RasterDataset(ident)
  912. def get_map_register(self):
  913. """Return the name of the map register table"""
  914. return self.metadata.get_raster_register()
  915. def set_map_register(self, name):
  916. """Set the name of the map register table"""
  917. self.metadata.set_raster_register(name)
  918. def spatial_overlapping(self, dataset):
  919. """Return True if the spatial extents 2d overlap"""
  920. return self.spatial_extent.overlapping_2d(dataset.spatial_extent)
  921. def spatial_relation(self, dataset):
  922. """Return the two dimensional spatial relation"""
  923. return self.spatial_extent.spatial_relation_2d(dataset.spatial_extent)
  924. def spatial_intersection(self, dataset):
  925. """Return the two dimensional intersection as spatial_extent
  926. object or None in case no intersection was found.
  927. :param dataset: The abstract dataset to intersect with
  928. :return: The intersection spatial extent or None
  929. """
  930. return self.spatial_extent.intersect_2d(dataset.spatial_extent)
  931. def spatial_union(self, dataset):
  932. """Return the two dimensional union as spatial_extent
  933. object or None in case the extents does not overlap or meet.
  934. :param dataset: The abstract dataset to create a union with
  935. :return: The union spatial extent or None
  936. """
  937. return self.spatial_extent.union_2d(dataset.spatial_extent)
  938. def spatial_disjoint_union(self, dataset):
  939. """Return the two dimensional union as spatial_extent object.
  940. :param dataset: The abstract dataset to create a union with
  941. :return: The union spatial extent
  942. """
  943. return self.spatial_extent.disjoint_union_2d(dataset.spatial_extent)
  944. def reset(self, ident):
  945. """Reset the internal structure and set the identifier"""
  946. self.base = STRDSBase(ident=ident)
  947. self.base.set_creator(str(getpass.getuser()))
  948. self.absolute_time = STRDSAbsoluteTime(ident=ident)
  949. self.relative_time = STRDSRelativeTime(ident=ident)
  950. self.spatial_extent = STRDSSpatialExtent(ident=ident)
  951. self.metadata = STRDSMetadata(ident=ident)
  952. ###############################################################################
  953. class SpaceTimeRaster3DDataset(AbstractSpaceTimeDataset):
  954. """Space time raster3d dataset class
  955. .. code-block:: python
  956. >>> import grass.temporal as tgis
  957. >>> tgis.init()
  958. >>> mapset = tgis.get_current_mapset()
  959. >>> str3ds = tgis.SpaceTimeRaster3DDataset("old@%s"%mapset)
  960. >>> str3ds.is_in_db()
  961. False
  962. >>> str3ds.is_stds()
  963. True
  964. >>> str3ds.get_type()
  965. 'str3ds'
  966. >>> newstrds = str3ds.get_new_instance("newstrds@%s"%mapset)
  967. >>> isinstance(newstrds, SpaceTimeRaster3DDataset)
  968. True
  969. >>> newmap = str3ds.get_new_map_instance("newmap@%s"%mapset)
  970. >>> isinstance(newmap, Raster3DDataset)
  971. True
  972. >>> str3ds.reset("new@%s"%mapset)
  973. >>> str3ds.is_in_db()
  974. False
  975. >>> str3ds.reset(None)
  976. >>> str3ds.is_in_db()
  977. False
  978. >>> str3ds.get_id()
  979. ...
  980. """
  981. def __init__(self, ident):
  982. AbstractSpaceTimeDataset.__init__(self, ident)
  983. def is_stds(self):
  984. """Return True if this class is a space time dataset
  985. :return: True if this class is a space time dataset, False otherwise
  986. """
  987. return True
  988. def get_type(self):
  989. return "str3ds"
  990. def get_new_instance(self, ident):
  991. """Return a new instance with the type of this class"""
  992. return SpaceTimeRaster3DDataset(ident)
  993. def get_new_map_instance(self, ident):
  994. """Return a new instance of a map dataset which is associated
  995. with the type of this class"""
  996. return Raster3DDataset(ident)
  997. def get_map_register(self):
  998. """Return the name of the map register table"""
  999. return self.metadata.get_raster3d_register()
  1000. def set_map_register(self, name):
  1001. """Set the name of the map register table"""
  1002. self.metadata.set_raster3d_register(name)
  1003. def spatial_overlapping(self, dataset):
  1004. """Return True if the spatial extents overlap"""
  1005. if self.get_type() == dataset.get_type() or dataset.get_type() == "str3ds":
  1006. return self.spatial_extent.overlapping(dataset.spatial_extent)
  1007. else:
  1008. return self.spatial_extent.overlapping_2d(dataset.spatial_extent)
  1009. def spatial_relation(self, dataset):
  1010. """Return the two or three dimensional spatial relation"""
  1011. if self.get_type() == dataset.get_type() or \
  1012. dataset.get_type() == "str3ds":
  1013. return self.spatial_extent.spatial_relation(dataset.spatial_extent)
  1014. else:
  1015. return self.spatial_extent.spatial_relation_2d(dataset.spatial_extent)
  1016. def spatial_intersection(self, dataset):
  1017. """Return the three or two dimensional intersection as spatial_extent
  1018. object or None in case no intersection was found.
  1019. :param dataset: The abstract dataset to intersect with
  1020. :return: The intersection spatial extent or None
  1021. """
  1022. if self.get_type() == dataset.get_type() or dataset.get_type() == "raster3d":
  1023. return self.spatial_extent.intersect(dataset.spatial_extent)
  1024. else:
  1025. return self.spatial_extent.intersect_2d(dataset.spatial_extent)
  1026. def spatial_union(self, dataset):
  1027. """Return the three or two dimensional union as spatial_extent
  1028. object or None in case the extents does not overlap or meet.
  1029. :param dataset: The abstract dataset to create a union with
  1030. :return: The union spatial extent or None
  1031. """
  1032. if self.get_type() == dataset.get_type() or dataset.get_type() == "raster3d":
  1033. return self.spatial_extent.union(dataset.spatial_extent)
  1034. else:
  1035. return self.spatial_extent.union_2d(dataset.spatial_extent)
  1036. def spatial_disjoint_union(self, dataset):
  1037. """Return the three or two dimensional union as spatial_extent object.
  1038. :param dataset: The abstract dataset to create a union with
  1039. :return: The union spatial extent
  1040. """
  1041. if self.get_type() == dataset.get_type() or dataset.get_type() == "raster3d":
  1042. return self.spatial_extent.disjoint_union(dataset.spatial_extent)
  1043. else:
  1044. return self.spatial_extent.disjoint_union_2d(dataset.spatial_extent)
  1045. def reset(self, ident):
  1046. """Reset the internal structure and set the identifier"""
  1047. self.base = STR3DSBase(ident=ident)
  1048. self.base.set_creator(str(getpass.getuser()))
  1049. self.absolute_time = STR3DSAbsoluteTime(ident=ident)
  1050. self.relative_time = STR3DSRelativeTime(ident=ident)
  1051. self.spatial_extent = STR3DSSpatialExtent(ident=ident)
  1052. self.metadata = STR3DSMetadata(ident=ident)
  1053. ###############################################################################
  1054. class SpaceTimeVectorDataset(AbstractSpaceTimeDataset):
  1055. """Space time vector dataset class
  1056. .. code-block:: python
  1057. >>> import grass.temporal as tgis
  1058. >>> tgis.init()
  1059. >>> mapset = tgis.get_current_mapset()
  1060. >>> stvds = tgis.SpaceTimeVectorDataset("old@%s"%mapset)
  1061. >>> stvds.is_in_db()
  1062. False
  1063. >>> stvds.is_stds()
  1064. True
  1065. >>> stvds.get_type()
  1066. 'stvds'
  1067. >>> newstvds = stvds.get_new_instance("newstvds@%s"%mapset)
  1068. >>> isinstance(newstvds, SpaceTimeVectorDataset)
  1069. True
  1070. >>> newmap = stvds.get_new_map_instance("newmap@%s"%mapset)
  1071. >>> isinstance(newmap, VectorDataset)
  1072. True
  1073. >>> stvds.reset("new@%s"%mapset)
  1074. >>> stvds.is_in_db()
  1075. False
  1076. >>> stvds.reset(None)
  1077. >>> stvds.is_in_db()
  1078. False
  1079. >>> stvds.get_id()
  1080. ...
  1081. """
  1082. def __init__(self, ident):
  1083. AbstractSpaceTimeDataset.__init__(self, ident)
  1084. def is_stds(self):
  1085. """Return True if this class is a space time dataset
  1086. :return: True if this class is a space time dataset, False otherwise
  1087. """
  1088. return True
  1089. def get_type(self):
  1090. return "stvds"
  1091. def get_new_instance(self, ident):
  1092. """Return a new instance with the type of this class"""
  1093. return SpaceTimeVectorDataset(ident)
  1094. def get_new_map_instance(self, ident):
  1095. """Return a new instance of a map dataset which is associated
  1096. with the type of this class"""
  1097. return VectorDataset(ident)
  1098. def get_map_register(self):
  1099. """Return the name of the map register table"""
  1100. return self.metadata.get_vector_register()
  1101. def set_map_register(self, name):
  1102. """Set the name of the map register table"""
  1103. self.metadata.set_vector_register(name)
  1104. def spatial_overlapping(self, dataset):
  1105. """Return True if the spatial extents 2d overlap"""
  1106. return self.spatial_extent.overlapping_2d(dataset.spatial_extent)
  1107. def spatial_relation(self, dataset):
  1108. """Return the two dimensional spatial relation"""
  1109. return self.spatial_extent.spatial_relation_2d(dataset.spatial_extent)
  1110. def spatial_intersection(self, dataset):
  1111. """Return the two dimensional intersection as spatial_extent
  1112. object or None in case no intersection was found.
  1113. :param dataset: The abstract dataset to intersect with
  1114. :return: The intersection spatial extent or None
  1115. """
  1116. return self.spatial_extent.intersect_2d(dataset.spatial_extent)
  1117. def spatial_union(self, dataset):
  1118. """Return the two dimensional union as spatial_extent
  1119. object or None in case the extents does not overlap or meet.
  1120. :param dataset: The abstract dataset to create a union with
  1121. :return: The union spatial extent or None
  1122. """
  1123. return self.spatial_extent.union_2d(dataset.spatial_extent)
  1124. def spatial_disjoint_union(self, dataset):
  1125. """Return the two dimensional union as spatial_extent object.
  1126. :param dataset: The abstract dataset to create a union with
  1127. :return: The union spatial extent
  1128. """
  1129. return self.spatial_extent.disjoint_union_2d(dataset.spatial_extent)
  1130. def reset(self, ident):
  1131. """Reset the internal structure and set the identifier"""
  1132. self.base = STVDSBase(ident=ident)
  1133. self.base.set_creator(str(getpass.getuser()))
  1134. self.absolute_time = STVDSAbsoluteTime(ident=ident)
  1135. self.relative_time = STVDSRelativeTime(ident=ident)
  1136. self.spatial_extent = STVDSSpatialExtent(ident=ident)
  1137. self.metadata = STVDSMetadata(ident=ident)
  1138. ###############################################################################
  1139. if __name__ == "__main__":
  1140. import doctest
  1141. doctest.testmod()