from tpmcqr_service import db from sqlalchemy.orm import aliased from sqlalchemy import any_ from sqlalchemy import func from geoalchemy2 import Geometry from zoneinfo import ZoneInfo class Lineas(db.Model): __tablename__ = 'linea' __table_args__ = { 'schema': 'public' } id_linea = db.Column(db.String(150), primary_key=True ) id_operador = db.Column(db.String(150)) route_short_name = db.Column(db.String(150)) route_long_name = db.Column(db.String(150)) route_color = db.Column(db.String(150)) route_text_color = db.Column(db.String(150)) vigente = db.Column(db.Boolean) class QRDev(db.Model): __tablename__ = 'dispositivo' __table_args__ = { 'schema': 'public' } id_dispositivo = db.Column(db.String(100), primary_key=True ) id_paradero = db.Column(db.String(50)) class Paraderos(db.Model): __tablename__ = 'paradero' __table_args__ = { 'schema': 'public' } id_paradero = db.Column(db.String(50), primary_key=True ) stop_name = db.Column(db.String(50)) stop_lat = db.Column(db.Float) stop_lon = db.Column(db.Float) class Shapes(db.Model): __tablename__ = 'gtfs_shape' __table_args__ = { 'schema': 'public' } id_gtfs_pk = db.Column(db.Integer, primary_key=True ) id_shape = db.Column(db.String(150)) shape_pt_lat = db.Column(db.Float) shape_pt_lon = db.Column(db.Float) shape_pt_sequence = db.Column(db.Integer) shape_dist_traveled = db.Column(db.Float) class Trips(db.Model): __tablename__ = 'gtfs_trips' __table_args__ = { 'schema': 'public' } id_trip = db.Column(db.String(150), primary_key=True) id_linea = db.Column(db.String(150)) id_shape = db.Column(db.String(150)) service_id = db.Column(db.String(50)) class Stops(db.Model): __tablename__ = 'gtfs_stop_times' __table_args__ = { 'schema': 'public' } id_paradero = db.Column(db.String(50), db.ForeignKey('paradero.id_paradero'), primary_key=True) id_trip = db.Column(db.String(150), db.ForeignKey('gtfs_trips.id_trip'), primary_key=True) def find_shape_position(shape_id, lat, lng): Shape1 = aliased(Shapes) Shape2 = aliased(Shapes) point = func.ST_SetSRID(func.ST_MakePoint(lng, lat), 4326) # Create PostGIS point segmento = db.session.query( Shape1.shape_pt_sequence.label("start_sequence"), # Shape2.shape_pt_sequence.label("end_sequence"), Shape1.shape_dist_traveled.label("traveled_start"), Shape2.shape_dist_traveled.label("traveled_end"), func.ST_Distance( func.ST_MakeLine( func.ST_SetSRID(func.ST_MakePoint(Shape1.shape_pt_lon, Shape1.shape_pt_lat), 4326), func.ST_SetSRID(func.ST_MakePoint(Shape2.shape_pt_lon, Shape2.shape_pt_lat), 4326) ), point ).label("distance"), func.ST_LineLocatePoint( # Compute fractional position on the segment func.ST_MakeLine( func.ST_SetSRID(func.ST_MakePoint(Shape1.shape_pt_lon, Shape1.shape_pt_lat), 4326), func.ST_SetSRID(func.ST_MakePoint(Shape2.shape_pt_lon, Shape2.shape_pt_lat), 4326) ), point ).label("fraction") ).filter( Shape1.id_shape == shape_id, Shape2.id_shape == shape_id, Shape2.shape_pt_sequence == Shape1.shape_pt_sequence + 1 # Ensure correct segment order ).order_by("distance").first() avanzado = segmento.traveled_start + segmento.fraction * (segmento.traveled_end - segmento.traveled_start) return ( segmento.start_sequence, avanzado )