555 lines
22 KiB
Python
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())
|