File size: 2,766 Bytes
cbbcd31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import io
import math

import numpy as np
import pandas as pd
import simplekml


def create_sector(kml: simplekml.Kml, row, arc_angle=65):
    """Create a sector shape for the telecom antenna in KML with sector details."""
    code, name, azimuth, lon, lat, size, color = (
        row["code"],
        row["name"],
        row["Azimut"],
        row["Longitude"],
        row["Latitude"],
        row["size"],
        row["color"],
    )

    num_points = 20  # Number of points for smooth arc
    start_angle = azimuth - (arc_angle / 2)
    end_angle = azimuth + (arc_angle / 2)

    coords = [(lon, lat)]  # Start with the site location (center point)

    # Generate points for the sector arc
    for angle in np.linspace(start_angle, end_angle, num_points):
        angle_rad = math.radians(angle)
        arc_lon = lon + (size / 111320) * math.sin(angle_rad)
        arc_lat = lat + (size / 111320) * math.cos(angle_rad)
        coords.append((arc_lon, arc_lat))

    coords.append((lon, lat))  # Close the polygon

    # Create the sector polygon
    pol = kml.newpolygon(name=name, outerboundaryis=coords)

    # Dynamically create the description from all DataFrame columns
    description = "<b>Sector Details:</b><br>"
    for column, value in row.items():
        description += f"<b>{column}:</b> {value}<br>"

    pol.description = description
    pol.style.polystyle.color = color  # Set color from DataFrame
    pol.style.polystyle.outline = 1  # Outline enabled
    pol.style.linestyle.color = "ff000000"  # Black outline


def generate_kml_from_df(df: pd.DataFrame):
    """Generate a KML file from a Pandas DataFrame for telecom sectors."""
    kml = simplekml.Kml()
    site_added = set()  # Keep track of sites already added to avoid duplicates

    # Sort the DataFrame to ensure 900 MHz (smaller) is drawn last (on top)
    df_sorted = df.sort_values(
        by="size", ascending=False
    )  # Larger first, smaller on top

    for _, row in df_sorted.iterrows():
        code, lon, lat = row["code"], row["Longitude"], row["Latitude"]

        # Add site name as a point only once
        if code not in site_added:
            pnt = kml.newpoint(name=code, coords=[(lon, lat)])
            pnt.style.iconstyle.icon.href = (
                "http://maps.google.com/mapfiles/kml/shapes/placemark_circle.png"
            )
            pnt.style.labelstyle.scale = 1.2  # Adjust label size
            pnt.description = f"Site: {code}<br>Location: {lat}, {lon}"
            site_added.add(code)

        create_sector(kml, row)

    kml_data = io.BytesIO()
    kml_str = kml.kml()  # Get KML as string
    kml_data.write(kml_str.encode("utf-8"))  # Write KML to BytesIO
    kml_data.seek(0)  # Move to beginning of BytesIO
    return kml_data