Skip to content

Commit

Permalink
Arch: IFC importer can now recreate extrusions
Browse files Browse the repository at this point in the history
By enabling the setting in IFC preferences, the IFC
importer can now detect if an input shape is a normal
extrusion, and create the object as a Part::Extrusion.
  • Loading branch information
yorikvanhavre committed Apr 24, 2015
1 parent 9967bbe commit c692d6e
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 14 deletions.
49 changes: 47 additions & 2 deletions src/Mod/Arch/ArchCommands.py
Expand Up @@ -208,6 +208,10 @@ def makeComponent(baseobj=None,name="Component",delete=False):
obj.Placement = baseobj.Placement
if delete:
FreeCAD.ActiveDocument.removeObject(baseobj.Name)
else:
obj.Base = baseobj
if FreeCAD.GuiUp:
baseobj.ViewObject.hide()
elif isinstance(baseobj,Part.Shape):
obj.Shape = baseobj
return obj
Expand Down Expand Up @@ -897,7 +901,45 @@ def rebuildArchShape(objects=None):
print "Failed"
FreeCAD.ActiveDocument.recompute()


def getExtrusionData(shape):
"""getExtrusionData(shape): returns a base face and an extrusion vector
if this shape can be described as a perpendicular extrusion, or None if not."""
if shape.isNull():
return None
if not shape.Solids:
return None
if len(shape.Faces) < 5:
return None
# build faces list with normals
faces = []
for f in shape.Faces:
faces.append([f,f.normalAt(0,0)])
# find opposite normals pairs
pairs = []
for i1, f1 in enumerate(faces):
for i2, f2 in enumerate(faces):
if f1[0].hashCode() != f2[0].hashCode():
if round(f1[1].getAngle(f2[1]),8) == 3.14159265:
pairs.append([i1,i2])
if not pairs:
return None
for p in pairs:
hc = [faces[p[0]][0].hashCode(),faces[p[1]][0].hashCode()]
ok = True
# check if other normals are all at 90 degrees
for f in faces:
if f[0].hashCode() not in hc:
if round(f[1].getAngle(faces[p[0]][1]),8) != 1.57079633:
ok = False
if ok:
return [faces[p[0]][0],faces[p[1]][0].CenterOfMass.sub(faces[p[0]][0].CenterOfMass)]
return None


# command definitions ###############################################


class _CommandAdd:
"the Arch Add command definition"
def GetResources(self):
Expand Down Expand Up @@ -1053,6 +1095,7 @@ def Activated(self):
for o in sel:
FreeCADGui.Selection.addSelection(o)


class _CommandRemoveShape:
"the Arch RemoveShape command definition"
def GetResources(self):
Expand All @@ -1067,6 +1110,7 @@ def Activated(self):
sel = FreeCADGui.Selection.getSelection()
removeShape(sel)


class _CommandCloseHoles:
"the Arch CloseHoles command definition"
def GetResources(self):
Expand All @@ -1083,6 +1127,7 @@ def Activated(self):
if s:
o.Shape = s


class _CommandCheck:
"the Arch Check command definition"
def GetResources(self):
Expand Down Expand Up @@ -1146,8 +1191,8 @@ def IsActive(self):
def Activated(self):
for o in FreeCADGui.Selection.getSelection():
toggleIfcBrepFlag(o)


class _CommandComponent:
"the Arch Component command definition"
def GetResources(self):
Expand Down
14 changes: 12 additions & 2 deletions src/Mod/Arch/ArchComponent.py
Expand Up @@ -306,7 +306,8 @@ def __init__(self,obj):
obj.Role = Roles

def execute(self,obj):
return
if obj.Base:
obj.Shape = obj.Base.Shape

def __getstate__(self):
return self.Type
Expand Down Expand Up @@ -378,7 +379,13 @@ def getProfiles(self,obj,noplacement=False):
wires = []
n,l,w,h = self.getDefaultValues(obj)
if obj.Base:
if obj.Base.isDerivedFrom("Part::Feature"):
if obj.Base.isDerivedFrom("Part::Extrusion"):
if obj.Base.Base:
base = obj.Base.Base.Shape.copy()
if noplacement:
base.Placement = FreeCAD.Placement()
return [base]
elif obj.Base.isDerivedFrom("Part::Feature"):
if obj.Base.Shape:
base = obj.Base.Shape.copy()
if noplacement:
Expand Down Expand Up @@ -469,6 +476,9 @@ def getProfiles(self,obj,noplacement=False):
def getExtrusionVector(self,obj,noplacement=False):
"Returns an extrusion vector of this component, if applicable"
n,l,w,h = self.getDefaultValues(obj)
if obj.Base:
if obj.Base.isDerivedFrom("Part::Extrusion"):
return obj.Base.Dir
if Draft.getType(obj) == "Structure":
if l > h:
v = n.multiply(l)
Expand Down
20 changes: 20 additions & 0 deletions src/Mod/Arch/Resources/ui/archprefs-import.ui
Expand Up @@ -137,6 +137,26 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="Gui::PrefCheckBox" name="checkBox_2">
<property name="toolTip">
<string>If this is checked, the importer will try to detect extrusions. This might slow things down...</string>
</property>
<property name="text">
<string>Detect extrusions</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>ifcGetExtrusions</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Arch</cstring>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_12">
<item>
Expand Down
34 changes: 24 additions & 10 deletions src/Mod/Arch/importIFC.py
Expand Up @@ -270,11 +270,13 @@ def insert(filename,docname,skip=[],only=[],root=None):
SKIP = p.GetString("ifcSkip","").split(",")
SEPARATE_OPENINGS = p.GetBool("ifcSeparateOpenings",False)
ROOT_ELEMENT = p.GetString("ifcRootElement","IfcProduct")
GET_EXTRUSIONS = p.GetBool("ifcGetExtrusions",False)
if root:
ROOT_ELEMENT = root
MERGE_MODE = p.GetInt("ifcImportMode",0)
if MERGE_MODE > 0:
SEPARATE_OPENINGS = False
GET_EXTRUSIONS = False
if not SEPARATE_OPENINGS:
SKIP.append("IfcOpeningElement")

Expand Down Expand Up @@ -418,13 +420,25 @@ def insert(filename,docname,skip=[],only=[],root=None):
if DEBUG: print shape.Solids
baseobj = shape
else:
baseobj = FreeCAD.ActiveDocument.addObject("Part::Feature",name+"_body")
baseobj.Shape = shape
if GET_EXTRUSIONS:
ex = Arch.getExtrusionData(shape)
if ex:
print "extrusion ",
baseface = FreeCAD.ActiveDocument.addObject("Part::Feature",name+"_footprint")
baseface.Shape = ex[0]
baseobj = FreeCAD.ActiveDocument.addObject("Part::Extrusion",name+"_body")
baseobj.Base = baseface
baseobj.Dir = ex[1]
if FreeCAD.GuiUp:
baseface.ViewObject.hide()
if not baseobj:
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
if DEBUG: print "invalid shape ",
#continue

else:
if DEBUG: print " no brep ",
Expand All @@ -436,6 +450,8 @@ def insert(filename,docname,skip=[],only=[],root=None):
if ptype in ifctypes:
obj = getattr(Arch,"make"+freecadtype)(baseobj=baseobj,name=name)
obj.Label = name
if FreeCAD.GuiUp and baseobj:
baseobj.ViewObject.hide()
# setting role
try:
r = ptype[3:]
Expand All @@ -455,7 +471,7 @@ def insert(filename,docname,skip=[],only=[],root=None):
obj.IfcAttributes = a
break
if not obj:
obj = Arch.makeComponent(baseobj,name=name,delete=True)
obj = Arch.makeComponent(baseobj,name=name)
if obj:
sols = str(obj.Shape.Solids) if hasattr(obj,"Shape") else "[]"
if DEBUG: print sols
Expand All @@ -469,7 +485,7 @@ def insert(filename,docname,skip=[],only=[],root=None):
if ptype in ifctypes:
obj = getattr(Arch,"make"+freecadtype)(baseobj=None,name=name)
elif baseobj:
obj = Arch.makeComponent(baseobj,name=name)
obj = Arch.makeComponent(baseobj,name=name,delete=True)

elif MERGE_MODE == 2:

Expand Down Expand Up @@ -545,7 +561,7 @@ def insert(filename,docname,skip=[],only=[],root=None):
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
if DEBUG: print "subtracting ",objects[subtraction[0]].Label, " from ", objects[subtraction[1]].Label
Arch.removeComponents(objects[subtraction[0]],objects[subtraction[1]])
if DEBUG: FreeCAD.ActiveDocument.recompute()

Expand All @@ -558,14 +574,12 @@ def insert(filename,docname,skip=[],only=[],root=None):
# avoid huge fusions
print "more than 10 shapes to add: skipping."
else:
if DEBUG: print "adding ",cobs, " to ", objects[host].Name
if DEBUG: print "adding ",len(cobs), " object(s) to ", objects[host].Label
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"):
Expand Down

0 comments on commit c692d6e

Please sign in to comment.