refactor: migrar utm→pyproj, limpiar código muerto, reestructurar en PVPlant/core/
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2026 Javier Brana <javier.branagutierrez@gmail.com> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify*
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307*
|
||||
# * USA *
|
||||
# * *
|
||||
# ***********************************************************************
|
||||
|
||||
"""
|
||||
Proyecciones y transformaciones geodésicas unificadas para PVPlant.
|
||||
|
||||
Reemplaza el uso disperso de la librería 'utm' con pyproj (PROJ),
|
||||
soporte multi-zona UTM y transformaciones entre datums.
|
||||
|
||||
Uso básico:
|
||||
from lib.projection import latlon_to_utm, utm_to_latlon, get_utm_zone
|
||||
"""
|
||||
|
||||
import FreeCAD
|
||||
from pyproj import CRS, Transformer
|
||||
from pyproj.aoi import AreaOfInterest
|
||||
from pyproj.database import query_utm_crs_info
|
||||
|
||||
# WGS84 – sistema de coordenadas geográfico de referencia
|
||||
_WGS84 = CRS.from_epsg(4326)
|
||||
|
||||
# Cache de transformadores UTM por zona (lazy)
|
||||
_utm_transformers = {}
|
||||
|
||||
|
||||
def _get_utm_transformer(lat, lon):
|
||||
"""Obtiene (o crea en caché) un transformador UTM para la zona de las coordenadas dadas.
|
||||
Returns:
|
||||
tuple: (transformer, zone_number, zone_letter)
|
||||
"""
|
||||
# Determinar la zona UTM a partir de lat/lon
|
||||
zone_number = int((lon + 180) / 6) + 1
|
||||
|
||||
if lat >= 0:
|
||||
zone_letter = 'N'
|
||||
epsg = 32600 + zone_number
|
||||
else:
|
||||
zone_letter = 'S'
|
||||
epsg = 32700 + zone_number
|
||||
|
||||
cache_key = (zone_number, zone_letter)
|
||||
if cache_key not in _utm_transformers:
|
||||
utm_crs = CRS.from_epsg(epsg)
|
||||
_utm_transformers[cache_key] = Transformer.from_crs(
|
||||
_WGS84, utm_crs, always_xy=True
|
||||
)
|
||||
|
||||
return _utm_transformers[cache_key], zone_number, zone_letter
|
||||
|
||||
|
||||
def latlon_to_utm(lat, lon):
|
||||
"""Convierte coordenadas geográficas (WGS84) a UTM (este, norte, zona, letra).
|
||||
|
||||
Args:
|
||||
lat (float): Latitud en grados.
|
||||
lon (float): Longitud en grados.
|
||||
|
||||
Returns:
|
||||
tuple: (easting, northing, zone_number, zone_letter)
|
||||
easting/northing en metros.
|
||||
"""
|
||||
transformer, zone_number, zone_letter = _get_utm_transformer(lat, lon)
|
||||
easting, northing = transformer.transform(lon, lat)
|
||||
return easting, northing, zone_number, zone_letter
|
||||
|
||||
|
||||
def utm_to_latlon(easting, northing, zone_number, zone_letter='N'):
|
||||
"""Convierte coordenadas UTM a geográficas (WGS84).
|
||||
|
||||
Args:
|
||||
easting (float): Coordenada E en metros.
|
||||
northing (float): Coordenada N en metros.
|
||||
zone_number (int): Número de zona UTM (1-60).
|
||||
zone_letter (str): Letra de zona ('N' o 'S').
|
||||
|
||||
Returns:
|
||||
tuple: (latitude, longitude) en grados.
|
||||
"""
|
||||
if zone_letter.upper() not in ('N', 'S'):
|
||||
zone_letter = 'N'
|
||||
|
||||
epsg = 32600 + zone_number if zone_letter.upper() == 'N' else 32700 + zone_number
|
||||
utm_crs = CRS.from_epsg(epsg)
|
||||
transformer = Transformer.from_crs(utm_crs, _WGS84, always_xy=True)
|
||||
lon, lat = transformer.transform(easting, northing)
|
||||
return lat, lon
|
||||
|
||||
|
||||
def get_utm_zone(lat, lon):
|
||||
"""Obtiene la zona UTM para unas coordenadas dadas.
|
||||
|
||||
Args:
|
||||
lat (float): Latitud en grados.
|
||||
lon (float): Longitud en grados.
|
||||
|
||||
Returns:
|
||||
tuple: (zone_number, zone_letter)
|
||||
"""
|
||||
_, _, zone_number, zone_letter = latlon_to_utm(lat, lon)
|
||||
return zone_number, zone_letter
|
||||
|
||||
|
||||
def latlon_to_utm_vector(lat, lon, elevation=0.0):
|
||||
"""Convierte lat/lon/elevación a un FreeCAD.Vector en UTM (mm).
|
||||
|
||||
Args:
|
||||
lat (float): Latitud en grados.
|
||||
lon (float): Longitud en grados.
|
||||
elevation (float): Elevación en metros (default 0).
|
||||
|
||||
Returns:
|
||||
FreeCAD.Vector: Coordenadas UTM en milímetros.
|
||||
"""
|
||||
transformer, _, _ = _get_utm_transformer(lat, lon)
|
||||
easting, northing = transformer.transform(lon, lat)
|
||||
return FreeCAD.Vector(
|
||||
round(easting, 0),
|
||||
round(northing, 0),
|
||||
round(elevation, 0)
|
||||
) * 1000
|
||||
Reference in New Issue
Block a user