space_time_datasets.py 51 KB

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