File size: 4,713 Bytes
5ff2435
 
 
932a171
ee77ee9
932a171
 
5ff2435
500b397
5ff2435
500b397
3e21d9f
 
 
 
 
 
 
 
 
 
5ff2435
 
500b397
ee77ee9
500b397
ee77ee9
 
 
 
3e21d9f
 
ee77ee9
 
500b397
ee77ee9
3e21d9f
 
 
 
 
 
 
 
500b397
 
 
 
ee77ee9
932a171
2793622
3e21d9f
 
2793622
ee77ee9
500b397
932a171
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
500b397
5ff2435
 
3e21d9f
5ff2435
9230299
3e21d9f
9230299
5ff2435
2793622
5ff2435
3fbf837
500b397
3e21d9f
 
 
 
932a171
97de2b1
5ff2435
ee77ee9
3e21d9f
5ff2435
500b397
5ff2435
 
 
3e21d9f
 
5ff2435
 
 
ee77ee9
cf2c7b4
2793622
 
cf2c7b4
 
5ff2435
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
import gradio as gr
import folium
import networkx as nx
from folium import Map, Marker, PolyLine
from math import radians, cos, sin, sqrt, atan2
from branca.element import MacroElement
from jinja2 import Template

# 1. Districts and Coordinates (Harimo Kigali)
places = {
    "Kigali": (-1.9441, 30.0619),  # Kigali city center
    "Nyarugenge": (-1.9577, 30.0619), "Gasabo": (-1.9400, 30.0861), "Kicukiro": (-1.9781, 30.0597),
    "Burera": (-1.4800, 29.7300), "Gakenke": (-1.5700, 29.7561), "Rulindo": (-1.8333, 30.0833),
    "Musanze": (-1.5014, 29.6344), "Gicumbi": (-1.5794, 30.0542), "Nyagatare": (-1.3100, 30.3000),
    "Gatsibo": (-1.6800, 30.3900), "Kayonza": (-2.0000, 30.5667), "Kirehe": (-2.3553, 30.7767),
    "Ngoma": (-2.1600, 30.4700), "Rwamagana": (-1.9491, 30.4349), "Bugesera": (-2.2083, 30.2576),
    "Kamonyi": (-2.0833, 29.9000), "Muhanga": (-2.1200, 29.7561), "Ruhango": (-2.2136, 29.7628),
    "Nyamagabe": (-2.4978, 29.4897), "Nyaruguru": (-2.5806, 29.4306), "Huye": (-2.5921, 29.7408),
    "Gisagara": (-2.6283, 29.6820), "Nyanza": (-2.3566, 29.7507), "Rutsiro": (-2.0986, 29.3269),
    "Karongi": (-2.0667, 29.4677), "Rubavu": (-1.7481, 29.2730), "Rusizi": (-2.5406, 29.3737),
    "Nyamasheke": (-2.4700, 29.3222), "Ngororero": (-1.8733, 29.5811)
}

# 2. Distance calculator (Haversine Formula)
def haversine(coord1, coord2):
    R = 6371  # Earth radius in km
    lat1, lon1 = coord1
    lat2, lon2 = coord2
    dlat = radians(lat2 - lat1)
    dlon = radians(lon2 - lon1)
    a = sin(dlat / 2)**2 + cos(radians(lat1)) * cos(radians(lat2)) * sin(dlon / 2)**2
    c = 2 * atan2(sqrt(a), sqrt(1 - a))
    return R * c

# 3. Edges (connect Kigali and other districts)
edges = [
    ("Nyarugenge", "Gasabo"), ("Gasabo", "Kicukiro"), ("Kicukiro", "Bugesera"), ("Bugesera", "Rwamagana"),
    ("Rwamagana", "Kayonza"), ("Kayonza", "Kirehe"), ("Kirehe", "Ngoma"), ("Ngoma", "Gatsibo"),
    ("Gatsibo", "Nyagatare"), ("Gatsibo", "Gicumbi"), ("Gicumbi", "Rulindo"), ("Rulindo", "Gakenke"),
    ("Gakenke", "Burera"), ("Burera", "Musanze"), ("Musanze", "Rubavu"), ("Rubavu", "Rutsiro"),
    ("Rutsiro", "Karongi"), ("Karongi", "Nyamasheke"), ("Nyamasheke", "Rusizi"), ("Rutsiro", "Ngororero"),
    ("Ngororero", "Muhanga"), ("Muhanga", "Kamonyi"), ("Kamonyi", "Nyarugenge"), ("Muhanga", "Ruhango"),
    ("Ruhango", "Nyanza"), ("Nyanza", "Huye"), ("Huye", "Gisagara"), ("Gisagara", "Nyaruguru"),
    ("Nyaruguru", "Nyamagabe"), ("Nyamagabe", "Karongi"), ("Ngororero", "Ruhango"),
    ("Gicumbi", "Gasabo"), ("Bugesera", "Ngoma"),

    # Kigali connections
    ("Kigali", "Nyarugenge"), ("Kigali", "Gasabo"), ("Kigali", "Kicukiro")
]

# 4. Create Graph
G = nx.Graph()
for u, v in edges:
    G.add_edge(u, v, weight=haversine(places[u], places[v]))

# 5. Animation class
class AnimateMarker(MacroElement):
    _template = Template("""
        {% macro script(this, kwargs) %}
        var marker = L.marker({{this.locations[0]}}).addTo({{this._parent.get_name()}});
        var latlngs = {{this.locations}};
        var index = 0;
        function moveMarker(){
            index++;
            if(index >= latlngs.length){
                return;
            }
            marker.setLatLng(latlngs[index]);
            setTimeout(moveMarker, 700);
        }
        moveMarker();
        {% endmacro %}
    """)
    def __init__(self, locations):
        super().__init__()
        self._name = "AnimateMarker"
        self.locations = locations

# 6. Routing Function
def generate_map(start, end):
    if start == end:
        return "Hitamo aho utangiriye n’aho ugiye bitandukanye.", ""

    if not nx.has_path(G, start, end):
        return f"Nta nzira ibaho hagati ya {start} na {end}.", ""

    try:
        path = nx.astar_path(G, start, end, heuristic=lambda u, v: haversine(places[u], places[v]), weight='weight')
        coords = [places[p] for p in path]

        m = Map(location=[-1.9441, 30.0619], zoom_start=9)
        for name, coord in places.items():
            Marker(location=coord, popup=name).add_to(m)

        PolyLine(coords, color="blue", weight=5).add_to(m)
        m.add_child(AnimateMarker(coords))

        return "Inzira ngufi ni: " + " ➔ ".join(path), m._repr_html_()
    except Exception as e:
        return f"Ntibishoboka kubona inzira: {str(e)}", ""

# 7. Gradio Interface
iface = gr.Interface(
    fn=generate_map,
    inputs=[
        gr.Dropdown(list(places.keys()), label="Hitamo aho uri"),
        gr.Dropdown(list(places.keys()), label="Hitamo aho ugiye")
    ],
    outputs=[
        gr.Textbox(label="Ubutumwa"),
        gr.HTML(label="Ikarita")
    ],
    title="🗺️ VIATEUR AI - Rwanda Smart Route Planner",
    theme="default"
)

iface.launch()