# /********************************************************************** # * * # * Copyright (c) 2021 Javier Braña * # * * # * 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())