import streamlit as st import folium from streamlit_folium import folium_static import pyproj from folium.plugins import Draw import json import leafmap.foliumap as leafmap st.set_page_config(layout="wide") @st.cache_data def get_coordinate_systems(): return { "EPSG:4326": "WGS 84", "EPSG:3857": "Web Mercator", "EPSG:2154": "RGF93 / Lambert-93 (France)", "EPSG:27572": "NTF (Paris) / Lambert zone II (France)", "EPSG:25832": "ETRS89 / UTM zone 32N (Germany)", } def convert_coordinates(bbox, from_crs, to_crs): transformer = pyproj.Transformer.from_crs(from_crs, to_crs, always_xy=True) min_x, min_y = transformer.transform(bbox[0], bbox[1]) max_x, max_y = transformer.transform(bbox[2], bbox[3]) return [min_x, min_y, max_x, max_y] # Styles CSS st.markdown(""" """, unsafe_allow_html=True) # Sidebar st.sidebar.title("About") st.sidebar.info( "This app is an improved version of the BBox Finder, " "inspired by bboxfinder.com and using Streamlit." ) st.sidebar.title("Contact") st.sidebar.info( "Your Name\n" "[GitHub](https://github.com/yourusername) | " "[LinkedIn](https://www.linkedin.com/in/yourprofile)" ) # Main layout col1, col2 = st.columns([4, 1]) with col1: st.title("Improved BBox Finder") # Map m = leafmap.Map(center=[46.2, 6.15], zoom=8) # Centered on Geneva draw = Draw( export=True, position='topleft', draw_options={'polyline': False, 'polygon': False, 'circle': False, 'marker': False, 'circlemarker': False}, edit_options={'edit': False} ) draw.add_to(m) # JavaScript to handle drawing and coordinate updates m.add_child(folium.Element(""" """)) m.to_streamlit(height=600) with col2: st.markdown("

Coordinates

", unsafe_allow_html=True) bbox_coords = st.text_input("", key="bbox_coords", label_visibility="collapsed") # CRS selection coordinate_systems = get_coordinate_systems() selected_crs = st.selectbox("Select Coordinate Reference System", options=list(coordinate_systems.keys()), format_func=lambda x: f"{x} - {coordinate_systems[x]}") if bbox_coords: try: bbox = [float(coord.strip()) for coord in bbox_coords.split(',')] if len(bbox) == 4: st.markdown(f"Selected CRS: {selected_crs}", unsafe_allow_html=True) converted_bbox = convert_coordinates(bbox, "EPSG:4326", selected_crs) result = f"{converted_bbox[0]:.6f},{converted_bbox[1]:.6f},{converted_bbox[2]:.6f},{converted_bbox[3]:.6f}" st.code(result, language="plaintext") if st.button(f"Copy {selected_crs}"): st.write(f"{selected_crs} coordinates copied!") # Display in other common CRSs st.markdown("Other common CRSs:", unsafe_allow_html=True) for epsg, name in coordinate_systems.items(): if epsg != selected_crs: converted_bbox = convert_coordinates(bbox, "EPSG:4326", epsg) result = f"{converted_bbox[0]:.6f},{converted_bbox[1]:.6f},{converted_bbox[2]:.6f},{converted_bbox[3]:.6f}" st.code(f"{epsg}: {result}", language="plaintext") # Additional formats (GeoJSON, WKT) st.markdown("GeoJSON", unsafe_allow_html=True) geojson = json.dumps({ "type": "Feature", "properties": {}, "geometry": { "type": "Polygon", "coordinates": [[ [bbox[0], bbox[1]], [bbox[2], bbox[1]], [bbox[2], bbox[3]], [bbox[0], bbox[3]], [bbox[0], bbox[1]] ]] } }, indent=2) st.code(geojson, language="json") if st.button("Copy GeoJSON"): st.write("GeoJSON copied!") st.markdown("WKT", unsafe_allow_html=True) wkt = f"POLYGON(({bbox[0]} {bbox[1]}, {bbox[2]} {bbox[1]}, {bbox[2]} {bbox[3]}, {bbox[0]} {bbox[3]}, {bbox[0]} {bbox[1]}))" st.code(wkt, language="plaintext") if st.button("Copy WKT"): st.write("WKT copied!") else: st.error("Please enter 4 coordinates separated by commas.") except ValueError: st.error("Please enter valid coordinates (numbers separated by commas).") # Footer st.markdown("
Created with Streamlit - Inspired by bboxfinder.com
", unsafe_allow_html=True)