refactor: separar PVPlantGeoreferencing, PVPlantImportGrid y PVPlantPlacement en submodulos
- PVPlantGeoreferencing → PVPlant/core/georef.py - PVPlantImportGrid → PVPlant/import_grid/grid.py - PVPlantPlacement → PVPlant/placement/placement.py Los archivos originales ahora son wrappers de compatibilidad. Preparado para revisión exhaustiva de PVPlantPlacement.
This commit is contained in:
@@ -0,0 +1,422 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <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 *
|
||||
# * *
|
||||
# ***********************************************************************
|
||||
|
||||
import FreeCAD
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtCore, QtGui
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
|
||||
import os
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt,txt):
|
||||
return txt
|
||||
def QT_TRANSLATE_NOOP(ctxt,txt):
|
||||
return txt
|
||||
# \endcond
|
||||
|
||||
import PVPlantResources
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
from PVPlantResources import DirResources as DirResources
|
||||
|
||||
|
||||
class MapWindow(QtGui.QWidget):
|
||||
def __init__(self, WinTitle="MapWindow"):
|
||||
super(MapWindow, self).__init__()
|
||||
self.raise_()
|
||||
self.lat = None
|
||||
self.lon = None
|
||||
self.minLat = None
|
||||
self.maxLat = None
|
||||
self.minLon = None
|
||||
self.maxLon = None
|
||||
self.zoom = None
|
||||
self.WinTitle = WinTitle
|
||||
self.georeference_coordinates = {'lat': None, 'lon': None}
|
||||
self.setupUi()
|
||||
|
||||
def setupUi(self):
|
||||
from PySide2.QtWebEngineWidgets import QWebEngineView
|
||||
from PySide2.QtWebChannel import QWebChannel
|
||||
|
||||
self.ui = FreeCADGui.PySideUic.loadUi(PVPlantResources.__dir__ + "/PVPlantGeoreferencing.ui", self)
|
||||
|
||||
self.resize(1200, 800)
|
||||
self.setWindowTitle(self.WinTitle)
|
||||
self.setWindowIcon(QtGui.QIcon(os.path.join(DirIcons, "Location.svg")))
|
||||
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
|
||||
|
||||
self.layout = QtGui.QHBoxLayout(self)
|
||||
self.layout.setContentsMargins(4, 4, 4, 4)
|
||||
|
||||
LeftWidget = QtGui.QWidget(self)
|
||||
LeftLayout = QtGui.QVBoxLayout(LeftWidget)
|
||||
LeftWidget.setLayout(LeftLayout)
|
||||
LeftLayout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
RightWidget = QtGui.QWidget(self)
|
||||
RightWidget.setFixedWidth(350)
|
||||
RightLayout = QtGui.QVBoxLayout(RightWidget)
|
||||
RightWidget.setLayout(RightLayout)
|
||||
RightLayout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
self.layout.addWidget(LeftWidget)
|
||||
self.layout.addWidget(RightWidget)
|
||||
|
||||
# Left Widgets:
|
||||
# -- Search Bar:
|
||||
self.valueSearch = QtGui.QLineEdit(self)
|
||||
self.valueSearch.setPlaceholderText("Search")
|
||||
self.valueSearch.returnPressed.connect(self.onSearch)
|
||||
|
||||
searchbutton = QtGui.QPushButton('Search')
|
||||
searchbutton.setFixedWidth(80)
|
||||
searchbutton.clicked.connect(self.onSearch)
|
||||
|
||||
SearchBarLayout = QtGui.QHBoxLayout(self)
|
||||
SearchBarLayout.addWidget(self.valueSearch)
|
||||
SearchBarLayout.addWidget(searchbutton)
|
||||
LeftLayout.addLayout(SearchBarLayout)
|
||||
|
||||
# -- Webbroser:
|
||||
self.view = QWebEngineView()
|
||||
self.channel = QWebChannel(self.view.page())
|
||||
self.view.page().setWebChannel(self.channel)
|
||||
self.channel.registerObject("MyApp", self)
|
||||
file = os.path.join(DirResources, "webs", "main.html")
|
||||
self.view.page().loadFinished.connect(self.onLoadFinished)
|
||||
self.view.page().load(QtCore.QUrl.fromLocalFile(file))
|
||||
LeftLayout.addWidget(self.view)
|
||||
|
||||
# -- Latitud y longitud:
|
||||
self.labelCoordinates = QtGui.QLabel()
|
||||
self.labelCoordinates.setFixedHeight(21)
|
||||
LeftLayout.addWidget(self.labelCoordinates)
|
||||
|
||||
# Right Widgets:
|
||||
labelKMZ = QtGui.QLabel()
|
||||
labelKMZ.setText("Cargar un archivo KMZ/KML:")
|
||||
self.kmlButton = QtGui.QPushButton()
|
||||
self.kmlButton.setFixedSize(32, 32)
|
||||
self.kmlButton.setIcon(QtGui.QIcon(os.path.join(DirIcons, "googleearth.svg")))
|
||||
widget = QtGui.QWidget(self)
|
||||
layout = QtGui.QHBoxLayout(widget)
|
||||
widget.setLayout(layout)
|
||||
layout.addWidget(labelKMZ)
|
||||
layout.addWidget(self.kmlButton)
|
||||
RightLayout.addWidget(widget)
|
||||
|
||||
# -----------------------
|
||||
self.groupbox = QtGui.QGroupBox("Importar datos desde:")
|
||||
self.groupbox.setCheckable(True)
|
||||
self.groupbox.setChecked(True)
|
||||
radio1 = QtGui.QRadioButton("Google Elevation")
|
||||
radio2 = QtGui.QRadioButton("Nube de Puntos")
|
||||
radio3 = QtGui.QRadioButton("Datos GPS")
|
||||
radio1.setChecked(True)
|
||||
|
||||
vbox = QtGui.QVBoxLayout(self)
|
||||
vbox.addWidget(radio1)
|
||||
vbox.addWidget(radio2)
|
||||
vbox.addWidget(radio3)
|
||||
|
||||
self.groupbox.setLayout(vbox)
|
||||
RightLayout.addWidget(self.groupbox)
|
||||
# ------------------------
|
||||
|
||||
self.checkboxImportGis = QtGui.QCheckBox("Importar datos GIS")
|
||||
RightLayout.addWidget(self.checkboxImportGis)
|
||||
|
||||
self.checkboxImportSatelitalImagen = QtGui.QCheckBox("Importar Imagen Satelital")
|
||||
RightLayout.addWidget(self.checkboxImportSatelitalImagen)
|
||||
|
||||
verticalSpacer = QtGui.QSpacerItem(20, 48, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
|
||||
RightLayout.addItem(verticalSpacer)
|
||||
|
||||
self.bAccept = QtGui.QPushButton('Accept')
|
||||
self.bAccept.clicked.connect(self.onAcceptClick)
|
||||
RightLayout.addWidget(self.bAccept)
|
||||
|
||||
# signals/slots
|
||||
QtCore.QObject.connect(self.kmlButton, QtCore.SIGNAL("clicked()"), self.importKML)
|
||||
|
||||
|
||||
def onLoadFinished(self):
|
||||
file = os.path.join(DirResources, "webs", "map.js")
|
||||
frame = self.view.page()
|
||||
with open(file, 'r') as f:
|
||||
frame.runJavaScript(f.read())
|
||||
|
||||
def onSearch(self):
|
||||
if self.valueSearch.text() == "":
|
||||
return
|
||||
|
||||
from geopy.geocoders import Nominatim
|
||||
|
||||
geolocator = Nominatim(user_agent="http")
|
||||
location = geolocator.geocode(self.valueSearch.text())
|
||||
self.valueSearch.setText(location.address)
|
||||
self.panMap(location.longitude, location.latitude, location.raw['boundingbox'])
|
||||
|
||||
def onAcceptClick(self):
|
||||
frame = self.view.page()
|
||||
# 1. georeferenciar
|
||||
frame.runJavaScript(
|
||||
"MyApp.georeference(drawnItems.getBounds().getCenter().lat, drawnItems.getBounds().getCenter().lng);"
|
||||
)
|
||||
|
||||
# 2. importar todos los elementos dibujados:
|
||||
frame.runJavaScript(
|
||||
"var data = drawnItems.toGeoJSON();"
|
||||
"MyApp.shapes(JSON.stringify(data));"
|
||||
)
|
||||
|
||||
self.close()
|
||||
|
||||
@QtCore.Slot(float, float)
|
||||
def onMapMove(self, lat, lng):
|
||||
from lib.projection import latlon_to_utm
|
||||
|
||||
self.lat = lat
|
||||
self.lon = lng
|
||||
easting, northing, zone_number, zone_letter = latlon_to_utm(lat, lng)
|
||||
self.labelCoordinates.setText('Longitud: {:.5f}, Latitud: {:.5f}'.format(lng, lat) +
|
||||
' | UTM: ' + str(zone_number) + zone_letter +
|
||||
', {:.5f}m E, {:.5f}m N'.format(easting, northing))
|
||||
|
||||
@QtCore.Slot(float, float, float, float, int)
|
||||
def onMapZoom(self, minLat, minLon, maxLat, maxLon, zoom):
|
||||
self.minLat = min([minLat, maxLat])
|
||||
self.maxLat = max([minLat, maxLat])
|
||||
self.minLon = min([minLon, maxLon])
|
||||
self.maxLon = max([minLon, maxLon])
|
||||
self.zoom = zoom
|
||||
|
||||
@QtCore.Slot(float, float)
|
||||
def georeference(self, lat, lng):
|
||||
import PVPlantSite
|
||||
from geopy.geocoders import Nominatim
|
||||
|
||||
self.georeference_coordinates['lat'] = lat
|
||||
self.georeference_coordinates['lon'] = lng
|
||||
|
||||
Site = PVPlantSite.get(create=True)
|
||||
Site.Proxy.setLatLon(lat, lng)
|
||||
|
||||
geolocator = Nominatim(user_agent="http")
|
||||
location = geolocator.reverse('{:.5f}, {:.5f}'.format(lat, lng))
|
||||
if location:
|
||||
if location.raw["address"].get("road"):
|
||||
str = location.raw["address"]["road"]
|
||||
if location.raw["address"].get("house_number"):
|
||||
str += ' ({0})'.format(location.raw["address"]["house_number"])
|
||||
Site.Address = str
|
||||
if location.raw["address"].get("city"):
|
||||
Site.City = location.raw["address"]["city"]
|
||||
if location.raw["address"].get("postcode"):
|
||||
Site.PostalCode = location.raw["address"]["postcode"]
|
||||
if location.raw["address"].get("address"):
|
||||
Site.Region = '{0}'.format(location.raw["address"]["province"])
|
||||
if location.raw["address"].get("state"):
|
||||
if Site.Region != "":
|
||||
Site.Region += " - "
|
||||
Site.Region += '{0}'.format(location.raw["address"]["state"])
|
||||
Site.Country = location.raw["address"]["country"]
|
||||
|
||||
@QtCore.Slot(str)
|
||||
def shapes(self, drawnItems):
|
||||
import geojson
|
||||
import PVPlantImportGrid as ImportElevation
|
||||
import Draft
|
||||
import PVPlantSite
|
||||
Site = PVPlantSite.get()
|
||||
|
||||
offset = FreeCAD.Vector(0, 0, 0)
|
||||
if not (self.lat is None or self.lon is None):
|
||||
offset = FreeCAD.Vector(Site.Origin)
|
||||
offset.z = 0
|
||||
|
||||
items = geojson.loads(drawnItems)
|
||||
for item in items['features']:
|
||||
if item['geometry']['type'] == "Point": # 1. if the feature is a Point or Circle:
|
||||
coord = item['geometry']['coordinates']
|
||||
point = ImportElevation.getElevationFromOE([[coord[1], coord[0]],])
|
||||
c = FreeCAD.Vector(point[0][0], point[0][1], point[0][2]).sub(offset)
|
||||
if item['properties'].get('radius'):
|
||||
r = round(item['properties']['radius'] * 1000, 0)
|
||||
p = FreeCAD.Placement()
|
||||
p.Base = c
|
||||
obj = Draft.makeCircle(r, placement=p, face=False)
|
||||
else:
|
||||
obj = Draft.make_point(c * 1000, color=(0.5, 0.3, 0.6), point_size=10)
|
||||
else: # 2. if the feature is a Polygon or Line:
|
||||
cw = False
|
||||
name = "Línea"
|
||||
lp = item['geometry']['coordinates']
|
||||
if item['geometry']['type'] == "Polygon":
|
||||
cw = True
|
||||
name = "Area"
|
||||
lp = item['geometry']['coordinates'][0]
|
||||
|
||||
pts = [[cords[1], cords[0]] for cords in lp]
|
||||
tmp = ImportElevation.getElevationFromOE(pts)
|
||||
pts = [p.sub(offset) for p in tmp]
|
||||
|
||||
obj = Draft.makeWire(pts, closed=cw, face=False)
|
||||
obj.Label = name
|
||||
Draft.autogroup(obj)
|
||||
|
||||
if item['properties'].get('name'):
|
||||
obj.Label = item['properties']['name']
|
||||
|
||||
if self.checkboxImportGis.isChecked():
|
||||
self.getDataFromOSM(self.minLat, self.minLon, self.maxLat, self.maxLon)
|
||||
|
||||
if self.checkboxImportSatelitalImagen.isChecked():
|
||||
from lib.projection import latlon_to_utm
|
||||
|
||||
s_lat = self.minLat
|
||||
s_lon = self.minLon
|
||||
n_lat = self.maxLat
|
||||
n_lon = self.maxLon
|
||||
|
||||
# Obtener puntos UTM para las esquinas y el punto de referencia
|
||||
points = [
|
||||
[s_lat, s_lon], # Suroeste
|
||||
[n_lat, n_lon], # Noreste
|
||||
[self.georeference_coordinates['lat'], self.georeference_coordinates['lon']] # Punto de referencia
|
||||
]
|
||||
utm_points = ImportElevation.getElevationFromOE(points)
|
||||
|
||||
if not utm_points or len(utm_points) < 3:
|
||||
FreeCAD.Console.PrintError("Error obteniendo elevaciones para las esquinas y referencia\n")
|
||||
return
|
||||
|
||||
sw_utm, ne_utm, ref_utm = utm_points
|
||||
|
||||
# Descargar imagen satelital
|
||||
from lib.GoogleSatelitalImageDownload import GoogleMapDownloader
|
||||
downloader = GoogleMapDownloader(
|
||||
zoom=self.zoom,
|
||||
layer='raw_satellite'
|
||||
)
|
||||
img = downloader.generateImage(
|
||||
sw_lat=s_lat,
|
||||
sw_lng=s_lon,
|
||||
ne_lat=n_lat,
|
||||
ne_lng=n_lon
|
||||
)
|
||||
|
||||
# Guardar imagen
|
||||
doc_path = os.path.dirname(FreeCAD.ActiveDocument.FileName) if FreeCAD.ActiveDocument.FileName else ""
|
||||
if not doc_path:
|
||||
doc_path = FreeCAD.ConfigGet("UserAppData")
|
||||
|
||||
filename = os.path.join(doc_path, "background.jpeg")
|
||||
img.save(filename)
|
||||
|
||||
# Calcular dimensiones reales en metros
|
||||
width_m = ne_utm.x - sw_utm.x
|
||||
height_m = ne_utm.y - sw_utm.y
|
||||
|
||||
# Calcular posición relativa del punto de referencia dentro de la imagen
|
||||
rel_x = (ref_utm.x - sw_utm.x) / width_m if width_m != 0 else 0.5
|
||||
rel_y = (ref_utm.y - sw_utm.y) / height_m if height_m != 0 else 0.5
|
||||
|
||||
# Crear objeto de imagen en FreeCAD
|
||||
doc = FreeCAD.ActiveDocument
|
||||
img_obj = doc.addObject('Image::ImagePlane', 'Background')
|
||||
img_obj.ImageFile = filename
|
||||
img_obj.Label = 'Background'
|
||||
|
||||
# FreeCAD trabaja en mm
|
||||
img_obj.XSize = width_m * 1000
|
||||
img_obj.YSize = height_m * 1000
|
||||
|
||||
# Posicionar para que el punto de referencia esté en (0,0,0)
|
||||
img_obj.Placement.Base = FreeCAD.Vector(
|
||||
-rel_x * width_m * 1000,
|
||||
-rel_y * height_m * 1000,
|
||||
0
|
||||
)
|
||||
|
||||
doc.recompute()
|
||||
|
||||
def getDataFromOSM(self, min_lat, min_lon, max_lat, max_lon):
|
||||
import Importer.importOSM as importOSM
|
||||
import PVPlantSite
|
||||
site = PVPlantSite.get()
|
||||
|
||||
offset = FreeCAD.Vector(0, 0, 0)
|
||||
if not (self.lat is None or self.lon is None):
|
||||
offset = FreeCAD.Vector(site.Origin)
|
||||
offset.z = 0
|
||||
importer = importOSM.OSMImporter(offset)
|
||||
osm_data = importer.get_osm_data(f"{min_lat},{min_lon},{max_lat},{max_lon}")
|
||||
importer.process_osm_data(osm_data)
|
||||
|
||||
def panMap(self, lng, lat, geometry=None):
|
||||
frame = self.view.page()
|
||||
|
||||
if not geometry or len(geometry) < 4:
|
||||
command = f'map.panTo(L.latLng({lat}, {lng}));'
|
||||
else:
|
||||
try:
|
||||
southwest = f"{float(geometry[1])}, {float(geometry[0])}"
|
||||
northeast = f"{float(geometry[3])}, {float(geometry[2])}"
|
||||
command = f'map.panTo(L.latLng({lat}, {lng}));'
|
||||
command += f'map.fitBounds(L.latLngBounds([{southwest}], [{northeast}]));'
|
||||
except (IndexError, ValueError, TypeError) as e:
|
||||
print(f"Error en geometry: {str(e)}")
|
||||
command = f'map.panTo(L.latLng({lat}, {lng}));'
|
||||
frame.runJavaScript(command)
|
||||
|
||||
def importKML(self):
|
||||
file = QtGui.QFileDialog.getOpenFileName(None, "FileDialog", "", "Google Earth (*.kml *.kmz)")[0]
|
||||
|
||||
from lib.kml2geojson import kmz_convert
|
||||
layers = kmz_convert(file, "", )
|
||||
frame = self.view.page()
|
||||
for layer in layers:
|
||||
command = "var geoJsonLayer = L.geoJSON({0}); drawnItems.addLayer(geoJsonLayer); map.fitBounds(geoJsonLayer.getBounds());".format( layer)
|
||||
frame.runJavaScript(command)
|
||||
|
||||
|
||||
class CommandPVPlantGeoreferencing:
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "Location.svg")),
|
||||
'Accel': "G, R",
|
||||
'MenuText': QT_TRANSLATE_NOOP("Georeferencing","Georeferencing"),
|
||||
'ToolTip': QT_TRANSLATE_NOOP("Georeferencing","Referenciar el lugar")}
|
||||
|
||||
def Activated(self):
|
||||
self.form = MapWindow()
|
||||
self.form.show()
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@@ -0,0 +1,671 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2021 Javier Braña <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 *
|
||||
# * *
|
||||
# ***********************************************************************
|
||||
|
||||
import json
|
||||
import urllib.request
|
||||
|
||||
import Draft
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
from PySide import QtCore, QtGui
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
|
||||
try:
|
||||
_fromUtf8 = QtCore.QString.fromUtf8
|
||||
except AttributeError:
|
||||
def _fromUtf8(s):
|
||||
return s
|
||||
|
||||
import os
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
import PVPlantSite
|
||||
|
||||
|
||||
def get_elevation_from_oe(coordinates):
|
||||
"""Obtiene elevaciones de Open-Elevation API y devuelve vectores FreeCAD en coordenadas UTM.
|
||||
Args:
|
||||
coordinates (list): Lista de tuplas con coordenadas (latitud, longitud)
|
||||
Returns:
|
||||
list: Lista de vectores FreeCAD con coordenadas UTM y elevación (en milímetros)
|
||||
o lista vacía en caso de error.
|
||||
"""
|
||||
if not coordinates:
|
||||
return []
|
||||
|
||||
import requests
|
||||
from lib.projection import latlon_to_utm
|
||||
from requests.exceptions import RequestException
|
||||
|
||||
locations = "|".join([f"{lat:.6f},{lon:.6f}" for lat, lon in coordinates])
|
||||
|
||||
try:
|
||||
response = requests.get(
|
||||
url="https://api.open-elevation.com/api/v1/lookup",
|
||||
params={'locations': locations},
|
||||
timeout=20,
|
||||
verify=True
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
except RequestException as e:
|
||||
print(f"Error en la solicitud: {str(e)}")
|
||||
return []
|
||||
|
||||
try:
|
||||
data = response.json()
|
||||
except ValueError:
|
||||
print("Respuesta JSON inválida")
|
||||
return []
|
||||
|
||||
if "results" not in data or len(data["results"]) != len(coordinates):
|
||||
print("Formato de respuesta inesperado")
|
||||
return []
|
||||
|
||||
points = []
|
||||
for result in data["results"]:
|
||||
try:
|
||||
easting, northing, _, _ = latlon_to_utm(
|
||||
result["latitude"],
|
||||
result["longitude"]
|
||||
)
|
||||
|
||||
points.append(FreeCAD.Vector(round(easting),
|
||||
round(northing),
|
||||
round(result["elevation"])) * 1000)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error procesando coordenadas: {str(e)}")
|
||||
continue
|
||||
|
||||
return points
|
||||
|
||||
|
||||
def getElevationFromOE(coordinates):
|
||||
"""Obtiene elevaciones de Open-Elevation API y devuelve vectores FreeCAD en coordenadas UTM."""
|
||||
|
||||
import certifi
|
||||
from requests.exceptions import RequestException
|
||||
if len(coordinates) == 0:
|
||||
return None
|
||||
|
||||
from requests import get
|
||||
from lib.projection import latlon_to_utm
|
||||
|
||||
locations_str=""
|
||||
total = len(coordinates) - 1
|
||||
for i, point in enumerate(coordinates):
|
||||
locations_str += '{:.6f},{:.6f}'.format(point[0], point[1])
|
||||
if i != total:
|
||||
locations_str += '|'
|
||||
query = 'https://api.open-elevation.com/api/v1/lookup?locations=' + locations_str
|
||||
points = []
|
||||
try:
|
||||
r = get(query, timeout=20, verify=certifi.where())
|
||||
results = r.json()
|
||||
for point in results["results"]:
|
||||
easting, northing, _, _ = latlon_to_utm(point["latitude"], point["longitude"])
|
||||
v = FreeCAD.Vector(round(easting, 0),
|
||||
round(northing, 0),
|
||||
round(point["elevation"], 0)) * 1000
|
||||
points.append(v)
|
||||
except RequestException as e:
|
||||
for point in coordinates:
|
||||
easting, northing, _, _ = latlon_to_utm(point[0], point[1])
|
||||
points.append(FreeCAD.Vector(round(easting, 0),
|
||||
round(northing, 0),
|
||||
0) * 1000)
|
||||
|
||||
return points
|
||||
|
||||
def getSinglePointElevationFromBing(lat, lng):
|
||||
import requests
|
||||
from lib.projection import latlon_to_utm
|
||||
|
||||
source = "http://dev.virtualearth.net/REST/v1/Elevation/List?points="
|
||||
source += str(lat) + "," + str(lng)
|
||||
source += "&heights=sealevel"
|
||||
source += "&key=AmsPZA-zRt2iuIdQgvXZIxme2gWcgLaz7igOUy7VPB8OKjjEd373eCnj1KFv2CqX"
|
||||
|
||||
response = requests.get(source)
|
||||
ans = response.text
|
||||
|
||||
s = json.loads(ans)
|
||||
print(s)
|
||||
res = s['resourceSets'][0]['resources'][0]['elevations']
|
||||
for elevation in res:
|
||||
easting, northing, _, _ = latlon_to_utm(lat, lng)
|
||||
v = FreeCAD.Vector(
|
||||
round(easting * 1000, 0),
|
||||
round(northing * 1000, 0),
|
||||
round(elevation * 1000, 0))
|
||||
return v
|
||||
|
||||
def getGridElevationFromBing(polygon, lat, lng, resolution = 1000):
|
||||
import math
|
||||
import requests
|
||||
from lib.projection import latlon_to_utm, utm_to_latlon
|
||||
|
||||
_, _, zone_number, zone_letter = latlon_to_utm(lat, lng)
|
||||
|
||||
points = []
|
||||
yy = polygon.Shape.BoundBox.YMax
|
||||
while yy > polygon.Shape.BoundBox.YMin:
|
||||
xx = polygon.Shape.BoundBox.XMin
|
||||
while xx < polygon.Shape.BoundBox.XMax:
|
||||
StepsXX = int(math.ceil((polygon.Shape.BoundBox.XMax - xx) / resolution))
|
||||
|
||||
if StepsXX > 1000:
|
||||
StepsXX = 1000
|
||||
xx1 = xx + 1000 * resolution
|
||||
else:
|
||||
xx1 = xx + StepsXX * resolution
|
||||
|
||||
point1 = utm_to_latlon(xx / 1000, yy / 1000, zone_number, zone_letter)
|
||||
point2 = utm_to_latlon(xx1 / 1000, yy / 1000, zone_number, zone_letter)
|
||||
|
||||
source = "http://dev.virtualearth.net/REST/v1/Elevation/Polyline?points="
|
||||
source += "{lat1},{lng1}".format(lat1=point1[0], lng1=point1[1])
|
||||
source += ","
|
||||
source += "{lat2},{lng2}".format(lat2=point2[0], lng2=point2[1])
|
||||
source += "&heights=sealevel"
|
||||
source += "&samples={steps}".format(steps=StepsXX)
|
||||
source += "&key=AmsPZA-zRt2iuIdQgvXZIxme2gWcgLaz7igOUy7VPB8OKjjEd373eCnj1KFv2CqX"
|
||||
|
||||
response = requests.get(source)
|
||||
ans = response.text
|
||||
|
||||
s = json.loads(ans)
|
||||
res = s['resourceSets'][0]['resources'][0]['elevations']
|
||||
|
||||
i = 0
|
||||
for elevation in res:
|
||||
v = FreeCAD.Vector(xx + resolution * i, yy, round(elevation * 1000, 4))
|
||||
points.append(v)
|
||||
i += 1
|
||||
xx = xx1 + resolution
|
||||
yy -= resolution
|
||||
|
||||
return points
|
||||
|
||||
def getSinglePointElevation(lat, lon):
|
||||
source = "https://maps.googleapis.com/maps/api/elevation/json?locations="
|
||||
source += str(lat) + "," + str(lon)
|
||||
source += "&key=AIzaSyB07X6lowYJ-iqyPmaFJvr-6zp1J63db8U"
|
||||
#print (source)
|
||||
|
||||
#response = request.urlopen(source)
|
||||
#ans = response.read()
|
||||
import requests
|
||||
response = requests.get(source)
|
||||
ans = response.text
|
||||
|
||||
# +# to do: error handling - wait and try again
|
||||
s = json.loads(ans)
|
||||
res = s['results']
|
||||
|
||||
from geopy.distance import geodesic
|
||||
for r in res:
|
||||
|
||||
reference = (0.0, 0.0)
|
||||
v = FreeCAD.Vector(
|
||||
round(geodesic(reference, (0.0, r['location']['lng'])).m, 2),
|
||||
round(geodesic(reference, (r['location']['lat'], 0.0)).m, 2),
|
||||
round(r['elevation'] * 1000, 2)
|
||||
)
|
||||
|
||||
return v
|
||||
|
||||
def _getSinglePointElevation(lat, lon):
|
||||
source = "https://maps.googleapis.com/maps/api/elevation/json?locations="
|
||||
source += str(lat) + "," + str(lon)
|
||||
source += "&key=AIzaSyB07X6lowYJ-iqyPmaFJvr-6zp1J63db8U"
|
||||
#print (source)
|
||||
|
||||
#response = request.urlopen(source)
|
||||
#ans = response.read()
|
||||
import requests
|
||||
response = requests.get(source)
|
||||
ans = response.text
|
||||
|
||||
# +# to do: error handling - wait and try again
|
||||
s = json.loads(ans)
|
||||
res = s['results']
|
||||
|
||||
import pymap3d as pm
|
||||
for r in res:
|
||||
x, y, z = pm.geodetic2ecef(round(r['location']['lng'], 2),
|
||||
round(r['location']['lat'], 2),
|
||||
0)
|
||||
v = FreeCAD.Vector(x,y,z)
|
||||
|
||||
return v
|
||||
|
||||
def getSinglePointElevation1(lat, lon):
|
||||
source = "https://maps.googleapis.com/maps/api/elevation/json?locations="
|
||||
source += str(lat) + "," + str(lon)
|
||||
source += "&key=AIzaSyB07X6lowYJ-iqyPmaFJvr-6zp1J63db8U"
|
||||
|
||||
#response = urllib.request.urlopen(source)
|
||||
#ans = response.read()
|
||||
import requests
|
||||
response = requests.get(source)
|
||||
ans = response.text
|
||||
|
||||
# +# to do: error handling - wait and try again
|
||||
s = json.loads(ans)
|
||||
res = s['results']
|
||||
|
||||
for r in res:
|
||||
c = tm.fromGeographic(r['location']['lat'], r['location']['lng'])
|
||||
v = FreeCAD.Vector(
|
||||
round(c[0], 4),
|
||||
round(c[1], 4),
|
||||
round(r['elevation'] * 1000, 2)
|
||||
)
|
||||
return v
|
||||
|
||||
def getSinglePointElevationUtm(lat, lon):
|
||||
import requests
|
||||
from lib.projection import latlon_to_utm
|
||||
|
||||
source = "https://maps.googleapis.com/maps/api/elevation/json?locations="
|
||||
source += str(lat) + "," + str(lon)
|
||||
source += "&key=AIzaSyB07X6lowYJ-iqyPmaFJvr-6zp1J63db8U"
|
||||
print(source)
|
||||
|
||||
response = requests.get(source)
|
||||
ans = response.text
|
||||
|
||||
s = json.loads(ans)
|
||||
res = s['results']
|
||||
print(res)
|
||||
|
||||
for r in res:
|
||||
easting, northing, _, _ = latlon_to_utm(r['location']['lat'], r['location']['lng'])
|
||||
v = FreeCAD.Vector(
|
||||
round(easting * 1000, 4),
|
||||
round(northing * 1000, 4),
|
||||
round(r['elevation'] * 1000, 2))
|
||||
print(v)
|
||||
return v
|
||||
|
||||
def getElevationUTM(polygon, lat, lng, resolution = 10000):
|
||||
from lib.projection import latlon_to_utm, utm_to_latlon
|
||||
|
||||
_, _, zone_number, zone_letter = latlon_to_utm(lat, lng)
|
||||
|
||||
StepsXX = int((polygon.Shape.BoundBox.XMax - polygon.Shape.BoundBox.XMin) / (resolution*1000))
|
||||
points = []
|
||||
yy = polygon.Shape.BoundBox.YMax
|
||||
while yy > polygon.Shape.BoundBox.YMin:
|
||||
point1 = utm_to_latlon(polygon.Shape.BoundBox.XMin / 1000, yy / 1000, zone_number, zone_letter)
|
||||
point2 = utm_to_latlon(polygon.Shape.BoundBox.XMax / 1000, yy / 1000, zone_number, zone_letter)
|
||||
|
||||
source = "https://maps.googleapis.com/maps/api/elevation/json?path="
|
||||
source += "{a},{b}".format(a = point1[0], b = point1[1])
|
||||
source += "|"
|
||||
source += "{a},{b}".format(a = point2[0], b = point2[1])
|
||||
source += "&samples={a}".format(a = StepsXX)
|
||||
source += "&key=AIzaSyB07X6lowYJ-iqyPmaFJvr-6zp1J63db8U"
|
||||
|
||||
import requests
|
||||
response = requests.get(source)
|
||||
ans = response.text
|
||||
|
||||
s = json.loads(ans)
|
||||
res = s['results']
|
||||
|
||||
for r in res:
|
||||
easting, northing, _, _ = latlon_to_utm(r['location']['lat'], r['location']['lng'])
|
||||
v = FreeCAD.Vector(
|
||||
round(easting * 1000, 2),
|
||||
round(northing * 1000, 2),
|
||||
round(r['elevation'] * 1000, 2)
|
||||
)
|
||||
points.append(v)
|
||||
yy -= (resolution*1000)
|
||||
|
||||
FreeCAD.activeDocument().recompute()
|
||||
return points
|
||||
|
||||
def getElevation1(polygon,resolution=10):
|
||||
|
||||
StepsXX = int((polygon.Shape.BoundBox.XMax - polygon.Shape.BoundBox.XMin) / (resolution * 1000))
|
||||
points = []
|
||||
yy = polygon.Shape.BoundBox.YMax
|
||||
while yy > polygon.Shape.BoundBox.YMin:
|
||||
point1 = tm.toGeographic(polygon.Shape.BoundBox.XMin, yy)
|
||||
point2 = tm.toGeographic(polygon.Shape.BoundBox.XMax, yy)
|
||||
|
||||
source = "https://maps.googleapis.com/maps/api/elevation/json?path="
|
||||
source += "{a},{b}".format(a = point1[0], b = point1[1])
|
||||
source += "|"
|
||||
source += "{a},{b}".format(a = point2[0], b = point2[1])
|
||||
source += "&samples={a}".format(a = StepsXX)
|
||||
source += "&key=AIzaSyB07X6lowYJ-iqyPmaFJvr-6zp1J63db8U"
|
||||
|
||||
try:
|
||||
#response = urllib.request.urlopen(source)
|
||||
#ans = response.read()
|
||||
import requests
|
||||
response = requests.get(source)
|
||||
ans = response.text
|
||||
|
||||
# +# to do: error handling - wait and try again
|
||||
|
||||
s = json.loads(ans)
|
||||
res = s['results']
|
||||
except:
|
||||
continue
|
||||
|
||||
#points = []
|
||||
for r in res:
|
||||
c = tm.fromGeographic(r['location']['lat'], r['location']['lng'])
|
||||
v = FreeCAD.Vector(
|
||||
round(c[0], 2),
|
||||
round(c[1], 2),
|
||||
round(r['elevation'] * 1000, 2)
|
||||
)
|
||||
points.append(v)
|
||||
|
||||
FreeCAD.activeDocument().recompute()
|
||||
yy -= (resolution*1000)
|
||||
|
||||
return points
|
||||
|
||||
## download the heights from google:
|
||||
def getElevation(lat, lon, b=50.35, le=11.17, size=40):
|
||||
#https://maps.googleapis.com/maps/api/elevation/json?path=36.578581,-118.291994|36.23998,-116.83171&samples=3&key=YOUR_API_KEY
|
||||
#https://maps.googleapis.com/maps/api/elevation/json?locations=39.7391536,-104.9847034&key=YOUR_API_KEY
|
||||
|
||||
source = "https://maps.googleapis.com/maps/api/elevation/json?path="
|
||||
source += str(b-size*0.001) + "," + str(le) + "|" + str(b+size*0.001) + "," + str(le)
|
||||
source += "&samples=" + str(100)
|
||||
source += "&key=AIzaSyB07X6lowYJ-iqyPmaFJvr-6zp1J63db8U"
|
||||
|
||||
response = urllib.request.urlopen(source)
|
||||
ans = response.read()
|
||||
|
||||
# +# to do: error handling - wait and try again
|
||||
s = json.loads(ans)
|
||||
res = s['results']
|
||||
|
||||
from geopy.distance import geodesic
|
||||
points = []
|
||||
for r in res:
|
||||
reference = (0.0, 0.0)
|
||||
v = FreeCAD.Vector(
|
||||
round(geodesic(reference, (0.0, r['location']['lat'])).m, 2),
|
||||
round(geodesic(reference, (r['location']['lng'], 0.0)).m, 2),
|
||||
round(r['elevation'] * 1000, 2) - baseheight
|
||||
)
|
||||
points.append(v)
|
||||
|
||||
line = Draft.makeWire(points, closed=False, face=False, support=None)
|
||||
line.ViewObject.Visibility = False
|
||||
#FreeCAD.activeDocument().recompute()
|
||||
FreeCADGui.updateGui()
|
||||
return FreeCAD.activeDocument().ActiveObject
|
||||
|
||||
class _ImportPointsTaskPanel:
|
||||
|
||||
def __init__(self, obj = None):
|
||||
self.obj = None
|
||||
self.Boundary = None
|
||||
self.select = 0
|
||||
self.filename = ""
|
||||
|
||||
# form:
|
||||
self.form1 = FreeCADGui.PySideUic.loadUi(os.path.dirname(__file__) + "/PVPlantImportGrid.ui")
|
||||
self.form1.radio1.toggled.connect(lambda: self.mainToggle(self.form1.radio1))
|
||||
self.form1.radio2.toggled.connect(lambda: self.mainToggle(self.form1.radio2))
|
||||
self.form1.radio1.setChecked(True) # << --------------Poner al final para que no dispare antes de crear los componentes a los que va a llamar
|
||||
#self.form.buttonAdd.clicked.connect(self.add)
|
||||
self.form1.buttonDEM.clicked.connect(self.openFileDEM)
|
||||
|
||||
self.form2 = FreeCADGui.PySideUic.loadUi(os.path.dirname(__file__) + "/PVPlantCreateTerrainMesh.ui")
|
||||
#self.form2.buttonAdd.clicked.connect(self.add)
|
||||
self.form2.buttonBoundary.clicked.connect(self.addBoundary)
|
||||
|
||||
|
||||
#self.form = [self.form1, self.form2]
|
||||
self.form = self.form1
|
||||
|
||||
''' future:
|
||||
def retranslateUi(self, dialog):
|
||||
self.form1.setWindowTitle("Configuracion del Rack")
|
||||
self.labelModule.setText(QtGui.QApplication.translate("PVPlant", "Modulo:", None))
|
||||
self.labelModuleLength.setText(QtGui.QApplication.translate("PVPlant", "Longitud:", None))
|
||||
self.labelModuleWidth.setText(QtGui.QApplication.translate("PVPlant", "Ancho:", None))
|
||||
self.labelModuleHeight.setText(QtGui.QApplication.translate("PVPlant", "Alto:", None))
|
||||
self.labelModuleFrame.setText(QtGui.QApplication.translate("PVPlant", "Ancho del marco:", None))
|
||||
self.labelModuleColor.setText(QtGui.QApplication.translate("PVPlant", "Color del modulo:", None))
|
||||
self.labelModules.setText(QtGui.QApplication.translate("Arch", "Colocacion de los Modulos", None))
|
||||
self.labelModuleOrientation.setText(QtGui.QApplication.translate("Arch", "Orientacion del modulo:", None))
|
||||
self.labelModuleGapX.setText(QtGui.QApplication.translate("Arch", "Separacion Horizontal (mm):", None))
|
||||
self.labelModuleGapY.setText(QtGui.QApplication.translate("Arch", "Separacion Vertical (mm):", None))
|
||||
self.labelModuleRows.setText(QtGui.QApplication.translate("Arch", "Filas de modulos:", None))
|
||||
self.labelModuleCols.setText(QtGui.QApplication.translate("Arch", "Columnas de modulos:", None))
|
||||
self.labelRack.setText(QtGui.QApplication.translate("Arch", "Configuracion de la estructura", None))
|
||||
self.labelRackType.setText(QtGui.QApplication.translate("Arch", "Tipo de estructura:", None))
|
||||
self.labelLevel.setText(QtGui.QApplication.translate("Arch", "Nivel:", None))
|
||||
self.labelOffset.setText(QtGui.QApplication.translate("Arch", "Offset", None))
|
||||
'''
|
||||
|
||||
def add(self):
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
if len(sel) > 0:
|
||||
self.obj = sel[0]
|
||||
self.lineEdit1.setText(self.obj.Label)
|
||||
|
||||
def addBoundary(self):
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
if len(sel) > 0:
|
||||
self.Boundary = sel[0]
|
||||
self.form2.editBoundary.setText(self.Boundary.Label)
|
||||
|
||||
def openFileDEM(self):
|
||||
filters = "Esri ASC (*.asc);;CSV (*.csv);;All files (*.*)"
|
||||
filename = QtGui.QFileDialog.getOpenFileName(None,
|
||||
"Open DEM,",
|
||||
"",
|
||||
filters)
|
||||
self.filename = filename[0]
|
||||
self.form1.editDEM.setText(filename[0])
|
||||
|
||||
def mainToggle(self, radiobox):
|
||||
if radiobox is self.form1.radio1:
|
||||
self.select = 0
|
||||
self.form1.gbLocalFile.setVisible(True)
|
||||
elif radiobox is self.form1.radio2:
|
||||
self.select = 1
|
||||
self.form1.gbLocalFile.setVisible(True)
|
||||
|
||||
def accept(self):
|
||||
from datetime import datetime
|
||||
starttime = datetime.now()
|
||||
|
||||
site = PVPlantSite.get()
|
||||
|
||||
try:
|
||||
PointGroups = FreeCAD.ActiveDocument.Point_Groups
|
||||
except:
|
||||
PointGroups = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", 'Point_Groups')
|
||||
PointGroups.Label = "Point Groups"
|
||||
|
||||
PointGroup = FreeCAD.ActiveDocument.addObject('Points::Feature', "Point_Group")
|
||||
PointGroup.Label = "Land_Grid_Points"
|
||||
FreeCAD.ActiveDocument.Point_Groups.addObject(PointGroup)
|
||||
PointObject = PointGroup.Points.copy()
|
||||
|
||||
if self.select == 0: # Google or bing or ...
|
||||
#for item in self.obj:
|
||||
#if self.groupbox.isChecked:break
|
||||
resol = FreeCAD.Units.Quantity(self.valueResolution.text()).Value
|
||||
Site = FreeCAD.ActiveDocument.Site
|
||||
pts = getGridElevationFromBing(self.obj, Site.Latitude, Site.Longitude, resol)
|
||||
PointObject.addPoints(pts)
|
||||
PointGroup.Points = PointObject
|
||||
|
||||
else:
|
||||
if self.filename == "":
|
||||
return
|
||||
|
||||
import Utils.importDEM as openDEM
|
||||
if self.select == 1: # DEM.
|
||||
import numpy as np
|
||||
root, extension = os.path.splitext(self.filename)
|
||||
if extension.lower() == ".asc":
|
||||
x, y, datavals, cellsize, nodata_value = openDEM.openEsri(self.filename)
|
||||
|
||||
if self.Boundary:
|
||||
inc_x = self.Boundary.Shape.BoundBox.XLength * 0.05
|
||||
inc_y = self.Boundary.Shape.BoundBox.YLength * 0.05
|
||||
|
||||
min_x = 0
|
||||
max_x = 0
|
||||
|
||||
comp = (self.Boundary.Shape.BoundBox.XMin - inc_x) / 1000
|
||||
for i in range(nx):
|
||||
if x[i] > comp:
|
||||
min_x = i - 1
|
||||
break
|
||||
comp = (self.Boundary.Shape.BoundBox.XMax + inc_x) / 1000
|
||||
for i in range(min_x, nx):
|
||||
if x[i] > comp:
|
||||
max_x = i
|
||||
break
|
||||
|
||||
min_y = 0
|
||||
max_y = 0
|
||||
|
||||
comp = (self.Boundary.Shape.BoundBox.YMax + inc_y) / 1000
|
||||
for i in range(ny):
|
||||
if y[i] < comp:
|
||||
max_y = i
|
||||
break
|
||||
comp = (self.Boundary.Shape.BoundBox.YMin - inc_y) / 1000
|
||||
for i in range(max_y, ny):
|
||||
if y[i] < comp:
|
||||
min_y = i
|
||||
break
|
||||
|
||||
x = x[min_x:max_x]
|
||||
y = y[max_y:min_y]
|
||||
datavals = datavals[max_y:min_y, min_x:max_x]
|
||||
|
||||
pts = []
|
||||
if True: # faster but more memory 46s - 4,25 gb
|
||||
x, y = np.meshgrid(x, y)
|
||||
xx = x.flatten()
|
||||
yy = y.flatten()
|
||||
zz = datavals.flatten()
|
||||
x[:] = 0
|
||||
y[:] = 0
|
||||
datavals[:] = 0
|
||||
|
||||
pts = []
|
||||
for i in range(0, len(xx)):
|
||||
pts.append(FreeCAD.Vector(xx[i], yy[i], zz[i]) * 1000)
|
||||
|
||||
xx[:] = 0
|
||||
yy[:] = 0
|
||||
zz[:] = 0
|
||||
|
||||
else: # 51s 3,2 gb
|
||||
createmesh = True
|
||||
if createmesh:
|
||||
import Part, Draft
|
||||
|
||||
lines=[]
|
||||
for j in range(len(y)):
|
||||
edges = []
|
||||
for i in range(0, len(x) - 1):
|
||||
ed = Part.makeLine(FreeCAD.Vector(x[i], y[j], datavals[j][i]) * 1000,
|
||||
FreeCAD.Vector(x[i + 1], y[j], datavals[j][i + 1]) * 1000)
|
||||
edges.append(ed)
|
||||
|
||||
#bspline = Draft.makeBSpline(pts)
|
||||
#bspline.ViewObject.hide()
|
||||
line = Part.Wire(edges)
|
||||
lines.append(line)
|
||||
|
||||
'''
|
||||
for i in range(0, len(bsplines), 100):
|
||||
p = Part.makeLoft(bsplines[i:i + 100], False, False, False)
|
||||
Part.show(p)
|
||||
'''
|
||||
p = Part.makeLoft(lines, False, True, False)
|
||||
p = Part.Solid(p)
|
||||
Part.show(p)
|
||||
|
||||
else:
|
||||
pts = []
|
||||
for j in range(ny):
|
||||
for i in range(nx):
|
||||
pts.append(FreeCAD.Vector(x[i], y[j], datavals[j][i]) * 1000)
|
||||
|
||||
elif extension.lower() == ".csv" or extension.lower() == ".txt": # x, y, z from gps
|
||||
pts = openDEM.interpolatePoints(openDEM.openCSV(self.filename))
|
||||
|
||||
PointObject.addPoints(pts)
|
||||
PointGroup.Points = PointObject
|
||||
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
FreeCADGui.Control.closeDialog()
|
||||
print("tiempo: ", datetime.now() - starttime)
|
||||
|
||||
def reject(self):
|
||||
FreeCADGui.Control.closeDialog()
|
||||
|
||||
## Comandos -----------------------------------------------------------------------------------------------------------
|
||||
class CommandImportPoints:
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "cloud.svg")),
|
||||
'MenuText': QT_TRANSLATE_NOOP("PVPlant", "Importer Grid"),
|
||||
'Accel': "B, U",
|
||||
'ToolTip': QT_TRANSLATE_NOOP("PVPlant", "Creates a cloud of points.")}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
def Activated(self):
|
||||
self.TaskPanel = _ImportPointsTaskPanel()
|
||||
FreeCADGui.Control.showDialog(self.TaskPanel)
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
class CommandPointsGroup:
|
||||
|
||||
def GetCommands(self):
|
||||
return tuple(['ImportPoints'
|
||||
])
|
||||
def GetResources(self):
|
||||
return { 'MenuText': QT_TRANSLATE_NOOP("",'Cloud of Points'),
|
||||
'ToolTip': QT_TRANSLATE_NOOP("",'Cloud of Points')
|
||||
}
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
FreeCADGui.addCommand('ImportPoints', CommandImportPoints())
|
||||
FreeCADGui.addCommand('PointsGroup', CommandPointsGroup())
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+5
-398
@@ -20,403 +20,10 @@
|
||||
# * *
|
||||
# ***********************************************************************
|
||||
|
||||
import FreeCAD
|
||||
"""
|
||||
PVPlantGeoreferencing - Wrapper de compatibilidad.
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtCore, QtGui
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
Código movido a PVPlant/core/georef.py.
|
||||
"""
|
||||
|
||||
import os
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt,txt):
|
||||
return txt
|
||||
def QT_TRANSLATE_NOOP(ctxt,txt):
|
||||
return txt
|
||||
# \endcond
|
||||
|
||||
import PVPlantResources
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
from PVPlantResources import DirResources as DirResources
|
||||
|
||||
|
||||
class MapWindow(QtGui.QWidget):
|
||||
def __init__(self, WinTitle="MapWindow"):
|
||||
super(MapWindow, self).__init__()
|
||||
self.raise_()
|
||||
self.lat = None
|
||||
self.lon = None
|
||||
self.minLat = None
|
||||
self.maxLat = None
|
||||
self.minLon = None
|
||||
self.maxLon = None
|
||||
self.zoom = None
|
||||
self.WinTitle = WinTitle
|
||||
self.georeference_coordinates = {'lat': None, 'lon': None}
|
||||
self.setupUi()
|
||||
|
||||
def setupUi(self):
|
||||
from PySide2.QtWebEngineWidgets import QWebEngineView
|
||||
from PySide2.QtWebChannel import QWebChannel
|
||||
|
||||
self.ui = FreeCADGui.PySideUic.loadUi(PVPlantResources.__dir__ + "/PVPlantGeoreferencing.ui", self)
|
||||
|
||||
self.resize(1200, 800)
|
||||
self.setWindowTitle(self.WinTitle)
|
||||
self.setWindowIcon(QtGui.QIcon(os.path.join(DirIcons, "Location.svg")))
|
||||
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
|
||||
|
||||
self.layout = QtGui.QHBoxLayout(self)
|
||||
self.layout.setContentsMargins(4, 4, 4, 4)
|
||||
|
||||
LeftWidget = QtGui.QWidget(self)
|
||||
LeftLayout = QtGui.QVBoxLayout(LeftWidget)
|
||||
LeftWidget.setLayout(LeftLayout)
|
||||
LeftLayout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
RightWidget = QtGui.QWidget(self)
|
||||
RightWidget.setFixedWidth(350)
|
||||
RightLayout = QtGui.QVBoxLayout(RightWidget)
|
||||
RightWidget.setLayout(RightLayout)
|
||||
RightLayout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
self.layout.addWidget(LeftWidget)
|
||||
self.layout.addWidget(RightWidget)
|
||||
|
||||
# Left Widgets:
|
||||
# -- Search Bar:
|
||||
self.valueSearch = QtGui.QLineEdit(self)
|
||||
self.valueSearch.setPlaceholderText("Search")
|
||||
self.valueSearch.returnPressed.connect(self.onSearch)
|
||||
|
||||
searchbutton = QtGui.QPushButton('Search')
|
||||
searchbutton.setFixedWidth(80)
|
||||
searchbutton.clicked.connect(self.onSearch)
|
||||
|
||||
SearchBarLayout = QtGui.QHBoxLayout(self)
|
||||
SearchBarLayout.addWidget(self.valueSearch)
|
||||
SearchBarLayout.addWidget(searchbutton)
|
||||
LeftLayout.addLayout(SearchBarLayout)
|
||||
|
||||
# -- Webbroser:
|
||||
self.view = QWebEngineView()
|
||||
self.channel = QWebChannel(self.view.page())
|
||||
self.view.page().setWebChannel(self.channel)
|
||||
self.channel.registerObject("MyApp", self)
|
||||
file = os.path.join(DirResources, "webs", "main.html")
|
||||
self.view.page().loadFinished.connect(self.onLoadFinished)
|
||||
self.view.page().load(QtCore.QUrl.fromLocalFile(file))
|
||||
LeftLayout.addWidget(self.view)
|
||||
|
||||
# -- Latitud y longitud:
|
||||
self.labelCoordinates = QtGui.QLabel()
|
||||
self.labelCoordinates.setFixedHeight(21)
|
||||
LeftLayout.addWidget(self.labelCoordinates)
|
||||
|
||||
# Right Widgets:
|
||||
labelKMZ = QtGui.QLabel()
|
||||
labelKMZ.setText("Cargar un archivo KMZ/KML:")
|
||||
self.kmlButton = QtGui.QPushButton()
|
||||
self.kmlButton.setFixedSize(32, 32)
|
||||
self.kmlButton.setIcon(QtGui.QIcon(os.path.join(DirIcons, "googleearth.svg")))
|
||||
widget = QtGui.QWidget(self)
|
||||
layout = QtGui.QHBoxLayout(widget)
|
||||
widget.setLayout(layout)
|
||||
layout.addWidget(labelKMZ)
|
||||
layout.addWidget(self.kmlButton)
|
||||
RightLayout.addWidget(widget)
|
||||
|
||||
# -----------------------
|
||||
self.groupbox = QtGui.QGroupBox("Importar datos desde:")
|
||||
self.groupbox.setCheckable(True)
|
||||
self.groupbox.setChecked(True)
|
||||
radio1 = QtGui.QRadioButton("Google Elevation")
|
||||
radio2 = QtGui.QRadioButton("Nube de Puntos")
|
||||
radio3 = QtGui.QRadioButton("Datos GPS")
|
||||
radio1.setChecked(True)
|
||||
|
||||
vbox = QtGui.QVBoxLayout(self)
|
||||
vbox.addWidget(radio1)
|
||||
vbox.addWidget(radio2)
|
||||
vbox.addWidget(radio3)
|
||||
|
||||
self.groupbox.setLayout(vbox)
|
||||
RightLayout.addWidget(self.groupbox)
|
||||
# ------------------------
|
||||
|
||||
self.checkboxImportGis = QtGui.QCheckBox("Importar datos GIS")
|
||||
RightLayout.addWidget(self.checkboxImportGis)
|
||||
|
||||
self.checkboxImportSatelitalImagen = QtGui.QCheckBox("Importar Imagen Satelital")
|
||||
RightLayout.addWidget(self.checkboxImportSatelitalImagen)
|
||||
|
||||
verticalSpacer = QtGui.QSpacerItem(20, 48, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
|
||||
RightLayout.addItem(verticalSpacer)
|
||||
|
||||
self.bAccept = QtGui.QPushButton('Accept')
|
||||
self.bAccept.clicked.connect(self.onAcceptClick)
|
||||
RightLayout.addWidget(self.bAccept)
|
||||
|
||||
# signals/slots
|
||||
QtCore.QObject.connect(self.kmlButton, QtCore.SIGNAL("clicked()"), self.importKML)
|
||||
|
||||
|
||||
def onLoadFinished(self):
|
||||
file = os.path.join(DirResources, "webs", "map.js")
|
||||
frame = self.view.page()
|
||||
with open(file, 'r') as f:
|
||||
frame.runJavaScript(f.read())
|
||||
|
||||
def onSearch(self):
|
||||
if self.valueSearch.text() == "":
|
||||
return
|
||||
|
||||
from geopy.geocoders import Nominatim
|
||||
|
||||
geolocator = Nominatim(user_agent="http")
|
||||
location = geolocator.geocode(self.valueSearch.text())
|
||||
self.valueSearch.setText(location.address)
|
||||
self.panMap(location.longitude, location.latitude, location.raw['boundingbox'])
|
||||
|
||||
def onAcceptClick(self):
|
||||
frame = self.view.page()
|
||||
# 1. georeferenciar
|
||||
frame.runJavaScript(
|
||||
"MyApp.georeference(drawnItems.getBounds().getCenter().lat, drawnItems.getBounds().getCenter().lng);"
|
||||
)
|
||||
|
||||
# 2. importar todos los elementos dibujados:
|
||||
frame.runJavaScript(
|
||||
"var data = drawnItems.toGeoJSON();"
|
||||
"MyApp.shapes(JSON.stringify(data));"
|
||||
)
|
||||
|
||||
self.close()
|
||||
|
||||
@QtCore.Slot(float, float)
|
||||
def onMapMove(self, lat, lng):
|
||||
from lib.projection import latlon_to_utm
|
||||
|
||||
self.lat = lat
|
||||
self.lon = lng
|
||||
easting, northing, zone_number, zone_letter = latlon_to_utm(lat, lng)
|
||||
self.labelCoordinates.setText('Longitud: {:.5f}, Latitud: {:.5f}'.format(lng, lat) +
|
||||
' | UTM: ' + str(zone_number) + zone_letter +
|
||||
', {:.5f}m E, {:.5f}m N'.format(easting, northing))
|
||||
|
||||
@QtCore.Slot(float, float, float, float, int)
|
||||
def onMapZoom(self, minLat, minLon, maxLat, maxLon, zoom):
|
||||
self.minLat = min([minLat, maxLat])
|
||||
self.maxLat = max([minLat, maxLat])
|
||||
self.minLon = min([minLon, maxLon])
|
||||
self.maxLon = max([minLon, maxLon])
|
||||
self.zoom = zoom
|
||||
|
||||
@QtCore.Slot(float, float)
|
||||
def georeference(self, lat, lng):
|
||||
import PVPlantSite
|
||||
from geopy.geocoders import Nominatim
|
||||
|
||||
self.georeference_coordinates['lat'] = lat
|
||||
self.georeference_coordinates['lon'] = lng
|
||||
|
||||
Site = PVPlantSite.get(create=True)
|
||||
Site.Proxy.setLatLon(lat, lng)
|
||||
|
||||
geolocator = Nominatim(user_agent="http")
|
||||
location = geolocator.reverse('{:.5f}, {:.5f}'.format(lat, lng))
|
||||
if location:
|
||||
if location.raw["address"].get("road"):
|
||||
str = location.raw["address"]["road"]
|
||||
if location.raw["address"].get("house_number"):
|
||||
str += ' ({0})'.format(location.raw["address"]["house_number"])
|
||||
Site.Address = str
|
||||
if location.raw["address"].get("city"):
|
||||
Site.City = location.raw["address"]["city"]
|
||||
if location.raw["address"].get("postcode"):
|
||||
Site.PostalCode = location.raw["address"]["postcode"]
|
||||
if location.raw["address"].get("address"):
|
||||
Site.Region = '{0}'.format(location.raw["address"]["province"])
|
||||
if location.raw["address"].get("state"):
|
||||
if Site.Region != "":
|
||||
Site.Region += " - "
|
||||
Site.Region += '{0}'.format(location.raw["address"]["state"])
|
||||
Site.Country = location.raw["address"]["country"]
|
||||
|
||||
@QtCore.Slot(str)
|
||||
def shapes(self, drawnItems):
|
||||
import geojson
|
||||
import PVPlantImportGrid as ImportElevation
|
||||
import Draft
|
||||
import PVPlantSite
|
||||
Site = PVPlantSite.get()
|
||||
|
||||
offset = FreeCAD.Vector(0, 0, 0)
|
||||
if not (self.lat is None or self.lon is None):
|
||||
offset = FreeCAD.Vector(Site.Origin)
|
||||
offset.z = 0
|
||||
|
||||
items = geojson.loads(drawnItems)
|
||||
for item in items['features']:
|
||||
if item['geometry']['type'] == "Point": # 1. if the feature is a Point or Circle:
|
||||
coord = item['geometry']['coordinates']
|
||||
point = ImportElevation.getElevationFromOE([[coord[1], coord[0]],])
|
||||
c = FreeCAD.Vector(point[0][0], point[0][1], point[0][2]).sub(offset)
|
||||
if item['properties'].get('radius'):
|
||||
r = round(item['properties']['radius'] * 1000, 0)
|
||||
p = FreeCAD.Placement()
|
||||
p.Base = c
|
||||
obj = Draft.makeCircle(r, placement=p, face=False)
|
||||
else:
|
||||
obj = Draft.make_point(c * 1000, color=(0.5, 0.3, 0.6), point_size=10)
|
||||
else: # 2. if the feature is a Polygon or Line:
|
||||
cw = False
|
||||
name = "Línea"
|
||||
lp = item['geometry']['coordinates']
|
||||
if item['geometry']['type'] == "Polygon":
|
||||
cw = True
|
||||
name = "Area"
|
||||
lp = item['geometry']['coordinates'][0]
|
||||
|
||||
pts = [[cords[1], cords[0]] for cords in lp]
|
||||
tmp = ImportElevation.getElevationFromOE(pts)
|
||||
pts = [p.sub(offset) for p in tmp]
|
||||
|
||||
obj = Draft.makeWire(pts, closed=cw, face=False)
|
||||
obj.Label = name
|
||||
Draft.autogroup(obj)
|
||||
|
||||
if item['properties'].get('name'):
|
||||
obj.Label = item['properties']['name']
|
||||
|
||||
if self.checkboxImportGis.isChecked():
|
||||
self.getDataFromOSM(self.minLat, self.minLon, self.maxLat, self.maxLon)
|
||||
|
||||
if self.checkboxImportSatelitalImagen.isChecked():
|
||||
from lib.projection import latlon_to_utm
|
||||
|
||||
s_lat = self.minLat
|
||||
s_lon = self.minLon
|
||||
n_lat = self.maxLat
|
||||
n_lon = self.maxLon
|
||||
|
||||
# Obtener puntos UTM para las esquinas y el punto de referencia
|
||||
points = [
|
||||
[s_lat, s_lon], # Suroeste
|
||||
[n_lat, n_lon], # Noreste
|
||||
[self.georeference_coordinates['lat'], self.georeference_coordinates['lon']] # Punto de referencia
|
||||
]
|
||||
utm_points = ImportElevation.getElevationFromOE(points)
|
||||
|
||||
if not utm_points or len(utm_points) < 3:
|
||||
FreeCAD.Console.PrintError("Error obteniendo elevaciones para las esquinas y referencia\n")
|
||||
return
|
||||
|
||||
sw_utm, ne_utm, ref_utm = utm_points
|
||||
|
||||
# Descargar imagen satelital
|
||||
from lib.GoogleSatelitalImageDownload import GoogleMapDownloader
|
||||
downloader = GoogleMapDownloader(
|
||||
zoom=self.zoom,
|
||||
layer='raw_satellite'
|
||||
)
|
||||
img = downloader.generateImage(
|
||||
sw_lat=s_lat,
|
||||
sw_lng=s_lon,
|
||||
ne_lat=n_lat,
|
||||
ne_lng=n_lon
|
||||
)
|
||||
|
||||
# Guardar imagen
|
||||
doc_path = os.path.dirname(FreeCAD.ActiveDocument.FileName) if FreeCAD.ActiveDocument.FileName else ""
|
||||
if not doc_path:
|
||||
doc_path = FreeCAD.ConfigGet("UserAppData")
|
||||
|
||||
filename = os.path.join(doc_path, "background.jpeg")
|
||||
img.save(filename)
|
||||
|
||||
# Calcular dimensiones reales en metros
|
||||
width_m = ne_utm.x - sw_utm.x
|
||||
height_m = ne_utm.y - sw_utm.y
|
||||
|
||||
# Calcular posición relativa del punto de referencia dentro de la imagen
|
||||
rel_x = (ref_utm.x - sw_utm.x) / width_m if width_m != 0 else 0.5
|
||||
rel_y = (ref_utm.y - sw_utm.y) / height_m if height_m != 0 else 0.5
|
||||
|
||||
# Crear objeto de imagen en FreeCAD
|
||||
doc = FreeCAD.ActiveDocument
|
||||
img_obj = doc.addObject('Image::ImagePlane', 'Background')
|
||||
img_obj.ImageFile = filename
|
||||
img_obj.Label = 'Background'
|
||||
|
||||
# FreeCAD trabaja en mm
|
||||
img_obj.XSize = width_m * 1000
|
||||
img_obj.YSize = height_m * 1000
|
||||
|
||||
# Posicionar para que el punto de referencia esté en (0,0,0)
|
||||
img_obj.Placement.Base = FreeCAD.Vector(
|
||||
-rel_x * width_m * 1000,
|
||||
-rel_y * height_m * 1000,
|
||||
0
|
||||
)
|
||||
|
||||
doc.recompute()
|
||||
|
||||
def getDataFromOSM(self, min_lat, min_lon, max_lat, max_lon):
|
||||
import Importer.importOSM as importOSM
|
||||
import PVPlantSite
|
||||
site = PVPlantSite.get()
|
||||
|
||||
offset = FreeCAD.Vector(0, 0, 0)
|
||||
if not (self.lat is None or self.lon is None):
|
||||
offset = FreeCAD.Vector(site.Origin)
|
||||
offset.z = 0
|
||||
importer = importOSM.OSMImporter(offset)
|
||||
osm_data = importer.get_osm_data(f"{min_lat},{min_lon},{max_lat},{max_lon}")
|
||||
importer.process_osm_data(osm_data)
|
||||
|
||||
def panMap(self, lng, lat, geometry=None):
|
||||
frame = self.view.page()
|
||||
|
||||
if not geometry or len(geometry) < 4:
|
||||
command = f'map.panTo(L.latLng({lat}, {lng}));'
|
||||
else:
|
||||
try:
|
||||
southwest = f"{float(geometry[1])}, {float(geometry[0])}"
|
||||
northeast = f"{float(geometry[3])}, {float(geometry[2])}"
|
||||
command = f'map.panTo(L.latLng({lat}, {lng}));'
|
||||
command += f'map.fitBounds(L.latLngBounds([{southwest}], [{northeast}]));'
|
||||
except (IndexError, ValueError, TypeError) as e:
|
||||
print(f"Error en geometry: {str(e)}")
|
||||
command = f'map.panTo(L.latLng({lat}, {lng}));'
|
||||
frame.runJavaScript(command)
|
||||
|
||||
def importKML(self):
|
||||
file = QtGui.QFileDialog.getOpenFileName(None, "FileDialog", "", "Google Earth (*.kml *.kmz)")[0]
|
||||
|
||||
from lib.kml2geojson import kmz_convert
|
||||
layers = kmz_convert(file, "", )
|
||||
frame = self.view.page()
|
||||
for layer in layers:
|
||||
command = "var geoJsonLayer = L.geoJSON({0}); drawnItems.addLayer(geoJsonLayer); map.fitBounds(geoJsonLayer.getBounds());".format( layer)
|
||||
frame.runJavaScript(command)
|
||||
|
||||
|
||||
class CommandPVPlantGeoreferencing:
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "Location.svg")),
|
||||
'Accel': "G, R",
|
||||
'MenuText': QT_TRANSLATE_NOOP("Georeferencing","Georeferencing"),
|
||||
'ToolTip': QT_TRANSLATE_NOOP("Georeferencing","Referenciar el lugar")}
|
||||
|
||||
def Activated(self):
|
||||
self.form = MapWindow()
|
||||
self.form.show()
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
from PVPlant.core.georef import MapWindow, CommandPVPlantGeoreferencing
|
||||
+17
-645
@@ -20,652 +20,24 @@
|
||||
# * *
|
||||
# ***********************************************************************
|
||||
|
||||
import json
|
||||
import urllib.request
|
||||
|
||||
import Draft
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
from PySide import QtCore, QtGui
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
|
||||
try:
|
||||
_fromUtf8 = QtCore.QString.fromUtf8
|
||||
except AttributeError:
|
||||
def _fromUtf8(s):
|
||||
return s
|
||||
|
||||
import os
|
||||
from PVPlantResources import DirIcons as DirIcons
|
||||
import PVPlantSite
|
||||
|
||||
|
||||
def get_elevation_from_oe(coordinates):
|
||||
"""Obtiene elevaciones de Open-Elevation API y devuelve vectores FreeCAD en coordenadas UTM.
|
||||
Args:
|
||||
coordinates (list): Lista de tuplas con coordenadas (latitud, longitud)
|
||||
Returns:
|
||||
list: Lista de vectores FreeCAD con coordenadas UTM y elevación (en milímetros)
|
||||
o lista vacía en caso de error.
|
||||
"""
|
||||
if not coordinates:
|
||||
return []
|
||||
PVPlantImportGrid - Wrapper de compatibilidad.
|
||||
|
||||
import requests
|
||||
from lib.projection import latlon_to_utm
|
||||
from requests.exceptions import RequestException
|
||||
Código movido a PVPlant/import_grid/grid.py.
|
||||
"""
|
||||
|
||||
locations = "|".join([f"{lat:.6f},{lon:.6f}" for lat, lon in coordinates])
|
||||
|
||||
try:
|
||||
response = requests.get(
|
||||
url="https://api.open-elevation.com/api/v1/lookup",
|
||||
params={'locations': locations},
|
||||
timeout=20,
|
||||
verify=True
|
||||
from PVPlant.import_grid.grid import (
|
||||
get_elevation_from_oe,
|
||||
getElevationFromOE,
|
||||
getSinglePointElevationFromBing,
|
||||
getGridElevationFromBing,
|
||||
getSinglePointElevation,
|
||||
_getSinglePointElevation,
|
||||
getSinglePointElevation1,
|
||||
getSinglePointElevationUtm,
|
||||
getElevationUTM,
|
||||
getElevation1,
|
||||
getElevation,
|
||||
_ImportPointsTaskPanel,
|
||||
CommandImportPoints,
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
except RequestException as e:
|
||||
print(f"Error en la solicitud: {str(e)}")
|
||||
return []
|
||||
|
||||
try:
|
||||
data = response.json()
|
||||
except ValueError:
|
||||
print("Respuesta JSON inválida")
|
||||
return []
|
||||
|
||||
if "results" not in data or len(data["results"]) != len(coordinates):
|
||||
print("Formato de respuesta inesperado")
|
||||
return []
|
||||
|
||||
points = []
|
||||
for result in data["results"]:
|
||||
try:
|
||||
easting, northing, _, _ = latlon_to_utm(
|
||||
result["latitude"],
|
||||
result["longitude"]
|
||||
)
|
||||
|
||||
points.append(FreeCAD.Vector(round(easting),
|
||||
round(northing),
|
||||
round(result["elevation"])) * 1000)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error procesando coordenadas: {str(e)}")
|
||||
continue
|
||||
|
||||
return points
|
||||
|
||||
|
||||
def getElevationFromOE(coordinates):
|
||||
"""Obtiene elevaciones de Open-Elevation API y devuelve vectores FreeCAD en coordenadas UTM."""
|
||||
|
||||
import certifi
|
||||
from requests.exceptions import RequestException
|
||||
if len(coordinates) == 0:
|
||||
return None
|
||||
|
||||
from requests import get
|
||||
from lib.projection import latlon_to_utm
|
||||
|
||||
locations_str=""
|
||||
total = len(coordinates) - 1
|
||||
for i, point in enumerate(coordinates):
|
||||
locations_str += '{:.6f},{:.6f}'.format(point[0], point[1])
|
||||
if i != total:
|
||||
locations_str += '|'
|
||||
query = 'https://api.open-elevation.com/api/v1/lookup?locations=' + locations_str
|
||||
points = []
|
||||
try:
|
||||
r = get(query, timeout=20, verify=certifi.where())
|
||||
results = r.json()
|
||||
for point in results["results"]:
|
||||
easting, northing, _, _ = latlon_to_utm(point["latitude"], point["longitude"])
|
||||
v = FreeCAD.Vector(round(easting, 0),
|
||||
round(northing, 0),
|
||||
round(point["elevation"], 0)) * 1000
|
||||
points.append(v)
|
||||
except RequestException as e:
|
||||
for point in coordinates:
|
||||
easting, northing, _, _ = latlon_to_utm(point[0], point[1])
|
||||
points.append(FreeCAD.Vector(round(easting, 0),
|
||||
round(northing, 0),
|
||||
0) * 1000)
|
||||
|
||||
return points
|
||||
|
||||
def getSinglePointElevationFromBing(lat, lng):
|
||||
import requests
|
||||
from lib.projection import latlon_to_utm
|
||||
|
||||
source = "http://dev.virtualearth.net/REST/v1/Elevation/List?points="
|
||||
source += str(lat) + "," + str(lng)
|
||||
source += "&heights=sealevel"
|
||||
source += "&key=AmsPZA-zRt2iuIdQgvXZIxme2gWcgLaz7igOUy7VPB8OKjjEd373eCnj1KFv2CqX"
|
||||
|
||||
response = requests.get(source)
|
||||
ans = response.text
|
||||
|
||||
s = json.loads(ans)
|
||||
print(s)
|
||||
res = s['resourceSets'][0]['resources'][0]['elevations']
|
||||
for elevation in res:
|
||||
easting, northing, _, _ = latlon_to_utm(lat, lng)
|
||||
v = FreeCAD.Vector(
|
||||
round(easting * 1000, 0),
|
||||
round(northing * 1000, 0),
|
||||
round(elevation * 1000, 0))
|
||||
return v
|
||||
|
||||
def getGridElevationFromBing(polygon, lat, lng, resolution = 1000):
|
||||
import math
|
||||
import requests
|
||||
from lib.projection import latlon_to_utm, utm_to_latlon
|
||||
|
||||
_, _, zone_number, zone_letter = latlon_to_utm(lat, lng)
|
||||
|
||||
points = []
|
||||
yy = polygon.Shape.BoundBox.YMax
|
||||
while yy > polygon.Shape.BoundBox.YMin:
|
||||
xx = polygon.Shape.BoundBox.XMin
|
||||
while xx < polygon.Shape.BoundBox.XMax:
|
||||
StepsXX = int(math.ceil((polygon.Shape.BoundBox.XMax - xx) / resolution))
|
||||
|
||||
if StepsXX > 1000:
|
||||
StepsXX = 1000
|
||||
xx1 = xx + 1000 * resolution
|
||||
else:
|
||||
xx1 = xx + StepsXX * resolution
|
||||
|
||||
point1 = utm_to_latlon(xx / 1000, yy / 1000, zone_number, zone_letter)
|
||||
point2 = utm_to_latlon(xx1 / 1000, yy / 1000, zone_number, zone_letter)
|
||||
|
||||
source = "http://dev.virtualearth.net/REST/v1/Elevation/Polyline?points="
|
||||
source += "{lat1},{lng1}".format(lat1=point1[0], lng1=point1[1])
|
||||
source += ","
|
||||
source += "{lat2},{lng2}".format(lat2=point2[0], lng2=point2[1])
|
||||
source += "&heights=sealevel"
|
||||
source += "&samples={steps}".format(steps=StepsXX)
|
||||
source += "&key=AmsPZA-zRt2iuIdQgvXZIxme2gWcgLaz7igOUy7VPB8OKjjEd373eCnj1KFv2CqX"
|
||||
|
||||
response = requests.get(source)
|
||||
ans = response.text
|
||||
|
||||
s = json.loads(ans)
|
||||
res = s['resourceSets'][0]['resources'][0]['elevations']
|
||||
|
||||
i = 0
|
||||
for elevation in res:
|
||||
v = FreeCAD.Vector(xx + resolution * i, yy, round(elevation * 1000, 4))
|
||||
points.append(v)
|
||||
i += 1
|
||||
xx = xx1 + resolution
|
||||
yy -= resolution
|
||||
|
||||
return points
|
||||
|
||||
def getSinglePointElevation(lat, lon):
|
||||
source = "https://maps.googleapis.com/maps/api/elevation/json?locations="
|
||||
source += str(lat) + "," + str(lon)
|
||||
source += "&key=AIzaSyB07X6lowYJ-iqyPmaFJvr-6zp1J63db8U"
|
||||
#print (source)
|
||||
|
||||
#response = request.urlopen(source)
|
||||
#ans = response.read()
|
||||
import requests
|
||||
response = requests.get(source)
|
||||
ans = response.text
|
||||
|
||||
# +# to do: error handling - wait and try again
|
||||
s = json.loads(ans)
|
||||
res = s['results']
|
||||
|
||||
from geopy.distance import geodesic
|
||||
for r in res:
|
||||
|
||||
reference = (0.0, 0.0)
|
||||
v = FreeCAD.Vector(
|
||||
round(geodesic(reference, (0.0, r['location']['lng'])).m, 2),
|
||||
round(geodesic(reference, (r['location']['lat'], 0.0)).m, 2),
|
||||
round(r['elevation'] * 1000, 2)
|
||||
)
|
||||
|
||||
return v
|
||||
|
||||
def _getSinglePointElevation(lat, lon):
|
||||
source = "https://maps.googleapis.com/maps/api/elevation/json?locations="
|
||||
source += str(lat) + "," + str(lon)
|
||||
source += "&key=AIzaSyB07X6lowYJ-iqyPmaFJvr-6zp1J63db8U"
|
||||
#print (source)
|
||||
|
||||
#response = request.urlopen(source)
|
||||
#ans = response.read()
|
||||
import requests
|
||||
response = requests.get(source)
|
||||
ans = response.text
|
||||
|
||||
# +# to do: error handling - wait and try again
|
||||
s = json.loads(ans)
|
||||
res = s['results']
|
||||
|
||||
import pymap3d as pm
|
||||
for r in res:
|
||||
x, y, z = pm.geodetic2ecef(round(r['location']['lng'], 2),
|
||||
round(r['location']['lat'], 2),
|
||||
0)
|
||||
v = FreeCAD.Vector(x,y,z)
|
||||
|
||||
return v
|
||||
|
||||
def getSinglePointElevation1(lat, lon):
|
||||
source = "https://maps.googleapis.com/maps/api/elevation/json?locations="
|
||||
source += str(lat) + "," + str(lon)
|
||||
source += "&key=AIzaSyB07X6lowYJ-iqyPmaFJvr-6zp1J63db8U"
|
||||
|
||||
#response = urllib.request.urlopen(source)
|
||||
#ans = response.read()
|
||||
import requests
|
||||
response = requests.get(source)
|
||||
ans = response.text
|
||||
|
||||
# +# to do: error handling - wait and try again
|
||||
s = json.loads(ans)
|
||||
res = s['results']
|
||||
|
||||
for r in res:
|
||||
c = tm.fromGeographic(r['location']['lat'], r['location']['lng'])
|
||||
v = FreeCAD.Vector(
|
||||
round(c[0], 4),
|
||||
round(c[1], 4),
|
||||
round(r['elevation'] * 1000, 2)
|
||||
)
|
||||
return v
|
||||
|
||||
def getSinglePointElevationUtm(lat, lon):
|
||||
import requests
|
||||
from lib.projection import latlon_to_utm
|
||||
|
||||
source = "https://maps.googleapis.com/maps/api/elevation/json?locations="
|
||||
source += str(lat) + "," + str(lon)
|
||||
source += "&key=AIzaSyB07X6lowYJ-iqyPmaFJvr-6zp1J63db8U"
|
||||
print(source)
|
||||
|
||||
response = requests.get(source)
|
||||
ans = response.text
|
||||
|
||||
s = json.loads(ans)
|
||||
res = s['results']
|
||||
print(res)
|
||||
|
||||
for r in res:
|
||||
easting, northing, _, _ = latlon_to_utm(r['location']['lat'], r['location']['lng'])
|
||||
v = FreeCAD.Vector(
|
||||
round(easting * 1000, 4),
|
||||
round(northing * 1000, 4),
|
||||
round(r['elevation'] * 1000, 2))
|
||||
print(v)
|
||||
return v
|
||||
|
||||
def getElevationUTM(polygon, lat, lng, resolution = 10000):
|
||||
from lib.projection import latlon_to_utm, utm_to_latlon
|
||||
|
||||
_, _, zone_number, zone_letter = latlon_to_utm(lat, lng)
|
||||
|
||||
StepsXX = int((polygon.Shape.BoundBox.XMax - polygon.Shape.BoundBox.XMin) / (resolution*1000))
|
||||
points = []
|
||||
yy = polygon.Shape.BoundBox.YMax
|
||||
while yy > polygon.Shape.BoundBox.YMin:
|
||||
point1 = utm_to_latlon(polygon.Shape.BoundBox.XMin / 1000, yy / 1000, zone_number, zone_letter)
|
||||
point2 = utm_to_latlon(polygon.Shape.BoundBox.XMax / 1000, yy / 1000, zone_number, zone_letter)
|
||||
|
||||
source = "https://maps.googleapis.com/maps/api/elevation/json?path="
|
||||
source += "{a},{b}".format(a = point1[0], b = point1[1])
|
||||
source += "|"
|
||||
source += "{a},{b}".format(a = point2[0], b = point2[1])
|
||||
source += "&samples={a}".format(a = StepsXX)
|
||||
source += "&key=AIzaSyB07X6lowYJ-iqyPmaFJvr-6zp1J63db8U"
|
||||
|
||||
import requests
|
||||
response = requests.get(source)
|
||||
ans = response.text
|
||||
|
||||
s = json.loads(ans)
|
||||
res = s['results']
|
||||
|
||||
for r in res:
|
||||
easting, northing, _, _ = latlon_to_utm(r['location']['lat'], r['location']['lng'])
|
||||
v = FreeCAD.Vector(
|
||||
round(easting * 1000, 2),
|
||||
round(northing * 1000, 2),
|
||||
round(r['elevation'] * 1000, 2)
|
||||
)
|
||||
points.append(v)
|
||||
yy -= (resolution*1000)
|
||||
|
||||
FreeCAD.activeDocument().recompute()
|
||||
return points
|
||||
|
||||
def getElevation1(polygon,resolution=10):
|
||||
|
||||
StepsXX = int((polygon.Shape.BoundBox.XMax - polygon.Shape.BoundBox.XMin) / (resolution * 1000))
|
||||
points = []
|
||||
yy = polygon.Shape.BoundBox.YMax
|
||||
while yy > polygon.Shape.BoundBox.YMin:
|
||||
point1 = tm.toGeographic(polygon.Shape.BoundBox.XMin, yy)
|
||||
point2 = tm.toGeographic(polygon.Shape.BoundBox.XMax, yy)
|
||||
|
||||
source = "https://maps.googleapis.com/maps/api/elevation/json?path="
|
||||
source += "{a},{b}".format(a = point1[0], b = point1[1])
|
||||
source += "|"
|
||||
source += "{a},{b}".format(a = point2[0], b = point2[1])
|
||||
source += "&samples={a}".format(a = StepsXX)
|
||||
source += "&key=AIzaSyB07X6lowYJ-iqyPmaFJvr-6zp1J63db8U"
|
||||
|
||||
try:
|
||||
#response = urllib.request.urlopen(source)
|
||||
#ans = response.read()
|
||||
import requests
|
||||
response = requests.get(source)
|
||||
ans = response.text
|
||||
|
||||
# +# to do: error handling - wait and try again
|
||||
|
||||
s = json.loads(ans)
|
||||
res = s['results']
|
||||
except:
|
||||
continue
|
||||
|
||||
#points = []
|
||||
for r in res:
|
||||
c = tm.fromGeographic(r['location']['lat'], r['location']['lng'])
|
||||
v = FreeCAD.Vector(
|
||||
round(c[0], 2),
|
||||
round(c[1], 2),
|
||||
round(r['elevation'] * 1000, 2)
|
||||
)
|
||||
points.append(v)
|
||||
|
||||
FreeCAD.activeDocument().recompute()
|
||||
yy -= (resolution*1000)
|
||||
|
||||
return points
|
||||
|
||||
## download the heights from google:
|
||||
def getElevation(lat, lon, b=50.35, le=11.17, size=40):
|
||||
#https://maps.googleapis.com/maps/api/elevation/json?path=36.578581,-118.291994|36.23998,-116.83171&samples=3&key=YOUR_API_KEY
|
||||
#https://maps.googleapis.com/maps/api/elevation/json?locations=39.7391536,-104.9847034&key=YOUR_API_KEY
|
||||
|
||||
source = "https://maps.googleapis.com/maps/api/elevation/json?path="
|
||||
source += str(b-size*0.001) + "," + str(le) + "|" + str(b+size*0.001) + "," + str(le)
|
||||
source += "&samples=" + str(100)
|
||||
source += "&key=AIzaSyB07X6lowYJ-iqyPmaFJvr-6zp1J63db8U"
|
||||
|
||||
response = urllib.request.urlopen(source)
|
||||
ans = response.read()
|
||||
|
||||
# +# to do: error handling - wait and try again
|
||||
s = json.loads(ans)
|
||||
res = s['results']
|
||||
|
||||
from geopy.distance import geodesic
|
||||
points = []
|
||||
for r in res:
|
||||
reference = (0.0, 0.0)
|
||||
v = FreeCAD.Vector(
|
||||
round(geodesic(reference, (0.0, r['location']['lat'])).m, 2),
|
||||
round(geodesic(reference, (r['location']['lng'], 0.0)).m, 2),
|
||||
round(r['elevation'] * 1000, 2) - baseheight
|
||||
)
|
||||
points.append(v)
|
||||
|
||||
line = Draft.makeWire(points, closed=False, face=False, support=None)
|
||||
line.ViewObject.Visibility = False
|
||||
#FreeCAD.activeDocument().recompute()
|
||||
FreeCADGui.updateGui()
|
||||
return FreeCAD.activeDocument().ActiveObject
|
||||
|
||||
class _ImportPointsTaskPanel:
|
||||
|
||||
def __init__(self, obj = None):
|
||||
self.obj = None
|
||||
self.Boundary = None
|
||||
self.select = 0
|
||||
self.filename = ""
|
||||
|
||||
# form:
|
||||
self.form1 = FreeCADGui.PySideUic.loadUi(os.path.dirname(__file__) + "/PVPlantImportGrid.ui")
|
||||
self.form1.radio1.toggled.connect(lambda: self.mainToggle(self.form1.radio1))
|
||||
self.form1.radio2.toggled.connect(lambda: self.mainToggle(self.form1.radio2))
|
||||
self.form1.radio1.setChecked(True) # << --------------Poner al final para que no dispare antes de crear los componentes a los que va a llamar
|
||||
#self.form.buttonAdd.clicked.connect(self.add)
|
||||
self.form1.buttonDEM.clicked.connect(self.openFileDEM)
|
||||
|
||||
self.form2 = FreeCADGui.PySideUic.loadUi(os.path.dirname(__file__) + "/PVPlantCreateTerrainMesh.ui")
|
||||
#self.form2.buttonAdd.clicked.connect(self.add)
|
||||
self.form2.buttonBoundary.clicked.connect(self.addBoundary)
|
||||
|
||||
|
||||
#self.form = [self.form1, self.form2]
|
||||
self.form = self.form1
|
||||
|
||||
''' future:
|
||||
def retranslateUi(self, dialog):
|
||||
self.form1.setWindowTitle("Configuracion del Rack")
|
||||
self.labelModule.setText(QtGui.QApplication.translate("PVPlant", "Modulo:", None))
|
||||
self.labelModuleLength.setText(QtGui.QApplication.translate("PVPlant", "Longitud:", None))
|
||||
self.labelModuleWidth.setText(QtGui.QApplication.translate("PVPlant", "Ancho:", None))
|
||||
self.labelModuleHeight.setText(QtGui.QApplication.translate("PVPlant", "Alto:", None))
|
||||
self.labelModuleFrame.setText(QtGui.QApplication.translate("PVPlant", "Ancho del marco:", None))
|
||||
self.labelModuleColor.setText(QtGui.QApplication.translate("PVPlant", "Color del modulo:", None))
|
||||
self.labelModules.setText(QtGui.QApplication.translate("Arch", "Colocacion de los Modulos", None))
|
||||
self.labelModuleOrientation.setText(QtGui.QApplication.translate("Arch", "Orientacion del modulo:", None))
|
||||
self.labelModuleGapX.setText(QtGui.QApplication.translate("Arch", "Separacion Horizontal (mm):", None))
|
||||
self.labelModuleGapY.setText(QtGui.QApplication.translate("Arch", "Separacion Vertical (mm):", None))
|
||||
self.labelModuleRows.setText(QtGui.QApplication.translate("Arch", "Filas de modulos:", None))
|
||||
self.labelModuleCols.setText(QtGui.QApplication.translate("Arch", "Columnas de modulos:", None))
|
||||
self.labelRack.setText(QtGui.QApplication.translate("Arch", "Configuracion de la estructura", None))
|
||||
self.labelRackType.setText(QtGui.QApplication.translate("Arch", "Tipo de estructura:", None))
|
||||
self.labelLevel.setText(QtGui.QApplication.translate("Arch", "Nivel:", None))
|
||||
self.labelOffset.setText(QtGui.QApplication.translate("Arch", "Offset", None))
|
||||
'''
|
||||
|
||||
def add(self):
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
if len(sel) > 0:
|
||||
self.obj = sel[0]
|
||||
self.lineEdit1.setText(self.obj.Label)
|
||||
|
||||
def addBoundary(self):
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
if len(sel) > 0:
|
||||
self.Boundary = sel[0]
|
||||
self.form2.editBoundary.setText(self.Boundary.Label)
|
||||
|
||||
def openFileDEM(self):
|
||||
filters = "Esri ASC (*.asc);;CSV (*.csv);;All files (*.*)"
|
||||
filename = QtGui.QFileDialog.getOpenFileName(None,
|
||||
"Open DEM,",
|
||||
"",
|
||||
filters)
|
||||
self.filename = filename[0]
|
||||
self.form1.editDEM.setText(filename[0])
|
||||
|
||||
def mainToggle(self, radiobox):
|
||||
if radiobox is self.form1.radio1:
|
||||
self.select = 0
|
||||
self.form1.gbLocalFile.setVisible(True)
|
||||
elif radiobox is self.form1.radio2:
|
||||
self.select = 1
|
||||
self.form1.gbLocalFile.setVisible(True)
|
||||
|
||||
def accept(self):
|
||||
from datetime import datetime
|
||||
starttime = datetime.now()
|
||||
|
||||
site = PVPlantSite.get()
|
||||
|
||||
try:
|
||||
PointGroups = FreeCAD.ActiveDocument.Point_Groups
|
||||
except:
|
||||
PointGroups = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", 'Point_Groups')
|
||||
PointGroups.Label = "Point Groups"
|
||||
|
||||
PointGroup = FreeCAD.ActiveDocument.addObject('Points::Feature', "Point_Group")
|
||||
PointGroup.Label = "Land_Grid_Points"
|
||||
FreeCAD.ActiveDocument.Point_Groups.addObject(PointGroup)
|
||||
PointObject = PointGroup.Points.copy()
|
||||
|
||||
if self.select == 0: # Google or bing or ...
|
||||
#for item in self.obj:
|
||||
#if self.groupbox.isChecked:break
|
||||
resol = FreeCAD.Units.Quantity(self.valueResolution.text()).Value
|
||||
Site = FreeCAD.ActiveDocument.Site
|
||||
pts = getGridElevationFromBing(self.obj, Site.Latitude, Site.Longitude, resol)
|
||||
PointObject.addPoints(pts)
|
||||
PointGroup.Points = PointObject
|
||||
|
||||
else:
|
||||
if self.filename == "":
|
||||
return
|
||||
|
||||
import Utils.importDEM as openDEM
|
||||
if self.select == 1: # DEM.
|
||||
import numpy as np
|
||||
root, extension = os.path.splitext(self.filename)
|
||||
if extension.lower() == ".asc":
|
||||
x, y, datavals, cellsize, nodata_value = openDEM.openEsri(self.filename)
|
||||
|
||||
if self.Boundary:
|
||||
inc_x = self.Boundary.Shape.BoundBox.XLength * 0.05
|
||||
inc_y = self.Boundary.Shape.BoundBox.YLength * 0.05
|
||||
|
||||
min_x = 0
|
||||
max_x = 0
|
||||
|
||||
comp = (self.Boundary.Shape.BoundBox.XMin - inc_x) / 1000
|
||||
for i in range(nx):
|
||||
if x[i] > comp:
|
||||
min_x = i - 1
|
||||
break
|
||||
comp = (self.Boundary.Shape.BoundBox.XMax + inc_x) / 1000
|
||||
for i in range(min_x, nx):
|
||||
if x[i] > comp:
|
||||
max_x = i
|
||||
break
|
||||
|
||||
min_y = 0
|
||||
max_y = 0
|
||||
|
||||
comp = (self.Boundary.Shape.BoundBox.YMax + inc_y) / 1000
|
||||
for i in range(ny):
|
||||
if y[i] < comp:
|
||||
max_y = i
|
||||
break
|
||||
comp = (self.Boundary.Shape.BoundBox.YMin - inc_y) / 1000
|
||||
for i in range(max_y, ny):
|
||||
if y[i] < comp:
|
||||
min_y = i
|
||||
break
|
||||
|
||||
x = x[min_x:max_x]
|
||||
y = y[max_y:min_y]
|
||||
datavals = datavals[max_y:min_y, min_x:max_x]
|
||||
|
||||
pts = []
|
||||
if True: # faster but more memory 46s - 4,25 gb
|
||||
x, y = np.meshgrid(x, y)
|
||||
xx = x.flatten()
|
||||
yy = y.flatten()
|
||||
zz = datavals.flatten()
|
||||
x[:] = 0
|
||||
y[:] = 0
|
||||
datavals[:] = 0
|
||||
|
||||
pts = []
|
||||
for i in range(0, len(xx)):
|
||||
pts.append(FreeCAD.Vector(xx[i], yy[i], zz[i]) * 1000)
|
||||
|
||||
xx[:] = 0
|
||||
yy[:] = 0
|
||||
zz[:] = 0
|
||||
|
||||
else: # 51s 3,2 gb
|
||||
createmesh = True
|
||||
if createmesh:
|
||||
import Part, Draft
|
||||
|
||||
lines=[]
|
||||
for j in range(len(y)):
|
||||
edges = []
|
||||
for i in range(0, len(x) - 1):
|
||||
ed = Part.makeLine(FreeCAD.Vector(x[i], y[j], datavals[j][i]) * 1000,
|
||||
FreeCAD.Vector(x[i + 1], y[j], datavals[j][i + 1]) * 1000)
|
||||
edges.append(ed)
|
||||
|
||||
#bspline = Draft.makeBSpline(pts)
|
||||
#bspline.ViewObject.hide()
|
||||
line = Part.Wire(edges)
|
||||
lines.append(line)
|
||||
|
||||
'''
|
||||
for i in range(0, len(bsplines), 100):
|
||||
p = Part.makeLoft(bsplines[i:i + 100], False, False, False)
|
||||
Part.show(p)
|
||||
'''
|
||||
p = Part.makeLoft(lines, False, True, False)
|
||||
p = Part.Solid(p)
|
||||
Part.show(p)
|
||||
|
||||
else:
|
||||
pts = []
|
||||
for j in range(ny):
|
||||
for i in range(nx):
|
||||
pts.append(FreeCAD.Vector(x[i], y[j], datavals[j][i]) * 1000)
|
||||
|
||||
elif extension.lower() == ".csv" or extension.lower() == ".txt": # x, y, z from gps
|
||||
pts = openDEM.interpolatePoints(openDEM.openCSV(self.filename))
|
||||
|
||||
PointObject.addPoints(pts)
|
||||
PointGroup.Points = PointObject
|
||||
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
FreeCADGui.Control.closeDialog()
|
||||
print("tiempo: ", datetime.now() - starttime)
|
||||
|
||||
def reject(self):
|
||||
FreeCADGui.Control.closeDialog()
|
||||
|
||||
## Comandos -----------------------------------------------------------------------------------------------------------
|
||||
class CommandImportPoints:
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(DirIcons, "cloud.svg")),
|
||||
'MenuText': QT_TRANSLATE_NOOP("PVPlant", "Importer Grid"),
|
||||
'Accel': "B, U",
|
||||
'ToolTip': QT_TRANSLATE_NOOP("PVPlant", "Creates a cloud of points.")}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
def Activated(self):
|
||||
self.TaskPanel = _ImportPointsTaskPanel()
|
||||
FreeCADGui.Control.showDialog(self.TaskPanel)
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
class CommandPointsGroup:
|
||||
|
||||
def GetCommands(self):
|
||||
return tuple(['ImportPoints'
|
||||
])
|
||||
def GetResources(self):
|
||||
return { 'MenuText': QT_TRANSLATE_NOOP("",'Cloud of Points'),
|
||||
'ToolTip': QT_TRANSLATE_NOOP("",'Cloud of Points')
|
||||
}
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
FreeCADGui.addCommand('ImportPoints', CommandImportPoints())
|
||||
FreeCADGui.addCommand('PointsGroup', CommandPointsGroup())
|
||||
|
||||
|
||||
+7
-2304
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user