Add cell-scale-factor to jsonschema
[oam.git] / code / network-generator / network_generation / model / python / nr_cell_du.py
1 # Copyright 2023 highstreet technologies USA CORP.
2 #
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
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
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.
14
15 # !/usr/bin/python
16
17 """
18 A Class representing a 3GPP new radio cell du (NrCellDu)
19 """
20 import xml.etree.ElementTree as ET
21 from typing import Any, cast
22
23 import network_generation.model.python.hexagon as Hexagon
24 from network_generation.model.python.geo_location import (
25     GeoLocation,
26     IGeoLocation,
27 )
28 from network_generation.model.python.o_ran_node import IORanNode, ORanNode
29 from network_generation.model.python.o_ran_termination_point import (
30     ORanTerminationPoint,
31 )
32 from network_generation.model.python.point import Point
33
34
35 # Define the "INrCellDu" interface
36 class INrCellDu(IORanNode):
37     cell_angle: int
38     azimuth: int
39
40
41 default_value: INrCellDu = cast(
42     INrCellDu,
43     {
44         **ORanNode.default(),
45         **{
46             "cellAngle": 120,
47             "cellScaleFactorForHandoverArea": 0,
48             "azimuth": 120,
49         },
50     },
51 )
52
53
54 # Define an abstract O-RAN Node class
55 class NrCellDu(ORanNode):
56     def __init__(
57         self,
58         data: dict[str, Any] = cast(dict[str, Any], default_value),
59         **kwargs: dict[str, Any]
60     ) -> None:
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"])
66         )
67         self._azimuth: int = int(str(cell_data["azimuth"]))
68
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():
72             if key in data:
73                 result[key] = data[key]  # type: ignore
74         return result
75
76     @property
77     def cell_angle(self) -> int:
78         return self._cell_angle
79
80     @cell_angle.setter
81     def cell_angle(self, value: int) -> None:
82         self._cell_angle = value
83
84     @property
85     def cell_scale_factor(self) -> int:
86         return self._cell_scale_factor
87
88     @cell_scale_factor.setter
89     def cell_scale_factor(self, value: int) -> None:
90         self._cell_scale_factor = value
91
92     @property
93     def azimuth(self) -> int:
94         return self._azimuth
95
96     @azimuth.setter
97     def azimuth(self, value: int) -> None:
98         self.azimuth = value
99
100     def termination_points(self) -> list[ORanTerminationPoint]:
101         result: list[ORanTerminationPoint] = super().termination_points()
102         result.append(
103             ORanTerminationPoint({"id": self.name, "name": self.name})
104         )
105         return result
106
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()
110         return result
111
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()
115         return result
116
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")
128
129         points: list[Point] = Hexagon.polygon_corners(
130             self.layout, self.position
131         )
132         method = (
133             self.parent.parent.parent.parent.parent.parent
134             .geo_location.point_to_geo_location
135         )
136         geo_locations: list[GeoLocation] = list(map(method, points))
137         text: list[str] = []
138
139         index: int = 1 + int(self._azimuth / self._cell_angle)
140         network_center: GeoLocation = (
141             self.parent.parent.parent.parent.parent.parent.geo_location
142         )
143
144         intersect1: Point = Point(
145             (points[(2 * index + 1) % 6].x + points[(2 * index + 2) % 6].x)
146             / 2,
147             (points[(2 * index + 1) % 6].y + points[(2 * index + 2) % 6].y)
148             / 2,
149         )
150         intersect_geo_location1: GeoLocation = (
151             network_center.point_to_geo_location(intersect1)
152         )
153
154         intersect2: Point = Point(
155             (points[(2 * index + 3) % 6].x + points[(2 * index + 4) % 6].x)
156             / 2,
157             (points[(2 * index + 3) % 6].y + points[(2 * index + 4) % 6].y)
158             / 2,
159         )
160         intersect_geo_location2: GeoLocation = (
161             network_center.point_to_geo_location(intersect2)
162         )
163
164         tower: GeoLocation = GeoLocation(cast(IGeoLocation, self.geo_location))
165         # TODO: Why a cast is required
166
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)
173         # close polygon
174         cell_polygon.append(tower)
175
176         for gl in cell_polygon:
177             index += 1
178             strs: list[str] = [
179                 str("%.6f" % float(gl.longitude)),
180                 str("%.6f" % float(gl.latitude)),
181                 str("%.6f" % float(gl.aboveMeanSeaLevel)),
182             ]
183             text.append(",".join(strs))
184         coordinates.text = " ".join(text)
185
186         if self.cell_scale_factor > 0:
187             print("hallo")
188
189         return placemark
190
191     def toSvg(self) -> ET.Element:
192         return ET.Element("to-be-implemented")