Spaces:
Running
Running
Update main.py
Browse files
main.py
CHANGED
|
@@ -12,6 +12,9 @@ app = FastAPI(title="GeoJSON and Heatmap API", description="API for random coord
|
|
| 12 |
# Global variable to store the last selected coordinate
|
| 13 |
last_coordinate: List[float] = None
|
| 14 |
|
|
|
|
|
|
|
|
|
|
| 15 |
# Load GeoJSON data from file
|
| 16 |
def load_geojson_data(file_path: str = "synthetic_ps_points.geojson") -> Dict[str, Any]:
|
| 17 |
try:
|
|
@@ -35,6 +38,19 @@ def load_csv_data(file_path: str = "synthetic_ps_points.csv") -> pd.DataFrame:
|
|
| 35 |
def calculate_distance(coord1: List[float], coord2: List[float]) -> float:
|
| 36 |
return math.sqrt((coord2[0] - coord1[0]) ** 2 + (coord2[1] - coord1[1]) ** 2)
|
| 37 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
# Find the closest feature to a given coordinate
|
| 39 |
def find_closest_feature(coord: List[float], features: List[Dict]) -> Dict:
|
| 40 |
min_distance = float('inf')
|
|
@@ -57,14 +73,14 @@ def generate_path(start_coord: List[float], end_coord: List[float], num_steps: i
|
|
| 57 |
path.append({"step": i, "coordinates": [lon, lat]})
|
| 58 |
return path
|
| 59 |
|
| 60 |
-
# Endpoint to get a single random coordinate, ensuring separation from the last coordinate
|
| 61 |
@app.get("/get-coordinates", response_model=dict)
|
| 62 |
-
async def get_random_coordinates(min_distance: float = 0.
|
| 63 |
"""
|
| 64 |
-
Returns a single random coordinate
|
| 65 |
|
| 66 |
Parameters:
|
| 67 |
-
- min_distance: Minimum distance from the last coordinate in degrees (default: 0.
|
| 68 |
"""
|
| 69 |
global last_coordinate
|
| 70 |
data = load_geojson_data()
|
|
@@ -72,12 +88,17 @@ async def get_random_coordinates(min_distance: float = 0.01):
|
|
| 72 |
if not features:
|
| 73 |
raise HTTPException(status_code=400, detail="No features found in GeoJSON data")
|
| 74 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
selected_feature = None
|
| 76 |
attempts = 0
|
| 77 |
-
max_attempts =
|
| 78 |
|
| 79 |
while attempts < max_attempts:
|
| 80 |
-
random_feature = random.choice(
|
| 81 |
random_coord = random_feature["geometry"]["coordinates"]
|
| 82 |
|
| 83 |
# Check distance from last coordinate (if it exists)
|
|
@@ -197,7 +218,7 @@ async def root():
|
|
| 197 |
return {
|
| 198 |
"message": "Welcome to the GeoJSON and Heatmap API",
|
| 199 |
"endpoints": {
|
| 200 |
-
"/get-coordinates": "Returns a single random coordinate
|
| 201 |
"/simulate-worker-path": "Simulates a worker's path from a normal risk to a high risk zone",
|
| 202 |
"/heatmap": "Returns raw HTML for a Folium heatmap of PS data"
|
| 203 |
}
|
|
|
|
| 12 |
# Global variable to store the last selected coordinate
|
| 13 |
last_coordinate: List[float] = None
|
| 14 |
|
| 15 |
+
# Polygon bounds for Singrauli
|
| 16 |
+
POLYGON_BOUNDS = [(82.5065, 22.3105), (82.628, 22.3105), (82.628, 22.3421), (82.5065, 22.3421)]
|
| 17 |
+
|
| 18 |
# Load GeoJSON data from file
|
| 19 |
def load_geojson_data(file_path: str = "synthetic_ps_points.geojson") -> Dict[str, Any]:
|
| 20 |
try:
|
|
|
|
| 38 |
def calculate_distance(coord1: List[float], coord2: List[float]) -> float:
|
| 39 |
return math.sqrt((coord2[0] - coord1[0]) ** 2 + (coord2[1] - coord1[1]) ** 2)
|
| 40 |
|
| 41 |
+
# Point-in-polygon check using ray-casting algorithm
|
| 42 |
+
def is_point_in_polygon(point: List[float], polygon: List[tuple]) -> bool:
|
| 43 |
+
x, y = point[0], point[1]
|
| 44 |
+
n = len(polygon)
|
| 45 |
+
inside = False
|
| 46 |
+
j = n - 1
|
| 47 |
+
for i in range(n):
|
| 48 |
+
if ((polygon[i][1] > y) != (polygon[j][1] > y)) and \
|
| 49 |
+
(x < (polygon[j][0] - polygon[i][0]) * (y - polygon[i][1]) / (polygon[j][1] - polygon[i][1]) + polygon[i][0]):
|
| 50 |
+
inside = not inside
|
| 51 |
+
j = i
|
| 52 |
+
return inside
|
| 53 |
+
|
| 54 |
# Find the closest feature to a given coordinate
|
| 55 |
def find_closest_feature(coord: List[float], features: List[Dict]) -> Dict:
|
| 56 |
min_distance = float('inf')
|
|
|
|
| 73 |
path.append({"step": i, "coordinates": [lon, lat]})
|
| 74 |
return path
|
| 75 |
|
| 76 |
+
# Endpoint to get a single random coordinate, ensuring wide separation from the last coordinate
|
| 77 |
@app.get("/get-coordinates", response_model=dict)
|
| 78 |
+
async def get_random_coordinates(min_distance: float = 0.05):
|
| 79 |
"""
|
| 80 |
+
Returns a single random coordinate within the Singrauli polygon, ensuring a minimum distance from the last selected coordinate.
|
| 81 |
|
| 82 |
Parameters:
|
| 83 |
+
- min_distance: Minimum distance from the last coordinate in degrees (default: 0.05, ~5.5 km)
|
| 84 |
"""
|
| 85 |
global last_coordinate
|
| 86 |
data = load_geojson_data()
|
|
|
|
| 88 |
if not features:
|
| 89 |
raise HTTPException(status_code=400, detail="No features found in GeoJSON data")
|
| 90 |
|
| 91 |
+
# Filter features within the Singrauli polygon
|
| 92 |
+
valid_features = [f for f in features if is_point_in_polygon(f["geometry"]["coordinates"], POLYGON_BOUNDS)]
|
| 93 |
+
if not valid_features:
|
| 94 |
+
raise HTTPException(status_code=400, detail="No features found within the Singrauli polygon")
|
| 95 |
+
|
| 96 |
selected_feature = None
|
| 97 |
attempts = 0
|
| 98 |
+
max_attempts = 200 # Increased to handle sparse valid selections
|
| 99 |
|
| 100 |
while attempts < max_attempts:
|
| 101 |
+
random_feature = random.choice(valid_features)
|
| 102 |
random_coord = random_feature["geometry"]["coordinates"]
|
| 103 |
|
| 104 |
# Check distance from last coordinate (if it exists)
|
|
|
|
| 218 |
return {
|
| 219 |
"message": "Welcome to the GeoJSON and Heatmap API",
|
| 220 |
"endpoints": {
|
| 221 |
+
"/get-coordinates": "Returns a single random coordinate within the Singrauli polygon, widely spaced from the last coordinate",
|
| 222 |
"/simulate-worker-path": "Simulates a worker's path from a normal risk to a high risk zone",
|
| 223 |
"/heatmap": "Returns raw HTML for a Folium heatmap of PS data"
|
| 224 |
}
|