From 147b4ecb20bd3f8e9152a5e9ad66a6f6304c02ad Mon Sep 17 00:00:00 2001 From: hack_21031301_c761d3 <21031301@itcelaya.edu.mx> Date: Sat, 23 May 2026 02:17:53 -0600 Subject: [PATCH] =?UTF-8?q?feat:=20geolocalizaci=C3=B3n=20GPS=20para=20det?= =?UTF-8?q?ectar=20zona=20de=20recolecci=C3=B3n=20autom=C3=A1ticamente?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/__pycache__/main.cpython-312.pyc | Bin 14198 -> 15347 bytes backend/__pycache__/simulator.cpython-312.pyc | Bin 4637 -> 6194 bytes backend/main.py | 21 ++++++++++++++ backend/simulator.py | 27 +++++++++++++++++- 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/backend/__pycache__/main.cpython-312.pyc b/backend/__pycache__/main.cpython-312.pyc index b6b5fa68ebc72844912ec56225ae185ecb8c91a9..864af120e4ac1f3a9c4529a459ed3716ccf74747 100644 GIT binary patch delta 1217 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 H?IrdN#J*fE diff --git a/backend/main.py b/backend/main.py index 8df1b51..60cd788 100644 --- a/backend/main.py +++ b/backend/main.py @@ -174,6 +174,27 @@ def get_alerta_activa( return alerta return {"activa": False, "mensaje": None} +@app.get("/domicilios/ruta-por-coordenadas") +def ruta_por_coordenadas( + lat: float, + lng: float, + current_user=Depends(auth.get_current_user) +): + ruta, distancia = simulator.encontrar_ruta_por_coordenadas(lat, lng) + if not ruta: + raise HTTPException(status_code=404, detail="No hay cobertura en esta ubicación") + colonia_info = next( + (c for c in simulator.COLONIAS.values() if c["routeId"] == ruta["routeId"]), + None + ) + return { + "route_id": ruta["routeId"], + "nombre_ruta": ruta["name"], + "colonia_sugerida": colonia_info["colonia"] if colonia_info else ruta["name"], + "distancia_metros": round(distancia), + "cobertura": True + } + @app.websocket("/ws/eta/{domicilio_id}") async def websocket_eta(websocket: WebSocket, domicilio_id: int, token: str, db: Session = Depends(get_db)): diff --git a/backend/simulator.py b/backend/simulator.py index 3d0ae2e..9ce9181 100644 --- a/backend/simulator.py +++ b/backend/simulator.py @@ -1,6 +1,7 @@ import json import os import datetime +import math from sqlalchemy.orm import Session from database import SessionLocal import models @@ -64,4 +65,28 @@ def get_eta(route_id: str, db: Session): mensaje = f"El camión llegará a tu zona entre las {ventana_inicio} y {ventana_fin}." return {"mensaje": mensaje, "evento": evento, "ventana_inicio": ventana_inicio, "ventana_fin": ventana_fin, - "current_position": pos} \ No newline at end of file + "current_position": pos} + +def haversine(lat1: float, lon1: float, lat2: float, lon2: float) -> float: + R = 6371 + dlat = math.radians(lat2 - lat1) + dlon = math.radians(lon2 - lon1) + a = (math.sin(dlat/2)**2 + + math.cos(math.radians(lat1)) * + math.cos(math.radians(lat2)) * + math.sin(dlon/2)**2) + c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a)) + return R * c * 1000 + +def encontrar_ruta_por_coordenadas(lat: float, lng: float): + mejor_ruta = None + menor_distancia = float('inf') + for ruta in RUTAS: + for pos in ruta["positions"]: + distancia = haversine(lat, lng, pos["lat"], pos["lng"]) + if distancia < menor_distancia: + menor_distancia = distancia + mejor_ruta = ruta + if menor_distancia < 5000: + return mejor_ruta, menor_distancia + return None, None \ No newline at end of file