coolfrxcrazy commited on
Commit
97b0716
1 Parent(s): d49890c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +224 -95
app.py CHANGED
@@ -1,16 +1,15 @@
1
- import streamlit as st
2
  import googlemaps
3
  from polyline import decode
4
  import os
5
- # from dotenv import load_dotenv
6
- from bs4 import BeautifulSoup
7
- import json
8
- import time
9
 
10
- # Load environment variables and initialize the Google Maps API client
11
- # load_dotenv()
12
- API_KEY = 'AIzaSyBvsVrsscV50q6bVV7ofEm2tzCz08F1k1A'
13
- gmaps = googlemaps.Client(key='AIzaSyBvsVrsscV50q6bVV7ofEm2tzCz08F1k1A')
 
14
 
15
  # Define avoided segments globally
16
  avoid_list = [
@@ -38,31 +37,43 @@ def do_routes_intersect(route_a_steps, route_b_steps):
38
  # Loop through steps of both routes
39
  for step_a in route_a_steps:
40
  for step_b in route_b_steps:
 
41
  if step_a == step_b:
42
  road_name_a = get_road_name_from_step(step_a)
43
  road_name_b = get_road_name_from_step(step_b)
44
  if road_name_a == road_name_b:
45
  return True
 
 
46
  return False
47
 
48
  def get_road_name_from_step(step):
 
49
  if 'html_instructions' in step:
50
  instruction = step['html_instructions']
 
51
  road_name = extract_road_name(instruction)
52
  return road_name
53
  return None
54
 
55
  def extract_road_name(instruction):
 
 
56
  return BeautifulSoup(instruction, "html.parser").text
57
 
 
58
  # Find a route that avoids all segments in avoid_list and return the avoided routes
59
  def find_route_avoiding_segments(start, end, avoid_list):
60
  directions_a_b = get_directions(start, end, alternatives=True)
 
61
  if not directions_a_b:
62
  return None, None
 
63
  avoided_routes = []
 
64
  for route in directions_a_b:
65
  route_a_b_points = decode_polyline_to_points(route['overview_polyline']['points'])
 
66
  avoid_crossing = False
67
  for avoid_start, avoid_end in avoid_list:
68
  directions_c_d = get_directions(avoid_start, avoid_end, alternatives=False)
@@ -70,98 +81,216 @@ def find_route_avoiding_segments(start, end, avoid_list):
70
  route_c_d_points = decode_polyline_to_points(directions_c_d[0]['overview_polyline']['points'])
71
  if do_routes_intersect(route_a_b_points, route_c_d_points):
72
  avoid_crossing = True
73
- avoided_routes.append(directions_c_d[0])
74
- break
 
75
  if not avoid_crossing:
76
- return route, avoided_routes
 
77
  return None, None
78
 
79
- # Streamlit app
80
- st.title("Vehicle Dashboard & Route Planner with Google Maps")
81
-
82
- # Vehicle Information
83
- st.subheader("Vehicle Information")
84
- col1, col2, col3, col4 = st.columns(4)
85
- col1.metric("Truck Cost (SAR)", 500)
86
- col2.metric("Car Cost (SAR)", 300)
87
- col3.metric("Motorbike Cost (SAR)", 100)
88
- col4.metric("Total Vehicles", 150)
89
-
90
- # Input fields for start and end locations
91
- start_location = st.text_input("Enter Start Latitude,Longitude (e.g., 24.7136,46.6753)", "")
92
- end_location = st.text_input("Enter End Latitude,Longitude (e.g., 24.7886,46.6544)", "")
93
-
94
- # Button to calculate the route
95
- if st.button("Calculate Route"):
96
- if start_location and end_location:
97
- start_coords = tuple(map(float, start_location.split(',')))
98
- end_coords = tuple(map(float, end_location.split(',')))
99
-
100
- # Find route avoiding segments
101
- route, avoided_routes = find_route_avoiding_segments(start_coords, end_coords, avoid_list)
102
-
103
- if route:
104
- st.success("Valid Route Found!")
105
- # Extract route details
106
- route_points = decode_polyline_to_points(route['overview_polyline']['points'])
107
-
108
- # Embed Google Maps using the polyline
109
- st.components.v1.html(f"""
110
- <!DOCTYPE html>
111
- <html lang="en">
112
- <head>
113
- <meta charset="UTF-8" />
114
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
115
- <script src="https://maps.googleapis.com/maps/api/js?key={API_KEY}&libraries=geometry"></script>
116
- <style>
117
- #map {{
118
- height: 500px;
119
- width: 100%;
120
- }}
121
- </style>
122
- </head>
123
- <body>
124
- <div id="map"></div>
125
- <script>
126
- function initMap() {{
127
- const map = new google.maps.Map(document.getElementById('map'), {{
128
- zoom: 12,
129
- center: {{ lat: {start_coords[0]}, lng: {start_coords[1]} }},
130
- }});
131
-
132
- const decodedPath = google.maps.geometry.encoding.decodePath("{route['overview_polyline']['points']}");
133
- const directionsPath = new google.maps.Polyline({{
134
- path: decodedPath,
135
- geodesic: true,
136
- strokeColor: "#0000FF",
137
- strokeOpacity: 1.0,
138
- strokeWeight: 4,
139
- }});
140
- directionsPath.setMap(map);
141
- }}
142
- window.onload = initMap;
143
- </script>
144
- </body>
145
- </html>
146
- """, height=550)
147
- else:
148
- st.error("No valid route found.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  else:
150
- st.error("Please enter both start and end locations.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
 
152
- # Button to display avoided routes
153
- if st.button("Show Avoided Routes"):
 
 
 
 
 
 
 
 
 
 
 
154
  avoided_routes_json = []
 
 
155
  for avoid_start, avoid_end in avoid_list:
156
  directions = get_directions(avoid_start, avoid_end, alternatives=False)
157
  if directions:
158
- avoided_routes_json.append({
159
- "start_address": directions[0]['legs'][0]['start_address'],
160
- "end_address": directions[0]['legs'][0]['end_address'],
161
- "overview_polyline": directions[0]['overview_polyline']['points']
162
- })
163
-
164
- if avoided_routes_json:
165
- st.json(avoided_routes_json)
166
- else:
167
- st.error("No avoided routes found.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, render_template, jsonify, request
2
  import googlemaps
3
  from polyline import decode
4
  import os
5
+ from dotenv import load_dotenv
6
+ from bs4 import BeautifulSoup # To clean HTML tags
 
 
7
 
8
+ load_dotenv()
9
+ API_KEY = os.getenv('GOOGLE_MAPS_API_KEY_3')
10
+ gmaps = googlemaps.Client(key=API_KEY)
11
+
12
+ app = Flask(__name__)
13
 
14
  # Define avoided segments globally
15
  avoid_list = [
 
37
  # Loop through steps of both routes
38
  for step_a in route_a_steps:
39
  for step_b in route_b_steps:
40
+ # Check if the routes share the same point (latitude and longitude)
41
  if step_a == step_b:
42
  road_name_a = get_road_name_from_step(step_a)
43
  road_name_b = get_road_name_from_step(step_b)
44
  if road_name_a == road_name_b:
45
  return True
46
+
47
+ # No intersection found
48
  return False
49
 
50
  def get_road_name_from_step(step):
51
+ # The road name is usually part of 'html_instructions'
52
  if 'html_instructions' in step:
53
  instruction = step['html_instructions']
54
+ # Optionally: Clean up the instruction to extract only the road name (e.g., remove HTML tags)
55
  road_name = extract_road_name(instruction)
56
  return road_name
57
  return None
58
 
59
  def extract_road_name(instruction):
60
+ # Here you can implement more complex logic if needed to extract the road name from the instruction
61
+ # e.g., remove HTML tags, get the road name from the instructions
62
  return BeautifulSoup(instruction, "html.parser").text
63
 
64
+
65
  # Find a route that avoids all segments in avoid_list and return the avoided routes
66
  def find_route_avoiding_segments(start, end, avoid_list):
67
  directions_a_b = get_directions(start, end, alternatives=True)
68
+
69
  if not directions_a_b:
70
  return None, None
71
+
72
  avoided_routes = []
73
+
74
  for route in directions_a_b:
75
  route_a_b_points = decode_polyline_to_points(route['overview_polyline']['points'])
76
+
77
  avoid_crossing = False
78
  for avoid_start, avoid_end in avoid_list:
79
  directions_c_d = get_directions(avoid_start, avoid_end, alternatives=False)
 
81
  route_c_d_points = decode_polyline_to_points(directions_c_d[0]['overview_polyline']['points'])
82
  if do_routes_intersect(route_a_b_points, route_c_d_points):
83
  avoid_crossing = True
84
+ avoided_routes.append(directions_c_d[0]) # Save the avoided route
85
+ break # This route crosses an avoidable segment, so skip it
86
+
87
  if not avoid_crossing:
88
+ return route, avoided_routes # Return the valid route and avoided routes
89
+
90
  return None, None
91
 
92
+ RIYADH_BOUNDING_BOX = {
93
+ 'north': 25.0885, # Northernmost latitude in Riyadh
94
+ 'south': 24.3246, # Southernmost latitude in Riyadh
95
+ 'west': 46.2613, # Westernmost longitude in Riyadh
96
+ 'east': 47.0484 # Easternmost longitude in Riyadh
97
+ }
98
+
99
+ def is_within_bounds(lat, lng):
100
+ """Check if a given latitude and longitude are within the Riyadh bounding box."""
101
+ return (RIYADH_BOUNDING_BOX['south'] <= lat <= RIYADH_BOUNDING_BOX['north'] and
102
+ RIYADH_BOUNDING_BOX['west'] <= lng <= RIYADH_BOUNDING_BOX['east'])
103
+
104
+ def is_route_within_bounds(route):
105
+ """Check if the entire route stays within the Riyadh bounding box."""
106
+ # Go through each step in the route and check the start and end locations
107
+ for leg in route['legs']:
108
+ for step in leg['steps']:
109
+ start_lat = step['start_location']['lat']
110
+ start_lng = step['start_location']['lng']
111
+ end_lat = step['end_location']['lat']
112
+ end_lng = step['end_location']['lng']
113
+
114
+ if not is_within_bounds(start_lat, start_lng) or not is_within_bounds(end_lat, end_lng):
115
+ return False
116
+ return True
117
+
118
+ def find_mid_point_between(start, end):
119
+ """Finds a mid-point between start and end, ensuring it is within Riyadh."""
120
+ start_lat, start_lng = map(float, start.split(','))
121
+ end_lat, end_lng = map(float, end.split(','))
122
+
123
+ mid_lat = (start_lat + end_lat) / 2
124
+ mid_lng = (start_lng + end_lng) / 2
125
+
126
+ # Check if the mid-point is within the Riyadh bounding box
127
+ if is_within_bounds(mid_lat, mid_lng):
128
+ return f"{mid_lat},{mid_lng}"
129
+ else:
130
+ # If the mid-point is outside bounds, return None
131
+ return None
132
+
133
+
134
+ def recursive_route_search(start, end, avoid_list, depth=0, max_depth=3):
135
+ """
136
+ Helper function that determines whether we can find valid segments
137
+ by recursively calculating mid-points.
138
+ """
139
+ if depth > max_depth:
140
+ return None
141
+
142
+ # Calculate the mid-point between start and end
143
+ mid_point = find_mid_point_between(start, end)
144
+
145
+ if not mid_point:
146
+ # If the mid-point is outside valid bounds, stop recursion
147
+ return None
148
+
149
+ # Check if direct route from start to mid-point is valid
150
+ first_segment = find_valid_route(start, mid_point, avoid_list)
151
+
152
+ if not first_segment:
153
+ # If we can't find a valid first segment, try smaller segments
154
+ return recursive_route_search(start, mid_point, avoid_list, depth + 1, max_depth)
155
+
156
+ # Check if direct route from mid-point to end is valid
157
+ second_segment = find_valid_route(mid_point, end, avoid_list)
158
+
159
+ if not second_segment:
160
+ # If we can't find a valid second segment, try smaller segments
161
+ return recursive_route_search(mid_point, end, avoid_list, depth + 1, max_depth)
162
+
163
+ # If both segments are valid, merge them and return
164
+ return merge_segments(first_segment, second_segment)
165
+
166
+ def merge_segments(first_segment, second_segment):
167
+ """Merges two route segments into one."""
168
+ merged_route = {
169
+ 'legs': first_segment['legs'] + second_segment['legs'],
170
+ 'overview_polyline': {
171
+ 'points': first_segment['overview_polyline']['points'] + second_segment['overview_polyline']['points']
172
+ }
173
+ }
174
+ return merged_route
175
+ def find_valid_route(start, end, avoid_list):
176
+ """Attempts to find a valid route from start to end, avoiding specific segments."""
177
+ # Get routes from A to B (with alternatives)
178
+ routes = get_directions(start, end, alternatives=True)
179
+
180
+ if not routes:
181
+ return None
182
+
183
+ # Iterate through all available routes
184
+ for route in routes:
185
+ route_a_b_points = decode_polyline_to_points(route['overview_polyline']['points'])
186
+
187
+ # Ensure the entire route stays within bounds
188
+ if not is_route_within_bounds(route):
189
+ continue # Skip this route if it goes outside the bounding box
190
+
191
+ # Assume this route is valid until proven otherwise
192
+ avoid_crossing = False
193
+
194
+ # Check if it crosses any avoided routes
195
+ for avoid_start, avoid_end in avoid_list:
196
+ directions_c_d = get_directions(avoid_start, avoid_end, alternatives=False)
197
+ if directions_c_d:
198
+ route_c_d_points = decode_polyline_to_points(directions_c_d[0]['overview_polyline']['points'])
199
+ if do_routes_intersect(route_a_b_points, route_c_d_points):
200
+ avoid_crossing = True
201
+ break # Exit loop since the route crosses an avoided route
202
+
203
+ if not avoid_crossing:
204
+ # Found a valid route that doesn't cross any avoided segments
205
+ return route
206
+
207
+ return None # No valid route found
208
+
209
+
210
+ @app.route('/calculate-route', methods=['POST'])
211
+ def calculate_route():
212
+ data = request.json
213
+ start = data['start']
214
+ end = data['end']
215
+
216
+ # Try to find a direct route first
217
+ route = find_valid_route(start, end, avoid_list)
218
+
219
+ if not route:
220
+ # If no valid direct route is found, try to find an alternative recursively
221
+ route = recursive_route_search(start, end, avoid_list)
222
+
223
+ if route:
224
+ route_json = format_route_to_json(route)
225
+ return jsonify({
226
+ 'status': 'success',
227
+ 'route': route_json
228
+ })
229
  else:
230
+ return jsonify({
231
+ 'status': 'error',
232
+ 'message': 'All routes cross an avoided street or no valid route found.'
233
+ })
234
+
235
+ # Helper function to format the route into JSON format
236
+ def format_route_to_json(route):
237
+ return {
238
+ 'start_address': route['legs'][0]['start_address'],
239
+ 'end_address': route['legs'][0]['end_address'],
240
+ 'distance': route['legs'][0]['distance']['text'],
241
+ 'duration': route['legs'][0]['duration']['text'],
242
+ 'overview_polyline': route['overview_polyline']['points']
243
+ }
244
+
245
+ # Define vehicle costs as functions
246
+ def get_truck_cost():
247
+ return 500 # Example cost for truck, can be dynamic
248
 
249
+ def get_car_cost():
250
+ return 300 # Example cost for car, can be dynamic
251
+
252
+ def get_motorbike_cost():
253
+ return 100 # Example cost for motorbike, can be dynamic
254
+
255
+ # Define a function to return the total number of vehicles
256
+ def get_total_vehicles():
257
+ return 150 # Example total, can be dynamic
258
+
259
+ # Return avoided routes on map initialization
260
+ @app.route('/get-avoided-routes', methods=['GET'])
261
+ def get_avoided_routes():
262
  avoided_routes_json = []
263
+
264
+ # Retrieve directions for each avoid list pair and add to the JSON
265
  for avoid_start, avoid_end in avoid_list:
266
  directions = get_directions(avoid_start, avoid_end, alternatives=False)
267
  if directions:
268
+ avoided_routes_json.append(format_route_to_json(directions[0]))
269
+
270
+ return jsonify({
271
+ 'status': 'success',
272
+ 'avoided_routes': avoided_routes_json
273
+ })
274
+
275
+
276
+ @app.route('/get-vehicle-info', methods=['GET'])
277
+ def get_vehicle_info():
278
+ return jsonify({
279
+ 'truck_cost': get_truck_cost(),
280
+ 'car_cost': get_car_cost(),
281
+ 'motorbike_cost': get_motorbike_cost(),
282
+ 'total_vehicles': get_total_vehicles()
283
+ })
284
+
285
+ @app.route('/')
286
+ def index():
287
+ return render_template(
288
+ 'index.html',
289
+ truck_cost=get_truck_cost(),
290
+ car_cost=get_car_cost(),
291
+ motorbike_cost=get_motorbike_cost(),
292
+ total_vehicles=get_total_vehicles()
293
+ )
294
+
295
+ if __name__ == "__main__":
296
+ app.run(host='0.0.0.0', port=5858,debug=True)