Files
PVPlant/PVPLantPlacement-old_2022.py
2025-03-28 19:40:11 +06:00

555 lines
22 KiB
Python

import ArchComponent
import FreeCAD
if FreeCAD.GuiUp:
import FreeCADGui
from PySide import QtCore, QtGui
from PySide.QtCore import QT_TRANSLATE_NOOP
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 threading
def makePlacement(baseobj=None, diameter=0, length=0, placement=None, name="Placement"):
"makePipe([baseobj,diamerter,length,placement,name]): creates an pipe object from the given base object"
if not FreeCAD.ActiveDocument:
FreeCAD.Console.PrintError("No active document. Aborting\n")
return
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", name)
obj.Label = name
_PVPlantPlacement(obj)
if FreeCAD.GuiUp:
_ViewProviderPVPlantPlacement(obj.ViewObject)
if baseobj:
baseobj.ViewObject.hide()
return obj
class _CommandPVPlantPlacement:
"the Arch Schedule command definition"
def GetResources(self):
return {'Pixmap': 'Placement',
'Accel': "P, S",
'MenuText': QT_TRANSLATE_NOOP("Placement", "Placement"),
'ToolTip': QT_TRANSLATE_NOOP("Placement", "Crear un campo fotovoltaico")}
def Activated(self):
taskd = _PVPlantPlacementTaskPanel()
FreeCADGui.Control.showDialog(taskd)
def IsActive(self):
if FreeCAD.ActiveDocument:
return True
else:
return False
class _PVPlantPlacement(ArchComponent.Component):
"the PVPlantPlacement object"
def __init__(self, obj):
ArchComponent.Component.__init__(self, obj)
self.setProperties(obj)
# Does a IfcType exist?
# obj.IfcType = "Fence"
obj.MoveWithHost = False
def setProperties(self, obj):
ArchComponent.Component.setProperties(self, obj)
pl = obj.PropertiesList
if not "Section" in pl:
obj.addProperty("App::PropertyLink", "Land", "Placement", QT_TRANSLATE_NOOP(
"App::Property", "A single section of the fence"))
if not "Post" in pl:
obj.addProperty("App::PropertyLink", "Structure", "Placement", QT_TRANSLATE_NOOP(
"App::Property", "A single fence post"))
if not "Path" in pl:
obj.addProperty("App::PropertyLink", "Path", "Placement", QT_TRANSLATE_NOOP(
"App::Property", "The Path the fence should follow"))
if not "NumberOfSections" in pl:
obj.addProperty("App::PropertyInteger", "NumberOfSections", "Count", QT_TRANSLATE_NOOP(
"App::Property", "The number of sections the fence is built of"))
obj.setEditorMode("NumberOfSections", 1)
if not "NumberOfPosts" in pl:
obj.addProperty("App::PropertyInteger", "NumberOfPosts", "Count", QT_TRANSLATE_NOOP(
"App::Property", "The number of posts used to build the fence"))
obj.setEditorMode("NumberOfPosts", 1)
self.Type = "Fence"
def execute(self, obj):
# fills columns A, B and C of the spreadsheet
if not obj.Description:
return
def __getstate__(self):
return self.Type
def __setstate__(self, state):
if state:
self.Type = state
class _ViewProviderPVPlantPlacement:
"A View Provider for PVPlantPlacement"
def __init__(self, vobj):
vobj.Proxy = self
def getIcon(self):
return ":/icons/Arch_Schedule.svg"
def attach(self, vobj):
self.Object = vobj.Object
def setEdit(self, vobj, mode):
# taskd = _ArchScheduleTaskPanel(vobj.Object)
# FreeCADGui.Control.showDialog(taskd)
return True
def doubleClicked(self, vobj):
# taskd = _ArchScheduleTaskPanel(vobj.Object)
# FreeCADGui.Control.showDialog(taskd)
return True
def unsetEdit(self, vobj, mode):
# FreeCADGui.Control.closeDialog()
return
def claimChildren(self):
# if hasattr(self,"Object"):
# return [self.Object.Result]
return None
def __getstate__(self):
return None
def __setstate__(self, state):
return None
def getDisplayModes(self, vobj):
return ["Default"]
def getDefaultDisplayMode(self):
return "Default"
def setDisplayMode(self, mode):
return mode
class _PVPlantPlacementTaskPanel:
'''The editmode TaskPanel for Schedules'''
def __init__(self, obj=None):
self.Terrain = None
self.Rack = None
self.Gap = 200
self.Pitch = 4500
# form:
self.form = QtGui.QWidget()
self.form.resize(800, 640)
self.form.setWindowTitle("Curvas de nivel")
self.form.setWindowIcon(QtGui.QIcon(":/icons/Arch_Schedule.svg"))
self.grid = QtGui.QGridLayout(self.form)
# parameters
self.labelTerrain = QtGui.QLabel()
self.labelTerrain.setText("Terreno:")
self.lineTerrain = QtGui.QLineEdit(self.form)
self.lineTerrain.setObjectName(_fromUtf8("lineTerrain"))
self.lineTerrain.readOnly = True
self.grid.addWidget(self.labelTerrain, self.grid.rowCount(), 0, 1, 1)
self.grid.addWidget(self.lineTerrain, self.grid.rowCount() - 1, 1, 1, 1)
self.buttonAddTerrain = QtGui.QPushButton('Sel')
self.grid.addWidget(self.buttonAddTerrain, self.grid.rowCount() - 1, 2, 1, 1)
self.labelRack = QtGui.QLabel()
self.labelRack.setText("Rack:")
self.lineRack = QtGui.QLineEdit(self.form)
self.lineRack.setObjectName(_fromUtf8("lineRack"))
self.lineRack.readOnly = True
self.grid.addWidget(self.labelRack, self.grid.rowCount(), 0, 1, 1)
self.grid.addWidget(self.lineRack, self.grid.rowCount() - 1, 1, 1, 1)
self.buttonAddRack = QtGui.QPushButton('Sel')
self.grid.addWidget(self.buttonAddRack, self.grid.rowCount() - 1, 2, 1, 1)
self.line1 = QtGui.QFrame()
self.line1.setFrameShape(QtGui.QFrame.HLine)
self.line1.setFrameShadow(QtGui.QFrame.Sunken)
self.grid.addWidget(self.line1, self.grid.rowCount(), 0, 1, -1)
self.labelTypeStructure = QtGui.QLabel()
self.labelTypeStructure.setText("Tipo de estructura:")
self.valueTypeStructure = QtGui.QComboBox()
self.valueTypeStructure.addItems(["Fixed", "Tracker 1 Axis"])
self.valueTypeStructure.setCurrentIndex(0)
self.grid.addWidget(self.labelTypeStructure, self.grid.rowCount(), 0, 1, 1)
self.grid.addWidget(self.valueTypeStructure, self.grid.rowCount() - 1, 1, 1, -1)
self.labelOrientation = QtGui.QLabel()
self.labelOrientation.setText("Orientacion:")
self.valueOrientation = QtGui.QComboBox()
self.valueOrientation.addItems(["Norte-Sur", "Este-Oeste"])
self.valueOrientation.setCurrentIndex(0)
self.grid.addWidget(self.labelOrientation, self.grid.rowCount(), 0, 1, 1)
self.grid.addWidget(self.valueOrientation, self.grid.rowCount() - 1, 1, 1, -1)
self.labelGap = QtGui.QLabel()
self.labelGap.setText("Espacio entre Columnas:")
self.valueGap = FreeCADGui.UiLoader().createWidget("Gui::InputField")
self.valueGap.setText(str(self.Gap) + " mm")
self.grid.addWidget(self.labelGap, self.grid.rowCount(), 0, 1, 1)
self.grid.addWidget(self.valueGap, self.grid.rowCount() - 1, 1, 1, -1)
self.labelPitch = QtGui.QLabel()
self.labelPitch.setText("Separacion entre Filas:")
self.valuePitch = FreeCADGui.UiLoader().createWidget("Gui::InputField")
self.valuePitch.setText(str(self.Pitch) + " mm")
self.grid.addWidget(self.labelPitch, self.grid.rowCount(), 0, 1, 1)
self.grid.addWidget(self.valuePitch, self.grid.rowCount() - 1, 1, 1, -1)
self.labelAlign = QtGui.QLabel()
self.labelAlign.setText("Método de alineación:")
self.valueAlign = QtGui.QComboBox()
self.valueAlign.addItems(["Si", "No"])
self.valueAlign.setCurrentIndex(0)
self.grid.addWidget(self.labelAlign, self.grid.rowCount(), 0, 1, 1)
self.grid.addWidget(self.valueAlign, self.grid.rowCount() - 1, 1, 1, -1)
self.line2 = QtGui.QFrame()
self.line2.setFrameShape(QtGui.QFrame.HLine)
self.line2.setFrameShadow(QtGui.QFrame.Sunken)
self.grid.addWidget(self.line2, self.grid.rowCount(), 0, 1, -1)
self.labelSideSlope = QtGui.QLabel()
self.labelSideSlope.setText("Maxima inclinacion longitudinal:")
self.valueSideSlope = FreeCADGui.UiLoader().createWidget("Gui::InputField")
self.valueSideSlope.setText("15")
self.grid.addWidget(self.labelSideSlope, self.grid.rowCount(), 0, 1, 1)
self.grid.addWidget(self.valueSideSlope, self.grid.rowCount() - 1, 1, 1, -1)
QtCore.QObject.connect(self.buttonAddTerrain, QtCore.SIGNAL("clicked()"), self.addTerrain)
QtCore.QObject.connect(self.buttonAddRack, QtCore.SIGNAL("clicked()"), self.addRack)
# QtCore.QObject.connect(self.form.buttonDel, QtCore.SIGNAL("clicked()"), self.remove)
# QtCore.QObject.connect(self.form.buttonClear, QtCore.SIGNAL("clicked()"), self.clear)
# QtCore.QObject.connect(self.form.buttonSelect, QtCore.SIGNAL("clicked()"), self.select)
def addTerrain(self):
sel = FreeCADGui.Selection.getSelection()
if len(sel) > 0:
self.Terrain = sel[0]
self.lineTerrain.setText(self.Terrain.Label)
def addRack(self):
sel = FreeCADGui.Selection.getSelection()
if len(sel) > 0:
self.Rack = sel[0]
self.lineRack.setText(self.Rack.Label)
def accept(self):
if self.Terrain is not None and self.Rack is not None:
self.Gap = FreeCAD.Units.Quantity(self.valueGap.text()).Value
self.Pitch = FreeCAD.Units.Quantity(self.valuePitch.text()).Value
self.placement()
return True
def placement(self):
if self.valueTypeStructure.currentIndex() == 0: # Fixed
print("Rack")
else:
print("Tracker")
if self.Rack.Height < self.Rack.Length:
print("rotar")
aux = self.Rack.Length
self.Rack.Length = self.Rack.Height
self.Rack.Height = aux
self.Rack.Placement.Base.x = self.Terrain.Shape.BoundBox.XMin
self.Rack.Placement.Base.y = self.Terrain.Shape.BoundBox.YMin
DistColls = self.Rack.Length.Value + self.Gap
DistRows = self.Rack.Height.Value + self.Pitch
area = self.Rack.Shape.Faces[0].Area # * 0.999999999
import Draft
rec = Draft.makeRectangle(length=self.Terrain.Shape.BoundBox.XLength, height=self.Rack.Height, face=True,
support=None)
rec.Placement.Base.x = self.Terrain.Shape.BoundBox.XMin
rec.Placement.Base.y = self.Terrain.Shape.BoundBox.YMin
try:
while rec.Shape.BoundBox.YMax <= self.Terrain.Shape.BoundBox.YMax:
common = self.Terrain.Shape.common(rec.Shape)
for shape in common.Faces:
if shape.Area >= area:
if False:
minorPoint = FreeCAD.Vector(0, 0, 0)
for spoint in shape.OuterWire.Vertexes:
if minorPoint.y >= spoint.Point.y:
if minorPoint.x >= spoint.x:
minorPoint = spoint
self.Rack.Placement.Base = spoint
else:
# más rápido
self.Rack.Placement.Base.x = shape.BoundBox.XMin
self.Rack.Placement.Base.y = shape.BoundBox.YMin
while self.Rack.Shape.BoundBox.XMax <= shape.BoundBox.XMax:
verts = [v.Point for v in rackClone.Shape.OuterWire.OrderedVertexes]
inside = True
for vert in verts:
if not shape.isInside(vert, 0, True):
inside = False
break
if inside:
raise
else:
# ajuste fino hasta encontrar el primer sitio:
rackClone.Placement.Base.x += 100 # un metro
'''old version
common1 = shape.common(self.Rack.Shape)
if common1.Area >= area:
raise
else:
# ajuste fino hasta encontrar el primer sitio:
self.Rack.Placement.Base.x += 500 # un metro
del common1
'''
# ajuste fino hasta encontrar el primer sitio:
rec.Placement.Base.y += 100
del common
except:
pass
#print("Found")
FreeCAD.ActiveDocument.removeObject(rec.Name)
from datetime import datetime
starttime = datetime.now()
if self.valueOrientation.currentIndex() == 0:
# Código para crear filas:
self.Rack.Placement.Base.x = self.Terrain.Shape.BoundBox.XMin
i = 1
yy = self.Rack.Placement.Base.y
while yy < self.Terrain.Shape.BoundBox.YMax:
CreateRow1(self.Rack.Placement.Base.x, yy, self.Rack, self.Terrain, DistColls, area, i)
i += 1
yy += DistRows
elif self.valueOrientation.currentIndex() == 2:
# Código para crear columnas:
while self.Rack.Placement.Base.x > self.Terrain.Shape.BoundBox.XMin:
self.Rack.Placement.Base.x -= DistColls
else:
xx = self.Rack.Placement.Base.x
while xx < self.Terrain.Shape.BoundBox.XMax:
CreateGrid(xx, self.Rack.Placement.Base.y, self.Rack, self.Terrain, DistRows, area)
xx += DistColls
FreeCAD.activeDocument().recompute()
print("Everything OK (", datetime.now() - starttime, ")")
# Alinear solo filas. las columnas donde se pueda
def CreateRow(XX, YY, rack, land, gap, area, rowNumber):
import Draft
rackClone = Draft.makeRectangle(length=rack.Length, height=rack.Height, face=True, support=None)
rackClone.Label = 'rackClone{a}'.format(a=rowNumber)
rackClone.Placement.Base.x = XX
rackClone.Placement.Base.y = YY
rec = Draft.makeRectangle(length=land.Shape.BoundBox.XLength, height=rack.Height, face=True, support=None)
rec.Placement.Base.x = land.Shape.BoundBox.XMin
rec.Placement.Base.y = YY
FreeCAD.activeDocument().recompute()
common = land.Shape.common(rec.Shape)
for shape in common.Faces:
if shape.Area >= area:
rackClone.Placement.Base.x = shape.BoundBox.XMin
rackClone.Placement.Base.y = shape.BoundBox.YMin
while rackClone.Shape.BoundBox.XMax <= shape.BoundBox.XMax:
common1 = shape.common(rackClone.Shape)
if common1.Area >= area:
tmp = Draft.makeRectangle(length=rack.Length, height=rack.Height, placement=rackClone.Placement,
face=True, support=None)
tmp.Label = 'R{:03}-000'.format(rowNumber)
rackClone.Placement.Base.x += gap
else:
# ajuste fino hasta encontrar el primer sitio:
rackClone.Placement.Base.x += 500 # un metro
del common1
del common
FreeCAD.ActiveDocument.removeObject(rackClone.Name)
FreeCAD.ActiveDocument.removeObject(rec.Name)
# Alinear solo filas. las columnas donde se pueda
def CreateRow1(XX, YY, rack, land, gap, area, rowNumber):
import Draft
rackClone = Draft.makeRectangle(length=rack.Length, height=rack.Height, face=True, support=None)
rackClone.Label = 'rackClone{a}'.format(a=rowNumber)
rackClone.Placement.Base.x = XX
rackClone.Placement.Base.y = YY
rec = Draft.makeRectangle(length=land.Shape.BoundBox.XLength, height=rack.Height, face=True, support=None)
rec.Placement.Base.x = land.Shape.BoundBox.XMin
rec.Placement.Base.y = YY
FreeCAD.activeDocument().recompute()
common = land.Shape.common(rec.Shape)
for shape in common.Faces:
if shape.Area >= area:
if False:
minorPoint = FreeCAD.Vector(0, 0, 0)
for spoint in shape.OuterWire.Vertexes:
if minorPoint.y >= spoint.Point.y:
if minorPoint.x >= spoint.x:
minorPoint = spoint
rackClone.Placement.Base = spoint
else:
# más rápido
rackClone.Placement.Base.x = shape.BoundBox.XMin
rackClone.Placement.Base.y = shape.BoundBox.YMin
while rackClone.Shape.BoundBox.XMax <= shape.BoundBox.XMax:
verts = [v.Point for v in rackClone.Shape.OuterWire.OrderedVertexes]
inside = True
for vert in verts:
if not shape.isInside(vert, 0, True):
inside = False
break
if inside:
#tmp = rack.Shape.copy()
#tmp.Placement = rack.Placement
tmp = Draft.makeRectangle(length=rack.Length, height=rack.Height, placement=rackClone.Placement,
face=True, support=None)
tmp.Label = 'R{:03}-000'.format(rowNumber)
rackClone.Placement.Base.x += gap
else:
# ajuste fino hasta encontrar el primer sitio:
rackClone.Placement.Base.x += 500 # un metro
del common
FreeCAD.ActiveDocument.removeObject(rackClone.Name)
FreeCAD.ActiveDocument.removeObject(rec.Name)
# Alinear columna y fila (grid perfecta)
def CreateGrid(XX, YY, rack, land, gap, area):
print("CreateGrid")
import Draft
rackClone = Draft.makeRectangle(length=rack.Length, height=rack.Height, face=True, support=None)
rackClone.Label = 'rackClone{a}'.format(a=XX)
rackClone.Placement.Base.x = XX
rackClone.Placement.Base.y = YY
# if False:
while rackClone.Shape.BoundBox.YMax < land.Shape.BoundBox.YMax:
common = land.Shape.common(rackClone.Shape)
if common.Area >= area:
tmp = Draft.makeRectangle(length=rack.Length, height=rack.Height,
placement=rackClone.Placement, face=True, support=None)
tmp.Label = 'rackClone{a}'.format(a=XX)
rackClone.Placement.Base.y += gap
# else:
# # ajuste fino hasta encontrar el primer sitio:
# rackClone.Placement.Base.y += 1000
FreeCAD.ActiveDocument.removeObject(rackClone.Name)
# Alinear solo filas. las columnas donde se pueda
def CreateCol(XX, YY, rack, land, gap, area):
import Draft
rackClone = Draft.makeRectangle(length=rack.Length, height=rack.Height, face=True, support=None)
rackClone.Label = 'rackClone{a}'.format(a=XX)
rackClone.Placement.Base.x = XX
rackClone.Placement.Base.y = YY
while rackClone.Shape.BoundBox.YMax < land.Shape.BoundBox.YMax:
common = land.Shape.common(rackClone.Shape)
if common.Area >= area:
tmp = Draft.makeRectangle(length=rack.Length, height=rack.Height,
placement=rackClone.Placement, face=True, support=None)
tmp.Label = 'rackClone{a}'.format(a=XX)
rackClone.Placement.Base.y += gap
else:
# ajuste fino hasta encontrar el primer sitio:
rackClone.Placement.Base.y += 100
FreeCAD.ActiveDocument.removeObject(rackClone.Name)
# TODO: Probar a usar hilos:
class _CreateCol(threading.Thread):
def __init__(self, args=()):
super().__init__()
self.XX = args[0]
self.YY = args[1]
self.rack = args[2]
self.land = args[3]
self.gap = args[4]
self.area = args[5]
def run(self):
import Draft
# rackClone = Draft.makeRectangle(length=land.Shape.BoundBox.XLength, height=rack.Height,
# face=True, support=None)
# rackClone = FreeCAD.activeDocument().addObject('Part::Feature')
# rackClone.Shape = self.rack.Shape
rackClone = Draft.makeRectangle(length=self.rack.Length, height=self.rack.Height, face=True, support=None)
rackClone.Label = 'rackClone{a}'.format(a=self.XX)
rackClone.Placement.Base.x = self.XX
rackClone.Placement.Base.y = self.YY
# if False:
while rackClone.Shape.BoundBox.YMax < self.land.Shape.BoundBox.YMax:
common = self.land.Shape.common(rackClone.Shape)
if common.Area >= self.area:
rack = Draft.makeRectangle(length=self.rack.Length, height=self.rack.Height,
placement=rackClone.Placement, face=True, support=None)
rack.Label = 'rackClone{a}'.format(a=self.XX)
rackClone.Placement.Base.y += self.gap
# else:
# # ajuste fino hasta encontrar el primer sitio:
# rackClone.Placement.Base.y += 1000
# FreeCAD.ActiveDocument.removeObject(rackClone.Name)
if FreeCAD.GuiUp:
FreeCADGui.addCommand('PVPlantPlacement', _CommandPVPlantPlacement())