Merge branch 'master' of ssh://git.code.sf.net/p/free-cad/code

This commit is contained in:
wmayer 2014-07-20 17:45:54 +02:00
commit 86a69f830e
11 changed files with 246 additions and 202 deletions

View File

@ -455,7 +455,6 @@ else(FREECAD_LIBPACK_USE)
TKXDESTEP
TKXDEIGES
TKMeshVS
TKAdvTools
)
set(OCC_INCLUDE_DIR ${OCE_INCLUDE_DIRS})
set(OCC_FOUND ${OCE_FOUND})

View File

@ -89,7 +89,6 @@ IF(OCC_LIBRARY)
TKXDESTEP
TKXDEIGES
TKMeshVS
TKAdvTools
)
ENDIF(OCC_LIBRARY)

View File

@ -21,7 +21,7 @@ endif
#AM_LDFLAGS = -version-info 1:0:0 -Wl,--no-undefined -L$(OCC_LIB)
AM_LDFLAGS = -version-info 1:0:0 -L$(OCC_LIB) \
-lTKernel -lTKService -lTKMath -lTKBRep -lTKTopAlgo -lTKGeomAlgo \
-lTKGeomBase -lTKG3d -lTKG2d -lTKMeshVS -lTKShHealing -lTKPrim -lTKAdvTools
-lTKGeomBase -lTKG3d -lTKG2d -lTKMeshVS -lTKShHealing -lTKPrim
#uninstall-local:
# -rm -rf $(DESTDIR)$(libdir)

View File

@ -26,12 +26,17 @@
#ifndef SMESH_IndexedMapOfShape_HeaderFile
#define SMESH_IndexedMapOfShape_HeaderFile
#include "Standard_Version.hxx"
#include "SMESH_SMESH.hxx"
#include "SMESHDS_DataMapOfShape.hxx"
#ifndef __BORLANDC__
#if OCC_VERSION_HEX >= 0x060703
#include <NCollection_IndexedMap.hxx>
#else
#include <NCollection_DefineIndexedMap.hxx>
#endif
#else
#include <SMESH_DefineIndexedMap.hxx>
#endif
@ -40,27 +45,42 @@
/// Class SMESH_IndexedMapOfShape
DEFINE_BASECOLLECTION (SMESH_BaseCollectionShape, TopoDS_Shape)
#if OCC_VERSION_HEX >= 0x060703
#ifndef __BORLANDC__
DEFINE_INDEXEDMAP (SMESH_IndexedMapOfShape, SMESH_BaseCollectionShape, TopoDS_Shape)
typedef NCollection_IndexedMap<TopoDS_Shape> SMESH_IndexedMapOfShape;
#else
DEFINE_BASECOLLECTION (SMESH_BaseCollectionShape, TopoDS_Shape)
SMESH_DEFINE_INDEXEDMAP (SMESH_IndexedMapOfShape, SMESH_BaseCollectionShape, TopoDS_Shape)
#endif
#else
DEFINE_INDEXEDMAP (SMESH_IndexedMapOfShape, SMESH_BaseCollectionShape, TopoDS_Shape)
#endif
#endif
#endif
#ifndef SMESH_IndexedDataMapOfShapeIndexedMapOfShape_HeaderFile
#define SMESH_IndexedDataMapOfShapeIndexedMapOfShape_HeaderFile
#if OCC_VERSION_HEX >= 0x060703
#include <NCollection_IndexedDataMap.hxx>
#else
#include <NCollection_DefineIndexedDataMap.hxx>
#endif
/// Class SMESH_IndexedDataMapOfShapeIndexedMapOfShape
#if OCC_VERSION_HEX >= 0x060703
typedef NCollection_IndexedDataMap<SMESH_IndexedMapOfShape,TopoDS_Shape> SMESH_IndexedDataMapOfShapeIndexedMapOfShape;
#else
#include <NCollection_DefineIndexedDataMap.hxx>
/// Class SMESH_IndexedDataMapOfShapeIndexedMapOfShape
DEFINE_BASECOLLECTION (SMESH_BaseCollectionIndexedMapOfShape, SMESH_IndexedMapOfShape)
DEFINE_INDEXEDDATAMAP (SMESH_IndexedDataMapOfShapeIndexedMapOfShape,
SMESH_BaseCollectionIndexedMapOfShape, TopoDS_Shape,
SMESH_IndexedMapOfShape)
#endif
#endif

View File

@ -28,6 +28,8 @@
#ifndef SMESH_MeshEditor_HeaderFile
#define SMESH_MeshEditor_HeaderFile
#include "Standard_Version.hxx"
#include "SMESH_SMESH.hxx"
#include "SMDS_MeshElement.hxx"

View File

@ -28,13 +28,21 @@
#include "SMESH_SMESH.hxx"
#if OCC_VERSION_HEX >= 0x060703
#include <NCollection_Sequence.hxx>
#else
#include <NCollection_DefineSequence.hxx>
#endif
#include <SMDS_MeshElement.hxx>
typedef const SMDS_MeshElement* SMDS_MeshElementPtr;
#if OCC_VERSION_HEX >= 0x060703
typedef NCollection_Sequence<SMDS_MeshElementPtr> SMESH_SequenceOfElemPtr;
#else
DEFINE_BASECOLLECTION (SMESH_BaseCollectionElemPtr, SMDS_MeshElementPtr)
DEFINE_SEQUENCE (SMESH_SequenceOfElemPtr, SMESH_BaseCollectionElemPtr, SMDS_MeshElementPtr)
#endif
#endif

View File

@ -29,12 +29,19 @@
#include "SMESH_SMESH.hxx"
#include <NCollection_DefineSequence.hxx>
#if OCC_VERSION_HEX >= 0x060703
#include <NCollection_IncAllocator.hxx>
#include <NCollection_Sequence.hxx>
#endif
typedef const SMDS_MeshNode* SMDS_MeshNodePtr;
#if OCC_VERSION_HEX >= 0x060703
typedef NCollection_Sequence<SMDS_MeshNodePtr> SMESH_SequenceOfNode;
#else
DEFINE_BASECOLLECTION (SMESH_BaseCollectionNodePtr, SMDS_MeshNodePtr)
DEFINE_SEQUENCE(SMESH_SequenceOfNode,
SMESH_BaseCollectionNodePtr, SMDS_MeshNodePtr)
#endif
#endif

View File

@ -66,12 +66,17 @@
#ifndef StdMeshers_Array2OfNode_HeaderFile
#define StdMeshers_Array2OfNode_HeaderFile
typedef const SMDS_MeshNode* SMDS_MeshNodePtr;
DEFINE_BASECOLLECTION (StdMeshers_BaseCollectionNodePtr, SMDS_MeshNodePtr)
#ifndef __BORLANDC__
DEFINE_ARRAY2(StdMeshers_Array2OfNode,
StdMeshers_BaseCollectionNodePtr, SMDS_MeshNodePtr)
#if OCC_VERSION_HEX >= 0x060703
typedef NCollection_Array2<SMDS_MeshNodePtr> StdMeshers_Array2OfNode;
#else
DEFINE_BASECOLLECTION (StdMeshers_BaseCollectionNodePtr, SMDS_MeshNodePtr)
DEFINE_ARRAY2(StdMeshers_Array2OfNode,
StdMeshers_BaseCollectionNodePtr, SMDS_MeshNodePtr)
#endif
#else
DEFINE_BASECOLLECTION (StdMeshers_BaseCollectionNodePtr, SMDS_MeshNodePtr)
SMESH_DEFINE_ARRAY2(StdMeshers_Array2OfNode,
StdMeshers_BaseCollectionNodePtr, SMDS_MeshNodePtr)
#endif

View File

@ -37,8 +37,6 @@ __title__="FreeCAD Arch Commands"
__author__ = "Yorik van Havre"
__url__ = "http://www.freecadweb.org"
CURVEMODE = "PARAMETER" # For trimmed curves. CARTESIAN or PARAMETER
# module functions ###############################################
def getStringList(objects):
@ -597,191 +595,6 @@ def check(objectslist,includehidden=False):
bad.append([o,translate("Arch","contains faces that are not part of any solid")])
return bad
def getTuples(data,scale=1,placement=None,normal=None,close=True):
"""getTuples(data,[scale,placement,normal,close]): returns a tuple or a list of tuples from a vector
or from the vertices of a shape. Scale can indicate a scale factor"""
rnd = False
import Part
if isinstance(data,FreeCAD.Vector):
if placement:
data = placement.multVec(data)
if rnd:
data = DraftVecUtils.rounded(data)
return (data.x*scale,data.y*scale,data.z*scale)
elif isinstance(data,Part.Shape):
t = []
if len(data.Wires) == 1:
import Part,DraftGeomUtils
data = Part.Wire(DraftGeomUtils.sortEdges(data.Wires[0].Edges))
verts = data.Vertexes
try:
c = data.CenterOfMass
v1 = verts[0].Point.sub(c)
v2 = verts[1].Point.sub(c)
if DraftVecUtils.angle(v2,v1,normal) >= 0:
# inverting verts order if the direction is couterclockwise
verts.reverse()
except:
pass
for v in verts:
pt = v.Point
if placement:
if not placement.isNull():
pt = placement.multVec(pt)
if rnd:
pt = DraftVecUtils.rounded(pt)
t.append((pt.x*scale,pt.y*scale,pt.z*scale))
if close: # faceloops must not be closed, but ifc profiles must.
t.append(t[0])
else:
print "Arch.getTuples(): Wrong profile data"
return t
def getIfcExtrusionData(obj,scale=1,nosubs=False):
"""getIfcExtrusionData(obj,[scale,nosubs]): returns a closed path (a list of tuples), a tuple expressing an extrusion
vector, and a list of 3 tuples for base position, x axis and z axis. Or returns None, if a base loop and
an extrusion direction cannot be extracted. Scale can indicate a scale factor."""
if hasattr(obj,"Additions"):
if obj.Additions:
# TODO provisorily treat objs with additions as breps
return None
if hasattr(obj,"Subtractions") and not nosubs:
if obj.Subtractions:
return None
if hasattr(obj,"Proxy"):
if hasattr(obj.Proxy,"getProfiles"):
p = obj.Proxy.getProfiles(obj,noplacement=True)
v = obj.Proxy.getExtrusionVector(obj,noplacement=True)
if (len(p) == 1) and v:
p = p[0]
r = FreeCAD.Placement()
#b = p.CenterOfMass
r = obj.Proxy.getPlacement(obj)
#b = obj.Placement.multVec(FreeCAD.Vector())
#r.Rotation = DraftVecUtils.getRotation(v,FreeCAD.Vector(0,0,1))
d = [r.Base,DraftVecUtils.rounded(r.Rotation.multVec(FreeCAD.Vector(1,0,0))),DraftVecUtils.rounded(r.Rotation.multVec(FreeCAD.Vector(0,0,1)))]
#r = r.inverse()
#print "getExtrusionData: computed placement:",r
import Part
if len(p.Edges) == 1:
if isinstance(p.Edges[0].Curve,Part.Circle):
# Circle profile
r1 = p.Edges[0].Curve.Radius*scale
return "circle", [getTuples(p.Edges[0].Curve.Center,scale), r1], getTuples(v,scale), d
elif isinstance(p.Edges[0].Curve,Part.Ellipse):
# Ellipse profile
r1 = p.Edges[0].Curve.MajorRadius*scale
r2 = p.Edges[0].Curve.MinorRadius*scale
return "ellipse", [getTuples(p.Edges[0].Curve.Center,scale), r1, r2], getTuples(v,scale), d
curves = False
for e in p.Edges:
if isinstance(e.Curve,Part.Circle):
curves = True
elif not isinstance(e.Curve,Part.Line):
print "Arch.getIfcExtrusionData: Warning: unsupported edge type in profile"
if curves:
# Composite profile
ecurves = []
last = None
import DraftGeomUtils
edges = DraftGeomUtils.sortEdges(p.Edges)
for e in edges:
if isinstance(e.Curve,Part.Circle):
import math
follow = True
if last:
if not DraftVecUtils.equals(last,e.Vertexes[0].Point):
follow = False
last = e.Vertexes[0].Point
else:
last = e.Vertexes[-1].Point
else:
last = e.Vertexes[-1].Point
p1 = math.degrees(-DraftVecUtils.angle(e.Vertexes[0].Point.sub(e.Curve.Center)))
p2 = math.degrees(-DraftVecUtils.angle(e.Vertexes[-1].Point.sub(e.Curve.Center)))
da = DraftVecUtils.angle(e.valueAt(e.FirstParameter+0.1).sub(e.Curve.Center),e.Vertexes[0].Point.sub(e.Curve.Center))
if p1 < 0:
p1 = 360 + p1
if p2 < 0:
p2 = 360 + p2
if da > 0:
follow = not(follow)
if CURVEMODE == "CARTESIAN":
# BUGGY
p1 = getTuples(e.Vertexes[0].Point,scale)
p2 = getTuples(e.Vertexes[-1].Point,scale)
ecurves.append(["arc",getTuples(e.Curve.Center,scale),e.Curve.Radius*scale,[p1,p2],follow,CURVEMODE])
else:
verts = [vertex.Point for vertex in e.Vertexes]
if last:
if not DraftVecUtils.equals(last,verts[0]):
verts.reverse()
last = e.Vertexes[0].Point
else:
last = e.Vertexes[-1].Point
else:
last = e.Vertexes[-1].Point
ecurves.append(["line",[getTuples(vert,scale) for vert in verts]])
return "composite", ecurves, getTuples(v,scale), d
else:
# Polyline profile
return "polyline", getTuples(p,scale), getTuples(v,scale), d
return None
def getIfcBrepFacesData(obj,scale=1,sub=False,tessellation=1):
"""getIfcBrepFacesData(obj,[scale,tesselation]): returns a list(0) of lists(1) of lists(2) of lists(3),
list(3) being a list of vertices defining a loop, list(2) describing a face from one or
more loops, list(1) being the whole solid made of several faces, list(0) being the list
of solids inside the object. Scale can indicate a scaling factor. Tesselation is the tesselation
factor to apply on curved faces."""
shape = None
if sub:
if hasattr(obj,"Proxy"):
if hasattr(obj.Proxy,"getSubVolume"):
shape = obj.Proxy.getSubVolume(obj)
if not shape:
if hasattr(obj,"Shape"):
if obj.Shape:
if not obj.Shape.isNull():
if obj.Shape.isValid():
shape = obj.Shape
if shape:
import Part
sols = []
for sol in shape.Solids:
s = []
curves = False
for face in sol.Faces:
for e in face.Edges:
if not isinstance(e.Curve,Part.Line):
curves = True
if curves:
tris = sol.tessellate(tessellation)
for tri in tris[1]:
f = []
for i in tri:
f.append(getTuples(tris[0][i],scale))
s.append([f])
else:
for face in sol.Faces:
f = []
f.append(getTuples(face.OuterWire,scale,normal=face.normalAt(0,0),close=False))
for wire in face.Wires:
if wire.hashCode() != face.OuterWire.hashCode():
f.append(getTuples(wire,scale,normal=DraftVecUtils.neg(face.normalAt(0,0)),close=False))
s.append(f)
sols.append(s)
return sols
return None
def getIfcElevation(obj):
"""getIfcElevation(obj): Returns the lowest height (Z coordinate) of this object"""
if obj.isDerivedFrom("Part::Feature"):
b = obj.Shape.BoundBox
return b.ZMin
return 0
def getHost(obj,strict=True):
"""getHost(obj,[strict]): returns the host of the current object. If strict is true (default),
the host can only be an object of a higher level than the given one, or in other words, if a wall

View File

@ -34,7 +34,7 @@ else:
def translate(ctxt,txt):
return txt
def makeSpace(objects=None,name=translate("Arch","Space")):
def makeSpace(objects=None,baseobj=None,name=translate("Arch","Space")):
"""makeSpace([objects]): 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)"""
@ -42,6 +42,8 @@ def makeSpace(objects=None,name=translate("Arch","Space")):
_Space(obj)
if FreeCAD.GuiUp:
_ViewProviderSpace(obj.ViewObject)
if baseobj:
objects = baseobj
if objects:
if not isinstance(objects,list):
objects = [objects]

View File

@ -1048,10 +1048,10 @@ def export(exportList,filename):
# get representation
if (not forcebrep) and (not brepflag):
gdata = Arch.getIfcExtrusionData(obj,scaling,SEPARATE_OPENINGS)
gdata = getIfcExtrusionData(obj,scaling,SEPARATE_OPENINGS)
#if DEBUG: print " extrusion data for ",obj.Label," : ",gdata
if not gdata:
fdata = Arch.getIfcBrepFacesData(obj,scaling)
fdata = getIfcBrepFacesData(obj,scaling)
#if DEBUG: print " brep data for ",obj.Label," : ",fdata
if not fdata:
if obj.isDerivedFrom("Part::Feature"):
@ -1094,7 +1094,7 @@ def export(exportList,filename):
elif otype == "Window":
extra = [obj.Width.Value*scaling, obj.Height.Value*scaling]
elif otype == "Space":
extra = ["ELEMENT","INTERNAL",Arch.getIfcElevation(obj)]
extra = ["ELEMENT","INTERNAL",getIfcElevation(obj)]
elif otype == "Part":
extra = ["ELEMENT"]
if not ifctype in supportedIfcTypes:
@ -1109,7 +1109,7 @@ def export(exportList,filename):
if SEPARATE_OPENINGS and gdata:
for o in obj.Subtractions:
print "Subtracting ",o.Label
fdata = Arch.getIfcBrepFacesData(o,scaling,sub=True)
fdata = getIfcBrepFacesData(o,scaling,sub=True)
representation = [ifc.addFacetedBrep(f, color=color) for f in fdata]
p2 = ifc.addProduct( "IfcOpeningElement", representation, storey=product, placement=None, name=str(o.Label), description=None)
@ -1172,6 +1172,195 @@ def export(exportList,filename):
print " " + o.Label
def getTuples(data,scale=1,placement=None,normal=None,close=True):
"""getTuples(data,[scale,placement,normal,close]): returns a tuple or a list of tuples from a vector
or from the vertices of a shape. Scale can indicate a scale factor"""
rnd = False
import Part
if isinstance(data,FreeCAD.Vector):
if placement:
data = placement.multVec(data)
if rnd:
data = DraftVecUtils.rounded(data)
return (data.x*scale,data.y*scale,data.z*scale)
elif isinstance(data,Part.Shape):
t = []
if len(data.Wires) == 1:
import Part,DraftGeomUtils
data = Part.Wire(DraftGeomUtils.sortEdges(data.Wires[0].Edges))
verts = data.Vertexes
try:
c = data.CenterOfMass
v1 = verts[0].Point.sub(c)
v2 = verts[1].Point.sub(c)
if DraftVecUtils.angle(v2,v1,normal) >= 0:
# inverting verts order if the direction is couterclockwise
verts.reverse()
except:
pass
for v in verts:
pt = v.Point
if placement:
if not placement.isNull():
pt = placement.multVec(pt)
if rnd:
pt = DraftVecUtils.rounded(pt)
t.append((pt.x*scale,pt.y*scale,pt.z*scale))
if close: # faceloops must not be closed, but ifc profiles must.
t.append(t[0])
else:
print "Arch.getTuples(): Wrong profile data"
return t
def getIfcExtrusionData(obj,scale=1,nosubs=False):
"""getIfcExtrusionData(obj,[scale,nosubs]): returns a closed path (a list of tuples), a tuple expressing an extrusion
vector, and a list of 3 tuples for base position, x axis and z axis. Or returns None, if a base loop and
an extrusion direction cannot be extracted. Scale can indicate a scale factor."""
CURVEMODE = "PARAMETER" # For trimmed curves. CARTESIAN or PARAMETER
if hasattr(obj,"Additions"):
if obj.Additions:
# TODO provisorily treat objs with additions as breps
return None
if hasattr(obj,"Subtractions") and not nosubs:
if obj.Subtractions:
return None
if hasattr(obj,"Proxy"):
if hasattr(obj.Proxy,"getProfiles"):
p = obj.Proxy.getProfiles(obj,noplacement=True)
v = obj.Proxy.getExtrusionVector(obj,noplacement=True)
if (len(p) == 1) and v:
p = p[0]
r = FreeCAD.Placement()
#b = p.CenterOfMass
r = obj.Proxy.getPlacement(obj)
#b = obj.Placement.multVec(FreeCAD.Vector())
#r.Rotation = DraftVecUtils.getRotation(v,FreeCAD.Vector(0,0,1))
d = [r.Base,DraftVecUtils.rounded(r.Rotation.multVec(FreeCAD.Vector(1,0,0))),DraftVecUtils.rounded(r.Rotation.multVec(FreeCAD.Vector(0,0,1)))]
#r = r.inverse()
#print "getExtrusionData: computed placement:",r
import Part
if len(p.Edges) == 1:
if isinstance(p.Edges[0].Curve,Part.Circle):
# Circle profile
r1 = p.Edges[0].Curve.Radius*scale
return "circle", [getTuples(p.Edges[0].Curve.Center,scale), r1], getTuples(v,scale), d
elif isinstance(p.Edges[0].Curve,Part.Ellipse):
# Ellipse profile
r1 = p.Edges[0].Curve.MajorRadius*scale
r2 = p.Edges[0].Curve.MinorRadius*scale
return "ellipse", [getTuples(p.Edges[0].Curve.Center,scale), r1, r2], getTuples(v,scale), d
curves = False
for e in p.Edges:
if isinstance(e.Curve,Part.Circle):
curves = True
elif not isinstance(e.Curve,Part.Line):
print "Arch.getIfcExtrusionData: Warning: unsupported edge type in profile"
if curves:
# Composite profile
ecurves = []
last = None
import DraftGeomUtils
edges = DraftGeomUtils.sortEdges(p.Edges)
for e in edges:
if isinstance(e.Curve,Part.Circle):
import math
follow = True
if last:
if not DraftVecUtils.equals(last,e.Vertexes[0].Point):
follow = False
last = e.Vertexes[0].Point
else:
last = e.Vertexes[-1].Point
else:
last = e.Vertexes[-1].Point
p1 = math.degrees(-DraftVecUtils.angle(e.Vertexes[0].Point.sub(e.Curve.Center)))
p2 = math.degrees(-DraftVecUtils.angle(e.Vertexes[-1].Point.sub(e.Curve.Center)))
da = DraftVecUtils.angle(e.valueAt(e.FirstParameter+0.1).sub(e.Curve.Center),e.Vertexes[0].Point.sub(e.Curve.Center))
if p1 < 0:
p1 = 360 + p1
if p2 < 0:
p2 = 360 + p2
if da > 0:
follow = not(follow)
if CURVEMODE == "CARTESIAN":
# BUGGY
p1 = getTuples(e.Vertexes[0].Point,scale)
p2 = getTuples(e.Vertexes[-1].Point,scale)
ecurves.append(["arc",getTuples(e.Curve.Center,scale),e.Curve.Radius*scale,[p1,p2],follow,CURVEMODE])
else:
verts = [vertex.Point for vertex in e.Vertexes]
if last:
if not DraftVecUtils.equals(last,verts[0]):
verts.reverse()
last = e.Vertexes[0].Point
else:
last = e.Vertexes[-1].Point
else:
last = e.Vertexes[-1].Point
ecurves.append(["line",[getTuples(vert,scale) for vert in verts]])
return "composite", ecurves, getTuples(v,scale), d
else:
# Polyline profile
return "polyline", getTuples(p,scale), getTuples(v,scale), d
return None
def getIfcBrepFacesData(obj,scale=1,sub=False,tessellation=1):
"""getIfcBrepFacesData(obj,[scale,tesselation]): returns a list(0) of lists(1) of lists(2) of lists(3),
list(3) being a list of vertices defining a loop, list(2) describing a face from one or
more loops, list(1) being the whole solid made of several faces, list(0) being the list
of solids inside the object. Scale can indicate a scaling factor. Tesselation is the tesselation
factor to apply on curved faces."""
shape = None
if sub:
if hasattr(obj,"Proxy"):
if hasattr(obj.Proxy,"getSubVolume"):
shape = obj.Proxy.getSubVolume(obj)
if not shape:
if hasattr(obj,"Shape"):
if obj.Shape:
if not obj.Shape.isNull():
if obj.Shape.isValid():
shape = obj.Shape
if shape:
import Part
sols = []
for sol in shape.Solids:
s = []
curves = False
for face in sol.Faces:
for e in face.Edges:
if not isinstance(e.Curve,Part.Line):
curves = True
if curves:
tris = sol.tessellate(tessellation)
for tri in tris[1]:
f = []
for i in tri:
f.append(getTuples(tris[0][i],scale))
s.append([f])
else:
for face in sol.Faces:
f = []
f.append(getTuples(face.OuterWire,scale,normal=face.normalAt(0,0),close=False))
for wire in face.Wires:
if wire.hashCode() != face.OuterWire.hashCode():
f.append(getTuples(wire,scale,normal=DraftVecUtils.neg(face.normalAt(0,0)),close=False))
s.append(f)
sols.append(s)
return sols
return None
def getIfcElevation(obj):
"""getIfcElevation(obj): Returns the lowest height (Z coordinate) of this object"""
if obj.isDerivedFrom("Part::Feature"):
b = obj.Shape.BoundBox
return b.ZMin
return 0
def explore(filename=None):
"explore the contents of an ifc file in a Qt dialog"
if not filename: