1 # Copyright 2023 highstreet technologies USA CORP.
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 3GPP new radio cell du (NrCellDu)
20 import xml.etree.ElementTree as ET
21 from typing import Any, cast
23 import network_generation.model.python.hexagon as Hexagon
24 from network_generation.model.python.geo_location import (
28 from network_generation.model.python.o_ran_node import IORanNode, ORanNode
29 from network_generation.model.python.o_ran_termination_point import (
32 from network_generation.model.python.point import Point
35 # Define the "INrCellDu" interface
36 class INrCellDu(IORanNode):
41 default_value: INrCellDu = cast(
47 "cellScaleFactorForHandoverArea": 0,
54 # Define an abstract O-RAN Node class
55 class NrCellDu(ORanNode):
58 data: dict[str, Any] = cast(dict[str, Any], default_value),
59 **kwargs: dict[str, Any]
61 cell_data: INrCellDu = self._to_cell_data(data)
62 super().__init__(cast(dict[str, Any], cell_data), **kwargs)
63 self._cell_angle: int = int(str(cell_data["cellAngle"]))
64 self._cell_scale_factor: int = int(
65 str(cell_data["cellScaleFactorForHandoverArea"])
67 self._azimuth: int = int(str(cell_data["azimuth"]))
69 def _to_cell_data(self, data: dict[str, Any]) -> INrCellDu:
70 result: INrCellDu = default_value
71 for key, key_type in INrCellDu.__annotations__.items():
73 result[key] = data[key] # type: ignore
77 def cell_angle(self) -> int:
78 return self._cell_angle
81 def cell_angle(self, value: int) -> None:
82 self._cell_angle = value
85 def cell_scale_factor(self) -> int:
86 return self._cell_scale_factor
88 @cell_scale_factor.setter
89 def cell_scale_factor(self, value: int) -> None:
90 self._cell_scale_factor = value
93 def azimuth(self) -> int:
97 def azimuth(self, value: int) -> None:
100 def termination_points(self) -> list[ORanTerminationPoint]:
101 result: list[ORanTerminationPoint] = super().termination_points()
103 ORanTerminationPoint({"id": self.name, "name": self.name})
107 def to_topology_nodes(self) -> list[dict[str, Any]]:
108 # a cell is not a node it is a Termination Point
109 result: list[dict[str, Any]] = [] # super().to_topology_nodes()
112 def to_topology_links(self) -> list[dict[str, Any]]:
113 # as a cell is not a node, it does not have links
114 result: list[dict[str, Any]] = [] # super().to_topology_links()
117 def toKml(self) -> ET.Element:
118 placemark: ET.Element = ET.Element("Placemark")
119 name: ET.Element = ET.SubElement(placemark, "name")
120 name.text = self.name
121 style: ET.Element = ET.SubElement(placemark, "styleUrl")
122 style.text = "#" + self.__class__.__name__
123 multi_geometry: ET.Element = ET.SubElement(placemark, "MultiGeometry")
124 polygon: ET.Element = ET.SubElement(multi_geometry, "Polygon")
125 outer_boundary: ET.Element = ET.SubElement(polygon, "outerBoundaryIs")
126 linear_ring: ET.Element = ET.SubElement(outer_boundary, "LinearRing")
127 coordinates: ET.Element = ET.SubElement(linear_ring, "coordinates")
129 points: list[Point] = Hexagon.polygon_corners(
130 self.layout, self.position
133 self.parent.parent.parent.parent.parent.parent
134 .geo_location.point_to_geo_location
136 geo_locations: list[GeoLocation] = list(map(method, points))
139 index: int = 1 + int(self._azimuth / self._cell_angle)
140 network_center: GeoLocation = (
141 self.parent.parent.parent.parent.parent.parent.geo_location
144 intersect1: Point = Point(
145 (points[(2 * index + 1) % 6].x + points[(2 * index + 2) % 6].x)
147 (points[(2 * index + 1) % 6].y + points[(2 * index + 2) % 6].y)
150 intersect_geo_location1: GeoLocation = (
151 network_center.point_to_geo_location(intersect1)
154 intersect2: Point = Point(
155 (points[(2 * index + 3) % 6].x + points[(2 * index + 4) % 6].x)
157 (points[(2 * index + 3) % 6].y + points[(2 * index + 4) % 6].y)
160 intersect_geo_location2: GeoLocation = (
161 network_center.point_to_geo_location(intersect2)
164 tower: GeoLocation = GeoLocation(cast(IGeoLocation, self.geo_location))
165 # TODO: Why a cast is required
167 cell_polygon: list[GeoLocation] = []
168 cell_polygon.append(tower)
169 cell_polygon.append(intersect_geo_location1)
170 cell_polygon.append(geo_locations[(2 * index + 2) % 6])
171 cell_polygon.append(geo_locations[(2 * index + 3) % 6])
172 cell_polygon.append(intersect_geo_location2)
174 cell_polygon.append(tower)
176 for gl in cell_polygon:
179 str("%.6f" % float(gl.longitude)),
180 str("%.6f" % float(gl.latitude)),
181 str("%.6f" % float(gl.aboveMeanSeaLevel)),
183 text.append(",".join(strs))
184 coordinates.text = " ".join(text)
186 if self.cell_scale_factor > 0:
191 def toSvg(self) -> ET.Element:
192 return ET.Element("to-be-implemented")