1 # Copyright 2023 highstreet technologies GmbH
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
18 A Class representing a Tower to mount O-RAN RUs
19 It can be interpreted as 'resource pool' for physical network
22 from model.python.o_ran_object import IORanObject
23 from model.python.o_ran_ru import IORanRu, ORanRu
24 import model.python.hexagon as Hexagon
25 from model.python.point import Point
26 from model.python.geo_location import GeoLocation
27 from model.python.o_ran_node import ORanNode
28 import xml.etree.ElementTree as ET
30 # Define the "IORanDu" interface
31 class ITower(IORanObject):
32 def __init__(self, o_ran_ru_count: int, **kwargs):
33 super().__init__(**kwargs)
34 self._o_ran_ru_count = o_ran_ru_count
36 # Implement a concrete O-RAN Node class
37 class Tower(ORanNode):
39 def __init__(self, tower_data: ITower = None, **kwargs):
40 super().__init__(tower_data, **kwargs)
41 self._o_ran_ru_count = tower_data["oRanRuCount"] if tower_data and "oRanRuCount" in tower_data else 3
42 self._o_ran_rus: list[ORanRu] = self._create_o_ran_rus()
44 def _create_o_ran_rus(self) -> list [ORanRu]:
45 result : list [ORanRu] = []
46 for index in range(self._o_ran_ru_count):
47 s: str = "00" + str(index)
49 [self.name.replace("Tower", "RU"), s[len(s) - 2 : len(s)]]
51 cell_count: int = self.parent.parent.parent.parent.parent.configuration()['pattern']["o-ran-ru"]["nr-cell-du-count"]
56 "geoLocation": self.geoLocation,
57 "position": self.position,
58 "layout": self.layout,
59 "spiralRadiusProfile": self.spiralRadiusProfile,
61 "cellCount": cell_count
67 def toKml(self) -> ET.Element:
68 placemark: ET.Element = ET.Element("Placemark")
69 name: ET.Element = ET.SubElement(placemark, "name")
71 style: ET.Element = ET.SubElement(placemark, "styleUrl")
72 style.text = "#" + self.__class__.__name__
73 multi_geometry: ET.Element = ET.SubElement(placemark, "MultiGeometry")
74 polygon: ET.Element = ET.SubElement(multi_geometry, "Polygon")
75 outer_boundary: ET.Element = ET.SubElement(polygon, "outerBoundaryIs")
76 linear_ring: ET.Element = ET.SubElement(outer_boundary, "LinearRing")
77 coordinates: ET.Element = ET.SubElement(linear_ring, "coordinates")
79 points: list[Point] = Hexagon.polygon_corners(self.layout, self.position)
80 points.append(points[0])
82 self.parent.parent.parent.parent.geoLocation
83 ).point_to_geo_location
84 geo_locations: list[GeoLocation] = list(map(method, points))
86 for geo_location in geo_locations:
88 f"{geo_location.longitude},{geo_location.latitude},{geo_location.aboveMeanSeaLevel}"
90 coordinates.text = " ".join(text)
93 cell_angle = self.parent.parent.parent.parent.parent.configuration()["pattern"]["nr-cell-du"]["cell-angle"]
94 for index in range(int(360 / cell_angle)):
95 line: ET.Element = ET.SubElement(multi_geometry, "LineString")
96 tessellate: ET.Element = ET.SubElement(line, "tessellate")
98 coordinates: ET.Element = ET.SubElement(line, "coordinates")
100 intersect: Point = Point(
101 (points[2 * index+2].x + points[2 * index + 1].x) / 2,
102 (points[2 * index+2].y + points[2 * index + 1].y) / 2,
104 intersect_geo_location: GeoLocation = GeoLocation(
105 self.parent.parent.parent.parent.geoLocation
106 ).point_to_geo_location(intersect)
109 f"{intersect_geo_location.longitude},{intersect_geo_location.latitude},{intersect_geo_location.aboveMeanSeaLevel}"
112 f"{self.geoLocation['longitude']},{self.geoLocation['latitude']},{self.geoLocation['aboveMeanSeaLevel']}"
114 coordinates.text = " ".join(text)
118 def toSvg(self) -> None: