File size: 5,651 Bytes
3535b1a d910b17 24b198e 6c147b4 3535b1a 7ca9ac5 3535b1a 7ca9ac5 1b5eabb 7ca9ac5 3535b1a 1b5eabb eff42fb 1b5eabb eff42fb 3535b1a 6c147b4 1b5eabb eff42fb 3535b1a eff42fb 6c147b4 1b5eabb eff42fb 24b198e 1b5eabb 6c147b4 eff42fb 7ca9ac5 6c147b4 3535b1a 7ca9ac5 6c147b4 eff42fb 7ca9ac5 1b5eabb 7ca9ac5 1b5eabb 7ca9ac5 1b5eabb 7ca9ac5 1b5eabb eff42fb 1b5eabb eff42fb 7ca9ac5 6c147b4 eff42fb 7ca9ac5 6c147b4 eff42fb 7ca9ac5 6c147b4 7ca9ac5 6c147b4 3535b1a eff42fb 6c147b4 |
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 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
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("""
<style>
.main { padding-top: 0; }
.stApp { margin-top: -80px; }
.css-1kyxreq { justify-content: center; }
.css-5rimss { font-size: 14px; }
</style>
""", 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("""
<script>
var drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
map.on(L.Draw.Event.CREATED, function (event) {
drawnItems.clearLayers();
var layer = event.layer;
drawnItems.addLayer(layer);
var bounds = layer.getBounds();
var bbox = [bounds.getWest(), bounds.getSouth(), bounds.getEast(), bounds.getNorth()];
var bboxString = bbox.join(',');
window.parent.postMessage({
type: 'streamlit:set_widget_value',
key: 'bbox_coords',
value: bboxString
}, '*');
});
</script>
"""))
m.to_streamlit(height=600)
with col2:
st.markdown("<h3 style='text-align: center;'>Coordinates</h3>", 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"<b>Selected CRS: {selected_crs}</b>", 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("<b>Other common CRSs:</b>", 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("<b>GeoJSON</b>", 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("<b>WKT</b>", 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("<div style='text-align: center; color: gray;'>Created with Streamlit - Inspired by bboxfinder.com</div>", unsafe_allow_html=True) |