# /********************************************************************** # * * # * 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 FreeCAD import ArchComponent import os import zipfile import re if FreeCAD.GuiUp: import FreeCADGui from DraftTools import translate else: # \cond def translate(ctxt,txt): return txt def QT_TRANSLATE_NOOP(ctxt,txt): return txt # \endcond import os from PVPlantResources import DirIcons as DirIcons __title__ = "PVPlant Areas" __author__ = "Javier Braña" __url__ = "http://www.sogos-solar.com" import PVPlantResources from PVPlantResources import DirIcons as DirIcons Dir3dObjects = os.path.join(PVPlantResources.DirResources, "3dObjects") def makeStringInverter(): obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "StringInverter") InverterBase(obj) ViewProviderStringInverter(obj.ViewObject) try: folder = FreeCAD.ActiveDocument.StringInverters except: folder = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", 'StringInverters') folder.Label = "StringInverters" folder.addObject(obj) return obj class InverterBase(ArchComponent.Component): def __init__(self, obj): ''' Initialize the Area object ''' ArchComponent.Component.__init__(self, obj) self.oldMPPTs = 0 self.Type = None self.obj = None self.setProperties(obj) def setProperties(self, obj): pl = obj.PropertiesList if not "File" in pl: obj.addProperty("App::PropertyFile", "File", "Inverter", "The base file this component is built upon") if not ("MPPTs" in pl): obj.addProperty("App::PropertyQuantity", "MPPTs", "Inverter", "Points that define the area" ).MPPTs = 0 if not ("Generator" in pl): obj.addProperty("App::PropertyEnumeration", "Generator", "Inverter", "Points that define the area" ).Generator = ["Generic", "Library"] obj.Generator = "Generic" if not ("Type" in pl): obj.addProperty("App::PropertyString", "Type", "Base", "Points that define the area" ).Type = "InverterBase" obj.setEditorMode("Type", 1) self.Type = obj.Type obj.Proxy = self def onDocumentRestored(self, obj): """ Method run when the document is restored """ self.setProperties(obj) def onBeforeChange(self, obj, prop): if prop == "MPPTs": self.oldMPPTs = int(obj.MPPTs) def onChanged(self, obj, prop): ''' ''' if prop == "Generator": if obj.Generator == "Generic": obj.setEditorMode("MPPTs", 0) else: obj.setEditorMode("MPPTs", 1) if prop == "MPPTs": ''' ''' if self.oldMPPTs > obj.MPPTs: ''' borrar sobrantes ''' obj.removeProperty() elif self.oldMPPTs < obj.MPPTs: ''' crear los faltantes ''' for i in range(self.oldMPPTs, int(obj.MPPTs)): ''' ''' print(i) else: pass if (prop == "File") and obj.File: ''' ''' def execute(self, obj): ''' ''' # obj.Shape: compound # |- body: compound # |-- inverter: solid # |-- door: solid # |-- holder: solid # |- connectors: compound # |-- DC: compound # |--- MPPT 1..x: compound # |---- positive: compound # |----- connector 1..y: ?? # |---- negative 1..y: compound # |----- connector 1..y: ?? # |-- AC: compound # |--- R,S,T,: ?? # |-- Communication pl = obj.Placement filename = self.getFile(obj) if filename: parts = self.getPartsList(obj) if parts: zdoc = zipfile.ZipFile(filename) if zdoc: f = zdoc.open(parts[list(parts.keys())[-1]][1]) shapedata = f.read() f.close() shapedata = shapedata.decode("utf8") shape = self.cleanShape(shapedata, obj, parts[list(parts.keys())[-1]][2]) obj.Shape = shape if not pl.isIdentity(): obj.Placement = pl obj.MPPTs = len(shape.SubShapes[1].SubShapes[0].SubShapes) def cleanShape(self, shapedata, obj, materials): "cleans the imported shape" import Part shape = Part.Shape() shape.importBrepFromString(shapedata) '''if obj.FuseArch and materials: # separate lone edges shapes = [] for edge in shape.Edges: found = False for solid in shape.Solids: for soledge in solid.Edges: if edge.hashCode() == soledge.hashCode(): found = True break if found: break if found: break else: shapes.append(edge) print("solids:",len(shape.Solids),"mattable:",materials) for key,solindexes in materials.items(): if key == "Undefined": # do not join objects with no defined material for solindex in [int(i) for i in solindexes.split(",")]: shapes.append(shape.Solids[solindex]) else: fusion = None for solindex in [int(i) for i in solindexes.split(",")]: if not fusion: fusion = shape.Solids[solindex] else: fusion = fusion.fuse(shape.Solids[solindex]) if fusion: shapes.append(fusion) shape = Part.makeCompound(shapes) try: shape = shape.removeSplitter() except Exception: print(obj.Label,": error removing splitter")''' return shape def getFile(self, obj, filename=None): "gets a valid file, if possible" if not filename: filename = obj.File if not filename: return None if not filename.lower().endswith(".fcstd"): return None if not os.path.exists(filename): # search for the file in the current directory if not found basename = os.path.basename(filename) currentdir = os.path.dirname(obj.Document.FileName) altfile = os.path.join(currentdir,basename) if altfile == obj.Document.FileName: return None elif os.path.exists(altfile): return altfile else: # search for subpaths in current folder altfile = None subdirs = self.splitall(os.path.dirname(filename)) for i in range(len(subdirs)): subpath = [currentdir]+subdirs[-i:]+[basename] altfile = os.path.join(*subpath) if os.path.exists(altfile): return altfile return None return filename def getPartsList(self, obj, filename=None): "returns a list of Part-based objects in a FCStd file" parts = {} materials = {} filename = self.getFile(obj,filename) if not filename: return parts zdoc = zipfile.ZipFile(filename) with zdoc.open("Document.xml") as docf: name = None label = None part = None materials = {} writemode = False for line in docf: line = line.decode("utf8") if "" in line: writemode = False elif "" in line: if name and label and part: parts[name] = [label,part,materials] name = None label = None part = None materials = {} writemode = False return parts def getColors(self,obj): "returns the DiffuseColor of the referenced object" filename = self.getFile(obj) if not filename: return None part = obj.Part if not obj.Part: return None zdoc = zipfile.ZipFile(filename) if not "GuiDocument.xml" in zdoc.namelist(): return None colorfile = None with zdoc.open("GuiDocument.xml") as docf: writemode1 = False writemode2 = False for line in docf: line = line.decode("utf8") if ("