# /********************************************************************** # * * # * 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 Part import PVPlantSite import Utils.PVPlantUtils as utils import MeshPart as mp import pivy from pivy import coin 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") ''' Default Area: ''' def makeArea(points = None, type = 0): obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Area") if type == 0: _Area(obj) _ViewProviderArea(obj.ViewObject) elif type == 1: _ForbiddenArea(obj) _ViewProviderForbiddenArea(obj.ViewObject) if points: obj.Points = points return obj class _Area: def __init__(self, obj): ''' Initialize the Area object ''' self.Type = None self.obj = None self.setProperties(obj) def setProperties(self, obj): pl = obj.PropertiesList if not ("Base" in pl): obj.addProperty("App::PropertyLink", "Base", "Area", "Base wire" ).Base = None if not ("Type" in pl): obj.addProperty("App::PropertyString", "Type", "Area", "Points that define the area" ).Type = "Area" 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 __getstate__(self): return None # No necesitamos guardar estado adicional def __setstate__(self, state): pass def execute(self, obj): ''' Execute the area object ''' pass class _ViewProviderArea: def __init__(self, vobj): vobj.Proxy = self def attach(self, vobj): ''' Create Object visuals in 3D view. ''' self.ViewObject = vobj def getIcon(self): ''' Return object treeview icon. ''' return str(os.path.join(DirIcons, "area.svg")) ''' def claimChildren(self): """ Provides object grouping """ return self.Object.Group ''' def setEdit(self, vobj, mode=0): """ Enable edit """ return True def unsetEdit(self, vobj, mode=0): """ Disable edit """ return False def doubleClicked(self, vobj): """ Detect double click """ pass def setupContextMenu(self, obj, menu): """ Context menu construction """ pass def edit(self): """ Edit callback """ pass def __getstate__(self): return None def __setstate__(self, state): pass ''' Frame Area ''' def makeFramedArea(base = None, select = None): obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "FrameArea") FrameArea(obj) ViewProviderFrameArea(obj.ViewObject) if base: obj.Base = base if select: frames = [] for o in select: if hasattr(o, "Proxy") and (o.Proxy.Type == "Tracker"): if not (o in frames): frames.append(o) if len(frames) > 0: print(frames) obj.Frames = frames try: group = FreeCAD.ActiveDocument.FrameZones except: group = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", 'FrameZones') group.Label = "FrameZones" group.addObject(obj) return obj class FrameArea(_Area): def __init__(self, obj): _Area.__init__(self, obj) self.setProperties(obj) self.obj = None def setProperties(self, obj): _Area.setProperties(self, obj) pl = obj.PropertiesList if not ("Frames" in pl): obj.addProperty("App::PropertyLinkList", "Frames", "Area", "All the frames inside this area." ) if not ("FrameNumber" in pl): obj.addProperty("App::PropertyInteger", "FrameNumber", "Area", "The number of frames inside this area." ) obj.setEditorMode("FrameNumber", 1) if not ("Type" in pl): obj.addProperty("App::PropertyString", "Type", "Base", "The facemaker type to use to build the profile of this object" ).Type = "FrameArea" obj.setEditorMode("Type", 1) self.Type = "FrameArea" obj.Proxy = self self.obj = obj def onDocumentRestored(self, obj): """Method run when the document is restored.""" self.setProperties(obj) def onBeforeChange(self, obj, prop): ''' ''' pass def onChanged(self, obj, prop): if prop == "Base": if obj.Base.Shape is None: obj.Shape = Part.Shape() return import Utils.PVPlantUtils as utils base = obj.Base.Shape land = PVPlantSite.get().Terrain.Mesh vec = FreeCAD.Vector(0,0,1) wire = utils.getProjected(base, vec) tmp = mp.projectShapeOnMesh(wire, land, vec) shape = Part.makeCompound([]) for section in tmp: shape.add(Part.makePolygon(section)) obj.Shape = shape if prop == "Frames": lf = [] for o in obj.Frames: if not hasattr(o, "Proxy"): continue if o.Proxy.Type == "Tracker": lf.append(o) obj.Frames = lf obj.FramesNumber = len(obj.Frames) def addFrame(self, frame): list = self.obj.Frames.copy() list.append(frame) self.obj.Frames = sorted(list, key=lambda x: x.Name) def execute(self, obj): ''' execute ''' if not hasattr(obj, "Frames"): return obj.FrameNumber = len(obj.Frames) def __getstate__(self): return None def __setstate__(self, state): pass class ViewProviderFrameArea(_ViewProviderArea): def __init__(self, vobj): ''' Set view properties. ''' self.Object = vobj.Object vobj.Proxy = self def getIcon(self): ''' Return object treeview icon ''' return str(os.path.join(DirIcons, "FrameArea.svg")) def claimChildren(self): """ Provides object grouping """ children = [] if self.Object.Base: children.append(self.Object.Base) return children ''' offsets ''' def makeOffsetArea(base = None, val=None): obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "OffsetArea") OffsetArea(obj) obj.Base = base ViewProviderOffsetArea(obj.ViewObject) if val: obj.OffsetDistance = val try: offsetsgroup = FreeCAD.ActiveDocument.Offsets except: offsetsgroup = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", 'Offsets') offsetsgroup.Label = "Offsets" offsetsgroup.addObject(obj) return obj class OffsetArea(_Area): def __init__(self, obj): '''_Area.__init__(self, obj) self.setProperties(obj)''' super().__init__(obj) # Llama al constructor de _Area def setProperties(self, obj): super().setProperties(obj) # Propiedades de la clase base pl = obj.PropertiesList if not ("OffsetDistance" in pl): obj.addProperty("App::PropertyDistance", "OffsetDistance", "OffsetArea", "Base wire" ) self.Type = obj.Type = "Area_Offset" def onDocumentRestored(self, obj): """Method run when the document is restored.""" self.setProperties(obj) def execute(self, obj): # Comprobar dependencias críticas if not hasattr(obj, "Base") or not obj.Base or not obj.Base.Shape: return if not hasattr(PVPlantSite, "get") or not PVPlantSite.get().Terrain: return base = obj.Base.Shape land = PVPlantSite.get().Terrain.Mesh vec = FreeCAD.Vector(0, 0, 1) wire = utils.getProjected(base, vec) wire = wire.makeOffset2D(obj.OffsetDistance.Value, 2, False, False, True) sections = mp.projectShapeOnMesh(wire, land, vec) print(" javi ", sections) pts = [] for section in sections: pts.extend(section) # Crear forma solo si hay resultados if len(pts)>0: obj.Shape = Part.makePolygon(pts) else: obj.Shape = Part.Shape() # Forma vacía si falla class ViewProviderOffsetArea(_ViewProviderArea): def getIcon(self): ''' Return object treeview icon. ''' return str(os.path.join(DirIcons, "offset.svg")) def claimChildren(self): """ Provides object grouping """ children = [] if self.ViewObject and self.ViewObject.Object.Base: children.append(self.ViewObject.Object.Base) return children ''' Forbidden Area: ''' def makeProhibitedArea(base = None): obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "ExclusionArea") ProhibitedArea(obj) ViewProviderForbiddenArea(obj.ViewObject) if base: obj.Base = base try: group = FreeCAD.ActiveDocument.getObject("Exclusions") except: group = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", 'Exclusions') group.Label = "Exclusions" group.addObject(obj) return obj class ProhibitedArea(OffsetArea): def __init__(self, obj): OffsetArea.__init__(self, obj) self.setProperties(obj) def setProperties(self, obj): OffsetArea.setProperties(self, obj) self.Type = obj.Type = "ProhibitedArea" obj.Proxy = self def onDocumentRestored(self, obj): """Method run when the document is restored.""" self.setProperties(obj) def execute(self, obj): # Comprobar dependencias if not hasattr(obj, "Base") or not obj.Base or not obj.Base.Shape: return if not hasattr(PVPlantSite, "get") or not PVPlantSite.get().Terrain: return base = obj.Base.Shape land = PVPlantSite.get().Terrain.Mesh vec = FreeCAD.Vector(0, 0, 1) # 1. Crear wire original original_wire = utils.getProjected(base, vec) sections_original = mp.projectShapeOnMesh(original_wire, land, vec) # 2. Crear wire offset offset_wire = original_wire.makeOffset2D(obj.OffsetDistance.Value, 2, False, False, True) sections_offset = mp.projectShapeOnMesh(offset_wire, land, vec) # Crear formas compuestas def make_polygon(sections): if not sections: return Part.Shape() pts = [] for section in sections: pts.extend(section) return Part.makePolygon(pts) compounds = [] if sections_original: compounds.append(make_polygon(sections_original)) if sections_offset: compounds.append(make_polygon(sections_offset)) if compounds: obj.Shape = Part.makeCompound(compounds) else: obj.Shape = Part.Shape() # Actualizar colores en la vista """if FreeCAD.GuiUp and obj.ViewObject: obj.ViewObject.Proxy.updateVisual()""" class ViewProviderForbiddenArea_old: def __init__(self, vobj): vobj.Proxy = self self.setProperties(vobj) def setProperties(self, vobj): # Propiedades de color if not hasattr(vobj, "OriginalColor"): vobj.addProperty("App::PropertyColor", "OriginalColor", "ObjectStyle", "Color for original wire") vobj.OriginalColor = (1.0, 0.0, 0.0) # Rojo if not hasattr(vobj, "OffsetColor"): vobj.addProperty("App::PropertyColor", "OffsetColor", "ObjectStyle", "Color for offset wire") vobj.OffsetColor = (1.0, 0.0, 0.0) # Rojo # Propiedades de grosor if not hasattr(vobj, "OriginalWidth"): vobj.addProperty("App::PropertyFloat", "OriginalWidth", "ObjectStyle", "Line width for original wire") vobj.OriginalWidth = 4.0 if not hasattr(vobj, "OffsetWidth"): vobj.addProperty("App::PropertyFloat", "OffsetWidth", "ObjectStyle", "Line width for offset wire") vobj.OffsetWidth = 4.0 # Deshabilitar el color por defecto vobj.setPropertyStatus("LineColor", "Hidden") vobj.setPropertyStatus("PointColor", "Hidden") vobj.setPropertyStatus("ShapeAppearance", "Hidden") def attach(self, vobj): self.ViewObject = vobj self.Object = vobj.Object # Crear la estructura de escena Coin3D self.root = coin.SoGroup() # Switch para habilitar/deshabilitar la selección self.switch = coin.SoSwitch() self.switch.whichChild = coin.SO_SWITCH_ALL # Separador para el wire original self.original_sep = coin.SoSeparator() self.original_color = coin.SoBaseColor() self.original_coords = coin.SoCoordinate3() self.original_line_set = coin.SoLineSet() self.original_draw_style = coin.SoDrawStyle() # Separador para el wire offset self.offset_sep = coin.SoSeparator() self.offset_color = coin.SoBaseColor() self.offset_coords = coin.SoCoordinate3() self.offset_line_set = coin.SoLineSet() self.offset_draw_style = coin.SoDrawStyle() # Construir la jerarquía de escena self.original_sep.addChild(self.original_color) self.original_sep.addChild(self.original_draw_style) self.original_sep.addChild(self.original_coords) self.original_sep.addChild(self.original_line_set) self.offset_sep.addChild(self.offset_color) self.offset_sep.addChild(self.offset_draw_style) self.offset_sep.addChild(self.offset_coords) self.offset_sep.addChild(self.offset_line_set) self.switch.addChild(self.original_sep) self.switch.addChild(self.offset_sep) self.root.addChild(self.switch) vobj.addDisplayMode(self.root, "Wireframe") # Inicializar estilos de dibujo self.original_draw_style.style = coin.SoDrawStyle.LINES self.offset_draw_style.style = coin.SoDrawStyle.LINES # Actualizar visualización inicial if hasattr(self.Object, 'Shape'): self.updateData(self.Object, "Shape") self.updateVisual() def updateData(self, obj, prop): if prop == "Shape" and obj.Shape and not obj.Shape.isNull(): self.updateGeometry() def updateGeometry(self): """Actualiza la geometría en la escena 3D""" if not hasattr(self, 'Object') or not self.Object.Shape or self.Object.Shape.isNull(): return # Limpiar coordenadas existentes self.original_coords.point.deleteValues(0) self.offset_coords.point.deleteValues(0) # Obtener los sub-shapes subshapes = [] if hasattr(self.Object.Shape, 'SubShapes') and self.Object.Shape.SubShapes: subshapes = self.Object.Shape.SubShapes elif hasattr(self.Object.Shape, 'ChildShapes') and self.Object.Shape.ChildShapes: subshapes = self.Object.Shape.ChildShapes # Procesar wire original (primer sub-shape) if len(subshapes) > 0: self.processShape(subshapes[0], self.original_coords, self.original_line_set) # Procesar wire offset (segundo sub-shape) if len(subshapes) > 1: self.processShape(subshapes[1], self.offset_coords, self.offset_line_set) # Actualizar colores y grosores self.updateVisual() def processShape(self, shape, coords_node, lineset_node): """Procesa una forma y la añade al nodo de coordenadas""" if not shape or shape.isNull(): return points = [] line_indices = [] current_index = 0 # Obtener todos los edges de la forma edges = [] if hasattr(shape, 'Edges'): edges = shape.Edges elif hasattr(shape, 'ChildShapes'): for child in shape.ChildShapes: if hasattr(child, 'Edges'): edges.extend(child.Edges) for edge in edges: try: # Discretizar la curva para obtener puntos vertices = edge.discretize(Number=50) for i, vertex in enumerate(vertices): points.append([vertex.x, vertex.y, vertex.z]) line_indices.append(current_index) current_index += 1 # Añadir -1 para indicar fin de línea line_indices.append(-1) except Exception as e: print(f"Error processing edge: {e}") continue # Configurar coordenadas y líneas if points: coords_node.point.setValues(0, len(points), points) lineset_node.numVertices.deleteValues(0) lineset_node.numVertices.setValues(0, len(line_indices), line_indices) def updateVisual(self): """Actualiza colores y grosores según las propiedades""" if not hasattr(self, 'ViewObject') or not self.ViewObject: return vobj = self.ViewObject try: # Configurar wire original if hasattr(vobj, "OriginalColor"): original_color = vobj.OriginalColor self.original_color.rgb.setValue(original_color[0], original_color[1], original_color[2]) if hasattr(vobj, "OriginalWidth"): self.original_draw_style.lineWidth = vobj.OriginalWidth # Configurar wire offset if hasattr(vobj, "OffsetColor"): offset_color = vobj.OffsetColor self.offset_color.rgb.setValue(offset_color[0], offset_color[1], offset_color[2]) if hasattr(vobj, "OffsetWidth"): self.offset_draw_style.lineWidth = vobj.OffsetWidth except Exception as e: print(f"Error updating visual: {e}") def onChanged(self, vobj, prop): """Maneja cambios en propiedades""" if prop in ["OriginalColor", "OffsetColor", "OriginalWidth", "OffsetWidth"]: self.updateVisual() def getDisplayModes(self, obj): return ["Wireframe"] def getDefaultDisplayMode(self): return "Wireframe" def setDisplayMode(self, mode): return mode def claimChildren(self): """Proporciona agrupamiento de objetos""" children = [] if hasattr(self, 'Object') and self.Object and hasattr(self.Object, "Base"): children.append(self.Object.Base) return children def getIcon(self): '''Return object treeview icon''' return str(os.path.join(DirIcons, "area_forbidden.svg")) def onDocumentRestored(self, vobj): """Método ejecutado cuando el documento es restaurado""" self.ViewObject = vobj self.Object = vobj.Object self.setProperties(vobj) self.attach(vobj) def __getstate__(self): return None def __setstate__(self, state): return None class ViewProviderForbiddenArea: def __init__(self, vobj): vobj.Proxy = self self.ViewObject = vobj # Inicializar propiedades PRIMERO self.setProperties(vobj) # Configurar colores iniciales self.updateColors(vobj) def setProperties(self, vobj): if not hasattr(vobj, "OriginalColor"): vobj.addProperty("App::PropertyColor", "OriginalColor", "Display", "Color for original wire") vobj.OriginalColor = (1.0, 0.0, 0.0) # Rojo if not hasattr(vobj, "OffsetColor"): vobj.addProperty("App::PropertyColor", "OffsetColor", "Display", "Color for offset wire") vobj.OffsetColor = (1.0, 0.5, 0.0) # Naranja def updateColors(self, vobj): """Actualiza los colores desde las propiedades""" try: if hasattr(vobj, "OriginalColor"): self.original_color.rgb.setValue(*vobj.OriginalColor) else: self.original_color.rgb.setValue(1.0, 0.0, 0.0) if hasattr(vobj, "OffsetColor"): self.offset_color.rgb.setValue(*vobj.OffsetColor) else: self.offset_color.rgb.setValue(1.0, 0.5, 0.0) except Exception as e: print(f"Error en updateColors: {e}") def onDocumentRestored(self, vobj): self.setProperties(vobj) # No llamar a __init__ de nuevo, solo actualizar propiedades self.updateColors(vobj) def getIcon(self): return str(os.path.join(DirIcons, "area_forbidden.svg")) def attach(self, vobj): self.ViewObject = vobj # Inicializar nodos Coin3D self.root = coin.SoGroup() self.original_coords = coin.SoCoordinate3() self.offset_coords = coin.SoCoordinate3() self.original_color = coin.SoBaseColor() self.offset_color = coin.SoBaseColor() self.original_lineset = coin.SoLineSet() self.offset_lineset = coin.SoLineSet() # Añadir un nodo de dibujo para establecer el estilo de línea self.draw_style = coin.SoDrawStyle() self.draw_style.style = coin.SoDrawStyle.LINES self.draw_style.lineWidth = 3.0 # Construir la escena self.root.addChild(self.draw_style) # Grupo para el polígono original original_group = coin.SoGroup() original_group.addChild(self.original_color) original_group.addChild(self.original_coords) original_group.addChild(self.original_lineset) # Grupo para el polígono offset offset_group = coin.SoGroup() offset_group.addChild(self.offset_color) offset_group.addChild(self.offset_coords) offset_group.addChild(self.offset_lineset) self.root.addChild(original_group) self.root.addChild(offset_group) vobj.addDisplayMode(self.root, "Standard") # Asegurar que la visibilidad esté activada vobj.Visibility = True def updateData(self, obj, prop): if prop == "Shape": self.updateVisual(obj) def updateVisual(self, obj): """Actualiza la representación visual basada en la forma del objeto""" if not hasattr(obj, 'Shape') or not obj.Shape or obj.Shape.isNull(): return try: # Obtener todos los bordes de la forma compuesta all_edges = obj.Shape.Edges # Separar bordes por polígono (asumimos que el primer polígono es el original) # Esto es una simplificación - podrías necesitar una lógica más sofisticada if len(all_edges) >= 2: # Polígono original - primer conjunto de bordes original_edges = [all_edges[0]] original_points = [] for edge in original_edges: for vertex in edge.Vertexes: original_points.append((vertex.Point.x, vertex.Point.y, vertex.Point.z)) # Polígono offset - segundo conjunto de bordes offset_edges = [all_edges[1]] offset_points = [] for edge in offset_edges: for vertex in edge.Vertexes: offset_points.append((vertex.Point.x, vertex.Point.y, vertex.Point.z)) # Asignar puntos a los nodos Coordinate3 if original_points: self.original_coords.point.setValues(0, len(original_points), original_points) self.original_lineset.numVertices.setValue(len(original_points)) if offset_points: self.offset_coords.point.setValues(0, len(offset_points), offset_points) self.offset_lineset.numVertices.setValue(len(offset_points)) # Actualizar colores if hasattr(obj, 'ViewObject') and obj.ViewObject: self.updateColors(obj.ViewObject) except Exception as e: print(f"Error en updateVisual: {e}") def onChanged(self, vobj, prop): if prop in ["OriginalColor", "OffsetColor"]: self.updateColors(vobj) elif prop == "Visibility" and vobj.Visibility: # Cuando la visibilidad cambia a True, actualizar visual self.updateVisual(vobj.Object) def getDisplayModes(self, obj): return ["Standard"] def getDefaultDisplayMode(self): return "Standard" def setDisplayMode(self, mode): return mode def claimChildren(self): children = [] if hasattr(self, 'ViewObject') and self.ViewObject and hasattr(self.ViewObject.Object, 'Base'): children.append(self.ViewObject.Object.Base) return children def dumps(self): return None def loads(self, state): return None ''' PV Area: ''' def makePVSubplant(): obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "PVSubplant") PVSubplant(obj) ViewProviderPVSubplant(obj.ViewObject) return obj class PVSubplant: def __init__(self, obj): self.setProperties(obj) self.Type = None self.obj = None def setProperties(self, obj): pl = obj.PropertiesList if not "Setup" in pl: obj.addProperty("App::PropertyEnumeration", "Setup", "PVSubplant", "The facemaker type to use to build the profile of this object" ).Setup = ["String Inverter", "Central Inverter"] if not ("Frames" in pl): obj.addProperty("App::PropertyLinkList", "Frames", "PVSubplant", "List of frames" ) if not ("Inverters" in pl): obj.addProperty("App::PropertyLinkList", "Inverters", "PVSubplant", "List of Inverters" ) if not ("Cables" in pl): obj.addProperty("App::PropertyLinkList", "Cables", "PVSubplant", "List of Cables" ) if not "TotalPVModules" in pl: obj.addProperty("App::PropertyQuantity", "TotalPVModules", "PVSubplant", "The facemaker type to use to build the profile of this object" ) if not "TotalPowerDC" in pl: obj.addProperty("App::PropertyQuantity", "TotalPowerDC", "PVSubplant", "The facemaker type to use to build the profile of this object" ) if not "Color" in pl: obj.addProperty("App::PropertyColor", "Color", "PVSubplant", "Color" ) if not "Type" in pl: obj.addProperty("App::PropertyString", "Type", "Base", "The facemaker type to use to build the profile of this object" ).Type = "PVSubplant" obj.setEditorMode("Type", 1) self.Type = obj.Type self.obj = obj obj.Proxy = self def onDocumentRestored(self, obj): """Method run when the document is restored.""" self.setProperties(obj) def onChanged(self, obj, prop): if prop == "Color": obj.ViewObject.LineColor = obj.Color obj.ViewObject.PointColor = obj.Color if prop == "Setup": if obj.Setup == "Central Inverter": if not ("StringBoxes" in obj.PropertiesList): obj.addProperty("App::PropertyLinkList", "StringBoxes", "PVSubplant", "List of String-Boxes" ) else: if hasattr(obj, "StringBoxes"): obj.removeProperty("StringBoxes") if prop == "Frames": import numpy as np # 1. Dibujar contorno: maxdist = 6000 if len(obj.Frames) > 0: onlyframes = [] for object in obj.Frames: if object.Name.startswith("Tracker"): onlyframes.append(object) obj.Frames = onlyframes pts = [] for frame in obj.Frames: for panel in frame.Shape.SubShapes[0].SubShapes[0].SubShapes: zm = panel.BoundBox.ZMax for i in range(8): pt = panel.BoundBox.getPoint(i) if pt.z == zm: pts.append(pt) import MeshTools.Triangulation as Triangulation import MeshTools.MeshGetBoundary as mgb m = Triangulation.Triangulate(np.array(pts), MaxlengthLE=maxdist, use3d=False) b = mgb.get_boundary(m) obj.Shape = b # 2. rellenar información power = 0 modulenum = 0 for frame in obj.Frames: modules = frame.Setup.ModuleColumns * frame.Setup.ModuleRows power += frame.Setup.ModulePower.Value * modules modulenum += modules obj.TotalPowerDC = power obj.TotalPVModules = modulenum obj.ViewObject.LineWidth = 5 def execute(self, obj): ''' ''' pass def __getstate__(self): return None def __setstate__(self, state): pass class ViewProviderPVSubplant: def __init__(self, vobj): ''' Set view properties. ''' self.Object = None vobj.Proxy = self def attach(self, vobj): ''' Create Object visuals in 3D view. ''' self.Object = vobj.Object return def getIcon(self): ''' Return object treeview icon. ''' return str(os.path.join(DirIcons, "subplant.svg")) def claimChildren(self): """ Provides object grouping """ children = [] if self.Object.Frames: children.extend(self.Object.Frames) return children def __getstate__(self): return None '''def onDelete(self, feature, subelements): try: for obj in self.claimChildren(): obj.ViewObject.show() except Exception as err: FreeCAD.Console.PrintError("Error in onDelete: " + str(err)) return True def canDragObjects(self): return True def canDropObjects(self): return True def canDragObject(self, dragged_object): return True def canDropObject(self, incoming_object): return hasattr(incoming_object, 'Shape') def dragObject(self, selfvp, dragged_object): objs = self.Object.Objects objs.remove(dragged_object) self.Object.Objects = objs def dropObject(self, selfvp, incoming_object): self.Object.Objects = self.Object.Objects + [incoming_object] def setEdit(self, vobj, mode=0): """ Enable edit """ return True def unsetEdit(self, vobj, mode=0): """ Disable edit """ return False def doubleClicked(self, vobj): """ Detect double click """ pass def setupContextMenu(self, obj, menu): """ Context menu construction """ pass def edit(self): """ Edit callback """ pass def __getstate__(self): """ Save variables to file. """ return None def __setstate__(self,state): """ Get variables from file. """ return None''' # Comandos: ----------------------------------------------------------------------------------------------------------- class CommandDivideArea: def GetResources(self): return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "area.svg")), 'Accel': "A, D", 'MenuText': "Divide Area", 'ToolTip': "Allowed Area"} def Activated(self): sel = FreeCADGui.Selection.getSelection()[0] def IsActive(self): if FreeCAD.ActiveDocument: return True else: return False class CommandBoundary: def GetResources(self): return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "area.svg")), 'Accel': "A, B", 'MenuText': "Area", 'ToolTip': "Allowed Area"} def Activated(self): sel = FreeCADGui.Selection.getSelection()[0] obj = makeArea([ver.Point for ver in sel.Shape.Vertexes]) #taskd = _PVPlantPlacementTaskPanel() #FreeCADGui.Control.showDialog(taskd) def IsActive(self): if FreeCAD.ActiveDocument: return True else: return False class CommandFrameArea: def GetResources(self): return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "FrameArea.svg")), 'Accel': "A, F", 'MenuText': "Frame Area", 'ToolTip': "Frame Area"} def Activated(self): for base in FreeCADGui.Selection.getSelection(): makeFramedArea(None, base) def IsActive(self): if FreeCAD.ActiveDocument: return True else: return False class CommandProhibitedArea: def GetResources(self): return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "area_forbidden.svg")), 'Accel': "A, F", 'MenuText': "Prohibited Area", 'ToolTip': "Prohibited Area"} def Activated(self): for base in FreeCADGui.Selection.getSelection(): makeProhibitedArea(base) def IsActive(self): if FreeCAD.ActiveDocument: return True else: return False class CommandPVSubplant: def GetResources(self): return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "subplant.svg")), 'Accel': "A, P", 'MenuText': "PV Subplant", 'ToolTip': "PV Subplant"} def Activated(self): area = makePVSubplant() sel = FreeCADGui.Selection.getSelection() for obj in sel: if hasattr(obj, 'Proxy') and obj.Proxy.Type == "Tracker": frame_list = area.Frames frame_list.append(obj) area.Frames = frame_list def IsActive(self): if FreeCAD.ActiveDocument: return True else: return False class CommandOffsetArea: def GetResources(self): return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "offset.svg")), 'Accel': "A, O", 'MenuText': "OffsetArea", 'ToolTip': "OffsetArea"} def Activated(self): for base in FreeCADGui.Selection.getSelection(): makeOffsetArea(base) def IsActive(self): if FreeCAD.ActiveDocument: return True else: return False '''if FreeCAD.GuiUp: class CommandAreaGroup: def GetCommands(self): return tuple([#'Area', 'FrameArea', 'ForbiddenArea', 'PVSubplant', 'OffsetArea' ]) def GetResources(self): return {'MenuText': 'Areas', 'ToolTip': 'Areas' } def IsActive(self): return not FreeCAD.ActiveDocument is None #FreeCADGui.addCommand('Area', CommandBoundary()) FreeCADGui.addCommand('FrameArea', CommandFrameArea()) FreeCADGui.addCommand('ForbiddenArea', CommandProhibitedArea()) FreeCADGui.addCommand('PVSubplant', CommandPVSubplant()) FreeCADGui.addCommand('OffsetArea', CommandOffsetArea()) FreeCADGui.addCommand('PVPlantAreas', CommandAreaGroup())'''