Optimize and order

This commit is contained in:
2025-03-11 21:20:18 +01:00
parent 3b38651609
commit 4981b00918
3 changed files with 478 additions and 83 deletions

90
Importer/importOSM.py Normal file
View File

@@ -0,0 +1,90 @@
# ***************************************************************************
# * *
# * Copyright (c) 2016 microelly <> *
# * Copyright (c) 2020 Bernd Hahnebach <bernd@bimstatik.org> *
# * Copyright (c) 2022 Hakan Seven <hakanseven12@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 data from OpenStreetMap
"""
import FreeCAD
import Part
from xml.etree import ElementTree as ET
import urllib.request
import urllib.parse
def import_osm_data(min_lat=40.41, min_lon=-3.71, max_lat=40.42, max_lon=-3.7):
# Configurar la consulta de Overpass API
overpass_url = "https://overpass-api.de/api/interpreter"
query = f"""
[out:xml];
(
node({min_lat},{min_lon},{max_lat},{max_lon});
way({min_lat},{min_lon},{max_lat},{max_lon});
);
out body;
>;
out skel qt;
"""
print("Descargando datos de OSM...")
response = urllib.request.urlopen(overpass_url, data=query.encode('utf-8'))
osm_data = response.read()
print("Procesando datos...")
root = ET.fromstring(osm_data)
nodes = {}
if not FreeCAD.ActiveDocument:
FreeCAD.newDocument()
doc = FreeCAD.ActiveDocument
# Creación de nodos corregida
for node in root.findall('node'):
node_id = node.attrib['id']
lat = float(node.attrib['lat'])
lon = float(node.attrib['lon'])
nodes[node_id] = FreeCAD.Vector(lon, lat, 0)
# Versión estable para todas las versiones de FreeCAD
point = Part.Vertex(nodes[node_id])
Part.show(point, f"Node_{node_id}")
# Procesar vías (manera alternativa)
for way in root.findall('way'):
way_points = [nodes[nd.attrib['ref']]
for nd in way.findall('nd')
if nd.attrib['ref'] in nodes]
if len(way_points) > 1:
try:
wire = Part.makePolygon(way_points)
Part.show(wire, f"Way_{way.attrib['id']}")
except Exception as e:
print(f"Error en vía {way.attrib['id']}: {str(e)}")
print("Importación completada!")
FreeCAD.ActiveDocument.recompute()
# Ejecutar la función
import_osm_data()

View File

@@ -20,53 +20,62 @@
# * * # * *
# *********************************************************************** # ***********************************************************************
__title__="FreeCAD Fotovoltaic Power Plant Toolkit" __title__ = "FreeCAD Fotovoltaic Power Plant Toolkit"
__author__ = "Javier Braña" __author__ = "Javier Braña"
__url__ = "sn" __url__ = "sn"
from pathlib import Path
import sys
import os
import FreeCADGui
FreeCADGui.updateLocale()
try:
import PVPlantGeoreferencing, PVPlantPlacement, \
PVPlantTerrainAnalisys, PVPlantSite, PVPlantImportGrid, PVPlantFence, \
PVPlantFoundation, PVPlantCreateTerrainMesh, \
PVPlantTreeGenerator, PVPlantBuilding, PVPlantTrench, PVPlantEarthWorks, \
PVPlantStringing, \
PVPlantPad, PVPlantRoad, PVPlantTerrain, PVPlantManhole, \
GraphProfile, Utils.PVPlantTrace, \
reload
import PVPlantRackChecking
from Project.Area import PVPlantArea, PVPlantAreaUtils
from Project import ProjectSetup
from Importer import importDXF
from Mechanical.Frame import PVPlantFrame
from Electrical.Cable import PVPlantCable, PVPlantElectricalLine
from Electrical.CombinerBox import PVPlantStringBox
from Electrical.Inverter import PVPlantInverter
except ImportError as e:
print(f"Error importing modules: {e}")
class PVPlantWorkbench (Workbench): class PVPlantWorkbench(Workbench):
import os
from PVPlantResources import DirIcons as DirIcons from PVPlantResources import DirIcons as DirIcons
MenuText = "PVPlant" MenuText = "PVPlant"
ToolTip = "Workbench for PV design" ToolTip = "Workbench for PV design"
Icon = str(os.path.join(DirIcons, "icon.svg")) Icon = str(os.path.join(DirIcons, "icon.svg"))
def Initialize(self): def Initialize(self):
import sys
sys.path.append(r"C:\Users\javie\AppData\Roaming\FreeCAD\Mod")
# Mias #sys.path.append(r"C:\Users\javie\AppData\Roaming\FreeCAD\Mod")
import PVPlantGeoreferencing, PVPlantPlacement, \ sys.path.append(os.path.join(FreeCAD.getUserAppDataDir(), 'Mod'))
PVPlantTerrainAnalisys, PVPlantSite, PVPlantImportGrid, PVPlantFence,\ import PVPlantTools
PVPlantFoundation, PVPlantCreateTerrainMesh, \
PVPlantTreeGenerator, PVPlantBuilding, PVPlantTrench, PVPlantEarthWorks, \
PVPlantStringing, \
PVPlantPad, PVPlantRoad, PVPlantTerrain, PVPlantManhole, \
GraphProfile, Utils.PVPlantTrace,\
reload
import PVPlantRackChecking
from Project.Area import PVPlantArea, PVPlantAreaUtils self.projectlist = PVPlantTools.projectlist
from Project import ProjectSetup
from Export import exportPVSyst, PVPlantBOQMechanical, PVPlantBOQElectrical, PVPlantBOQCivil,\
exportDXF
from Importer import importDXF
from Mechanical.Frame import PVPlantFrame
from Electrical.Cable import PVPlantCable, PVPlantElectricalLine
from Electrical.CombinerBox import PVPlantStringBox
from Electrical.Inverter import PVPlantInverter
# A list of command names created in the line above # A list of command names created in the line above
self.projectlist = ["Reload", '''self.projectlist = ["Reload",
"PVPlantSite", "PVPlantSite",
"PVPlantGeoreferencing", "PVPlantGeoreferencing",
"ProjectSetup", "ProjectSetup",
#"ImportGrid", # "ImportGrid",
"Terrain", "Terrain",
"PointsGroup", "PointsGroup",
"PVPlantCreateTerrainMesh", "PVPlantCreateTerrainMesh",
@@ -78,35 +87,28 @@ class PVPlantWorkbench (Workbench):
"PVPlantPad", "PVPlantPad",
"PVPlantRoad", "PVPlantRoad",
"PVPlantManhole", "PVPlantManhole",
#"PVPlantFoundation" # "PVPlantFoundation"
"GraphTerrainProfile", "GraphTerrainProfile",
"Trace", "Trace",
] ]'''
self.framelist = [ self.framelist = [
"RackType", "RackType",
"PVPlantRackCheck", "PVPlantRackCheck",
"Separator", "Separator",
"PVPlantPlacement", "PVPlantPlacement",
"PVPlantAdjustToTerrain", "PVPlantAdjustToTerrain",
"PVPlantConvertTo", "PVPlantConvertTo",
"PVArea" "PVArea"
] ]
self.objectlist = [ self.objectlist = [
"PVPlantTree", "PVPlantTree",
"PVPlantBuilding", "PVPlantBuilding",
"PVPlantFenceGroup", "PVPlantFenceGroup",
] ]
self.inportExportlist = ["BOQCivil",
"BOQMechanical",
"BOQElectrical",
"Separator",
"exportDXF",
#"importDXF",
"ExportToPVSyst",
]
from Export import ExporterCommands
self.inportExportlist = ExporterCommands.Exportlist
self.electricalList = ["PVPlantStringBox", self.electricalList = ["PVPlantStringBox",
"PVPlantCable", "PVPlantCable",
"PVPlanElectricalLine", "PVPlanElectricalLine",
@@ -114,14 +116,14 @@ class PVPlantWorkbench (Workbench):
"Stringing", "Stringing",
"Separator", "Separator",
"StringInverter", "StringInverter",
] ]
self.roads = ["PVPlantRoad", self.roads = ["PVPlantRoad",
] ]
self.pads = ["PVPlantPad", self.pads = ["PVPlantPad",
"Separator" "Separator"
] ]
# Toolbar # Toolbar
@@ -140,34 +142,36 @@ class PVPlantWorkbench (Workbench):
# Draft tools # Draft tools
from DraftTools import translate from DraftTools import translate
self.drafttools = ["Draft_Line","Draft_Wire","Draft_Circle","Draft_Arc","Draft_Ellipse", self.drafttools = ["Draft_Line", "Draft_Wire", "Draft_Circle", "Draft_Arc", "Draft_Ellipse",
"Draft_Polygon","Draft_Rectangle", "Draft_Text", "Draft_Polygon", "Draft_Rectangle", "Draft_Text",
"Draft_Dimension", "Draft_BSpline","Draft_Point", "Draft_Dimension", "Draft_BSpline", "Draft_Point",
"Draft_Facebinder","Draft_BezCurve","Draft_Label"] "Draft_Facebinder", "Draft_BezCurve", "Draft_Label"]
self.draftmodtools = ["Draft_Move","Draft_Rotate","Draft_Offset", self.draftmodtools = ["Draft_Move", "Draft_Rotate", "Draft_Offset",
"Draft_Trimex", "Draft_Upgrade", "Draft_Downgrade", "Draft_Scale", "Draft_Trimex", "Draft_Upgrade", "Draft_Downgrade", "Draft_Scale",
"Draft_Shape2DView","Draft_Draft2Sketch","Draft_Array", "Draft_Shape2DView", "Draft_Draft2Sketch", "Draft_Array",
"Draft_Clone"] "Draft_Clone"]
self.draftextratools = ["Draft_WireToBSpline","Draft_ShapeString", self.draftextratools = ["Draft_WireToBSpline", "Draft_ShapeString",
"Draft_PathArray","Draft_Mirror","Draft_Stretch"] "Draft_PathArray", "Draft_Mirror", "Draft_Stretch"]
self.draftcontexttools = ["Draft_ApplyStyle","Draft_ToggleDisplayMode","Draft_AddToGroup","Draft_AutoGroup", self.draftcontexttools = ["Draft_ApplyStyle", "Draft_ToggleDisplayMode", "Draft_AddToGroup", "Draft_AutoGroup",
"Draft_SelectGroup","Draft_SelectPlane", "Draft_SelectGroup", "Draft_SelectPlane",
"Draft_ShowSnapBar","Draft_ToggleGrid",] "Draft_ShowSnapBar", "Draft_ToggleGrid", ]
self.draftutils = ["Draft_Heal","Draft_FlipDimension", self.draftutils = ["Draft_Heal", "Draft_FlipDimension",
"Draft_ToggleConstructionMode","Draft_ToggleContinueMode","Draft_Edit", "Draft_ToggleConstructionMode", "Draft_ToggleContinueMode", "Draft_Edit",
"Draft_Slope","Draft_AddConstruction"] "Draft_Slope", "Draft_AddConstruction"]
self.snapList = ['Draft_Snap_Lock','Draft_Snap_Midpoint','Draft_Snap_Perpendicular', self.snapList = ['Draft_Snap_Lock', 'Draft_Snap_Midpoint', 'Draft_Snap_Perpendicular',
'Draft_Snap_Grid','Draft_Snap_Intersection','Draft_Snap_Parallel', 'Draft_Snap_Grid', 'Draft_Snap_Intersection', 'Draft_Snap_Parallel',
'Draft_Snap_Endpoint','Draft_Snap_Angle','Draft_Snap_Center', 'Draft_Snap_Endpoint', 'Draft_Snap_Angle', 'Draft_Snap_Center',
'Draft_Snap_Extension','Draft_Snap_Near','Draft_Snap_Ortho','Draft_Snap_Special', 'Draft_Snap_Extension', 'Draft_Snap_Near', 'Draft_Snap_Ortho', 'Draft_Snap_Special',
'Draft_Snap_Dimensions','Draft_Snap_WorkingPlane'] 'Draft_Snap_Dimensions', 'Draft_Snap_WorkingPlane']
def QT_TRANSLATE_NOOP(scope, text): return text def QT_TRANSLATE_NOOP(scope, text): return text
self.appendToolbar(QT_TRANSLATE_NOOP("Workbench", "Draft tools"), self.drafttools) self.appendToolbar(QT_TRANSLATE_NOOP("Workbench", "Draft tools"), self.drafttools)
self.appendToolbar(QT_TRANSLATE_NOOP("Workbench", "Draft mod tools"), self.draftmodtools) self.appendToolbar(QT_TRANSLATE_NOOP("Workbench", "Draft mod tools"), self.draftmodtools)
self.appendMenu(QT_TRANSLATE_NOOP("arch", "&Draft"), self.drafttools + self.draftmodtools + self.draftextratools) self.appendMenu(QT_TRANSLATE_NOOP("arch", "&Draft"),
self.appendMenu([QT_TRANSLATE_NOOP("arch", "&Draft"), QT_TRANSLATE_NOOP("arch", "Utilities")], self.draftutils + self.draftcontexttools) self.drafttools + self.draftmodtools + self.draftextratools)
self.appendMenu([QT_TRANSLATE_NOOP("arch", "&Draft"), QT_TRANSLATE_NOOP("arch", "Utilities")],
self.draftutils + self.draftcontexttools)
self.appendMenu([QT_TRANSLATE_NOOP("arch", "&Draft"), QT_TRANSLATE_NOOP("arch", "Snapping")], self.snapList) self.appendMenu([QT_TRANSLATE_NOOP("arch", "&Draft"), QT_TRANSLATE_NOOP("arch", "Snapping")], self.snapList)
import Part import Part
@@ -205,10 +209,10 @@ class PVPlantWorkbench (Workbench):
"This is executed whenever the user right-clicks on screen" "This is executed whenever the user right-clicks on screen"
# "recipient" will be either "view" or "tree" # "recipient" will be either "view" or "tree"
#if FreeCAD.activeDraftCommand is None: # if FreeCAD.activeDraftCommand is None:
if recipient.lower() == "view": if recipient.lower() == "view":
print("Menus en la 'View'") print("Menus en la 'View'")
#if FreeCAD.activeDraftCommand is None: # if FreeCAD.activeDraftCommand is None:
presel = FreeCADGui.Selection.getPreselection() presel = FreeCADGui.Selection.getPreselection()
print(presel.SubElementNames, " - ", presel.PickedPoints) print(presel.SubElementNames, " - ", presel.PickedPoints)
if not presel is None: if not presel is None:
@@ -239,7 +243,7 @@ class PVPlantWorkbench (Workbench):
self.contextMenu.show() self.contextMenu.show()
''' '''
def GetClassName(self): def GetClassName(self):
# this function is mandatory if this is a full python workbench # this function is mandatory if this is a full python workbench
return "Gui::PythonWorkbench" return "Gui::PythonWorkbench"

301
Photovoltaic/Module.py Normal file
View File

@@ -0,0 +1,301 @@
# /**********************************************************************
# * *
# * 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 ArchComponent
import FreeCAD
import Part
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtCore
import draftguitools.gui_trackers as DraftTrackers
else:
# \cond
def translate(ctxt, txt):
return txt
def QT_TRANSLATE_NOOP(ctxt, txt):
return txt
# \endcond
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
import os
import PVPlantResources
from PVPlantResources import DirIcons as DirIcons
def makeModule(name="Module"):
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", name)
obj.Label = name
Module(obj)
ViewProviderModule(obj.ViewObject)
FreeCAD.ActiveDocument.recompute()
return obj
class Module(ArchComponent.Component):
"A Manhole Obcject"
def __init__(self, obj):
# Definición de Variables:
ArchComponent.Component.__init__(self, obj)
self.setProperties(obj)
def setProperties(self, obj):
pl = obj.PropertiesList
# Base de datos: -----------------------------------------------------------------------------------------------
if not ("Manufacturer" in pl):
obj.addProperty("App::PropertyStringList",
"Manufacturer",
"Module",
"The manufacturer of this object"
)
if not ("Model" in pl):
obj.addProperty("App::PropertyStringList",
"Model",
"Module",
"The model of this object"
)
# Dimensions: --------------------------------------------------------------------------------------------------
if not ("Height" in pl):
obj.addProperty("App::PropertyLength",
"Height",
"Manhole",
"The height of this object"
).Height = 2804
if not ("Width" in pl):
obj.addProperty("App::PropertyLength",
"Width",
"Manhole",
"The width of this object"
).Width = 1303
if not ("Thickness" in pl):
obj.addProperty("App::PropertyLength",
"Thickness",
"Manhole",
"The height of this object"
).Thickness = 35
# Electrical: --------------------------------------------------------------------------------------------------
if not ("Power" in pl):
obj.addProperty("App::PropertyPower",
"Power",
"Outputs",
"The height of this object"
).Power = 650
if not ("Umpp" in pl):
obj.addProperty("App::PropertyElectricCurrent",
"Umpp",
"Outputs",
"The height of this object"
).Umpp = 650
if not ("Impp" in pl):
obj.addProperty("App::PropertyElectricCurrent",
"Impp",
"Outputs",
"The height of this object"
).Impp = 650
if not ("Uoc" in pl):
obj.addProperty("App::PropertyElectricCurrent",
"Uoc",
"Outputs",
"The height of this object"
).Uoc = 650
if not ("Isc" in pl):
obj.addProperty("App::PropertyElectricCurrent",
"Isc",
"Outputs",
"The height of this object"
).Isc = 650
if not ("Isc" in pl):
obj.addProperty("App::PropertyElectricCurrent",
"Impp",
"Outputs",
"The height of this object"
).Impp = 650
self.Type = "Module"
obj.Proxy = self
def onDocumentRestored(self, obj):
"""Method run when the document is restored.
Re-adds the Arch component, and Arch wall properties."""
ArchComponent.Component.onDocumentRestored(self, obj)
self.setProperties(obj)
def onChanged(self, obj, prop):
'''Do something when a property has changed'''
def execute(self, obj):
box = Part.makeBox(obj.Width, obj.Height, obj.Thickness)
box.translate(FreeCAD.Vector(-obj.Width, -obj.Height, 0) / 2)
obj.Shape = box
class ViewProviderModule(ArchComponent.ViewProviderComponent):
"A View Provider for the Module object"
def __init__(self, vobj):
ArchComponent.ViewProviderComponent.__init__(self, vobj)
def getIcon(self):
return str(os.path.join(DirIcons, "manhole.svg"))
def setEdit(self, vobj, mode):
"""Method called when the document requests the object to enter edit mode.
Edit mode is entered when a user double clicks on an object in the tree
view, or when they use the menu option [Edit -> Toggle Edit Mode].
Just display the standard Arch component task panel.
Parameters
----------
mode: int or str
The edit mode the document has requested. Set to 0 when requested via
a double click or [Edit -> Toggle Edit Mode].
Returns
-------
bool
If edit mode was entered.
"""
if (mode == 0) and hasattr(self, "Object"):
taskd = _ManholeTaskPanel(self.Object)
taskd.obj = self.Object
# taskd.update()
FreeCADGui.Control.showDialog(taskd)
return True
return False
class ManholeTaskPanel:
def __init__(self, obj=None):
self.new = False
if obj is None:
self.new = True
obj = makeManhole()
self.obj = obj
self.form = FreeCADGui.PySideUic.loadUi(PVPlantResources.__dir__ + "/PVPlantManhole.ui")
self.node = None
self.view = FreeCADGui.ActiveDocument.ActiveView
self.tracker = DraftTrackers.ghostTracker(obj)
self.tracker.on()
self.call = self.view.addEventCallback("SoEvent", self.action)
def action(self, arg):
"""Handle the 3D scene events.
This is installed as an EventCallback in the Inventor view.
Parameters
----------
arg: dict
Dictionary with strings that indicates the type of event received
from the 3D view.
"""
if arg["Type"] == "SoKeyboardEvent" and arg["Key"] == "ESCAPE":
self.finish()
elif arg["Type"] == "SoLocation2Event":
point, ctrlPoint, info = gui_tool_utils.getPoint(self, arg)
if info:
self.tracker.move(FreeCAD.Vector(info["x"], info["y"], info["z"]))
else:
self.tracker.move(point)
elif (arg["Type"] == "SoMouseButtonEvent" and
arg["State"] == "DOWN" and
arg["Button"] == "BUTTON1"):
point, ctrlPoint, info = gui_tool_utils.getPoint(self, arg)
if info:
self.obj.Placement.Base = FreeCAD.Vector(info["x"], info["y"], info["z"])
else:
self.obj.Placement.Base = point
self.finish()
def finish(self):
self.accept()
def accept(self):
self.closeForm()
return True
def reject(self):
if self.new:
FreeCAD.ActiveDocument.removeObject(self.obj.Name)
self.closeForm()
return True
def closeForm(self):
self.tracker.finalize()
FreeCADGui.Control.closeDialog()
self.view.removeEventCallback("SoEvent", self.call)
'''class _CommandManhole:
"the Arch Building command definition"
def GetResources(self):
return {'Pixmap': str(os.path.join(DirIcons, "manhole.svg")),
'MenuText': "Manhole",
'Accel': "C, M",
'ToolTip': "Creates a Manhole object from setup dialog."}
def IsActive(self):
return not FreeCAD.ActiveDocument is None
if FreeCAD.ActiveDocument is not None:
if FreeCADGui.Selection.getCompleteSelection():
for ob in FreeCAD.ActiveDocument.Objects:
if ob.Name[:4] == "Site":
return True
def Activated(self):
TaskPanel = _ManholeTaskPanel()
FreeCADGui.Control.showDialog(TaskPanel)
return
if FreeCAD.GuiUp:
FreeCADGui.addCommand('PVPlantManhole', _CommandManhole())'''