# ---------------------------------------------------------------------------------------------------------------------- # The Secondo Python API (pySecondo) # Victor Silva (victor.silva@posteo.de) # January 2020 # ---------------------------------------------------------------------------------------------------------------------- # Module # ---------------------------------------------------------------------------------------------------------------------- # Secondo Spatial Algebra # secondospatialalgebra.py # ---------------------------------------------------------------------------------------------------------------------- """ The module Secondo Spatial Algebra implements the data types for the conversion of list expression objects with values of the types contained in the SpatialAlgebra 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 dataclasses import dataclass from secondodb.api.support.secondolistexpr import ListExp @dataclass class Segment: """ Implements a single segment of a line. """ __slots__ = ["x1", "y1", "x2", "y2"] x1: float y1: float x2: float y2: float @dataclass class Point: """ Implements a single point expressing two coordinates X and Y. """ __slots__ = ["x", "y"] x: float y: float @dataclass class Line: """ Implements a line as a list of single segments of the class Segment. """ __slots__ = ["segments"] segments: [] @dataclass class Region: """ Implements a region as a list of faces of the class Face. """ __slots__ = ["faces"] faces: [] @dataclass class Face: """ Implements a single face of a region, containing an outercycle (list of single points) and holecycles (a list of cycles, where each cycle is a list of points). """ __slots__ = ["outercycle", "holecycles"] outercycle: [] holecycles: [] def convert_point_to_list_exp_str(point: Point) -> str: """ Converts a point object to a nested list in string format. :param point: A point object. :return: The nested list as string. """ point: Point list_exp_str = '(' \ + str(point.x) \ + ' ' \ + str(point.y) \ + ')' return list_exp_str def convert_points_to_list_exp_str(points: []) -> str: """ Converts a points object to a nested list in string format. :param points: A points object. :return: The nested list as string. """ list_exp_str = '(' point_count = 1 for point in points: point_le = convert_point_to_list_exp_str(point) list_exp_str = list_exp_str + point_le if point_count < len(points): list_exp_str = list_exp_str + ' ' else: list_exp_str = list_exp_str + ')' point_count += 1 return list_exp_str def convert_line_to_list_exp_str(line: Line) -> str: """ Converts a line object to a nested list in string format. :param line: A line object. :return: The nested list as string. """ line: Line list_exp_str = '(' segments = line.segments segment_count = 1 for segment in segments: segment_str = '(' \ + str(segment.x1) \ + ' ' \ + str(segment.y1) \ + ' ' \ + str(segment.x2) \ + ' ' \ + str(segment.y2) \ + ')' list_exp_str = list_exp_str + segment_str if segment_count < len(segments): list_exp_str = list_exp_str + ' ' else: list_exp_str = list_exp_str + ')' segment_count += 1 return list_exp_str def convert_region_to_list_exp_str(region: Region) -> str: """ Converts a region object to a nested list in string format. :param region: A region object. :return: The nested list as string. """ region: Region face_str = '' list_exp_str = '(' face_count = 1 for face in region.faces: face_str = '(' outercycle_str = '(' point_count = 1 for point in face.outercycle: point_str = convert_point_to_list_exp_str(point) outercycle_str = outercycle_str + point_str if point_count < len(face.outercycle): outercycle_str = outercycle_str + ' ' else: outercycle_str = outercycle_str + ')' point_count += 1 face_str = face_str + outercycle_str if len(face.holecycles) > 0: holecycle_count = 1 for holecycle in face.holecycles: face_str = face_str + ' ' holecycle_str = '(' point_count = 1 for point in holecycle: point_str = convert_point_to_list_exp_str(point) holecycle_str = holecycle_str + point_str if point_count < len(holecycle): holecycle_str = holecycle_str + ' ' else: holecycle_str = holecycle_str + ')' point_count += 1 if holecycle_count < len(face.holecycles): face_str = face_str + holecycle_str + ' ' else: face_str = face_str + holecycle_str + ')' holecycle_count += 1 else: # no holes face_str = face_str + ')' if face_count < len(region.faces): list_exp_str = list_exp_str + face_str + ' ' else: list_exp_str = list_exp_str + face_str + ')' face_count += 1 return list_exp_str def parse_point(list_expr: ListExp) -> Point: """ Transforms a list expression object containing a point (point) to a named tuple. :param list_expr: A list expression object containing a point (point). :return: A named tuple with the point. """ x = list_expr.get_first_element().value y = list_expr.get_second_element().value return Point(x=x, y=y) def parse_points(list_expr: ListExp) -> []: """ Transforms a list expression object containing points (points) to a named tuple. :param list_expr: A list expression object containing points (points). :return: A named tuple with the points. """ points = [] next_element = list_expr while next_element.next is not None: point = parse_point(next_element.value) points.append(point) next_element = next_element.next return points def parse_line(list_expr: ListExp) -> Line: """ Transforms a list expression object containing a line (line) to a named tuple. :param list_expr: A list expression object containing a line (line). :return: A named tuple with the line. """ segments = [] length = list_expr.get_list_length() for i in range(1, length): segment = parse_segment(list_expr.get_the_n_element(i)) segments.append(segment) return Line(segments) def parse_region(list_expr: ListExp) -> Region: """ Transforms a list expression object containing a region (region) to a named tuple. :param list_expr: A list expression object containing a region (region). :return: A named tuple with the region. """ qty_faces = list_expr.get_list_length() faces = [] for i in range(1, qty_faces): face_le: ListExp = list_expr.get_the_n_element(i) cycles_count = face_le.get_list_length() outercycle_le = face_le.get_first_element() outercycle = [] if outercycle_le is not None: outercycle = parse_points(outercycle_le) holecycles = [] if cycles_count > 1: for j in range(2, cycles_count): holecycle_le = face_le.get_the_n_element(j) holecycle = [] if holecycle_le is not None: holecycle = parse_points(holecycle_le) holecycles.append(holecycle) face = Face(outercycle, holecycles) faces.append(face) return Region(faces) def parse_segment(list_expr: ListExp) -> Segment: """ Transforms a list expression object containing a segment (segment) to a named tuple. :param list_expr: A list expression object containing a segment (segment). :return: A named tuple with the segment. """ x1 = list_expr.get_first_element().value y1 = list_expr.get_second_element().value x2 = list_expr.get_third_element().value y2 = list_expr.get_fourth_element().value return Segment(x1=x1, y1=y1, x2=x2, y2=y2)