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 = "Sector Details:
" for column, value in row.items(): description += f"{column}: {value}
" 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}
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