Arch: Misc improvements for IFC workflow

* Added utility to make non-parametric Arch component
* Ability for all Arch components to be a clone of another Arch component of same type
* Modified the Draft Clone tool to produce Arch Clones if applicable
* Fixed Arch Roofs so they can be based on a solid shape like other Arch objects
* Ability to change the Root element to be imported in IFC preferences
* Ability to import IFC files also as compounds, Part shapes or non-parametric Arch objects
* Added an "only" parameter to importIFC.open() to import only a certain object ID.
* Ability to read colors (IfcSurfaceStyle) from IFC objects
This commit is contained in:
Yorik van Havre 2015-04-08 12:34:48 -03:00
parent 694b0339fd
commit 892b7ae509
18 changed files with 579 additions and 98 deletions

View File

@ -192,6 +192,23 @@ def removeComponents(objectsList,host=None):
if o in a:
a.remove(o)
h.Objects = a
def makeComponent(baseobj=None,name="Component"):
'''makeComponent([baseobj]): creates an undefined, non-parametric Arch
component from the given base object'''
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name)
obj.Label = translate("Arch",name)
ArchComponent.Component(obj)
if FreeCAD.GuiUp:
ArchComponent.ViewProviderComponent(obj.ViewObject)
if baseobj:
import Part
if baseobj.isDerivedFrom("Part::Feature"):
obj.Shape = baseobj.Shape
obj.Placement = baseobj.Placement
elif isinstance(baseobj,Part.Shape):
obj.Shape = baseobj
return obj
def fixWindow(obj):
'''fixWindow(object): Fixes non-DAG problems in windows
@ -1114,6 +1131,29 @@ class _ToggleIfcBrepFlag:
def Activated(self):
for o in FreeCADGui.Selection.getSelection():
toggleIfcBrepFlag(o)
class _CommandComponent:
"the Arch Component command definition"
def GetResources(self):
return {'Pixmap' : 'Arch_Component',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Arch_Component","Component"),
'Accel': "C, M",
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_Component","Creates an undefined architectural component")}
def IsActive(self):
return not FreeCAD.ActiveDocument is None
def Activated(self):
sel = FreeCADGui.Selection.getSelection()
if sel:
FreeCAD.ActiveDocument.openTransaction(translate("Arch","Create Component"))
FreeCADGui.addModule("Arch")
FreeCADGui.Control.closeDialog()
for o in sel:
FreeCADGui.doCommand("Arch.makeComponent(FreeCAD.ActiveDocument."+o.Name+")")
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()
if FreeCAD.GuiUp:
@ -1128,3 +1168,4 @@ if FreeCAD.GuiUp:
FreeCADGui.addCommand('Arch_IfcExplorer',_CommandIfcExplorer())
FreeCADGui.addCommand('Arch_Survey',_CommandSurvey())
FreeCADGui.addCommand('Arch_ToggleIfcBrepFlag',_ToggleIfcBrepFlag())
FreeCADGui.addCommand('Arch_Component',_CommandComponent())

View File

@ -40,6 +40,7 @@ if FreeCAD.GuiUp:
else:
def translate(ctxt,txt):
return txt
def addToComponent(compobject,addobject,mod=None):
'''addToComponent(compobject,addobject,mod): adds addobject
@ -132,8 +133,8 @@ class SelectionTaskPanel:
FreeCADGui.Selection.removeObserver(FreeCAD.ArchObserver)
del FreeCAD.ArchObserver
return True
class ComponentTaskPanel:
'''The default TaskPanel for all Arch components'''
def __init__(self):
@ -289,6 +290,7 @@ class Component:
"The default Arch Component object"
def __init__(self,obj):
obj.addProperty("App::PropertyLink","Base","Arch",translate("Arch","The base object this component is built upon"))
obj.addProperty("App::PropertyLink","CloneOf","Arch",translate("Arch","The object this component is cloning"))
obj.addProperty("App::PropertyLinkList","Additions","Arch",translate("Arch","Other shapes that are appended to this object"))
obj.addProperty("App::PropertyLinkList","Subtractions","Arch",translate("Arch","Other shapes that are subtracted from this object"))
obj.addProperty("App::PropertyString","Description","Arch",translate("Arch","An optional description for this component"))
@ -316,6 +318,17 @@ class Component:
def onChanged(self,obj,prop):
pass
def clone(self,obj):
"if this object is a clone, sets the shape. Returns True if this is the case"
if hasattr(obj,"CloneOf"):
if obj.CloneOf:
if Draft.getType(obj.CloneOf) == Draft.getType(obj):
pl = obj.Placement
obj.Shape = obj.CloneOf.Shape.copy()
obj.Placement = pl
return True
return False
def getSiblings(self,obj):
"returns a list of objects with the same type and same base as this object"
if not hasattr(obj,"Base"):
@ -642,6 +655,10 @@ class ViewProviderComponent:
def updateData(self,obj,prop):
return
def getIcon(self):
import Arch_rc
return ":/icons/Arch_Component.svg"
def onChanged(self,vobj,prop):
if prop == "Visibility":

View File

@ -248,6 +248,10 @@ class _Equipment(ArchComponent.Component):
self.hideSubobjects(obj,prop)
def execute(self,obj):
if self.clone(obj):
return
pl = obj.Placement
if obj.Base:
if obj.isDerivedFrom("Mesh::Feature"):

View File

@ -90,6 +90,10 @@ class _Frame(ArchComponent.Component):
obj.Role = Roles
def execute(self,obj):
if self.clone(obj):
return
if not obj.Base:
return
if not obj.Base.Shape:

View File

@ -265,6 +265,9 @@ class _Panel(ArchComponent.Component):
def execute(self,obj):
"creates the panel shape"
if self.clone(obj):
return
import Part, DraftGeomUtils

View File

@ -158,6 +158,10 @@ class _Rebar(ArchComponent.Component):
return None,None
def execute(self,obj):
if self.clone(obj):
return
if len(obj.InList) != 1:
return
if Draft.getType(obj.InList[0]) != "Structure":

View File

@ -35,19 +35,28 @@ __title__="FreeCAD Roof"
__author__ = "Yorik van Havre", "Jonathan Wiedemann"
__url__ = "http://www.freecadweb.org"
def makeRoof(baseobj=None,facenr=1, angles=[45.,], run = [], idrel = [0,],thickness = [1.,], overhang=[2.,], name="Roof"):
def makeRoof(baseobj=None,facenr=0, angles=[45.,], run = [], idrel = [0,],thickness = [1.,], overhang=[2.,], name="Roof"):
'''makeRoof(baseobj,[facenr],[angle],[name]) : Makes a roof based on a closed wire.
face from an existing object. You can provide a list of angles, run, idrel, thickness,
overhang for each edges in the wire to define the roof shape. The default for angle is 45
and the list is automatically complete to match with number of edges in the wire.'''
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name)
obj.Label = translate("Arch",name)
w = None
_Roof(obj)
if FreeCAD.GuiUp:
_ViewProviderRoof(obj.ViewObject)
if baseobj:
obj.Base = baseobj
if obj.Base.isDerivedFrom("Part::Feature"):
if (facenr == 0) and obj.Base.Shape.Solids:
# the base shape is a solid and facenr hasn't been set:
# assume its shape is copied over
if FreeCAD.GuiUp:
obj.Base.ViewObject.hide()
else:
# set facenr to 1
facenr = 1
if (obj.Base.Shape.Faces and obj.Face):
w = obj.Base.Shape.Faces[obj.Face-1].Wires[0]
elif obj.Base.Shape.Wires:
@ -509,6 +518,10 @@ class _Roof(ArchComponent.Component):
print("PROFIL " + str(i) + " : End calculs")
def execute(self,obj):
if self.clone(obj):
return
import Part, math, DraftGeomUtils
pl = obj.Placement
self.baseface = None

View File

@ -236,6 +236,10 @@ class _Space(ArchComponent.Component):
obj.Role = Roles
def execute(self,obj):
if self.clone(obj):
return
self.getShape(obj)
def onChanged(self,obj,prop):

View File

@ -130,7 +130,10 @@ class _Stairs(ArchComponent.Component):
def execute(self,obj):
"constructs the shape of the stairs"
if self.clone(obj):
return
import Part
self.steps = []
self.pseudosteps = []

View File

@ -577,6 +577,9 @@ class _Structure(ArchComponent.Component):
"creates the structure shape"
import Part, DraftGeomUtils
if self.clone(obj):
return
normal,length,width,height = self.getDefaultValues(obj)

View File

@ -402,6 +402,9 @@ class _Wall(ArchComponent.Component):
def execute(self,obj):
"builds the wall shape"
if self.clone(obj):
return
import Part, DraftGeomUtils
pl = obj.Placement

View File

@ -636,6 +636,10 @@ class _Window(ArchComponent.Component):
def execute(self,obj):
if self.clone(obj):
return
import Part, DraftGeomUtils
pl = obj.Placement
base = None

View File

@ -75,7 +75,7 @@ class ArchWorkbench(Workbench):
"Arch_SectionPlane","Arch_Space","Arch_Stairs",
"Arch_Panel","Arch_Equipment",
"Arch_Frame","Arch_CutPlane","Arch_Add","Arch_Remove","Arch_Survey"]
self.utilities = ["Arch_SplitMesh","Arch_MeshToShape",
self.utilities = ["Arch_Component","Arch_SplitMesh","Arch_MeshToShape",
"Arch_SelectNonSolidMeshes","Arch_RemoveShape",
"Arch_CloseHoles","Arch_MergeWalls","Arch_Check",
"Arch_IfcExplorer","Arch_ToggleIfcBrepFlag","Arch_3Views",

View File

@ -53,6 +53,7 @@
<file>icons/Arch_CutPlane.svg</file>
<file>icons/Arch_Bimserver.svg</file>
<file>icons/Git.svg</file>
<file>icons/Arch_Component.svg</file>
<file>ui/archprefs-base.ui</file>
<file>ui/archprefs-defaults.ui</file>
<file>ui/archprefs-import.ui</file>

View File

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg2980"
sodipodi:version="0.32"
inkscape:version="0.48.5 r10040"
sodipodi:docname="Tree_Part.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1">
<defs
id="defs2982">
<linearGradient
id="linearGradient3864">
<stop
id="stop3866"
offset="0"
style="stop-color:#71b2f8;stop-opacity:1;" />
<stop
id="stop3868"
offset="1"
style="stop-color:#002795;stop-opacity:1;" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="64 : 32 : 1"
inkscape:persp3d-origin="32 : 21.333333 : 1"
id="perspective2988" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.5"
inkscape:cx="3"
inkscape:cy="32.181818"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1920"
inkscape:window-height="1053"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata2985">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
id="g3845"
transform="matrix(0.9624254,0,0,0.9624254,-63.864287,-126.15825)"
style="fill:#ffffff;fill-opacity:1">
<path
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:bevel;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 96.18444,141.44968 L 76.37003,148.62889 L 105.80493,152.60098 L 105.08136,188.72763 L 122.34017,177.78375 L 122.91604,143.3989 L 96.18444,141.44968 z"
id="path3823"
sodipodi:nodetypes="ccccccc" />
<path
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:bevel;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 75.57941,148.6589 L 106.28825,152.02452 L 106.28825,188.50171 L 75.16442,183.43692 L 75.57941,148.6589 z"
id="path3825"
sodipodi:nodetypes="ccccc" />
<path
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 106.05435,152.06948 L 122.78033,143.66068"
id="path3827" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>503</width>
<height>526</height>
<width>463</width>
<height>516</height>
</rect>
</property>
<property name="windowTitle">
@ -26,12 +26,83 @@
<string>IFC import</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Import IFC objects as</string>
</property>
</widget>
</item>
<item>
<widget class="Gui::PrefComboBox" name="comboBox">
<property name="toolTip">
<string>Specifies what kind of objects will be created in FreeCAD</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>ifcImportMode</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Arch</cstring>
</property>
<item>
<property name="text">
<string>Parametric Arch objects</string>
</property>
</item>
<item>
<property name="text">
<string>Non-parametric Arch objects</string>
</property>
</item>
<item>
<property name="text">
<string>Simple Part shapes</string>
</property>
</item>
<item>
<property name="text">
<string>One compound per floor</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Root element:</string>
</property>
</widget>
</item>
<item>
<widget class="Gui::PrefLineEdit" name="lineEdit_2">
<property name="toolTip">
<string>Only subtypes of this element will be imported. Keep value as &quot;IfcProduct&quot; to import all building elements.</string>
</property>
<property name="text">
<string>IfcProduct</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>ifcRootElement</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Arch</cstring>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<widget class="Gui::PrefCheckBox" name="gui::prefcheckbox_5">
<property name="toolTip">
<string>Check this to display debug messages while importing IFC files</string>
<string>Show verbose information during import and export of IFC files</string>
</property>
<property name="text">
<string>Show debug messages</string>
@ -86,6 +157,29 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="Gui::PrefCheckBox" name="checkBox_3">
<property name="toolTip">
<string>Check this to retrieve object colors.</string>
</property>
<property name="text">
<string>Read colors</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>ifcReadColors</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Arch</cstring>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_13">
<item>
@ -125,6 +219,17 @@
<string>IFC export</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>&quot;Show debug messages&quot; option above will apply to export too</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
@ -250,6 +355,11 @@
<extends>QCheckBox</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
<customwidget>
<class>Gui::PrefComboBox</class>
<extends>QComboBox</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
<customwidget>
<class>Gui::PrefLineEdit</class>
<extends>QLineEdit</extends>

View File

@ -246,24 +246,36 @@ def explore(filename=None):
return
def open(filename,skip=[]):
def open(filename,skip=[],only=[],root=None):
"opens an IFC file in a new document"
docname = os.path.splitext(os.path.basename(filename))[0]
doc = FreeCAD.newDocument(docname)
doc.Label = docname
doc = insert(filename,doc.Name,skip)
doc = insert(filename,doc.Name,skip,only,root)
return doc
def insert(filename,docname,skip=[]):
"imports the contents of an IFC file"
def insert(filename,docname,skip=[],only=[],root=None):
"""insert(filename,docname,skip=[],only=[],root=None): imports the contents of an IFC file.
skip can contain a list of ids of objects to be skipped, only can restrict the import to
certain object ids (will also get their children) and root can be used to
import only the derivates of a certain element type (default = ifcProduct)."""
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch")
DEBUG = p.GetBool("ifcDebug",False)
PREFIX_NUMBERS = p.GetBool("ifcPrefixNumbers",False)
SKIP = p.GetString("ifcSkip","")
SKIP = p.GetString("ifcSkip","").split(",")
SEPARATE_OPENINGS = p.GetBool("ifcSeparateOpenings",False)
ROOT_ELEMENT = p.GetString("ifcRootElement","IfcProduct")
if root:
ROOT_ELEMENT = root
MERGE_MODE = p.GetInt("ifcImportMode",0)
if MERGE_MODE > 0:
SEPARATE_OPENINGS = False
READ_COLORS = p.GetBool("ifcReadColors",True)
if not SEPARATE_OPENINGS:
SKIP.append("IfcOpeningElement")
try:
import ifcopenshell
@ -271,13 +283,15 @@ def insert(filename,docname,skip=[]):
FreeCAD.Console.PrintError("IfcOpenShell was not found on this system. IFC support is disabled\n")
return
if DEBUG: print "opening ",filename,"..."
if DEBUG: print "Opening ",filename,"...",
try:
doc = FreeCAD.getDocument(docname)
except:
doc = FreeCAD.newDocument(docname)
FreeCAD.ActiveDocument = doc
if DEBUG: print "done."
global ifcfile # keeping global for debugging purposes
if isinstance(filename,unicode):
import sys #workaround since ifcopenshell currently can't handle unicode filenames
@ -293,15 +307,19 @@ def insert(filename,docname,skip=[]):
sites = ifcfile.by_type("IfcSite")
buildings = ifcfile.by_type("IfcBuilding")
floors = ifcfile.by_type("IfcBuildingStorey")
products = ifcfile.by_type("IfcProduct")
products = ifcfile.by_type(ROOT_ELEMENT)
openings = ifcfile.by_type("IfcOpeningElement")
annotations = ifcfile.by_type("IfcAnnotation")
if DEBUG: print "Building relationships table...",
# building relations tables
objects = {} # { id:object, ... }
additions = {} # { host:[child,...], ... }
subtractions = [] # [ [opening,host], ... ]
properties = {} # { host:[property, ...], ... }
colors = {} # { id:(r,g,b) }
shapes = {} # { id:shaoe } only used for merge mode
for r in ifcfile.by_type("IfcRelContainedInSpatialStructure"):
additions.setdefault(r.RelatingStructure.id(),[]).extend([e.id() for e in r.RelatedElements])
for r in ifcfile.by_type("IfcRelAggregates"):
@ -312,101 +330,239 @@ def insert(filename,docname,skip=[]):
for obj in r.RelatedObjects:
if r.RelatingPropertyDefinition.is_a("IfcPropertySet"):
properties.setdefault(obj.id(),[]).extend([e.id() for e in r.RelatingPropertyDefinition.HasProperties])
if READ_COLORS:
for r in ifcfile.by_type("IfcStyledItem"):
if r.Item and r.Styles[0].is_a("IfcPresentationStyleAssignment"):
if r.Styles[0].Styles[0].is_a("IfcSurfaceStyle"):
if r.Styles[0].Styles[0].Styles[0].is_a("IfcSurfaceStyleRendering"):
if r.Styles[0].Styles[0].Styles[0].SurfaceColour:
c = r.Styles[0].Styles[0].Styles[0].SurfaceColour
for p in ifcfile.by_type("IfcProduct"):
if p.Representation:
for it in p.Representation.Representations:
if it.Items:
if it.Items[0].id() == r.Item.id():
colors[p.id()] = (c.Red,c.Green,c.Blue)
elif it.Items[0].is_a("IfcBooleanResult"):
if (it.Items[0].FirstOperand.id() == r.Item.id()):
colors[p.id()] = (c.Red,c.Green,c.Blue)
if only: # only import a list of IDs and their children
ids = []
while only:
currentid = only.pop()
ids.append(currentid)
if currentid in additions.keys():
only.extend(additions[currentid])
products = [ifcfile[currentid] for currentid in ids]
if DEBUG: print "done."
count = 0
from FreeCAD import Base
progressbar = Base.ProgressIndicator()
progressbar.start("Importing IFC objects...",len(products))
# products
for product in products:
pid = product.id()
guid = product.GlobalId
ptype = product.is_a()
if DEBUG: print count,"/",len(products)," creating object ",pid," : ",ptype,
name = product.Name or str(ptype[3:])
if PREFIX_NUMBERS: name = "ID" + str(pid) + " " + name
obj = None
baseobj = None
brep = None
if (ptype == "IfcOpeningElement") and (not SEPARATE_OPENINGS): continue
if pid in skip: continue # user given id skip list
if ptype in SKIP: continue # preferences-set type skip list
if pid in skip: # user given id skip list
if DEBUG: print " skipped."
continue
if ptype in SKIP: # preferences-set type skip list
if DEBUG: print " skipped."
continue
try:
cr = ifcopenshell.geom.create_shape(settings,product)
brep = cr.geometry.brep_data
except:
pass
pass # IfcOpenShell will yield an error if a given product has no shape, but we don't care
if brep:
if DEBUG: print " ",str(len(brep)/1000),"k ",
shape = Part.Shape()
shape.importBrepFromString(brep)
shape.scale(1000.0) # IfcOpenShell always outputs in meters
if not shape.isNull():
baseobj = FreeCAD.ActiveDocument.addObject("Part::Feature",name+"_body")
baseobj.Shape = shape
for freecadtype,ifctypes in typesmap.iteritems():
if ptype in ifctypes:
obj = getattr(Arch,"make"+freecadtype)(baseobj=baseobj,name=name)
if MERGE_MODE > 0:
if ptype == "IfcSpace": # do not add spaces to compounds
if DEBUG: print "skipping space ",pid
else:
shapes[pid] = shape
if DEBUG: print shape.Solids
baseobj = shape
else:
baseobj = FreeCAD.ActiveDocument.addObject("Part::Feature",name+"_body")
baseobj.Shape = shape
else:
if DEBUG: print "null shape ",
if not shape.isValid():
if DEBUG: print "invalid shape. Skipping"
continue
else:
if DEBUG: print " no brep "
if MERGE_MODE == 0:
# full Arch objects
for freecadtype,ifctypes in typesmap.items():
if ptype in ifctypes:
obj = getattr(Arch,"make"+freecadtype)(baseobj=baseobj,name=name)
obj.Label = name
# setting role
try:
r = ptype[3:]
tr = dict((v,k) for k, v in translationtable.iteritems())
if r in tr.keys():
r = tr[r]
# remove the "StandardCase"
if "StandardCase" in r:
r = r[:-12]
obj.Role = r
except:
pass
# setting uid
if hasattr(obj,"IfcAttributes"):
a = obj.IfcAttributes
a["IfcUID"] = str(guid)
obj.IfcAttributes = a
break
if not obj:
obj = baseobj
if obj:
sols = str(baseobj.Shape.Solids) if hasattr(baseobj,"Shape") else "[]"
if DEBUG: print sols
objects[pid] = obj
elif MERGE_MODE == 1:
# non-parametric Arch objects
if ptype in ["IfcSite","IfcBuilding","IfcBuildingStorey"]:
for freecadtype,ifctypes in typesmap.items():
if ptype in ifctypes:
obj = getattr(Arch,"make"+freecadtype)(baseobj=None,name=name)
obj.Label = name
objects[pid] = obj
elif baseobj:
obj = Arch.makeComponent(baseobj,name=name)
obj.Label = name
# setting role
try:
r = ptype[3:]
tr = dict((v,k) for k, v in translationtable.iteritems())
if r in tr.keys():
r = tr[r]
# remove the "StandardCase"
if "StandardCase" in r:
r = r[:-12]
obj.Role = r
except:
pass
# setting uid
objects[pid] = obj
elif MERGE_MODE == 2:
# Part shapes
if ptype in ["IfcSite","IfcBuilding","IfcBuildingStorey"]:
for freecadtype,ifctypes in typesmap.items():
if ptype in ifctypes:
obj = getattr(Arch,"make"+freecadtype)(baseobj=None,name=name)
obj.Label = name
objects[pid] = obj
elif baseobj:
obj = FreeCAD.ActiveDocument.addObject("Part::Feature",name)
obj.Label = name
obj.Shape = shape
if obj:
# properties
if pid in properties:
if hasattr(obj,"IfcAttributes"):
a = obj.IfcAttributes
a["IfcUID"] = str(guid)
for p in properties[pid]:
o = ifcfile[p]
if o.is_a("IfcPropertySingleValue"):
a[o.Name] = str(o.NominalValue)
obj.IfcAttributes = a
break
if not obj:
obj = baseobj
if obj:
sh = baseobj.Shape.ShapeType if hasattr(baseobj,"Shape") else "None"
sols = str(baseobj.Shape.Solids) if hasattr(baseobj,"Shape") else ""
pc = str(int((float(count)/(len(products)+len(annotations))*100)))+"% "
if DEBUG: print pc,"creating object ",pid," : ",ptype, " with shape: ",sh," ",sols
objects[pid] = obj
# properties
if pid in properties:
if hasattr(obj,"IfcAttributes"):
a = obj.IfcAttributes
for p in properties[pid]:
o = ifcfile[p]
if o.is_a("IfcPropertySingleValue"):
a[o.Name] = str(o.NominalValue)
obj.IfcAttributes = a
# color
if FreeCAD.GuiUp and (pid in colors):
if DEBUG: print " setting color: ",colors[pid]
obj.ViewObject.ShapeColor = colors[pid]
# if DEBUG is on, recompute after each shape
if DEBUG: FreeCAD.ActiveDocument.recompute()
count += 1
progressbar.next()
progressbar.stop()
FreeCAD.ActiveDocument.recompute()
if DEBUG: print "Processing relationships..."
if MERGE_MODE == 3:
if DEBUG: print "Joining shapes..."
for host,children in additions.items():
if ifcfile[host].is_a("IfcBuildingStorey"):
compound = []
for c in children:
if c in shapes.keys():
compound.append(shapes[c])
del shapes[c]
if c in additions.keys():
for c2 in additions[c]:
if c2 in shapes.keys():
compound.append(shapes[c2])
del shapes[c2]
if compound:
name = ifcfile[host].Name or "Floor"
if PREFIX_NUMBERS: name = "ID" + str(host) + " " + name
obj = FreeCAD.ActiveDocument.addObject("Part::Feature",name)
obj.Label = name
obj.Shape = Part.makeCompound(compound)
if shapes: # remaining shapes
obj = FreeCAD.ActiveDocument.addObject("Part::Feature","Unclaimed")
obj.Shape = Part.makeCompound(shapes.values())
# subtractions
if SEPARATE_OPENINGS:
for subtraction in subtractions:
if (subtraction[0] in objects.keys()) and (subtraction[1] in objects.keys()):
#print objects[subtraction[0]].Name, objects[subtraction[1]].Name
Arch.removeComponents(objects[subtraction[0]],objects[subtraction[1]])
# additions
for host,children in additions.iteritems():
if host in objects.keys():
cobs = [objects[child] for child in children if child in objects.keys()]
if cobs:
Arch.addComponents(cobs,objects[host])
FreeCAD.ActiveDocument.recompute()
else:
# cleaning bad shapes
for obj in objects.values():
if obj.isDerivedFrom("Part::Feature"):
if obj.Shape.isNull():
Arch.rebuildArchShape(obj)
if DEBUG: print "Processing relationships..."
# subtractions
if SEPARATE_OPENINGS:
for subtraction in subtractions:
if (subtraction[0] in objects.keys()) and (subtraction[1] in objects.keys()):
if DEBUG: print "subtracting ",objects[subtraction[0]].Name, " from ", objects[subtraction[1]].Name
Arch.removeComponents(objects[subtraction[0]],objects[subtraction[1]])
if DEBUG: FreeCAD.ActiveDocument.recompute()
# additions
for host,children in additions.items():
if host in objects.keys():
cobs = [objects[child] for child in children if child in objects.keys()]
if cobs:
if DEBUG and (len(cobs) > 10) and ( not(Draft.getType(objects[host]) in ["Site","Building","Floor"])):
# avoid huge fusions
print "more than 10 shapes to add: skipping."
else:
if DEBUG: print "adding ",cobs, " to ", objects[host].Name
Arch.addComponents(cobs,objects[host])
if DEBUG: FreeCAD.ActiveDocument.recompute()
FreeCAD.ActiveDocument.recompute()
if DEBUG: print "Cleaning..."
# cleaning bad shapes
for obj in objects.values():
if obj.isDerivedFrom("Part::Feature"):
if obj.Shape.isNull():
Arch.rebuildArchShape(obj)
FreeCAD.ActiveDocument.recompute()
@ -433,10 +589,11 @@ def insert(filename,docname,skip=[]):
count += 1
FreeCAD.ActiveDocument.recompute()
if FreeCAD.GuiUp:
import FreeCADGui
FreeCADGui.SendMsgToActiveView("ViewFit")
print "Finished importing."
return doc
@ -552,7 +709,7 @@ def export(exportList,filename):
elif ifctype == "IfcBuilding":
args = args + ["ELEMENT",None,None,None]
elif ifctype == "IfcBuildingStorey":
args = args + ["ELEMENT",None]
args = args + ["ELEMENT",obj.Placement.Base.z]
# creating the product
product = getattr(ifcfile,"create"+ifctype)(*args)
@ -580,22 +737,26 @@ def export(exportList,filename):
for key in obj.IfcAttributes:
if not (key in ["IfcUID","FlagForceBrep"]):
r = obj.IfcAttributes[key].strip(")").split("(")
tp = r[0]
val = "(".join(r[1:])
val = val.strip("'")
val = val.strip('"')
if DEBUG: print " property ",key," : ",str(val), " (", str(tp), ")"
if tp in ["IfcLabel","IfcText","IfcIdentifier"]:
val = str(val)
elif tp == "IfcBoolean":
if val == ".T.":
val = True
else:
val = False
elif tp == "IfcInteger":
val = int(val)
if len(r) == 1:
tp = "IfcText"
val = r[0]
else:
val = float(val)
tp = r[0]
val = "(".join(r[1:])
val = val.strip("'")
val = val.strip('"')
if DEBUG: print " property ",key," : ",str(val), " (", str(tp), ")"
if tp in ["IfcLabel","IfcText","IfcIdentifier"]:
val = str(val)
elif tp == "IfcBoolean":
if val == ".T.":
val = True
else:
val = False
elif tp == "IfcInteger":
val = int(val)
else:
val = float(val)
props.append(ifcfile.createIfcPropertySingleValue(str(key),None,ifcfile.create_entity(str(tp),val),None))
if props:
pset = ifcfile.createIfcPropertySet(ifcopenshell.guid.compress(uuid.uuid1().hex),history,'PropertySet',None,props)
@ -781,8 +942,11 @@ def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tess
for fcface in fcsolid.Faces:
for e in fcface.Edges:
if not isinstance(e.Curve,Part.Line):
curves = True
if e.curvatureAt(e.FirstParameter+(e.LastParameter-e.FirstParameter)/2) > 0.0001:
curves = True
break
if curves:
shapetype = "triangulated"
tris = fcsolid.tessellate(tessellation)
for tri in tris[1]:
pts = [ifcfile.createIfcCartesianPoint(tuple(tris[0][i])) for i in tri]
@ -791,6 +955,7 @@ def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tess
face = ifcfile.createIfcFace([bound])
faces.append(face)
else:
shapetype = "brep"
for fcface in fcsolid.Faces:
loops = []
verts = [v.Point for v in Part.Wire(DraftGeomUtils.sortEdges(fcface.OuterWire.Edges)).Vertexes]
@ -820,7 +985,6 @@ def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tess
shell = ifcfile.createIfcClosedShell(faces)
shape = ifcfile.createIfcFacetedBrep(shell)
shapes.append(shape)
shapetype = "brep"
if shapes:

View File

@ -2430,6 +2430,13 @@ def clone(obj,delta=None):
if (len(obj) == 1) and obj[0].isDerivedFrom("Part::Part2DObject"):
cl = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython","Clone2D")
cl.Label = "Clone of " + obj[0].Label + " (2D)"
elif (len(obj) == 1) and hasattr(obj[0],"IfcAttributes"):
# arch objects can be clones
import Arch
cl = getattr(Arch,"make"+obj[0].Proxy.Type)()
cl.Label = "Clone of " + obj[0].Label
cl.CloneOf = obj[0]
return cl
else:
cl = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Clone")
cl.Label = "Clone of " + obj[0].Label