primera subida
This commit is contained in:
803
Project/Area/PVPlantArea.py
Normal file
803
Project/Area/PVPlantArea.py
Normal file
@@ -0,0 +1,803 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * 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 FreeCAD
|
||||
import Part
|
||||
import PVPlantSite
|
||||
import Utils.PVPlantUtils as utils
|
||||
import MeshPart as mp
|
||||
|
||||
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
|
||||
|
||||
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)
|
||||
|
||||
|
||||
class _ViewProviderArea:
|
||||
def __init__(self, vobj):
|
||||
self.Object = vobj.Object
|
||||
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, "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):
|
||||
"""
|
||||
Save variables to file.
|
||||
"""
|
||||
return None
|
||||
|
||||
def __setstate__(self, state):
|
||||
"""
|
||||
Get variables from file.
|
||||
"""
|
||||
return None
|
||||
|
||||
|
||||
''' 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(obj)
|
||||
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 '''
|
||||
#_Area.execute(self, obj)
|
||||
|
||||
obj.FrameNumber = len(obj.Frames)
|
||||
|
||||
|
||||
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.Distance = val
|
||||
|
||||
offsets = None
|
||||
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)
|
||||
|
||||
def setProperties(self, obj):
|
||||
_Area.setProperties(self, obj)
|
||||
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):
|
||||
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)
|
||||
wire = wire.makeOffset2D(obj.OffsetDistance.Value, 2, False, False, True)
|
||||
tmp = mp.projectShapeOnMesh(wire, land, vec)
|
||||
pts = []
|
||||
for section in tmp:
|
||||
pts.extend(section)
|
||||
obj.Shape = Part.makePolygon(pts)
|
||||
|
||||
|
||||
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.Object.Base:
|
||||
children.append(self.Object.Base)
|
||||
return children
|
||||
|
||||
|
||||
''' Forbidden Area: '''
|
||||
|
||||
|
||||
def makeProhibitedArea(base = None):
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "ProhibitedArea")
|
||||
ProhibitedArea(obj)
|
||||
ViewProviderForbiddenArea(obj.ViewObject)
|
||||
if base:
|
||||
obj.Base = base
|
||||
try:
|
||||
group = FreeCAD.ActiveDocument.Exclusion
|
||||
except:
|
||||
group = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", 'Exclusion')
|
||||
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)
|
||||
|
||||
|
||||
class ViewProviderForbiddenArea(_ViewProviderArea):
|
||||
def getIcon(self):
|
||||
''' Return object treeview icon '''
|
||||
return str(os.path.join(DirIcons, "area_forbidden.svg"))
|
||||
|
||||
def claimChildren(self):
|
||||
""" Provides object grouping """
|
||||
children = []
|
||||
if self.Object.Base:
|
||||
children.append(self.Object.Base)
|
||||
return children
|
||||
|
||||
|
||||
''' 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
|
||||
|
||||
|
||||
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):
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
makeFramedArea(None, sel)
|
||||
|
||||
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):
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
makeProhibitedArea(sel[0])
|
||||
|
||||
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 obj.Name[:7] == "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):
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
base = None
|
||||
if sel:
|
||||
base = sel[0]
|
||||
obj = 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())
|
||||
167
Project/Area/PVPlantAreaUtils.py
Normal file
167
Project/Area/PVPlantAreaUtils.py
Normal file
@@ -0,0 +1,167 @@
|
||||
# /**********************************************************************
|
||||
# * *
|
||||
# * 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 FreeCAD
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
import os
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt, txt):
|
||||
return txt
|
||||
|
||||
|
||||
def QT_TRANSLATE_NOOP(ctxt, txt):
|
||||
return txt
|
||||
# \endcond
|
||||
|
||||
__title__ = "PVPlant Area Utils"
|
||||
__author__ = "Javier Braña"
|
||||
__url__ = "http://www.sogos-solar.com"
|
||||
|
||||
import PVPlantResources
|
||||
|
||||
|
||||
def splitArea(area, tool):
|
||||
if (not area) or (not tool):
|
||||
return None
|
||||
|
||||
import Part, TechDraw
|
||||
import BOPTools.SplitAPI as splitter
|
||||
tool = tool.Shape
|
||||
if tool.BoundBox.ZMax != tool.BoundBox.ZMin:
|
||||
tool = TechDraw.projectEx(tool, FreeCAD.Vector(0, 0, 1))[0]
|
||||
tool = tool.extrude(FreeCAD.Vector(0, 0, 1000))
|
||||
tool.Placement.Base.z -= 500
|
||||
|
||||
shape = area.Shape
|
||||
if shape.BoundBox.ZMax != shape.BoundBox.ZMin:
|
||||
shape = TechDraw.projectEx(shape, FreeCAD.Vector(0, 0, 1))[0]
|
||||
face = Part.Face(Part.Wire(shape.Edges))
|
||||
|
||||
return splitter.slice(face, [tool, ], "Split")
|
||||
|
||||
|
||||
class splitAreaTaskPanel:
|
||||
def __init__(self):
|
||||
self.area = None
|
||||
self.tool = None
|
||||
|
||||
self.form = FreeCADGui.PySideUic.loadUi(os.path.join(PVPlantResources.__dir__, "Project", "Area", "PVPlantSplitArea.ui"))
|
||||
self.form.buttonAreaSel.clicked.connect(self.addArea)
|
||||
self.form.buttonToolSel.clicked.connect(self.addTool)
|
||||
|
||||
#self.view = FreeCADGui.ActiveDocument.ActiveView
|
||||
#self.call = self.view.addEventCallback("SoEvent", self.action)
|
||||
|
||||
def addArea(self):
|
||||
self.area = FreeCADGui.Selection.getSelection()[0]
|
||||
self.form.lineArea.setText(self.area.Name)
|
||||
|
||||
def addTool(self):
|
||||
self.tool = FreeCADGui.Selection.getSelection()[0]
|
||||
self.form.lineTool.setText(self.tool.Name)
|
||||
|
||||
def accept(self):
|
||||
import Part
|
||||
self.closeForm()
|
||||
results = splitArea(self.area, self.tool)
|
||||
if isinstance(results, Part.Compound):
|
||||
for face in results.Faces:
|
||||
Part.show(face.Wire, self.area.Label + "-split")
|
||||
elif isinstance(results, list):
|
||||
for face in results:
|
||||
Part.show(face.Wire, self.area.Label + "-split")
|
||||
else:
|
||||
Part.show(results)
|
||||
|
||||
|
||||
if self.form.checkBoxDeleteTool.isChecked():
|
||||
FreeCAD.ActiveDocument.removeObject(self.tool.Name)
|
||||
if self.form.checkBoxDeleteArea.isChecked():
|
||||
FreeCAD.ActiveDocument.removeObject(self.area.Name)
|
||||
return True
|
||||
|
||||
def reject(self):
|
||||
print(" .. Rejecting .. ")
|
||||
if self.new:
|
||||
FreeCAD.ActiveDocument.removeObject(self.obj.Name)
|
||||
self.closeForm()
|
||||
return True
|
||||
|
||||
def closeForm(self):
|
||||
print(" .. Closing .. ")
|
||||
#self.view.removeEventCallback("SoEvent", self.call)
|
||||
FreeCADGui.Control.closeDialog()
|
||||
|
||||
def joinAreas(areas):
|
||||
if len(areas) == 0:
|
||||
return None
|
||||
|
||||
import TechDraw
|
||||
shapes = []
|
||||
for area in areas:
|
||||
shape = area.Shape
|
||||
if shape.BoundBox.ZMax != shape.BoundBox.ZMin:
|
||||
shape = TechDraw.projectEx(shape, FreeCAD.Vector(0, 0, 1))[0]
|
||||
shapes.append(shape)
|
||||
shape = shapes.pop()
|
||||
shape.fuse(shapes)
|
||||
return shape
|
||||
|
||||
class CommandSplitArea:
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "split_area.svg")),
|
||||
'Accel': "A, S",
|
||||
'MenuText': "Split Area",
|
||||
'ToolTip': "Split Area"}
|
||||
|
||||
def IsActive(self):
|
||||
return (not FreeCAD.ActiveDocument is None and
|
||||
not FreeCAD.ActiveDocument.findObjects(Name="ProhibitedArea") is None and
|
||||
not FreeCAD.ActiveDocument.findObjects(Name="OffsetArea") is None)
|
||||
def Activated(self):
|
||||
self.TaskPanel = splitAreaTaskPanel()
|
||||
FreeCADGui.Control.showDialog(self.TaskPanel)
|
||||
return
|
||||
|
||||
class CommandJoinAreas:
|
||||
def GetResources(self):
|
||||
return {'Pixmap': str(os.path.join(PVPlantResources.DirIcons, "split_area.svg")),
|
||||
'Accel': "A, J",
|
||||
'MenuText': "Join Areas",
|
||||
'ToolTip': "Join Areas"}
|
||||
|
||||
def IsActive(self):
|
||||
return (not FreeCAD.ActiveDocument is None and
|
||||
not FreeCAD.ActiveDocument.findObjects(Name="ProhibitedArea") is None and
|
||||
not FreeCAD.ActiveDocument.findObjects(Name="OffsetArea") is None)
|
||||
def Activated(self):
|
||||
self.TaskPanel = splitAreaTaskPanel()
|
||||
FreeCADGui.Control.showDialog(self.TaskPanel)
|
||||
return
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('SplitArea', CommandSplitArea())
|
||||
FreeCADGui.addCommand('JoinAreas', CommandJoinAreas())
|
||||
|
||||
|
||||
106
Project/Area/PVPlantSplitArea.ui
Normal file
106
Project/Area/PVPlantSplitArea.ui
Normal file
@@ -0,0 +1,106 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>formSplitArea</class>
|
||||
<widget class="QWidget" name="formSplitArea">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>313</width>
|
||||
<height>301</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Split Area</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Herramienta de corte</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineTool">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonToolSel">
|
||||
<property name="text">
|
||||
<string>Seleccionar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Area</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLineEdit" name="lineArea">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QPushButton" name="buttonAreaSel">
|
||||
<property name="text">
|
||||
<string>Seleccionar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>Resultado</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxDeleteTool">
|
||||
<property name="text">
|
||||
<string>Borrar herramienta de corte</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxDeleteArea">
|
||||
<property name="text">
|
||||
<string>Borrar Area inicial</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
Reference in New Issue
Block a user