373 lines
14 KiB
Python
373 lines
14 KiB
Python
|
|
# /**********************************************************************
|
||
|
|
# * *
|
||
|
|
# * 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, os
|
||
|
|
from PySide import QtCore
|
||
|
|
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||
|
|
from pivy import coin
|
||
|
|
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 PVPlantResources
|
||
|
|
|
||
|
|
def makeStringbox():
|
||
|
|
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "StringBox")
|
||
|
|
_StringBox(obj)
|
||
|
|
_ViewProviderStringBox(obj.ViewObject)
|
||
|
|
FreeCAD.ActiveDocument.recompute()
|
||
|
|
#FreeCADGui.ActiveDocument.ActiveView.fitAll()
|
||
|
|
return obj
|
||
|
|
|
||
|
|
class _StringBox(ArchComponent.Component):
|
||
|
|
|
||
|
|
def __init__(self, obj):
|
||
|
|
# Definición de Variables:
|
||
|
|
ArchComponent.Component.__init__(self, obj)
|
||
|
|
self.obj = obj
|
||
|
|
self.setProperties(obj)
|
||
|
|
self.Type = "StringBox"
|
||
|
|
|
||
|
|
# Does a IfcType exist?
|
||
|
|
obj.IfcType = "Electric Distribution Board"
|
||
|
|
obj.setEditorMode("IfcType", 1)
|
||
|
|
# obj.MoveWithHost = False
|
||
|
|
|
||
|
|
def setProperties(self, obj):
|
||
|
|
# Definicion de Propiedades:
|
||
|
|
'''[
|
||
|
|
'App::PropertyBool',
|
||
|
|
'App::PropertyBoolList',
|
||
|
|
'App::PropertyFloat',
|
||
|
|
'App::PropertyFloatList',
|
||
|
|
'App::PropertyFloatConstraint',
|
||
|
|
'App::PropertyPrecision',
|
||
|
|
'App::PropertyQuantity',
|
||
|
|
'App::PropertyQuantityConstraint',
|
||
|
|
'App::PropertyAngle',
|
||
|
|
'App::PropertyDistance',
|
||
|
|
'App::PropertyLength',
|
||
|
|
'App::PropertyArea',
|
||
|
|
'App::PropertyVolume',
|
||
|
|
'App::PropertyFrequency',
|
||
|
|
'App::PropertySpeed',
|
||
|
|
'App::PropertyAcceleration',
|
||
|
|
'App::PropertyForce',
|
||
|
|
'App::PropertyPressure',
|
||
|
|
'App::PropertyVacuumPermittivity',
|
||
|
|
'App::PropertyInteger',
|
||
|
|
'App::PropertyIntegerConstraint',
|
||
|
|
'App::PropertyPercent',
|
||
|
|
'App::PropertyEnumeration',
|
||
|
|
'App::PropertyIntegerList',
|
||
|
|
'App::PropertyIntegerSet',
|
||
|
|
'App::PropertyMap',
|
||
|
|
'App::PropertyString',
|
||
|
|
'App::PropertyPersistentObject',
|
||
|
|
'App::PropertyUUID',
|
||
|
|
'App::PropertyFont',
|
||
|
|
'App::PropertyStringList',
|
||
|
|
'App::PropertyLink',
|
||
|
|
'App::PropertyLinkChild',
|
||
|
|
'App::PropertyLinkGlobal',
|
||
|
|
'App::PropertyLinkHidden',
|
||
|
|
'App::PropertyLinkSub',
|
||
|
|
'App::PropertyLinkSubChild',
|
||
|
|
'App::PropertyLinkSubGlobal',
|
||
|
|
'App::PropertyLinkSubHidden',
|
||
|
|
'App::PropertyLinkList',
|
||
|
|
'App::PropertyLinkListChild',
|
||
|
|
'App::PropertyLinkListGlobal',
|
||
|
|
'App::PropertyLinkListHidden',
|
||
|
|
'App::PropertyLinkSubList',
|
||
|
|
'App::PropertyLinkSubListChild',
|
||
|
|
'App::PropertyLinkSubListGlobal',
|
||
|
|
'App::PropertyLinkSubListHidden',
|
||
|
|
'App::PropertyXLink',
|
||
|
|
'App::PropertyXLinkSub',
|
||
|
|
'App::PropertyXLinkSubList',
|
||
|
|
'App::PropertyXLinkList',
|
||
|
|
'App::PropertyMatrix',
|
||
|
|
'App::PropertyVector',
|
||
|
|
'App::PropertyVectorDistance',
|
||
|
|
'App::PropertyPosition',
|
||
|
|
'App::PropertyDirection',
|
||
|
|
'App::PropertyVectorList',
|
||
|
|
'App::PropertyPlacement',
|
||
|
|
'App::PropertyPlacementList',
|
||
|
|
'App::PropertyPlacementLink',
|
||
|
|
'App::PropertyColor',
|
||
|
|
'App::PropertyColorList',
|
||
|
|
'App::PropertyMaterial',
|
||
|
|
'App::PropertyMaterialList',
|
||
|
|
'App::PropertyPath',
|
||
|
|
'App::PropertyFile',
|
||
|
|
'App::PropertyFileIncluded',
|
||
|
|
'App::PropertyPythonObject',
|
||
|
|
'App::PropertyExpressionEngine',
|
||
|
|
'Part::PropertyPartShape',
|
||
|
|
'Part::PropertyGeometryList',
|
||
|
|
'Part::PropertyShapeHistory',
|
||
|
|
'Part::PropertyFilletEdges',
|
||
|
|
'Mesh::PropertyNormalList',
|
||
|
|
'Mesh::PropertyCurvatureList',
|
||
|
|
'Mesh::PropertyMeshKernel',
|
||
|
|
'Sketcher::PropertyConstraintList'
|
||
|
|
]'''
|
||
|
|
|
||
|
|
pl = obj.PropertiesList
|
||
|
|
if not "InputsFromStrings" in pl:
|
||
|
|
obj.addProperty("App::PropertyQuantity",
|
||
|
|
"InputsFromStrings",
|
||
|
|
"Connections",
|
||
|
|
QT_TRANSLATE_NOOP("App::Property", "Connection ")).InputsFromStrings = 12
|
||
|
|
|
||
|
|
if not ("PositiveInputs" in pl):
|
||
|
|
obj.addProperty("App::PropertyVectorList",
|
||
|
|
"PositiveInputs",
|
||
|
|
"Connections",
|
||
|
|
QT_TRANSLATE_NOOP("App::Property", "The height of this object")
|
||
|
|
).PositiveInputs = []
|
||
|
|
obj.setEditorMode("PositiveInputs", 1)
|
||
|
|
|
||
|
|
if not ("NegativeInputs" in pl):
|
||
|
|
obj.addProperty("App::PropertyVectorList",
|
||
|
|
"NegativeInputs",
|
||
|
|
"Connections",
|
||
|
|
QT_TRANSLATE_NOOP("App::Property", "The height of this object")
|
||
|
|
).NegativeInputs = []
|
||
|
|
obj.setEditorMode("NegativeInputs", 1)
|
||
|
|
|
||
|
|
if not "InputCables" in pl:
|
||
|
|
obj.addProperty("App::PropertyLinkList",
|
||
|
|
"InputCables",
|
||
|
|
"Connections",
|
||
|
|
QT_TRANSLATE_NOOP("App::Property", "InputCables"))
|
||
|
|
|
||
|
|
# Outputs
|
||
|
|
'''
|
||
|
|
if not "Outputs" in pl:
|
||
|
|
obj.addProperty("App::PropertyQuantity",
|
||
|
|
"Outputs",
|
||
|
|
"Connections",
|
||
|
|
QT_TRANSLATE_NOOP("App::Property", "Connection ")).Outputs = 1
|
||
|
|
'''
|
||
|
|
|
||
|
|
if not ("PositiveOut" in pl):
|
||
|
|
obj.addProperty("Part::PropertyPartShape",
|
||
|
|
"PositiveOut",
|
||
|
|
"Connections",
|
||
|
|
QT_TRANSLATE_NOOP("App::Property", "The height of this object")
|
||
|
|
)
|
||
|
|
obj.setEditorMode("PositiveOut", 1)
|
||
|
|
|
||
|
|
if not ("NegativeOut" in pl):
|
||
|
|
obj.addProperty("Part::PropertyPartShape",
|
||
|
|
"NegativeOut",
|
||
|
|
"Connections",
|
||
|
|
QT_TRANSLATE_NOOP("App::Property", "The height of this object")
|
||
|
|
)
|
||
|
|
obj.setEditorMode("NegativeOut", 1)
|
||
|
|
|
||
|
|
# Size:
|
||
|
|
if not "Width" in pl:
|
||
|
|
obj.addProperty("App::PropertyLength",
|
||
|
|
"Width",
|
||
|
|
"Box",
|
||
|
|
QT_TRANSLATE_NOOP("App::Property", "Connection ")).Width = 330
|
||
|
|
|
||
|
|
if not "Length" in pl:
|
||
|
|
obj.addProperty("App::PropertyLength",
|
||
|
|
"Length",
|
||
|
|
"Box",
|
||
|
|
QT_TRANSLATE_NOOP("App::Property", "Connection ")).Length = 848
|
||
|
|
|
||
|
|
if not "Height" in pl:
|
||
|
|
obj.addProperty("App::PropertyLength",
|
||
|
|
"Height",
|
||
|
|
"Box",
|
||
|
|
QT_TRANSLATE_NOOP("App::Property", "Connection ")).Height = 615
|
||
|
|
|
||
|
|
|
||
|
|
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)
|
||
|
|
obj.Proxy = self
|
||
|
|
|
||
|
|
def onChanged(self, obj, prop):
|
||
|
|
'''Do something when a property has changed'''
|
||
|
|
|
||
|
|
if prop == "InputsFromStrings":
|
||
|
|
for i in range(int(obj.getPropertyByName(prop).Value)):
|
||
|
|
obj.removeProperty("PositiveInput" + str(i+1))
|
||
|
|
obj.removeProperty("NegativeInput" + str(i + 1))
|
||
|
|
|
||
|
|
|
||
|
|
def execute(self, obj):
|
||
|
|
# obj.Shape: compound
|
||
|
|
# |- body: compound
|
||
|
|
# |-- body: solid
|
||
|
|
# |-- door: solid
|
||
|
|
# |-- inputs: solids
|
||
|
|
# |-- outputs: solids
|
||
|
|
# |- inputs references: compound
|
||
|
|
# |-- positives: compound
|
||
|
|
# |--- positive: point of vertex
|
||
|
|
|
||
|
|
solids = []
|
||
|
|
pts = []
|
||
|
|
|
||
|
|
def getdownFace(object):
|
||
|
|
downface = object.Faces[0]
|
||
|
|
for face in object.Faces:
|
||
|
|
if face.CenterOfMass.z < downface.CenterOfMass.z:
|
||
|
|
downface = face
|
||
|
|
return downface
|
||
|
|
|
||
|
|
def drawInputs(numrows, offsetx, type, cpd):
|
||
|
|
numInputs = int(obj.InputsFromStrings.Value)
|
||
|
|
nperrow = int(round(numInputs / numrows, 0))
|
||
|
|
gap = 45
|
||
|
|
diameter = 20
|
||
|
|
points = []
|
||
|
|
cnt = 0
|
||
|
|
for r in range(numrows):
|
||
|
|
xx = -obj.Length.Value / 2 + offsetx + gap / 2 * (r % 2)
|
||
|
|
yy = -diameter + gap * r
|
||
|
|
for i in range(min(numInputs, nperrow)):
|
||
|
|
cyl = Part.makeCylinder(10, 20, FreeCAD.Vector(xx + gap * i, yy, -20))
|
||
|
|
solids.append(cyl)
|
||
|
|
points.append(getdownFace(cyl).CenterOfMass)
|
||
|
|
cnt += 1
|
||
|
|
inname = ("PositiveIn" if type == 0 else "NegativeIn") + str(cnt)
|
||
|
|
obj.addProperty("Part::PropertyPartShape",
|
||
|
|
inname,
|
||
|
|
"Inputs",
|
||
|
|
QT_TRANSLATE_NOOP("App::Property", "The height of this object")
|
||
|
|
)
|
||
|
|
obj.setEditorMode(inname, 1)
|
||
|
|
setattr(obj, inname, getdownFace(cyl))
|
||
|
|
cpd.add(cyl)
|
||
|
|
numInputs -= nperrow
|
||
|
|
return points
|
||
|
|
|
||
|
|
box = Part.makeBox(obj.Length.Value, obj.Width.Value, obj.Height.Value)
|
||
|
|
box.Placement.Base.x -= obj.Length.Value / 2
|
||
|
|
box.Placement.Base.y -= obj.Width.Value / 2
|
||
|
|
|
||
|
|
# Output:
|
||
|
|
cpd_out = Part.makeCompound([])
|
||
|
|
outp = Part.makeCylinder(65/2, 20, FreeCAD.Vector(0, 0, -20))
|
||
|
|
#out.Placement.Base.x += 50
|
||
|
|
#out.Placement.Base.y += 65/2
|
||
|
|
solids.append(outp)
|
||
|
|
cpd_out.add(outp)
|
||
|
|
obj.PositiveOut = getdownFace(outp)
|
||
|
|
|
||
|
|
outn = outp.copy()
|
||
|
|
outn.Placement.Base.x += 65 + 10
|
||
|
|
solids.append(outn)
|
||
|
|
cpd_out.add(outn)
|
||
|
|
obj.NegativeOut = getdownFace(outn)
|
||
|
|
|
||
|
|
# Inputs:
|
||
|
|
cpd_Pos_Inputs = Part.makeCompound([])
|
||
|
|
cpd_Neg_Inputs = Part.makeCompound([])
|
||
|
|
obj.PositiveInputs = drawInputs(2, 80, 0, cpd_Pos_Inputs).copy()
|
||
|
|
obj.NegativeInputs = drawInputs(4, 650, 1, cpd_Neg_Inputs).copy()
|
||
|
|
|
||
|
|
pts.append(getdownFace(box).CenterOfMass)
|
||
|
|
pts.append(getdownFace(outn).CenterOfMass)
|
||
|
|
pts.append(getdownFace(outp).CenterOfMass)
|
||
|
|
|
||
|
|
obj.Shape = Part.makeCompound([box, cpd_out, cpd_Pos_Inputs, cpd_Neg_Inputs])
|
||
|
|
|
||
|
|
class _ViewProviderStringBox(ArchComponent.ViewProviderComponent):
|
||
|
|
"A View Provider for the Pipe object"
|
||
|
|
|
||
|
|
def __init__(self, vobj):
|
||
|
|
ArchComponent.ViewProviderComponent.__init__(self, vobj)
|
||
|
|
|
||
|
|
def getIcon(self):
|
||
|
|
return str(os.path.join(PVPlantResources.DirIcons, "StringBox.svg"))
|
||
|
|
|
||
|
|
def attach(self, vobj):
|
||
|
|
self.Object = vobj.Object
|
||
|
|
sep = coin.SoSeparator()
|
||
|
|
self.coords = coin.SoCoordinate3()
|
||
|
|
sep.addChild(self.coords)
|
||
|
|
self.coords.point.deleteValues(0)
|
||
|
|
symbol = coin.SoMarkerSet()
|
||
|
|
symbol.markerIndex = FreeCADGui.getMarkerIndex("", 5)
|
||
|
|
sep.addChild(symbol)
|
||
|
|
rn = vobj.RootNode
|
||
|
|
rn.addChild(sep)
|
||
|
|
ArchComponent.ViewProviderComponent.attach(self, vobj)
|
||
|
|
|
||
|
|
def updateData(self, obj, prop):
|
||
|
|
|
||
|
|
if prop == "PositiveInputs":
|
||
|
|
if obj.PositiveInputs:
|
||
|
|
self.coords.point.setNum(len(obj.PositiveInputs))
|
||
|
|
self.coords.point.setValues([[p.x, p.y, p.z] for p in obj.PositiveInputs])
|
||
|
|
else:
|
||
|
|
self.coords.point.deleteValues(0)
|
||
|
|
|
||
|
|
|
||
|
|
class _CommandBoxEnclosure:
|
||
|
|
|
||
|
|
def GetResources(self):
|
||
|
|
return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "StringBox.svg")),
|
||
|
|
'Accel': "C, E",
|
||
|
|
'MenuText': QT_TRANSLATE_NOOP("Placement", "Movimiento de tierras"),
|
||
|
|
'ToolTip': QT_TRANSLATE_NOOP("Placement", "Calcular el movimiento de tierras")}
|
||
|
|
|
||
|
|
def Activated(self):
|
||
|
|
makeStringbox()
|
||
|
|
|
||
|
|
def IsActive(self):
|
||
|
|
if FreeCAD.ActiveDocument:
|
||
|
|
return True
|
||
|
|
else:
|
||
|
|
return False
|
||
|
|
|
||
|
|
if FreeCAD.GuiUp:
|
||
|
|
FreeCADGui.addCommand('PVPlantStringBox', _CommandBoxEnclosure())
|