# ---------------------------------------------------------------------------------------------------------------------- # The Secondo Python API (pySecondo) # Victor Silva (victor.silva@posteo.de) # January 2020 # ---------------------------------------------------------------------------------------------------------------------- # Module # ---------------------------------------------------------------------------------------------------------------------- # Secondo Spatio-Temporal Algebra # secondospatiotemporalalgebra.py # ---------------------------------------------------------------------------------------------------------------------- """ The module Secondo Spatio-Temporal Algebra implements the data types for the conversion of list expression objects with values of the types contained in the TemporalAlgebra of the |sec| system. The data types are implemented in Python using Data Classes. Data Classes are implemented in the API like normal classes without behaviour. Like regular classes their attributes can be called through the given names. """ from collections import namedtuple from dataclasses import dataclass from secondodb.api.support.secondolistexpr import ListExp import secondodb.api.algebras.secondospatialalgebra as spatial from datetime import datetime @dataclass class Interval: """ Implements a time interval. """ __slots__ = ["start_time", "end_time", "close_left", "close_right"] start_time: datetime end_time: datetime close_left: bool close_right: bool @dataclass class MotionVector: """ Implements a motion vector of a moving point. """ __slots__ = ["x1", "y1", "x2", "y2"] x1: float y1: float x2: float y2: float @dataclass class PointInInterval: """ Implements a structure to store the time interval and the motion vector of a moving point. """ __slots__ = ["interval", "motion_vector"] interval: Interval motion_vector: MotionVector @dataclass class MPoint: """ Implements a moving point as a series of points in intervals. """ __slots__ = ['intervals'] intervals: [] @dataclass class MapPoint: """ Implements a map point, i.e. a motion vector for a point of a moving region. """ __slots__ = ["x1", "y1", "x2", "y2"] x1: float y1: float x2: float y2: float @dataclass class RegionInInterval: """ Implements a structure to store the time interval and the motion vector of a moving region. """ __slots__ = ["interval", "map_faces"] interval: Interval map_faces: [] @dataclass class MRegion: """ Implements a moving region as a series of regions in intervals. """ __slots__ = ['intervals'] intervals: [] @dataclass class MBool: """ Implements a moving boolean as a series of booleans in intervals. """ __slots__ = ['intervals'] intervals: [] @dataclass class BoolInInterval: """ Implements a structure to store the time interval and the value vector of a moving boolean. """ __slots__ = ["interval", "value_vector"] interval: Interval value_vector: [] @dataclass class ValueVectorBool: """ Implements the value vector for a moving boolean. """ __slots__ = ["value"] value: bool @dataclass class RealInInterval: """ Implements a structure to store the time interval and the value vector of a moving real. """ __slots__ = ["interval", "value_vector"] interval: Interval value_vector: [] @dataclass class ValueVectorReal: """ Implements the value vector for a moving real. """ __slots__ = ["start_value", "end_value", "boolean"] start_value: float end_value: float boolean: bool @dataclass class MReal: """ Implements a moving real as a series of real values in intervals. """ __slots__ = ['intervals'] intervals: [] @dataclass class MString: """ Implements a moving string as a series of string values in intervals. """ __slots__ = ['intervals'] intervals: [] @dataclass class StringInInterval: """ Implements a structure to store the time interval and the value vector of a moving string. """ __slots__ = ["interval", "value_vector"] interval: Interval value_vector: [] @dataclass class ValueVectorString: """ Implements the value vector for a moving string. """ __slots__ = ["value"] value: str @dataclass class MInt: """ Implements a moving integer as a series of integer values in intervals. """ __slots__ = ['intervals'] intervals: [] @dataclass class IntInInterval: """ Implements a structure to store the time interval and the value vector of a moving integer. """ __slots__ = ["interval", "value_vector"] interval: Interval value_vector: [] @dataclass class ValueVectorInt: """ Implements the value vector for a moving integer. """ __slots__ = ["value"] value: int @dataclass class IRegion: """ Implements an instant region as a region for a specific instant. """ __slots__ = ["instant", "region"] instant: datetime region: spatial.Region @dataclass class IPoint: """ Implements an instant point as a point for a specific instant. """ __slots__ = ["instant", "point"] instant: datetime point: spatial.Point def parse_timestamp(timestamp: str) -> datetime: """ Parses a timestamp string using the Python module datetime. Formats supported: '%Y-%m-%d-%H:%M' '%Y-%m-%d-%H:%M:%S' '%Y-%m-%d-%H:%M:%S.%f' :param timestamp: A string with a timestamp. :return: A datetime object. """ try: timestamp_as_datetime = datetime.strptime(timestamp, '%Y-%m-%d-%H:%M') except ValueError: pass else: return timestamp_as_datetime try: timestamp_as_datetime = datetime.strptime(timestamp, '%Y-%m-%d-%H:%M:%S') except ValueError: pass else: return timestamp_as_datetime try: timestamp_as_datetime = datetime.strptime(timestamp, '%Y-%m-%d-%H:%M:%S.%f') except ValueError: pass else: return timestamp_as_datetime try: timestamp_as_datetime = datetime.strptime(timestamp, '%Y-%m-%d') except ValueError: pass else: return timestamp_as_datetime if timestamp == 'begin of time': try: timestamp_as_datetime = datetime.strptime('1900-01-01', '%Y-%m-%d') except ValueError: pass else: return timestamp_as_datetime if timestamp == 'end of time': try: timestamp_as_datetime = datetime.strptime('9999-12-31', '%Y-%m-%d') except ValueError: pass else: return timestamp_as_datetime def parse_mpoint(list_expr: ListExp) -> MPoint: """ Transforms a list expression object containing a moving point (mpoint) to a named tuple. :param list_expr: A list expression object containing a moving point (mpoint). :return: An object of the data class MPoint with the moving point. """ number_of_intervals = list_expr.get_list_length() intervals = [] for i in range(1, number_of_intervals): point_in_interval_as_le: ListExp = list_expr.get_the_n_element(i) # Parse interval interval_as_le: ListExp = point_in_interval_as_le.get_first_element() start_time = parse_timestamp(interval_as_le.get_first_element().value) end_time = parse_timestamp(interval_as_le.get_second_element().value) close_left = interval_as_le.get_third_element().value close_right = interval_as_le.get_fourth_element().value interval = Interval(start_time=start_time, end_time=end_time, close_left=close_left, close_right=close_right) # Parse motion vector motion_vector_as_le: ListExp = point_in_interval_as_le.get_second_element() x1 = motion_vector_as_le.get_first_element().value y1 = motion_vector_as_le.get_second_element().value x2 = motion_vector_as_le.get_third_element().value y2 = motion_vector_as_le.get_fourth_element().value motion_vector = MotionVector(x1=x1, y1=y1, x2=x2, y2=y2) point_in_interval = PointInInterval(interval, motion_vector) intervals.append(point_in_interval) return MPoint(intervals) def parse_mregion(list_expr: ListExp) -> MRegion: """ Transforms a list expression object containing a moving region (mregion) to a named tuple. :param list_expr: A list expression object containing a moving region (mregion). :return: An object of the data class MRegion with the moving region. """ number_of_intervals = list_expr.get_list_length() intervals = [] for i in range(1, number_of_intervals): region_in_interval_as_le: ListExp = list_expr.get_the_n_element(i) # Parse interval interval_as_le: ListExp = region_in_interval_as_le.get_first_element() start_time = parse_timestamp(interval_as_le.get_first_element().value) end_time = parse_timestamp(interval_as_le.get_second_element().value) close_left = interval_as_le.get_third_element().value close_right = interval_as_le.get_fourth_element().value interval = Interval(start_time=start_time, end_time=end_time, close_left=close_left, close_right=close_right) # Parse map faces map_faces_as_le: ListExp = region_in_interval_as_le.get_second_element() number_of_map_faces = map_faces_as_le.get_list_length() map_faces = [] for j in range(1, number_of_map_faces): map_face_as_le: ListExp = map_faces_as_le.get_the_n_element(j) number_of_cycles = map_face_as_le.get_list_length() - 1 if number_of_cycles == 1: # Parse outercycle outercycle_as_le: ListExp = map_face_as_le.get_first_element() number_of_map_points = outercycle_as_le.get_list_length() map_points = [] for k in range(1, number_of_map_points): map_point_as_le: ListExp = outercycle_as_le.get_the_n_element(k) x1 = map_point_as_le.get_first_element().value y1 = map_point_as_le.get_second_element().value x2 = map_point_as_le.get_third_element().value y2 = map_point_as_le.get_fourth_element().value map_points.append(MapPoint(x1=x1, y1=y1, x2=x2, y2=y2)) map_faces.append(spatial.Face(outercycle=map_points, holecycles=[])) elif number_of_cycles == 2: # Parse outercycle outercycle_as_le: ListExp = map_face_as_le.get_first_element() number_of_map_points = outercycle_as_le.get_list_length() outercycle = [] for k in range(1, number_of_map_points): map_point_as_le: ListExp = outercycle_as_le.get_the_n_element(k) x1 = map_point_as_le.get_first_element().value y1 = map_point_as_le.get_second_element().value x2 = map_point_as_le.get_third_element().value y2 = map_point_as_le.get_fourth_element().value outercycle.append(MapPoint(x1=x1, y1=y1, x2=x2, y2=y2)) # Parse holecycle holecycle_as_le: ListExp = map_face_as_le.get_second_element() number_of_map_points = holecycle_as_le.get_list_length() holecycle = [] for k in range(1, number_of_map_points): map_point = namedtuple('map_point', ['x1', 'y1', 'x2', 'y2']) map_point_as_le: ListExp = holecycle_as_le.get_the_n_element(k) map_point.x1 = map_point_as_le.get_first_element().value map_point.y1 = map_point_as_le.get_second_element().value map_point.x2 = map_point_as_le.get_third_element().value map_point.y2 = map_point_as_le.get_fourth_element().value holecycle.append(map_point) map_faces.append(spatial.Face(outercycle=outercycle, holecycles=[holecycle])) intervals.append(RegionInInterval(interval, map_faces)) return MRegion(intervals) def parse_mreal(list_expr) -> MReal: """ Transforms a list expression object containing a moving real (mreal) to a named tuple. :param list_expr: A list expression object containing a moving real (mreal). :return: An object of the data class MReal with the moving real. """ number_of_intervals = list_expr.get_list_length() intervals = [] for i in range(1, number_of_intervals): real_in_interval_as_le: ListExp = list_expr.get_the_n_element(i) # Parse interval interval_as_le: ListExp = real_in_interval_as_le.get_first_element() start_time = parse_timestamp(interval_as_le.get_first_element().value) end_time = parse_timestamp(interval_as_le.get_second_element().value) close_left = interval_as_le.get_third_element().value close_right = interval_as_le.get_fourth_element().value interval = Interval(start_time=start_time, end_time=end_time, close_left=close_left, close_right=close_right) # Parse value vector motion_vector_as_le: ListExp = real_in_interval_as_le.get_second_element() start_value = motion_vector_as_le.get_second_element().value end_value = motion_vector_as_le.get_third_element().value boolean = motion_vector_as_le.get_fourth_element().value value_vector = ValueVectorReal(start_value=start_value, end_value=end_value, boolean=boolean) intervals.append(RealInInterval(interval=interval, value_vector=value_vector)) return MReal(intervals=intervals) def parse_mbool(list_expr: ListExp) -> MBool: """ Transforms a list expression object containing a moving boolean (mbool) to a named tuple. :param list_expr: A list expression object containing a moving boolean (mbool). :return: An object of the data class MBool with the moving boolean. """ number_of_intervals = list_expr.get_list_length() intervals = [] for i in range(1, number_of_intervals): bool_in_interval_as_le: ListExp = list_expr.get_the_n_element(i) # Parse interval interval_as_le: ListExp = bool_in_interval_as_le.get_first_element() start_time = parse_timestamp(interval_as_le.get_first_element().value) end_time = parse_timestamp(interval_as_le.get_second_element().value) close_left = interval_as_le.get_third_element().value close_right = interval_as_le.get_fourth_element().value interval = Interval(start_time=start_time, end_time=end_time, close_left=close_left, close_right=close_right) # Parse value vector value_vector_as_le: ListExp = bool_in_interval_as_le.get_second_element() value = value_vector_as_le.value value_vector = ValueVectorBool(value=value) bool_in_interval = BoolInInterval(interval=interval, value_vector=value_vector) intervals.append(bool_in_interval) return MBool(intervals) def parse_mstring(list_expr: ListExp) -> MString: """ Transforms a list expression object containing a moving string (mstring) to a named tuple. :param list_expr: A list expression object containing a moving string (mstring). :return: An object of the data class MString with the moving string. """ number_of_intervals = list_expr.get_list_length() intervals = [] for i in range(1, number_of_intervals): string_in_interval_as_le: ListExp = list_expr.get_the_n_element(i) # Parse interval interval_as_le: ListExp = string_in_interval_as_le.get_first_element() start_time = parse_timestamp(interval_as_le.get_first_element().value) end_time = parse_timestamp(interval_as_le.get_second_element().value) close_left = interval_as_le.get_third_element().value close_right = interval_as_le.get_fourth_element().value interval = Interval(start_time=start_time, end_time=end_time, close_left=close_left, close_right=close_right) # Parse value vector value_vector_as_le: ListExp = string_in_interval_as_le.get_second_element() value_vector = ValueVectorString(value=value_vector_as_le.value) string_in_interval = StringInInterval(interval=interval, value_vector=value_vector) intervals.append(string_in_interval) return MString(intervals=intervals) def parse_mint(list_expr: ListExp) -> MInt: """ Transforms a list expression object containing a moving integer (mint) to a named tuple. :param list_expr: A list expression object containing a moving integer (mint). :return: An object of the data class MInt with the moving integer. """ number_of_intervals = list_expr.get_list_length() intervals = [] for i in range(1, number_of_intervals): int_in_interval_as_le: ListExp = list_expr.get_the_n_element(i) # Parse interval interval_as_le: ListExp = int_in_interval_as_le.get_first_element() start_time = parse_timestamp(interval_as_le.get_first_element().value) end_time = parse_timestamp(interval_as_le.get_second_element().value) close_left = interval_as_le.get_third_element().value close_right = interval_as_le.get_fourth_element().value interval = Interval(start_time=start_time, end_time=end_time, close_left=close_left, close_right=close_right) # Parse value vector value_vector_as_le: ListExp = int_in_interval_as_le.get_second_element() value_vector = ValueVectorInt(value_vector_as_le.value) int_in_interval = IntInInterval(interval=interval, value_vector=value_vector) intervals.append(int_in_interval) return MInt(intervals=intervals) def parse_iregion(list_expr: ListExp) -> IRegion: """ Transforms a list expression object containing an instant region (iregion) to a named tuple. :param list_expr: A list expression object containing an instant region (iregion). :return: An object of the data class IRegion with the instant region. """ # Parse instant instant_as_le: ListExp = list_expr.get_first_element() instant = parse_timestamp(instant_as_le.value) # Parse region region_as_le: ListExp = list_expr.get_second_element() region = spatial.parse_region(region_as_le) return IRegion(instant=instant, region=region) def parse_ipoint(list_expr: ListExp) -> IPoint: """ Transforms a list expression object containing an instant point (ipoint) to a named tuple. :param list_expr: A list expression object containing an instant region (ipoint). :return: An object of the data class IPoint with the instant point. """ # Parse instant instant_as_le: ListExp = list_expr.get_first_element() instant = parse_timestamp(instant_as_le.value) # Parse point point_as_le: ListExp = list_expr.get_second_element() point = spatial.parse_point(point_as_le) return IPoint(instant=instant, point=point)