space_time_datasets.py 54 KB

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