space_time_datasets.py 51 KB

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