freecad-cam/Mod/BIM/Arch.py
2026-02-01 01:59:24 +01:00

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