Skip to content

Instantly share code, notes, and snippets.

@recalde
Last active December 25, 2024 14:53
Show Gist options
  • Save recalde/ad5c33644841020634fe62c036d7aff1 to your computer and use it in GitHub Desktop.
Save recalde/ad5c33644841020634fe62c036d7aff1 to your computer and use it in GitHub Desktop.
import tkinter as tk
from tkinter import filedialog, messagebox
import simplekml
def add_coordinate():
if len(coordinates) < 10:
lat = lat_entry.get()
lon = lon_entry.get()
diameter = diameter_entry.get()
if not lat or not lon or not diameter:
messagebox.showerror("Error", "Please fill in all fields.")
return
try:
lat = float(lat)
lon = float(lon)
diameter = float(diameter)
except ValueError:
messagebox.showerror("Error", "Latitude, Longitude, and Diameter must be numeric.")
return
coordinates.append((lat, lon, diameter))
listbox.insert(tk.END, f"Lat: {lat}, Lon: {lon}, Diameter: {diameter}m")
lat_entry.delete(0, tk.END)
lon_entry.delete(0, tk.END)
diameter_entry.delete(0, tk.END)
else:
messagebox.showerror("Error", "You can add up to 10 coordinates.")
def remove_coordinate():
selected = listbox.curselection()
if selected:
listbox.delete(selected)
del coordinates[selected[0]]
else:
messagebox.showerror("Error", "Please select a coordinate to remove.")
def export_kml():
if not coordinates:
messagebox.showerror("Error", "No coordinates to export.")
return
file_path = filedialog.asksaveasfilename(
defaultextension=".kml",
filetypes=[("KML files", "*.kml")]
)
if not file_path:
return
kml = simplekml.Kml()
for lat, lon, diameter in coordinates:
circle = kml.newpolygon(name=f"Circle at {lat},{lon}")
radius = diameter / 2 / 1000 # Convert diameter to radius in km
circle.outerboundaryis = generate_circle(lat, lon, radius)
circle.innerboundaryis = []
circle.style.polystyle.color = simplekml.Color.changealphaint(100, simplekml.Color.red)
circle.style.polystyle.fill = 1
kml.save(file_path)
messagebox.showinfo("Success", f"KML file saved to {file_path}.")
def generate_circle(lat, lon, radius, segments=36):
from math import sin, cos, radians
coords = []
for i in range(segments + 1):
angle = radians(i * (360 / segments))
dlat = radius * cos(angle) / 111 # Approximation for 1 degree latitude
dlon = radius * sin(angle) / (111 * cos(radians(lat)))
coords.append((lon + dlon, lat + dlat))
return coords
# GUI setup
root = tk.Tk()
root.title("Google Earth Circle Drawer")
coordinates = []
frame = tk.Frame(root)
frame.pack(padx=10, pady=10)
tk.Label(frame, text="Latitude:").grid(row=0, column=0, padx=5, pady=5)
lat_entry = tk.Entry(frame)
lat_entry.grid(row=0, column=1, padx=5, pady=5)
tk.Label(frame, text="Longitude:").grid(row=1, column=0, padx=5, pady=5)
lon_entry = tk.Entry(frame)
lon_entry.grid(row=1, column=1, padx=5, pady=5)
tk.Label(frame, text="Diameter (m):").grid(row=2, column=0, padx=5, pady=5)
diameter_entry = tk.Entry(frame)
diameter_entry.grid(row=2, column=1, padx=5, pady=5)
tk.Button(frame, text="Add Coordinate", command=add_coordinate).grid(row=3, column=0, columnspan=2, pady=5)
tk.Button(frame, text="Remove Selected", command=remove_coordinate).grid(row=4, column=0, columnspan=2, pady=5)
tk.Button(frame, text="Export to KML", command=export_kml).grid(row=5, column=0, columnspan=2, pady=5)
listbox = tk.Listbox(root, width=50, height=10)
listbox.pack(padx=10, pady=10)
root.mainloop()

Prompt

Can you code me a python app that will have a gui I can paste or type up to 10 latitude and longitude coordinates and export a file that I can use in Google earth. Each coordinate should have a configurable diameter and draw a circle with filled volume on the map.

Response

Below is a Python application using the tkinter library for the GUI and the simplekml library to create the Google Earth file. The app allows you to input up to 10 latitude and longitude coordinates along with a configurable diameter for each circle. It then generates a KML file with filled circles for use in Google Earth.

Prerequisites

  1. Install the required libraries:

pip install simplekml

How It Works

  1. Adding Coordinates: Input latitude, longitude, and diameter in meters, then click "Add Coordinate."

  2. Removing Coordinates: Select a coordinate in the list and click "Remove Selected."

  3. Exporting to KML: Click "Export to KML," choose a file location, and the app generates the KML file.

Features

The circle is drawn with a configurable diameter.

The circle is semi-transparent and filled with a red color for visibility in Google Earth.

You can add up to 10 coordinates and export them at once.

Let me know if you need further customizations!

To remove non-intersecting circles and display a warning, we need to calculate whether each circle intersects with any other circle. Here's an updated version of the code that includes this functionality:
Updated Code
import tkinter as tk
from tkinter import filedialog, messagebox
import simplekml
from math import sin, cos, radians, sqrt
def add_coordinate():
if len(coordinates) < 10:
lat = lat_entry.get()
lon = lon_entry.get()
diameter = diameter_entry.get()
if not lat or not lon or not diameter:
messagebox.showerror("Error", "Please fill in all fields.")
return
try:
lat = float(lat)
lon = float(lon)
diameter = float(diameter)
except ValueError:
messagebox.showerror("Error", "Latitude, Longitude, and Diameter must be numeric.")
return
coordinates.append((lat, lon, diameter))
listbox.insert(tk.END, f"Lat: {lat}, Lon: {lon}, Diameter: {diameter}m")
lat_entry.delete(0, tk.END)
lon_entry.delete(0, tk.END)
diameter_entry.delete(0, tk.END)
else:
messagebox.showerror("Error", "You can add up to 10 coordinates.")
def remove_coordinate():
selected = listbox.curselection()
if selected:
listbox.delete(selected)
del coordinates[selected[0]]
else:
messagebox.showerror("Error", "Please select a coordinate to remove.")
def export_kml():
if not coordinates:
messagebox.showerror("Error", "No coordinates to export.")
return
non_intersecting = remove_non_intersecting_circles()
if not coordinates:
messagebox.showerror("Error", "No intersecting circles remain.")
return
if non_intersecting:
messagebox.showwarning(
"Warning",
f"{len(non_intersecting)} non-intersecting circles were removed."
)
file_path = filedialog.asksaveasfilename(
defaultextension=".kml",
filetypes=[("KML files", "*.kml")]
)
if not file_path:
return
kml = simplekml.Kml()
for lat, lon, diameter in coordinates:
circle = kml.newpolygon(name=f"Circle at {lat},{lon}")
radius = diameter / 2 / 1000 # Convert diameter to radius in km
circle.outerboundaryis = generate_circle(lat, lon, radius)
circle.innerboundaryis = []
circle.style.polystyle.color = simplekml.Color.changealphaint(100, simplekml.Color.red)
circle.style.polystyle.fill = 1
kml.save(file_path)
messagebox.showinfo("Success", f"KML file saved to {file_path}.")
def remove_non_intersecting_circles():
non_intersecting = []
for i, (lat1, lon1, diameter1) in enumerate(coordinates):
radius1 = diameter1 / 2 / 1000 # Radius in km
intersecting = False
for j, (lat2, lon2, diameter2) in enumerate(coordinates):
if i != j:
radius2 = diameter2 / 2 / 1000 # Radius in km
if circles_intersect(lat1, lon1, radius1, lat2, lon2, radius2):
intersecting = True
break
if not intersecting:
non_intersecting.append((lat1, lon1, diameter1))
for circle in non_intersecting:
coordinates.remove(circle)
listbox.delete(0, tk.END)
for coord in coordinates:
listbox.insert(tk.END, f"Lat: {coord[0]}, Lon: {coord[1]}, Diameter: {coord[2]}m")
return non_intersecting
def circles_intersect(lat1, lon1, radius1, lat2, lon2, radius2):
distance = haversine(lat1, lon1, lat2, lon2)
return distance <= (radius1 + radius2)
def haversine(lat1, lon1, lat2, lon2):
R = 6371 # Earth radius in km
dlat = radians(lat2 - lat1)
dlon = radians(lon2 - lon1)
a = sin(dlat / 2) ** 2 + cos(radians(lat1)) * cos(radians(lat2)) * sin(dlon / 2) ** 2
return 2 * R * atan2(sqrt(a), sqrt(1 - a))
def generate_circle(lat, lon, radius, segments=36):
coords = []
for i in range(segments + 1):
angle = radians(i * (360 / segments))
dlat = radius * cos(angle) / 111 # Approximation for 1 degree latitude
dlon = radius * sin(angle) / (111 * cos(radians(lat)))
coords.append((lon + dlon, lat + dlat))
return coords
# GUI setup
root = tk.Tk()
root.title("Google Earth Circle Drawer")
coordinates = []
frame = tk.Frame(root)
frame.pack(padx=10, pady=10)
tk.Label(frame, text="Latitude:").grid(row=0, column=0, padx=5, pady=5)
lat_entry = tk.Entry(frame)
lat_entry.grid(row=0, column=1, padx=5, pady=5)
tk.Label(frame, text="Longitude:").grid(row=1, column=0, padx=5, pady=5)
lon_entry = tk.Entry(frame)
lon_entry.grid(row=1, column=1, padx=5, pady=5)
tk.Label(frame, text="Diameter (m):").grid(row=2, column=0, padx=5, pady=5)
diameter_entry = tk.Entry(frame)
diameter_entry.grid(row=2, column=1, padx=5, pady=5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment