1# -*- coding: utf-8 -*- 2""" 3Temporal topology dataset connector class 4 5Usage: 6 7.. code-block:: python: 8 9 >>> import grass.temporal as tgis 10 >>> tmr = tgis.TemporalTopologyDatasetConnector() 11 12(C) 2012-2013 by the GRASS Development Team 13This program is free software under the GNU General Public 14License (>=v2). Read the file COPYING that comes with GRASS 15for details. 16 17:authors: Soeren Gebbert 18""" 19from __future__ import print_function 20import copy 21 22 23class TemporalTopologyDatasetConnector(object): 24 """This class implements a temporal topology access structure to connect 25 temporal related datasets 26 27 This object will be set up by temporal topology creation method provided 28 by the SpatioTemporalTopologyBuilder. 29 30 If correctly initialize the calls next() and prev() 31 let the user walk temporally forward and backward in time. 32 33 The following temporal relations with access methods are supported: 34 35 - equal 36 - follows 37 - precedes 38 - overlaps 39 - overlapped 40 - during (including starts, finishes) 41 - contains (including started, finished) 42 - starts 43 - started 44 - finishes 45 - finished 46 47 .. code-block:: python: 48 49 # We have build the temporal topology and we know the first map 50 start = first 51 while start: 52 53 # Print all maps this map temporally contains 54 dlist = start.get_contains() 55 for map in dlist: 56 map.print_info() 57 58 start = start.next() 59 60 >>> import grass.temporal as tgis 61 >>> tgis.init() 62 >>> map = tgis.RasterDataset("a@P") 63 >>> tmr = tgis.TemporalTopologyDatasetConnector() 64 >>> tmr.set_next(map) 65 >>> tmr.set_prev(map) 66 >>> tmr.append_equal(map) 67 >>> tmr.append_follows(map) 68 >>> tmr.append_precedes(map) 69 >>> tmr.append_overlapped(map) 70 >>> tmr.append_overlaps(map) 71 >>> tmr.append_during(map) 72 >>> tmr.append_contains(map) 73 >>> tmr.append_starts(map) 74 >>> tmr.append_started(map) 75 >>> tmr.append_finishes(map) 76 >>> tmr.append_finished(map) 77 >>> tmr.print_temporal_topology_info() 78 +-------------------- Temporal Topology -------------------------------------+ 79 | Next: ...................... a@P 80 | Previous: .................. a@P 81 | Equal:...................... a@P 82 | Follows: ................... a@P 83 | Precedes: .................. a@P 84 | Overlaps: .................. a@P 85 | Overlapped: ................ a@P 86 | During: .................... a@P 87 | Contains: .................. a@P 88 | Starts:.. .................. a@P 89 | Started:. .................. a@P 90 | Finishes:................... a@P 91 | Finished:................... a@P 92 >>> tmr.print_temporal_topology_shell_info() 93 next=a@P 94 prev=a@P 95 equal=a@P 96 follows=a@P 97 precedes=a@P 98 overlaps=a@P 99 overlapped=a@P 100 during=a@P 101 contains=a@P 102 starts=a@P 103 started=a@P 104 finishes=a@P 105 finished=a@P 106 >>> rlist = tmr.get_temporal_relations() 107 >>> if "FINISHED" in rlist.keys(): 108 ... print(rlist["FINISHED"][0].get_id()) 109 a@P 110 111 """ 112 113 def __init__(self): 114 self.reset_temporal_topology() 115 116 def reset_temporal_topology(self): 117 """Reset any information about temporal topology""" 118 self._temporal_topology = {} 119 self._has_temporal_topology = False 120 121 def get_temporal_relations(self): 122 """Return the dictionary of temporal relationships 123 124 Keys are the temporal relationships in upper case, 125 values are abstract map objects. 126 127 :return: The temporal relations dictionary 128 """ 129 return copy.copy(self._temporal_topology) 130 131 def get_number_of_temporal_relations(self): 132 """ Return a dictionary in which the keys are the relation names and 133 the value are the number of relations. 134 135 The following relations are available: 136 137 - equal 138 - follows 139 - precedes 140 - overlaps 141 - overlapped 142 - during (including starts, finishes) 143 - contains (including started, finished) 144 - starts 145 - started 146 - finishes 147 - finished 148 149 To access topological information the temporal topology must be build 150 first using the SpatioTemporalTopologyBuilder. 151 152 :return: the dictionary with relations as keys and number as values 153 or None in case the topology wasn't build 154 """ 155 if self._has_temporal_topology is False: 156 return None 157 158 relations = {} 159 try: 160 relations["equal"] = len(self._temporal_topology["EQUAL"]) 161 except: 162 relations["equal"] = 0 163 try: 164 relations["follows"] = len(self._temporal_topology["FOLLOWS"]) 165 except: 166 relations["follows"] = 0 167 try: 168 relations["precedes"] = len(self._temporal_topology["PRECEDES"]) 169 except: 170 relations["precedes"] = 0 171 try: 172 relations["overlaps"] = len(self._temporal_topology["OVERLAPS"]) 173 except: 174 relations["overlaps"] = 0 175 try: 176 relations["overlapped"] = len(self._temporal_topology["OVERLAPPED"]) 177 except: 178 relations["overlapped"] = 0 179 try: 180 relations["during"] = len(self._temporal_topology["DURING"]) 181 except: 182 relations["during"] = 0 183 try: 184 relations["contains"] = len(self._temporal_topology["CONTAINS"]) 185 except: 186 relations["contains"] = 0 187 try: 188 relations["starts"] = len(self._temporal_topology["STARTS"]) 189 except: 190 relations["starts"] = 0 191 try: 192 relations["started"] = len(self._temporal_topology["STARTED"]) 193 except: 194 relations["started"] = 0 195 try: 196 relations["finishes"] = len(self._temporal_topology["FINISHES"]) 197 except: 198 relations["finishes"] = 0 199 try: 200 relations["finished"] = len(self._temporal_topology["FINISHED"]) 201 except: 202 relations["finished"] = 0 203 204 return relations 205 206 def set_temporal_topology_build_true(self): 207 """Same as name""" 208 self._has_temporal_topology = True 209 210 def set_temporal_topology_build_false(self): 211 """Same as name""" 212 self._has_temporal_topology = False 213 214 def is_temporal_topology_build(self): 215 """Check if the temporal topology was build""" 216 return self._has_temporal_topology 217 218 def set_next(self, map): 219 """Set the map that is temporally as closest located after this map. 220 221 Temporally located means that the start time of the "next" map is 222 temporally located AFTER the start time of this map, but temporally 223 near than other maps of the same dataset. 224 225 :param map: This object should be of type AbstractMapDataset 226 or derived classes 227 """ 228 self._temporal_topology["NEXT"] = map 229 230 def set_prev(self, map): 231 """Set the map that is temporally as closest located before this map. 232 233 Temporally located means that the start time of the "previous" map 234 is temporally located BEFORE the start time of this map, but 235 temporally near than other maps of the same dataset. 236 237 :param map: This object should be of type AbstractMapDataset 238 or derived classes 239 """ 240 self._temporal_topology["PREV"] = map 241 242 def next(self): 243 """Return the map with a start time temporally located after 244 the start time of this map, but temporal closer than other maps 245 246 :return: A map object or None 247 """ 248 if "NEXT" not in self._temporal_topology: 249 return None 250 return self._temporal_topology["NEXT"] 251 252 def prev(self): 253 """Return the map with a start time temporally located before 254 the start time of this map, but temporal closer than other maps 255 256 :return: A map object or None 257 """ 258 if "PREV" not in self._temporal_topology: 259 return None 260 return self._temporal_topology["PREV"] 261 262 def append_equal(self, map): 263 """Append a map with equivalent temporal extent as this map 264 265 :param map: This object should be of type AbstractMapDataset 266 or derived classes 267 """ 268 if "EQUAL" not in self._temporal_topology: 269 self._temporal_topology["EQUAL"] = [] 270 self._temporal_topology["EQUAL"].append(map) 271 272 def get_equal(self): 273 """Return a list of map objects with equivalent temporal extent as 274 this map 275 276 :return: A list of map objects or None 277 """ 278 if "EQUAL" not in self._temporal_topology: 279 return None 280 return self._temporal_topology["EQUAL"] 281 282 def append_starts(self, map): 283 """Append a map that this map temporally starts with 284 285 :param map: This object should be of type AbstractMapDataset 286 or derived classes 287 """ 288 if "STARTS" not in self._temporal_topology: 289 self._temporal_topology["STARTS"] = [] 290 self._temporal_topology["STARTS"].append(map) 291 292 def get_starts(self): 293 """Return a list of map objects that this map temporally starts with 294 295 :return: A list of map objects or None 296 """ 297 if "STARTS" not in self._temporal_topology: 298 return None 299 return self._temporal_topology["STARTS"] 300 301 def append_started(self, map): 302 """Append a map that this map temporally started with 303 304 :param map: This object should be of type AbstractMapDataset 305 or derived classes 306 """ 307 if "STARTED" not in self._temporal_topology: 308 self._temporal_topology["STARTED"] = [] 309 self._temporal_topology["STARTED"].append(map) 310 311 def get_started(self): 312 """Return a list of map objects that this map temporally started with 313 314 :return: A list of map objects or None 315 """ 316 if "STARTED" not in self._temporal_topology: 317 return None 318 return self._temporal_topology["STARTED"] 319 320 def append_finishes(self, map): 321 """Append a map that this map temporally finishes with 322 323 :param map: This object should be of type AbstractMapDataset 324 or derived classes 325 """ 326 if "FINISHES" not in self._temporal_topology: 327 self._temporal_topology["FINISHES"] = [] 328 self._temporal_topology["FINISHES"].append(map) 329 330 def get_finishes(self): 331 """Return a list of map objects that this map temporally finishes with 332 333 :return: A list of map objects or None 334 """ 335 if "FINISHES" not in self._temporal_topology: 336 return None 337 return self._temporal_topology["FINISHES"] 338 339 def append_finished(self, map): 340 """Append a map that this map temporally finished with 341 342 :param map: This object should be of type AbstractMapDataset 343 or derived classes 344 """ 345 if "FINISHED" not in self._temporal_topology: 346 self._temporal_topology["FINISHED"] = [] 347 self._temporal_topology["FINISHED"].append(map) 348 349 def get_finished(self): 350 """Return a list of map objects that this map temporally finished with 351 352 :return: A list of map objects or None 353 """ 354 if "FINISHED" not in self._temporal_topology: 355 return None 356 return self._temporal_topology["FINISHED"] 357 358 def append_overlaps(self, map): 359 """Append a map that this map temporally overlaps 360 361 :param map: This object should be of type AbstractMapDataset 362 or derived classes 363 """ 364 if "OVERLAPS" not in self._temporal_topology: 365 self._temporal_topology["OVERLAPS"] = [] 366 self._temporal_topology["OVERLAPS"].append(map) 367 368 def get_overlaps(self): 369 """Return a list of map objects that this map temporally overlaps 370 371 :return: A list of map objects or None 372 """ 373 if "OVERLAPS" not in self._temporal_topology: 374 return None 375 return self._temporal_topology["OVERLAPS"] 376 377 def append_overlapped(self, map): 378 """Append a map that this map temporally overlapped 379 380 :param map: This object should be of type AbstractMapDataset 381 or derived classes 382 """ 383 if "OVERLAPPED" not in self._temporal_topology: 384 self._temporal_topology["OVERLAPPED"] = [] 385 self._temporal_topology["OVERLAPPED"].append(map) 386 387 def get_overlapped(self): 388 """Return a list of map objects that this map temporally overlapped 389 390 :return: A list of map objects or None 391 """ 392 if "OVERLAPPED" not in self._temporal_topology: 393 return None 394 return self._temporal_topology["OVERLAPPED"] 395 396 def append_follows(self, map): 397 """Append a map that this map temporally follows 398 399 :param map: This object should be of type AbstractMapDataset 400 or derived classes 401 """ 402 if "FOLLOWS" not in self._temporal_topology: 403 self._temporal_topology["FOLLOWS"] = [] 404 self._temporal_topology["FOLLOWS"].append(map) 405 406 def get_follows(self): 407 """Return a list of map objects that this map temporally follows 408 409 :return: A list of map objects or None 410 """ 411 if "FOLLOWS" not in self._temporal_topology: 412 return None 413 return self._temporal_topology["FOLLOWS"] 414 415 def append_precedes(self, map): 416 """Append a map that this map temporally precedes 417 418 :param map: This object should be of type AbstractMapDataset 419 or derived classes 420 """ 421 if "PRECEDES" not in self._temporal_topology: 422 self._temporal_topology["PRECEDES"] = [] 423 self._temporal_topology["PRECEDES"].append(map) 424 425 def get_precedes(self): 426 """Return a list of map objects that this map temporally precedes 427 428 :return: A list of map objects or None 429 """ 430 if "PRECEDES" not in self._temporal_topology: 431 return None 432 return self._temporal_topology["PRECEDES"] 433 434 def append_during(self, map): 435 """Append a map that this map is temporally located during 436 This includes temporal relationships starts and finishes 437 438 :param map: This object should be of type 439 AbstractMapDataset or derived classes 440 """ 441 if "DURING" not in self._temporal_topology: 442 self._temporal_topology["DURING"] = [] 443 self._temporal_topology["DURING"].append(map) 444 445 def get_during(self): 446 """Return a list of map objects that this map is temporally located during 447 This includes temporally relationships starts and finishes 448 449 :return: A list of map objects or None 450 """ 451 if "DURING" not in self._temporal_topology: 452 return None 453 return self._temporal_topology["DURING"] 454 455 def append_contains(self, map): 456 """Append a map that this map temporally contains 457 This includes temporal relationships started and finished 458 459 :param map: This object should be of type AbstractMapDataset 460 or derived classes 461 """ 462 if "CONTAINS" not in self._temporal_topology: 463 self._temporal_topology["CONTAINS"] = [] 464 self._temporal_topology["CONTAINS"].append(map) 465 466 def get_contains(self): 467 """Return a list of map objects that this map temporally contains 468 This includes temporal relationships started and finished 469 470 :return: A list of map objects or None 471 """ 472 if "CONTAINS" not in self._temporal_topology: 473 return None 474 return self._temporal_topology["CONTAINS"] 475 476 def _generate_map_list_string(self, map_list, line_wrap=True): 477 count = 0 478 string = "" 479 for map_ in map_list: 480 if line_wrap and count > 0 and count % 3 == 0: 481 string += "\n | ............................ " 482 count = 0 483 if count == 0: 484 string += map_.get_id() 485 else: 486 string += ",%s" % map_.get_id() 487 count += 1 488 489 return string 490 491 # Set the properties 492 equal = property(fget=get_equal, fset=append_equal) 493 follows = property(fget=get_follows, fset=append_follows) 494 precedes = property(fget=get_precedes, fset=append_precedes) 495 overlaps = property(fget=get_overlaps, fset=append_overlaps) 496 overlapped = property(fget=get_overlapped, fset=append_overlapped) 497 during = property(fget=get_during, fset=append_during) 498 contains = property(fget=get_contains, fset=append_contains) 499 starts = property(fget=get_starts, fset=append_starts) 500 started = property(fget=get_started, fset=append_started) 501 finishes = property(fget=get_finishes, fset=append_finishes) 502 finished = property(fget=get_finished, fset=append_finished) 503 504 def print_temporal_topology_info(self): 505 """Print information about this class in human readable style""" 506 507 print(" +-------------------- Temporal Topology -------------------------------------+") 508 # 0123456789012345678901234567890 509 if self.next() is not None: 510 print(" | Next: ...................... " + str(self.next().get_id())) 511 if self.prev() is not None: 512 print(" | Previous: .................. " + str(self.prev().get_id())) 513 if self.equal is not None: 514 print(" | Equal:...................... " + 515 self._generate_map_list_string(self.equal)) 516 if self.follows is not None: 517 print(" | Follows: ................... " + 518 self._generate_map_list_string(self.follows)) 519 if self.precedes is not None: 520 print(" | Precedes: .................. " + 521 self._generate_map_list_string(self.precedes)) 522 if self.overlaps is not None: 523 print(" | Overlaps: .................. " + 524 self._generate_map_list_string(self.overlaps)) 525 if self.overlapped is not None: 526 print(" | Overlapped: ................ " + 527 self._generate_map_list_string(self.overlapped)) 528 if self.during is not None: 529 print(" | During: .................... " + 530 self._generate_map_list_string(self.during)) 531 if self.contains is not None: 532 print(" | Contains: .................. " + 533 self._generate_map_list_string(self.contains)) 534 if self.starts is not None: 535 print(" | Starts:.. .................. " + 536 self._generate_map_list_string(self.starts)) 537 if self.started is not None: 538 print(" | Started:. .................. " + 539 self._generate_map_list_string(self.started)) 540 if self.finishes is not None: 541 print(" | Finishes:................... " + 542 self._generate_map_list_string(self.finishes)) 543 if self.finished is not None: 544 print(" | Finished:................... " + 545 self._generate_map_list_string(self.finished)) 546 547 def print_temporal_topology_shell_info(self): 548 """Print information about this class in shell style""" 549 550 if self.next() is not None: 551 print("next=" + self.next().get_id()) 552 if self.prev() is not None: 553 print("prev=" + self.prev().get_id()) 554 if self.equal is not None: 555 print("equal=" + self._generate_map_list_string(self.equal, False)) 556 if self.follows is not None: 557 print("follows=" + self._generate_map_list_string(self.follows, 558 False)) 559 if self.precedes is not None: 560 print("precedes=" + self._generate_map_list_string( 561 self.precedes, False)) 562 if self.overlaps is not None: 563 print("overlaps=" + self._generate_map_list_string( 564 self.overlaps, False)) 565 if self.overlapped is not None: 566 print("overlapped=" + 567 self._generate_map_list_string(self.overlapped, False)) 568 if self.during is not None: 569 print("during=" + self._generate_map_list_string(self.during, 570 False)) 571 if self.contains is not None: 572 print("contains=" + self._generate_map_list_string( 573 self.contains, False)) 574 if self.starts is not None: 575 print("starts=" + 576 self._generate_map_list_string(self.starts)) 577 if self.started is not None: 578 print("started=" + 579 self._generate_map_list_string(self.started)) 580 if self.finishes is not None: 581 print("finishes=" + 582 self._generate_map_list_string(self.finishes)) 583 if self.finished is not None: 584 print("finished=" + 585 self._generate_map_list_string(self.finished)) 586 587############################################################################### 588 589if __name__ == "__main__": 590 import doctest 591 doctest.testmod() 592