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)