1142 lines
38 KiB
Python
1142 lines
38 KiB
Python
#***************************************************************************
|
|
#* Copyright (c) 2011 Yorik van Havre <yorik@uncreated.net> *
|
|
#* *
|
|
#* 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 *
|
|
#* *
|
|
#***************************************************************************
|
|
|
|
__title__ = "FreeCAD Arch API"
|
|
__author__ = "Yorik van Havre"
|
|
__url__ = "https://www.freecad.org"
|
|
|
|
## \defgroup ARCH Arch
|
|
# \ingroup PYTHONWORKBENCHES
|
|
# \brief Architecture and BIM tools
|
|
#
|
|
# This module provides tools specialized in Building Information Modeling (BIM).
|
|
# such as convenience tools to build walls, windows or structures, and
|
|
# IFC import/export capabilities.
|
|
|
|
'''The Arch module provides tools specialized in BIM modeling.'''
|
|
|
|
import FreeCAD
|
|
if FreeCAD.GuiUp:
|
|
import FreeCADGui
|
|
FreeCADGui.updateLocale()
|
|
QT_TRANSLATE_NOOP = FreeCAD.Qt.QT_TRANSLATE_NOOP
|
|
translate = FreeCAD.Qt.translate
|
|
|
|
|
|
# generic functions
|
|
|
|
from ArchCommands import *
|
|
from ArchWindowPresets import *
|
|
|
|
|
|
# TODO: migrate this one
|
|
|
|
from ArchStructure import *
|
|
from ArchSpace import *
|
|
|
|
# make functions
|
|
|
|
def makeAxis(num=1,size=1000,name=None):
|
|
|
|
'''makeAxis([num],[size],[name]): makes an Axis set
|
|
based on the given number of axes and interval distances'''
|
|
|
|
import ArchAxis
|
|
if not FreeCAD.ActiveDocument:
|
|
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
|
return
|
|
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Axis")
|
|
obj.Label = name if name else translate("Arch","Axes")
|
|
ArchAxis._Axis(obj)
|
|
if FreeCAD.GuiUp:
|
|
ArchAxis._ViewProviderAxis(obj.ViewObject)
|
|
if num:
|
|
dist = []
|
|
angles = []
|
|
for i in range(num):
|
|
if i == 0:
|
|
dist.append(0)
|
|
else:
|
|
dist.append(float(size))
|
|
angles.append(float(0))
|
|
obj.Distances = dist
|
|
obj.Angles = angles
|
|
FreeCAD.ActiveDocument.recompute()
|
|
return obj
|
|
|
|
|
|
def makeAxisSystem(axes,name=None):
|
|
|
|
'''makeAxisSystem(axes,[name]): makes a system from the given list of axes'''
|
|
|
|
import ArchAxisSystem
|
|
if not isinstance(axes,list):
|
|
axes = [axes]
|
|
obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython","AxisSystem")
|
|
obj.Label = name if name else translate("Arch","Axis System")
|
|
ArchAxisSystem._AxisSystem(obj)
|
|
obj.Axes = axes
|
|
if FreeCAD.GuiUp:
|
|
ArchAxisSystem._ViewProviderAxisSystem(obj.ViewObject)
|
|
FreeCAD.ActiveDocument.recompute()
|
|
return obj
|
|
|
|
|
|
def makeBuildingPart(objectslist=None,baseobj=None,name=None):
|
|
|
|
'''makeBuildingPart([objectslist],[name]): creates a buildingPart including the
|
|
objects from the given list.'''
|
|
|
|
import ArchBuildingPart
|
|
obj = FreeCAD.ActiveDocument.addObject("App::GeometryPython","BuildingPart")
|
|
#obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython","BuildingPart")
|
|
obj.Label = name if name else translate("Arch","BuildingPart")
|
|
ArchBuildingPart.BuildingPart(obj)
|
|
obj.IfcType = "Building Element Part"
|
|
if FreeCAD.GuiUp:
|
|
ArchBuildingPart.ViewProviderBuildingPart(obj.ViewObject)
|
|
if objectslist:
|
|
obj.addObjects(objectslist)
|
|
return obj
|
|
|
|
|
|
def makeFloor(objectslist=None,baseobj=None,name=None):
|
|
|
|
"""makes a BuildingPart and turns it into a Floor/Level"""
|
|
|
|
obj = makeBuildingPart(objectslist)
|
|
obj.Label = name if name else translate("Arch","Level")
|
|
obj.IfcType = "Building Storey"
|
|
return obj
|
|
|
|
|
|
def makeBuilding(objectslist=None,baseobj=None,name=None):
|
|
|
|
"""makes a BuildingPart and turns it into a Building"""
|
|
|
|
import ArchBuildingPart
|
|
obj = makeBuildingPart(objectslist)
|
|
obj.Label = name if name else translate("Arch","Building")
|
|
obj.IfcType = "Building"
|
|
t = QT_TRANSLATE_NOOP("App::Property","The type of this building")
|
|
obj.addProperty("App::PropertyEnumeration","BuildingType","Building",t)
|
|
obj.BuildingType = ArchBuildingPart.BuildingTypes
|
|
if FreeCAD.GuiUp:
|
|
obj.ViewObject.ShowLevel = False
|
|
obj.ViewObject.ShowLabel = False
|
|
return obj
|
|
|
|
|
|
def convertFloors(floor=None):
|
|
|
|
"""convert the given Floor or Building (or all Arch Floors from the
|
|
active document if none is given) into BuildingParts"""
|
|
|
|
import Draft
|
|
import ArchBuildingPart
|
|
todel = []
|
|
if floor:
|
|
objset = [floor]
|
|
else:
|
|
objset = FreeCAD.ActiveDocument.Objects
|
|
for obj in objset:
|
|
if Draft.getType(obj) in ["Floor","Building"]:
|
|
nobj = makeBuildingPart(obj.Group)
|
|
if Draft.getType(obj) == "Floor":
|
|
nobj.IfcType = "Building Storey"
|
|
else:
|
|
nobj.IfcType = "Building"
|
|
t = QT_TRANSLATE_NOOP("App::Property","The type of this building")
|
|
nobj.addProperty("App::PropertyEnumeration","BuildingType","Building",t)
|
|
nobj.BuildingType = ArchBuildingPart.BuildingTypes
|
|
label = obj.Label
|
|
for parent in obj.InList:
|
|
if hasattr(parent,"Group"):
|
|
if obj in parent.Group:
|
|
parent.addObject(nobj)
|
|
#g = parent.Group
|
|
#g.append(nobj)
|
|
#parent.Group = g
|
|
todel.append(obj.Name)
|
|
if obj.ViewObject:
|
|
# some bug makes this trigger even efter the object has been deleted...
|
|
obj.ViewObject.Proxy.Object = None
|
|
# in case FreeCAD doesn't allow 2 objs with same label
|
|
obj.Label = obj.Label+" to delete"
|
|
nobj.Label = label
|
|
for n in todel:
|
|
from DraftGui import todo
|
|
todo.delay(FreeCAD.ActiveDocument.removeObject,n)
|
|
|
|
|
|
def makeCurtainWall(baseobj=None,name=None):
|
|
|
|
"""makeCurtainWall([baseobj],[name]): Creates a curtain wall in the active document"""
|
|
|
|
import ArchCurtainWall
|
|
if not FreeCAD.ActiveDocument:
|
|
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
|
return
|
|
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","CurtainWall")
|
|
obj.Label = name if name else translate("Arch","Curtain Wall")
|
|
ArchCurtainWall.CurtainWall(obj)
|
|
if FreeCAD.GuiUp:
|
|
ArchCurtainWall.ViewProviderCurtainWall(obj.ViewObject)
|
|
if baseobj:
|
|
obj.Base = baseobj
|
|
if FreeCAD.GuiUp:
|
|
baseobj.ViewObject.hide()
|
|
return obj
|
|
|
|
|
|
def makeEquipment(baseobj=None,placement=None,name=None):
|
|
|
|
"""makeEquipment([baseobj],[placement],[name]): creates an equipment object
|
|
from the given base object."""
|
|
|
|
import ArchEquipment
|
|
if not FreeCAD.ActiveDocument:
|
|
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
|
return
|
|
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Equipment")
|
|
obj.Label = name if name else translate("Arch","Equipment")
|
|
ArchEquipment._Equipment(obj)
|
|
if baseobj:
|
|
if baseobj.isDerivedFrom("Mesh::Feature"):
|
|
obj.Mesh = baseobj
|
|
else:
|
|
obj.Base = baseobj
|
|
if placement:
|
|
obj.Placement = placement
|
|
if FreeCAD.GuiUp:
|
|
ArchEquipment._ViewProviderEquipment(obj.ViewObject)
|
|
if baseobj:
|
|
baseobj.ViewObject.hide()
|
|
return obj
|
|
|
|
|
|
def makeFence(section, post, path):
|
|
|
|
"""Makes a Fence object"""
|
|
|
|
import ArchFence
|
|
obj = FreeCAD.ActiveDocument.addObject('Part::FeaturePython', 'Fence')
|
|
ArchFence._Fence(obj)
|
|
obj.Section = section
|
|
obj.Post = post
|
|
obj.Path = path
|
|
if FreeCAD.GuiUp:
|
|
ArchFence._ViewProviderFence(obj.ViewObject)
|
|
ArchFence.hide(section)
|
|
ArchFence.hide(post)
|
|
ArchFence.hide(path)
|
|
return obj
|
|
|
|
|
|
def makeFrame(baseobj,profile,name=None):
|
|
|
|
"""makeFrame(baseobj,profile,[name]): creates a frame object from a base sketch (or any other object
|
|
containing wires) and a profile object (an extrudable 2D object containing faces or closed wires)"""
|
|
|
|
import ArchFrame
|
|
if not FreeCAD.ActiveDocument:
|
|
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
|
return
|
|
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Frame")
|
|
obj.Label = name if name else translate("Arch","Frame")
|
|
ArchFrame._Frame(obj)
|
|
if FreeCAD.GuiUp:
|
|
ArchFrame._ViewProviderFrame(obj.ViewObject)
|
|
if baseobj:
|
|
obj.Base = baseobj
|
|
if profile:
|
|
obj.Profile = profile
|
|
if FreeCAD.GuiUp:
|
|
profile.ViewObject.hide()
|
|
return obj
|
|
|
|
|
|
def makeGrid(name=None):
|
|
|
|
'''makeGrid([name]): makes a grid object'''
|
|
|
|
import ArchGrid
|
|
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Grid")
|
|
obj.Label = name if name else translate("Arch","Grid")
|
|
ArchGrid.ArchGrid(obj)
|
|
if FreeCAD.GuiUp:
|
|
ArchGrid.ViewProviderArchGrid(obj.ViewObject)
|
|
obj.ViewObject.Transparency = 85
|
|
FreeCAD.ActiveDocument.recompute()
|
|
return obj
|
|
|
|
|
|
def makeMaterial(name=None,color=None,transparency=None):
|
|
|
|
'''makeMaterial([name],[color],[transparency]): makes an Material object'''
|
|
|
|
import ArchMaterial
|
|
if not FreeCAD.ActiveDocument:
|
|
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
|
return
|
|
obj = FreeCAD.ActiveDocument.addObject("App::MaterialObjectPython","Material")
|
|
obj.Label = name if name else translate("Arch","Material")
|
|
ArchMaterial._ArchMaterial(obj)
|
|
if FreeCAD.GuiUp:
|
|
ArchMaterial._ViewProviderArchMaterial(obj.ViewObject)
|
|
getMaterialContainer().addObject(obj)
|
|
if color:
|
|
obj.Color = color[:3]
|
|
if len(color) > 3:
|
|
obj.Transparency = color[3]*100
|
|
if transparency:
|
|
obj.Transparency = transparency
|
|
return obj
|
|
|
|
|
|
def makeMultiMaterial(name=None):
|
|
|
|
'''makeMultiMaterial([name]): makes an MultiMaterial object'''
|
|
|
|
import ArchMaterial
|
|
obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython","MultiMaterial")
|
|
obj.Label = name if name else translate("Arch","MultiMaterial")
|
|
ArchMaterial._ArchMultiMaterial(obj)
|
|
if FreeCAD.GuiUp:
|
|
ArchMaterial._ViewProviderArchMultiMaterial(obj.ViewObject)
|
|
getMaterialContainer().addObject(obj)
|
|
return obj
|
|
|
|
|
|
def getMaterialContainer():
|
|
|
|
'''getMaterialContainer(): returns a group object to put materials in'''
|
|
|
|
import ArchMaterial
|
|
for obj in FreeCAD.ActiveDocument.Objects:
|
|
if obj.Name == "MaterialContainer":
|
|
return obj
|
|
obj = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroupPython","MaterialContainer")
|
|
obj.Label = "Materials"
|
|
ArchMaterial._ArchMaterialContainer(obj)
|
|
if FreeCAD.GuiUp:
|
|
ArchMaterial._ViewProviderArchMaterialContainer(obj.ViewObject)
|
|
return obj
|
|
|
|
|
|
def getDocumentMaterials():
|
|
|
|
'''getDocumentMaterials(): returns all the arch materials of the document'''
|
|
|
|
for obj in FreeCAD.ActiveDocument.Objects:
|
|
if obj.Name == "MaterialContainer":
|
|
mats = []
|
|
for o in obj.Group:
|
|
if o.isDerivedFrom("App::MaterialObjectPython"):
|
|
mats.append(o)
|
|
return mats
|
|
return []
|
|
|
|
|
|
def makePanel(baseobj=None,length=0,width=0,thickness=0,placement=None,name=None):
|
|
|
|
'''makePanel([baseobj],[length],[width],[thickness],[placement],[name]): creates a
|
|
panel element based on the given profile object and the given
|
|
extrusion thickness. If no base object is given, you can also specify
|
|
length and width for a simple cubic object.'''
|
|
|
|
import ArchPanel
|
|
if not FreeCAD.ActiveDocument:
|
|
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
|
return
|
|
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Panel")
|
|
obj.Label = name if name else translate("Arch","Panel")
|
|
ArchPanel._Panel(obj)
|
|
if FreeCAD.GuiUp:
|
|
ArchPanel._ViewProviderPanel(obj.ViewObject)
|
|
if baseobj:
|
|
obj.Base = baseobj
|
|
if FreeCAD.GuiUp:
|
|
obj.Base.ViewObject.hide()
|
|
if width:
|
|
obj.Width = width
|
|
if thickness:
|
|
obj.Thickness = thickness
|
|
if length:
|
|
obj.Length = length
|
|
return obj
|
|
|
|
|
|
def makePanelCut(panel,name=None):
|
|
|
|
"""makePanelCut(panel,[name]) : Creates a 2D view of the given panel
|
|
in the 3D space, positioned at the origin."""
|
|
|
|
import ArchPanel
|
|
view = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","PanelCut")
|
|
view.Label = name if name else translate("Arch","View of")+" "+panel.Label
|
|
ArchPanel.PanelCut(view)
|
|
view.Source = panel
|
|
if FreeCAD.GuiUp:
|
|
ArchPanel.ViewProviderPanelCut(view.ViewObject)
|
|
return view
|
|
|
|
|
|
def makePanelSheet(panels=[],name=None):
|
|
|
|
"""makePanelSheet([panels],[name]) : Creates a sheet with the given panel cuts
|
|
in the 3D space, positioned at the origin."""
|
|
|
|
import ArchPanel
|
|
sheet = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","PanelSheet")
|
|
sheet.Label = name if name else translate("Arch","PanelSheet")
|
|
ArchPanel.PanelSheet(sheet)
|
|
if panels:
|
|
sheet.Group = panels
|
|
if FreeCAD.GuiUp:
|
|
ArchPanel.ViewProviderPanelSheet(sheet.ViewObject)
|
|
return sheet
|
|
|
|
|
|
def makePipe(baseobj=None,diameter=0,length=0,placement=None,name=None):
|
|
|
|
"makePipe([baseobj],[diameter],[length],[placement],[name]): creates an pipe object from the given base object"
|
|
|
|
import ArchPipe
|
|
if not FreeCAD.ActiveDocument:
|
|
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
|
return
|
|
obj= FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Pipe")
|
|
obj.Label = name if name else translate("Arch","Pipe")
|
|
ArchPipe._ArchPipe(obj)
|
|
if FreeCAD.GuiUp:
|
|
ArchPipe._ViewProviderPipe(obj.ViewObject)
|
|
if baseobj:
|
|
baseobj.ViewObject.hide()
|
|
if baseobj:
|
|
obj.Base = baseobj
|
|
else:
|
|
if length:
|
|
obj.Length = length
|
|
else:
|
|
obj.Length = 1000
|
|
if diameter:
|
|
obj.Diameter = diameter
|
|
else:
|
|
obj.Diameter = params.get_param_arch("PipeDiameter")
|
|
obj.Width = obj.Diameter
|
|
obj.Height = obj.Diameter
|
|
if placement:
|
|
obj.Placement = placement
|
|
return obj
|
|
|
|
|
|
def makePipeConnector(pipes,radius=0,name=None):
|
|
|
|
"makePipeConnector(pipes,[radius],[name]): creates a connector between the given pipes"
|
|
|
|
import ArchPipe
|
|
if not FreeCAD.ActiveDocument:
|
|
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
|
return
|
|
obj= FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Connector")
|
|
obj.Label = name if name else translate("Arch","Connector")
|
|
ArchPipe._ArchPipeConnector(obj)
|
|
obj.Pipes = pipes
|
|
if not radius:
|
|
radius = pipes[0].Diameter
|
|
obj.Radius = radius
|
|
if FreeCAD.GuiUp:
|
|
ArchPipe._ViewProviderPipe(obj.ViewObject)
|
|
return obj
|
|
|
|
|
|
def makeProfile(profile=[0,'REC','REC100x100','R',100,100]):
|
|
|
|
'''makeProfile(profile): returns a shape with the face defined by the profile data'''
|
|
|
|
import ArchProfile
|
|
if not FreeCAD.ActiveDocument:
|
|
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
|
return
|
|
obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython", "Profile")
|
|
obj.Label = profile[2] + "_"
|
|
if profile[3]=="C":
|
|
ArchProfile._ProfileC(obj, profile)
|
|
elif profile[3]=="H":
|
|
ArchProfile._ProfileH(obj, profile)
|
|
elif profile[3]=="R":
|
|
ArchProfile._ProfileR(obj, profile)
|
|
elif profile[3]=="RH":
|
|
ArchProfile._ProfileRH(obj, profile)
|
|
elif profile[3]=="U":
|
|
ArchProfile._ProfileU(obj, profile)
|
|
elif profile[3]=="L":
|
|
ArchProfile._ProfileL(obj, profile)
|
|
elif profile[3]=="T":
|
|
ArchProfile._ProfileT(obj, profile)
|
|
else :
|
|
print("Profile not supported")
|
|
if FreeCAD.GuiUp:
|
|
ArchProfile.ViewProviderProfile(obj.ViewObject)
|
|
return obj
|
|
|
|
|
|
def makeProject(sites=None, name=None):
|
|
|
|
"""Create an Arch project.
|
|
|
|
If sites are provided, add them as children of the new project.
|
|
|
|
Parameters
|
|
----------
|
|
sites: list of <Part::FeaturePython>, optional
|
|
Sites to add as children of the project. Ultimately this could be
|
|
anything, however.
|
|
name: str, optional
|
|
The label for the project.
|
|
|
|
Returns
|
|
-------
|
|
<Part::FeaturePython>
|
|
The created project.
|
|
|
|
WARNING: This object is obsoleted in favour of the NativeIFC project
|
|
"""
|
|
|
|
import ArchProject
|
|
import Part
|
|
if not FreeCAD.ActiveDocument:
|
|
return FreeCAD.Console.PrintError("No active document. Aborting\n")
|
|
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Project")
|
|
obj.Label = name if name else translate("Arch", "Project")
|
|
ArchProject._Project(obj)
|
|
if FreeCAD.GuiUp:
|
|
ArchProject._ViewProviderProject(obj.ViewObject)
|
|
if sites:
|
|
obj.Group = sites
|
|
return obj
|
|
|
|
|
|
def makeRebar(baseobj=None,sketch=None,diameter=None,amount=1,offset=None,name=None):
|
|
|
|
"""makeRebar([baseobj],[sketch],[diameter],[amount],[offset],[name]):
|
|
adds a Reinforcement Bar object to the given structural object,
|
|
using the given sketch as profile."""
|
|
|
|
import ArchRebar
|
|
if not FreeCAD.ActiveDocument:
|
|
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
|
return
|
|
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Rebar")
|
|
obj.Label = name if name else translate("Arch","Rebar")
|
|
ArchRebar._Rebar(obj)
|
|
if FreeCAD.GuiUp:
|
|
ArchRebar._ViewProviderRebar(obj.ViewObject)
|
|
if baseobj and sketch:
|
|
if hasattr(sketch,"AttachmentSupport"):
|
|
if sketch.AttachmentSupport:
|
|
if isinstance(sketch.AttachmentSupport,tuple):
|
|
if sketch.AttachmentSupport[0] == baseobj:
|
|
sketch.AttachmentSupport = None
|
|
elif sketch.AttachmentSupport == baseobj:
|
|
sketch.AttachmentSupport = None
|
|
obj.Base = sketch
|
|
if FreeCAD.GuiUp:
|
|
sketch.ViewObject.hide()
|
|
obj.Host = baseobj
|
|
elif sketch and not baseobj:
|
|
# a rebar could be based on a wire without the existence of a Structure
|
|
obj.Base = sketch
|
|
if FreeCAD.GuiUp:
|
|
sketch.ViewObject.hide()
|
|
obj.Host = None
|
|
elif baseobj and not sketch:
|
|
obj.Shape = baseobj.Shape
|
|
if diameter:
|
|
obj.Diameter = diameter
|
|
else:
|
|
obj.Diameter = params.get_param_arch("RebarDiameter")
|
|
obj.Amount = amount
|
|
obj.Document.recompute()
|
|
if offset is not None:
|
|
obj.OffsetStart = offset
|
|
obj.OffsetEnd = offset
|
|
else:
|
|
obj.OffsetStart = params.get_param_arch("RebarOffset")
|
|
obj.OffsetEnd = params.get_param_arch("RebarOffset")
|
|
obj.Mark = obj.Label
|
|
return obj
|
|
|
|
|
|
def makeReference(filepath=None, partname=None, name=None):
|
|
|
|
"""makeReference([filepath],[partname],[name]): Creates an Arch Reference object"""
|
|
|
|
import ArchReference
|
|
if not FreeCAD.ActiveDocument:
|
|
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
|
return
|
|
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","ArchReference")
|
|
obj.Label = name if name else translate("Arch","External Reference")
|
|
ArchReference.ArchReference(obj)
|
|
if FreeCAD.GuiUp:
|
|
ArchReference.ViewProviderArchReference(obj.ViewObject)
|
|
if filepath:
|
|
obj.File = filepath
|
|
if partname:
|
|
obj.Part = partname
|
|
import Draft
|
|
Draft.select(obj)
|
|
return obj
|
|
|
|
|
|
def makeRoof(baseobj=None,
|
|
facenr=0,
|
|
angles=[45.0],
|
|
run=[250.0],
|
|
idrel=[-1],
|
|
thickness=[50.0],
|
|
overhang=[100.0],
|
|
name=None):
|
|
|
|
'''makeRoof(baseobj, [facenr], [angle], [name]): Makes a roof based on
|
|
a closed wire or an object.
|
|
|
|
You can provide a list of angles, run, idrel, thickness, overhang for
|
|
each edge in the wire to define the roof shape. The default for angle is
|
|
45 and the list is automatically completed to match the number of edges
|
|
in the wire.
|
|
|
|
If the base object is a solid the roof uses its shape.
|
|
'''
|
|
|
|
import ArchRoof
|
|
import Part
|
|
if not FreeCAD.ActiveDocument:
|
|
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
|
return
|
|
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Roof")
|
|
obj.Label = name if name else translate("Arch", "Roof")
|
|
baseWire = None
|
|
ArchRoof._Roof(obj)
|
|
if FreeCAD.GuiUp:
|
|
ArchRoof._ViewProviderRoof(obj.ViewObject)
|
|
if baseobj:
|
|
obj.Base = baseobj
|
|
if hasattr(obj.Base, "Shape"):
|
|
if obj.Base.Shape.Solids:
|
|
if FreeCAD.GuiUp:
|
|
obj.Base.ViewObject.hide()
|
|
else:
|
|
if (obj.Base.Shape.Faces and obj.Face):
|
|
baseWire = obj.Base.Shape.Faces[obj.Face-1].Wires[0]
|
|
if FreeCAD.GuiUp:
|
|
obj.Base.ViewObject.hide()
|
|
elif obj.Base.Shape.Wires:
|
|
baseWire = obj.Base.Shape.Wires[0]
|
|
if FreeCAD.GuiUp:
|
|
obj.Base.ViewObject.hide()
|
|
if baseWire:
|
|
if baseWire.isClosed():
|
|
if FreeCAD.GuiUp:
|
|
obj.Base.ViewObject.hide()
|
|
edges = Part.__sortEdges__(baseWire.Edges)
|
|
ln = len(edges)
|
|
obj.Angles = ArchRoof.adjust_list_len(angles, ln, angles[0])
|
|
obj.Runs = ArchRoof.adjust_list_len(run, ln, run[0])
|
|
obj.IdRel = ArchRoof.adjust_list_len(idrel, ln, idrel[0])
|
|
obj.Thickness = ArchRoof.adjust_list_len(thickness, ln, thickness[0])
|
|
obj.Overhang = ArchRoof.adjust_list_len(overhang, ln, overhang[0])
|
|
obj.Face = facenr
|
|
return obj
|
|
|
|
|
|
def makeSectionPlane(objectslist=None,name=None):
|
|
|
|
"""makeSectionPlane([objectslist],[name]) : Creates a Section plane objects including the
|
|
given objects. If no object is given, the whole document will be considered."""
|
|
|
|
import ArchSectionPlane
|
|
import Draft
|
|
import WorkingPlane
|
|
if not FreeCAD.ActiveDocument:
|
|
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
|
return
|
|
obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython","Section")
|
|
obj.Label = name if name else translate("Arch","Section")
|
|
ArchSectionPlane._SectionPlane(obj)
|
|
if FreeCAD.GuiUp:
|
|
ArchSectionPlane._ViewProviderSectionPlane(obj.ViewObject)
|
|
if objectslist:
|
|
obj.Objects = objectslist
|
|
bb = FreeCAD.BoundBox()
|
|
for o in Draft.get_group_contents(objectslist):
|
|
if hasattr(o,"Shape") and hasattr(o.Shape,"BoundBox"):
|
|
bb.add(o.Shape.BoundBox)
|
|
obj.Placement = WorkingPlane.get_working_plane().get_placement()
|
|
obj.Placement.Base = bb.Center
|
|
if FreeCAD.GuiUp:
|
|
margin = bb.XLength*0.1
|
|
obj.ViewObject.DisplayLength = bb.XLength+margin
|
|
obj.ViewObject.DisplayHeight = bb.YLength+margin
|
|
return obj
|
|
|
|
|
|
def makeSite(objectslist=None,baseobj=None,name=None):
|
|
|
|
'''makeBuilding([objectslist],[baseobj],[name]): creates a site including the
|
|
objects from the given list.'''
|
|
|
|
import ArchSite
|
|
if not FreeCAD.ActiveDocument:
|
|
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
|
return
|
|
import Part
|
|
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Site")
|
|
obj.Label = name if name else translate("Arch","Site")
|
|
ArchSite._Site(obj)
|
|
if FreeCAD.GuiUp:
|
|
ArchSite._ViewProviderSite(obj.ViewObject)
|
|
if objectslist:
|
|
obj.Group = objectslist
|
|
if baseobj:
|
|
import Part
|
|
if isinstance(baseobj,Part.Shape):
|
|
obj.Shape = baseobj
|
|
else:
|
|
obj.Terrain = baseobj
|
|
return obj
|
|
|
|
|
|
def makeSpace(objects=None,baseobj=None,name=None):
|
|
|
|
"""makeSpace([objects],[baseobj],[name]): Creates a space object from the given objects.
|
|
Objects can be one document object, in which case it becomes the base shape of the space
|
|
object, or a list of selection objects as got from getSelectionEx(), or a list of tuples
|
|
(object, subobjectname)"""
|
|
|
|
import ArchSpace
|
|
if not FreeCAD.ActiveDocument:
|
|
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
|
return
|
|
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Space")
|
|
obj.Label = name if name else translate("Arch","Space")
|
|
ArchSpace._Space(obj)
|
|
if FreeCAD.GuiUp:
|
|
ArchSpace._ViewProviderSpace(obj.ViewObject)
|
|
if baseobj:
|
|
objects = baseobj
|
|
if objects:
|
|
if not isinstance(objects,list):
|
|
objects = [objects]
|
|
if len(objects) == 1:
|
|
obj.Base = objects[0]
|
|
if FreeCAD.GuiUp:
|
|
objects[0].ViewObject.hide()
|
|
else:
|
|
obj.Proxy.addSubobjects(obj,objects)
|
|
return obj
|
|
|
|
|
|
def makeStairs(baseobj=None,length=None,width=None,height=None,steps=None,name=None):
|
|
|
|
"""makeStairs([baseobj],[length],[width],[height],[steps],[name]): creates a Stairs
|
|
objects with given attributes."""
|
|
|
|
import ArchStairs
|
|
if not FreeCAD.ActiveDocument:
|
|
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
|
return
|
|
|
|
stairs = []
|
|
additions = []
|
|
label = name if name else translate("Arch","Stairs")
|
|
|
|
def setProperty(obj,length,width,height,steps):
|
|
if length:
|
|
obj.Length = length
|
|
else:
|
|
obj.Length = params.get_param_arch("StairsLength")
|
|
if width:
|
|
obj.Width = width
|
|
else:
|
|
obj.Width = params.get_param_arch("StairsWidth")
|
|
if height:
|
|
obj.Height = height
|
|
else:
|
|
obj.Height = params.get_param_arch("StairsHeight")
|
|
if steps:
|
|
obj.NumberOfSteps = steps
|
|
obj.Structure = "Massive"
|
|
obj.StructureThickness = 150
|
|
obj.DownSlabThickness = 150
|
|
obj.UpSlabThickness = 150
|
|
|
|
obj.RailingOffsetLeft = 60
|
|
obj.RailingOffsetRight = 60
|
|
obj.RailingHeightLeft = 900
|
|
obj.RailingHeightRight = 900
|
|
|
|
if baseobj:
|
|
if not isinstance(baseobj,list):
|
|
baseobj = [baseobj]
|
|
lenSelection = len(baseobj)
|
|
if lenSelection > 1:
|
|
stair = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Stairs")
|
|
stair.Label = label
|
|
ArchStairs._Stairs(stair)
|
|
stairs.append(stair)
|
|
stairs[0].Label = label
|
|
i = 1
|
|
else:
|
|
i = 0
|
|
for baseobjI in baseobj:
|
|
stair = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Stairs")
|
|
stair.Label = label
|
|
ArchStairs._Stairs(stair)
|
|
stairs.append(stair)
|
|
stairs[i].Label = label
|
|
stairs[i].Base = baseobjI
|
|
|
|
if len(baseobjI.Shape.Edges) > 1:
|
|
stepsI = 1 #'landing' if 'multi-edges' currently
|
|
elif steps:
|
|
stepsI = steps
|
|
else:
|
|
stepsI = 20
|
|
setProperty(stairs[i],None,width,height,stepsI)
|
|
|
|
if i > 1:
|
|
additions.append(stairs[i])
|
|
stairs[i].LastSegment = stairs[i-1]
|
|
else:
|
|
if len(stairs) > 1: # i.e. length >1, have a 'master' staircase created
|
|
stairs[0].Base = stairs[1]
|
|
i += 1
|
|
if lenSelection > 1:
|
|
stairs[0].Additions = additions
|
|
else:
|
|
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Stairs")
|
|
obj.Label = label
|
|
ArchStairs._Stairs(obj)
|
|
setProperty(obj,length,width,height,steps)
|
|
stairs.append(obj)
|
|
if FreeCAD.GuiUp:
|
|
if baseobj:
|
|
for stair in stairs:
|
|
ArchStairs._ViewProviderStairs(stair.ViewObject)
|
|
else:
|
|
ArchStairs._ViewProviderStairs(obj.ViewObject)
|
|
if stairs:
|
|
for stair in stairs:
|
|
stair.recompute()
|
|
makeRailing(stairs)
|
|
# return stairs - all other functions expect one object as return value
|
|
return stairs[0]
|
|
else:
|
|
obj.recompute()
|
|
return obj
|
|
|
|
|
|
def makeRailing(stairs):
|
|
|
|
"simple make Railing function"
|
|
|
|
import ArchPipe
|
|
|
|
def makeRailingLorR(stairs,side="L"):
|
|
for stair in reversed(stairs):
|
|
if side == "L":
|
|
outlineLR = stair.OutlineLeft
|
|
outlineLRAll = stair.OutlineLeftAll
|
|
stairRailingLR = "RailingLeft"
|
|
elif side == "R":
|
|
outlineLR = stair.OutlineRight
|
|
outlineLRAll = stair.OutlineRightAll
|
|
stairRailingLR = "RailingRight"
|
|
if outlineLR or outlineLRAll:
|
|
lrRail = makePipe(baseobj=None,diameter=0,length=0,placement=None,name=translate("Arch","Railing"))
|
|
if outlineLRAll:
|
|
setattr(stair, stairRailingLR, lrRail)
|
|
break
|
|
elif outlineLR:
|
|
setattr(stair, stairRailingLR, lrRail)
|
|
|
|
if stairs is None:
|
|
sel = FreeCADGui.Selection.getSelection()
|
|
sel0 = sel[0]
|
|
stairs = []
|
|
# TODO currently consider 1st selected object, then would tackle multiple objects?
|
|
if Draft.getType(sel[0]) == "Stairs":
|
|
stairs.append(sel0)
|
|
if Draft.getType(sel0.Base) == "Stairs":
|
|
stairs.append(sel0.Base)
|
|
additions = sel0.Additions
|
|
for additionsI in additions:
|
|
if Draft.getType(additionsI) == "Stairs":
|
|
stairs.append(additionsI)
|
|
else:
|
|
stairs.append(sel[0])
|
|
else:
|
|
print("No Stairs object selected")
|
|
return
|
|
|
|
makeRailingLorR(stairs,"L")
|
|
makeRailingLorR(stairs,"R")
|
|
|
|
|
|
def makeTruss(baseobj=None,name=None):
|
|
|
|
"""
|
|
makeTruss([baseobj],[name]): Creates a space object from the given object (a line)
|
|
"""
|
|
|
|
import ArchTruss
|
|
if not FreeCAD.ActiveDocument:
|
|
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
|
return
|
|
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Truss")
|
|
obj.Label = name if name else translate("Arch","Truss")
|
|
ArchTruss.Truss(obj)
|
|
if FreeCAD.GuiUp:
|
|
ArchTruss.ViewProviderTruss(obj.ViewObject)
|
|
if baseobj:
|
|
obj.Base = baseobj
|
|
if FreeCAD.GuiUp:
|
|
baseobj.ViewObject.hide()
|
|
return obj
|
|
|
|
|
|
def makeWall(baseobj=None,height=None,length=None,width=None,align=None,face=None,name=None):
|
|
"""Create a wall based on a given object, and returns the generated wall.
|
|
|
|
TODO: It is unclear what defines which units this function uses.
|
|
|
|
Parameters
|
|
----------
|
|
baseobj: <Part::PartFeature>, optional
|
|
The base object with which to build the wall. This can be a sketch, a
|
|
draft object, a face, or a solid. It can also be left as None.
|
|
height: float, optional
|
|
The height of the wall.
|
|
length: float, optional
|
|
The length of the wall. Not used if the wall is based off an object.
|
|
Will use Arch default if left empty.
|
|
width: float, optional
|
|
The width of the wall. Not used if the base object is a face. Will use
|
|
Arch default if left empty.
|
|
align: str, optional
|
|
Either "Center", "Left", or "Right". Effects the alignment of the wall
|
|
on its baseline.
|
|
face: int, optional
|
|
The index number of a face on the given baseobj, to base the wall on.
|
|
name: str, optional
|
|
The name to give to the created wall.
|
|
|
|
Returns
|
|
-------
|
|
<Part::FeaturePython>
|
|
Returns the generated wall.
|
|
|
|
Notes
|
|
-----
|
|
Creates a new <Part::FeaturePython> object, and turns it into a parametric wall
|
|
object. This <Part::FeaturePython> object does not yet have any shape.
|
|
|
|
The wall then uses the baseobj.Shape as the basis to extrude out a wall shape,
|
|
giving the new <Part::FeaturePython> object a shape.
|
|
|
|
It then hides the original baseobj.
|
|
"""
|
|
|
|
import ArchWall
|
|
import Draft
|
|
from draftutils import params
|
|
if not FreeCAD.ActiveDocument:
|
|
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
|
return
|
|
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Wall")
|
|
if name:
|
|
obj.Label = name
|
|
else:
|
|
obj.Label = translate("Arch","Wall")
|
|
ArchWall._Wall(obj)
|
|
if FreeCAD.GuiUp:
|
|
ArchWall._ViewProviderWall(obj.ViewObject)
|
|
if baseobj:
|
|
if hasattr(baseobj,'Shape') or baseobj.isDerivedFrom("Mesh::Feature"):
|
|
obj.Base = baseobj
|
|
else:
|
|
FreeCAD.Console.PrintWarning(str(translate("Arch","Walls can only be based on Part or Mesh objects")))
|
|
if face:
|
|
obj.Face = face
|
|
if length:
|
|
obj.Length = length
|
|
if width:
|
|
obj.Width = width
|
|
else:
|
|
obj.Width = params.get_param_arch("WallWidth")
|
|
if height:
|
|
obj.Height = height
|
|
else:
|
|
obj.Height = params.get_param_arch("WallHeight")
|
|
if align:
|
|
obj.Align = align
|
|
else:
|
|
obj.Align = ["Center","Left","Right"][params.get_param_arch("WallAlignment")]
|
|
if obj.Base and FreeCAD.GuiUp:
|
|
if Draft.getType(obj.Base) != "Space":
|
|
obj.Base.ViewObject.hide()
|
|
return obj
|
|
|
|
|
|
def joinWalls(walls,delete=False):
|
|
"""Join the given list of walls into one sketch-based wall.
|
|
|
|
Take the first wall in the list, and adds on the other walls in the list.
|
|
Return the modified first wall.
|
|
|
|
Setting delete to True, will delete the other walls. Only join walls
|
|
if the walls have the same width, height and alignment.
|
|
|
|
Parameters
|
|
----------
|
|
walls: list of <Part::FeaturePython>
|
|
List containing the walls to add to the first wall in the list. Walls must
|
|
be based off a base object.
|
|
delete: bool, optional
|
|
If True, deletes the other walls in the list.
|
|
|
|
Returns
|
|
-------
|
|
<Part::FeaturePython>
|
|
"""
|
|
|
|
import Part
|
|
import Draft
|
|
import ArchWall
|
|
if not walls:
|
|
return None
|
|
if not isinstance(walls,list):
|
|
walls = [walls]
|
|
if not ArchWall.areSameWallTypes(walls):
|
|
return None
|
|
deleteList = []
|
|
base = walls.pop()
|
|
if base.Base:
|
|
if base.Base.Shape.Faces:
|
|
return None
|
|
# Use ArchSketch if SketchArch add-on is present
|
|
if Draft.getType(base.Base) == "ArchSketch":
|
|
sk = base.Base
|
|
else:
|
|
try:
|
|
import ArchSketchObject
|
|
newSk=ArchSketchObject.makeArchSketch()
|
|
except:
|
|
if Draft.getType(base.Base) != "Sketcher::SketchObject":
|
|
newSk=FreeCAD.ActiveDocument.addObject("Sketcher::SketchObject","WallTrace")
|
|
else:
|
|
newSk=None
|
|
if newSk:
|
|
sk = Draft.makeSketch(base.Base,autoconstraints=True, addTo=newSk)
|
|
base.Base = sk
|
|
else:
|
|
sk = base.Base
|
|
for w in walls:
|
|
if w.Base:
|
|
if not w.Base.Shape.Faces:
|
|
for e in w.Base.Shape.Edges:
|
|
l = e.Curve
|
|
if isinstance(l,Part.Line):
|
|
l = Part.LineSegment(e.Vertexes[0].Point,e.Vertexes[-1].Point)
|
|
sk.addGeometry(l)
|
|
deleteList.append(w.Name)
|
|
if delete:
|
|
for n in deleteList:
|
|
FreeCAD.ActiveDocument.removeObject(n)
|
|
FreeCAD.ActiveDocument.recompute()
|
|
base.ViewObject.show()
|
|
return base
|
|
|
|
|
|
def makeWindow(baseobj=None,width=None,height=None,parts=None,name=None):
|
|
|
|
'''makeWindow(baseobj,[width,height,parts,name]): creates a window based on the
|
|
given base 2D object (sketch or draft).'''
|
|
|
|
import ArchWindow
|
|
import Draft
|
|
from DraftGui import todo
|
|
if not FreeCAD.ActiveDocument:
|
|
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
|
return
|
|
if baseobj:
|
|
if Draft.getType(baseobj) == "Window":
|
|
obj = Draft.clone(baseobj)
|
|
return obj
|
|
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Window")
|
|
ArchWindow._Window(obj)
|
|
if name:
|
|
obj.Label = name
|
|
else:
|
|
obj.Label = translate("Arch","Window")
|
|
if FreeCAD.GuiUp:
|
|
ArchWindow._ViewProviderWindow(obj.ViewObject)
|
|
if width:
|
|
obj.Width = width
|
|
if height:
|
|
obj.Height = height
|
|
if baseobj:
|
|
obj.Normal = baseobj.Placement.Rotation.multVec(FreeCAD.Vector(0,0,-1))
|
|
obj.Base = baseobj
|
|
if parts is not None:
|
|
obj.WindowParts = parts
|
|
else:
|
|
if baseobj:
|
|
if baseobj.getLinkedObject().isDerivedFrom("Part::Part2DObject"):
|
|
# create default component
|
|
if baseobj.Shape.Wires:
|
|
tp = "Frame"
|
|
if len(baseobj.Shape.Wires) == 1:
|
|
tp = "Solid panel"
|
|
i = 0
|
|
ws = ''
|
|
for w in baseobj.Shape.Wires:
|
|
if w.isClosed():
|
|
if ws: ws += ","
|
|
ws += "Wire" + str(i)
|
|
i += 1
|
|
obj.WindowParts = ["Default",tp,ws,"1","0"]
|
|
else:
|
|
# bind properties from base obj if existing
|
|
for prop in ["Height","Width","Subvolume","Tag","Description","Material"]:
|
|
for p in baseobj.PropertiesList:
|
|
if (p == prop) or p.endswith("_"+prop):
|
|
obj.setExpression(prop, baseobj.Name+"."+p)
|
|
|
|
if obj.Base and FreeCAD.GuiUp:
|
|
obj.Base.ViewObject.DisplayMode = "Wireframe"
|
|
obj.Base.ViewObject.hide()
|
|
todo.delay(ArchWindow.recolorize,[obj.Document.Name,obj.Name])
|
|
return obj
|