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

This commit is contained in:
wmayer 2014-04-24 13:30:09 +02:00
commit d8dba90ab4
8 changed files with 215 additions and 53 deletions

View File

@ -649,11 +649,15 @@ def getExtrusionData(obj,scale=1):
return None
if hasattr(obj,"Proxy"):
if hasattr(obj.Proxy,"BaseProfile") and hasattr(obj.Proxy,"ExtrusionVector"):
import Part
pl = FreeCAD.Placement(obj.Placement)
r = FreeCAD.Rotation(obj.Placement.Rotation)
if pl.isNull():
pl = r = None
return getTuples(obj.Proxy.BaseProfile,scale,pl), getTuples(obj.Proxy.ExtrusionVector,scale,r)
if len(obj.Proxy.BaseProfile.Edges) == 1:
if isinstance(obj.Proxy.BaseProfile.Edges[0].Curve,Part.Circle):
return "circle", getTuples(obj.Proxy.BaseProfile.Edges[0].Curve.Center,scale), obj.Proxy.BaseProfile.Edges[0].Curve.Radius*scale, getTuples(obj.Proxy.ExtrusionVector,scale,r)
return "polyline", getTuples(obj.Proxy.BaseProfile,scale,pl), getTuples(obj.Proxy.ExtrusionVector,scale,r)
return None
def getBrepFacesData(obj,scale=1):

File diff suppressed because one or more lines are too long

View File

@ -279,6 +279,26 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_10">
<item>
<widget class="Gui::PrefCheckBox" name="checkBox_3">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Objects containing multiple solids are normally exported as multiple representations. Some applications don't like that,though. You can use this option to unite these solids into one.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Join multi-solid objects</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>ifcJoinSolids</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Arch</cstring>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>

View File

@ -385,6 +385,18 @@ class IfcDocument(object):
f.write(l)
f.close()
def union(self,solids):
"""union(solids): creates a boolean union between all the solids of the list"""
if len(solids) == 1:
return solids[0]
else:
s1 = solids.pop(0)
s2 = solids.pop(0)
base = create(self._fileobject,"IfcBooleanResult",["UNION",s1,s2])
for s in solids:
base = create(self._fileobject,"IfcBooleanResult",["UNION",base,s])
return base
def addPlacement(self,reference=None,origin=(0,0,0),xaxis=(1,0,0),zaxis=(0,0,1),local=True):
"""addPlacement([reference,origin,xaxis,zaxis,local]): adds a placement. origin,
xaxis and zaxis can be either tuples or 3d vectors. If local is False, a global
@ -463,14 +475,14 @@ class IfcDocument(object):
self._relate(storey,wal)
return wal
def addStructure(self,ifctype,shapes,storey=None,placement=None,name="Default Structure",description=None,standard=False):
def addStructure(self,ifctype,shapes,storey=None,placement=None,name="Default Structure",description=None,extrusion=False):
"""addStructure(ifctype,shapes,[storey,placement,name,description]): creates a structure
from the given representation shape(s). Ifctype is the type of structural object (IfcBeam, IfcColumn, etc)"""
if not placement:
placement = self.addPlacement()
if not isinstance(shapes,list):
shapes = [shapes]
if standard:
if extrusion:
solidType = "SweptSolid"
else:
solidType = "Brep"
@ -508,17 +520,23 @@ class IfcDocument(object):
"""addPolyline(points): creates a polyline from the given points"""
pts = [create(self._fileobject,"IfcCartesianPoint",getTuple(p)) for p in points]
pol = create(self._fileobject,"IfcPolyline",[pts])
return pol
area = create(self._fileobject,"IfcArbitraryClosedProfileDef",["AREA",None,pol])
return area
def addExtrusion(self,polyline,extrusion,placement=None):
"""addExtrusion(polyline,extrusion,[placement]): makes an
def addCircle(self,radius):
"""addCircle(radius): creates a polyline from the given points"""
lpl = self.addPlacement()
cir = create(self._fileobject,"IfcCircleProfileDef",["AREA",None,lpl,float(radius)])
return cir
def addExtrusion(self,profile,extrusion,placement=None):
"""addExtrusion(profile,extrusion,[placement]): makes an
extrusion of the given polyline with the given extrusion vector"""
if not placement:
placement = self.addPlacement(local=False)
value,norm = getValueAndDirection(extrusion)
edir = create(self._fileobject,"IfcDirection",[norm])
area = create(self._fileobject,"IfcArbitraryClosedProfileDef",["AREA",None,polyline])
solid = create(self._fileobject,"IfcExtrudedAreaSolid",[area,placement,edir,value])
solid = create(self._fileobject,"IfcExtrudedAreaSolid",[profile,placement,edir,value])
return solid
def addExtrudedPolyline(self,points,extrusion,placement=None):
@ -528,6 +546,15 @@ class IfcDocument(object):
exp = self.addExtrusion(pol,extrusion,placement)
return exp
def addExtrudedCircle(self,center,radius,extrusion,placement=None):
"""addExtrudedCircle(radius,extrusion,[placement]): makes an extruded circle
from the given radius and the given extrusion vector"""
cir = self.addCircle(radius)
if not placement:
placement = self.addPlacement(origin=center)
exp = self.addExtrusion(cir,extrusion,placement)
return exp
def addFace(self,face):
"""addFace(face): creates a face from the given face data (a list of lists of points).
The first is the outer wire, the next are optional inner wires. They must be reversed in order"""

View File

@ -34,6 +34,7 @@ SCHEMA = "http://www.steptools.com/support/stdev_docs/express/ifc2x3/ifc2x3_tc1.
MAKETEMPFILES = False # if True, shapes are passed from ifcopenshell to freecad through temp files
DEBUG = True # this is only for the python console, this value is overridden when importing through the GUI
SKIP = ["IfcBuildingElementProxy","IfcFlowTerminal","IfcFurnishingElement"] # default. overwritten by the GUI options
TOUCH = True # arch objects based on profiles need to be reexecuted after loading the file (this is temporary)
# end config
if open.__module__ == '__builtin__':
@ -62,7 +63,7 @@ def insert(filename,docname,skip=None):
def getConfig():
"Gets Arch IFC import preferences"
global CREATE_IFC_GROUPS, ASMESH, PREFIX_NUMBERS, FORCE_PYTHON_PARSER, SEPARATE_OPENINGS, SEPARATE_PLACEMENTS
global CREATE_IFC_GROUPS, ASMESH, PREFIX_NUMBERS, FORCE_PYTHON_PARSER, SEPARATE_OPENINGS, SEPARATE_PLACEMENTS, JOINSOLIDS
CREATE_IFC_GROUPS = False
IMPORT_IFC_FURNITURE = False
ASMESH = ["IfcFurnishingElement"]
@ -76,6 +77,7 @@ def getConfig():
SEPARATE_OPENINGS = p.GetBool("ifcSeparateOpenings",False)
SEPARATE_PLACEMENTS = p.GetBool("ifcSeparatePlacements",False)
PREFIX_NUMBERS = p.GetBool("ifcPrefixNumbers",False)
JOINSOLIDS = p.GetBool("ifcJoinSolids",False)
skiplist = p.GetString("ifcSkip","")
if skiplist:
SKIP = skiplist.split(",")
@ -923,9 +925,9 @@ def export(exportList,filename):
version of IfcOpenShell available from https://github.com/aothms/IfcOpenShell"""
return
import ifcWriter
import Arch,Draft
# creating base IFC project
import Arch,Draft
getConfig()
ifcWriter.PRECISION = Draft.precision()
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch")
@ -944,6 +946,13 @@ def export(exportList,filename):
# get all children and reorder list to get buildings and floors processed first
objectslist = Draft.getGroupContents(exportList,walls=True,addgroups=True)
objectslist = Arch.pruneIncluded(objectslist)
# workaround: loaded objects loose their profile info - needs to recompute...
if TOUCH:
for o in objectslist:
if Draft.getType(o) in ["Wall", "Structure"]:
o.Proxy.execute(o)
buildings = []
floors = []
others = []
@ -971,20 +980,45 @@ def export(exportList,filename):
if DEBUG: print "adding ",obj.Label
# getting geometry
if not forcebrep:
gdata = Arch.getExtrusionData(obj,scaling)
#if DEBUG: print "extrusion data for ",obj.Label," : ",gdata
if not gdata:
fdata = Arch.getBrepFacesData(obj,scaling)
#if DEBUG: print "brep data for ",obj.Label," : ",fdata
if DEBUG: print " Brep"
if not fdata:
if obj.isDerivedFrom("Part::Feature"):
print "IFC export: error retrieving the shape of object ", obj.Name
continue
else:
if DEBUG: print " No geometry"
else:
if DEBUG: print " Brep"
else:
if DEBUG: print " Extrusion"
# compute final placement
basepoint = None
if obj.isDerivedFrom("Part::Feature"):
b1 = None
b2 = None
if hasattr(obj,"Base"):
if obj.Base:
b1 = FreeCAD.Vector(obj.Base.Placement.Base).multiply(scaling)
if hasattr(obj,"Placement"):
b2 = FreeCAD.Vector(obj.Placement.Base).multiply(scaling)
if b2:
if b1:
basepoint = b2.add(b1)
else:
basepoint = b2
elif b1:
basepoint = b1
if basepoint:
basepoint = Arch.getTuples(basepoint)
# writing text log
spacer = ""
for i in range(36-len(obj.Label)):
spacer += " "
@ -997,6 +1031,7 @@ def export(exportList,filename):
tp = otype
txt.append(obj.Label + spacer + tp)
# writing IFC data
if otype == "Building":
ifc.addBuilding( name=name )
@ -1009,11 +1044,18 @@ def export(exportList,filename):
if parent:
parent = ifc.findByName("IfcBuildingStorey",str(parent.Label))
if gdata:
ifc.addWall( ifc.addExtrudedPolyline(gdata[0],gdata[1]), storey=parent, name=name, standard=True )
if gdata[0] == "polyline":
ifc.addWall( ifc.addExtrudedPolyline(gdata[1], gdata[2]), storey=parent, name=name, standard=True )
elif gdata[0] == "circle":
ifc.addWall( ifc.addExtrudedCircle(gdata[1], gdata[2], gdata[3]), storey=parent, name=name )
elif fdata:
ifc.addWall( [ifc.addFacetedBrep(f) for f in fdata], storey=parent, name=name )
if JOINSOLIDS:
ifc.addWall( ifc.join([ifc.addFacetedBrep(f) for f in fdata]), storey=parent, name=name )
else:
ifc.addWall( [ifc.addFacetedBrep(f) for f in fdata], storey=parent, name=name )
elif otype == "Structure":
placement = None
if parent:
parent = ifc.findByName("IfcBuildingStorey",str(parent.Label))
role = "IfcBeam"
@ -1025,15 +1067,29 @@ def export(exportList,filename):
elif obj.Role == "Foundation":
role = "IfcFooting"
if gdata:
#ifc.addStructure( role, ifc.addExtrudedPolyline(gdata[0],gdata[1]), storey=parent, name=name )
if FreeCAD.Vector(gdata[1]).getAngle(FreeCAD.Vector(0,0,1)) < .01:
# Workaround for non-Z extrusions, apparently not supported by ifc++ TODO: fix this
ifc.addStructure( role, ifc.addExtrudedPolyline(gdata[0],gdata[1]), storey=parent, name=name, standard=True )
else:
fdata = Arch.getBrepFacesData(obj,scaling)
ifc.addStructure( role, [ifc.addFacetedBrep(f) for f in fdata], storey=parent, name=name )
if gdata[0] == "polyline":
#ifc.addStructure( role, ifc.addExtrudedPolyline(gdata[0],gdata[1]), storey=parent, name=name )
if FreeCAD.Vector(gdata[2]).getAngle(FreeCAD.Vector(0,0,1)) < .01:
# the placement of polylines is weird... The Z values from the polyline info is not used,
# so we need to give it now as a placement.
if basepoint:
if round(basepoint[2],Draft.precision()) != 0:
placement = ifc.addPlacement(origin=(0.0,0.0,basepoint[2]))
ifc.addStructure( role, ifc.addExtrudedPolyline(gdata[1],gdata[2]), storey=parent, placement=placement, name=name, extrusion=True )
else:
# Workaround for non-Z extrusions, apparently not supported by ifc++ TODO: fix this
print " switching to Brep"
fdata = Arch.getBrepFacesData(obj,scaling)
ifc.addStructure( role, [ifc.addFacetedBrep(f) for f in fdata], storey=parent, name=name )
elif gdata[0] == "circle":
if basepoint:
placement = ifc.addPlacement(origin=basepoint)
ifc.addStructure( role, ifc.addExtrudedCircle(gdata[1], gdata[2], gdata[3]), storey=parent, placement=placement, name=name, extrusion=True )
elif fdata:
ifc.addStructure( role, [ifc.addFacetedBrep(f) for f in fdata], storey=parent, name=name )
if JOINSOLIDS:
ifc.addStructure( role, ifc.join([ifc.addFacetedBrep(f) for f in fdata]), storey=parent, name=name )
else:
ifc.addStructure( role, [ifc.addFacetedBrep(f) for f in fdata], storey=parent, name=name )
elif otype == "Window":
if parent:
@ -1052,9 +1108,13 @@ def export(exportList,filename):
if obj.Role == "Door":
role = "IfcDoor"
if gdata:
ifc.addWindow( role, obj.Width*scaling, obj.Height*scaling, ifc.addExtrudedPolyline(gdata[0],gdata[1]), host=parent, name=name )
if gdata[0] == "polyline":
ifc.addWindow( role, obj.Width*scaling, obj.Height*scaling, ifc.addExtrudedPolyline(gdata[1], gdata[2]), host=parent, name=name )
elif fdata:
ifc.addWindow( role, obj.Width*scaling, obj.Height*scaling, [ifc.addFacetedBrep(f) for f in fdata], host=parent, name=name )
if JOINSOLIDS:
ifc.addWindow( role, obj.Width*scaling, obj.Height*scaling, ifc.union([ifc.addFacetedBrep(f) for f in fdata]), host=parent, name=name )
else:
ifc.addWindow( role, obj.Width*scaling, obj.Height*scaling, [ifc.addFacetedBrep(f) for f in fdata], host=parent, name=name )
else:
print "IFC export: object type ", otype, " is not supported yet."
@ -1082,6 +1142,8 @@ def export(exportList,filename):
f.write(txtstring)
f.close()
FreeCAD.ActiveDocument.recompute()
def explore(filename=None):
"explore the contents of an ifc file in a Qt dialog"

View File

@ -4174,11 +4174,13 @@ class _Shape2DView(_DraftObject):
obj.addProperty("App::PropertyEnumeration","ProjectionMode","Draft","The way the viewed object must be projected")
obj.addProperty("App::PropertyIntegerList","FaceNumbers","Draft","The indices of the faces to be projected in Individual Faces mode")
obj.addProperty("App::PropertyBool","HiddenLines","Draft","Show hidden lines")
obj.addProperty("App::PropertyBool","Tessellation","Draft","Tessellate BSplines into line segments using number of spline poles")
obj.addProperty("App::PropertyBool","Tessellation","Draft","Tessellate Ellipses and BSplines into line segments")
obj.addProperty("App::PropertyFloat","SegmentLength","Draft","Length of line segments if tessellating Ellipses or BSplines into line segments")
obj.Projection = Vector(0,0,1)
obj.ProjectionMode = ["Solid","Individual Faces","Cutlines","Cutfaces"]
obj.HiddenLines = False
obj.Tessellation = True
obj.Tessellation = False
obj.SegmentLength = .05
_DraftObject.__init__(self,obj,"Shape2DView")
def getProjected(self,obj,shape,direction):
@ -4195,9 +4197,10 @@ class _Shape2DView(_DraftObject):
edges.append(g)
#return Part.makeCompound(edges)
if hasattr(obj,"Tessellation"):
return DraftGeomUtils.cleanProjection(Part.makeCompound(edges),obj.Tessellation)
return DraftGeomUtils.cleanProjection(Part.makeCompound(edges),obj.Tessellation,obj.SegmentLength)
else:
return DraftGeomUtils.cleanProjection(Part.makeCompound(edges))
return Part.makeCompound(edges)
#return DraftGeomUtils.cleanProjection(Part.makeCompound(edges))
def execute(self,obj):
import DraftGeomUtils

View File

@ -1808,10 +1808,12 @@ def curvetowire(obj,steps):
p0 = p
return edgelist
def cleanProjection(shape,tessellate=False):
def cleanProjection(shape,tessellate=True,seglength=.05):
"returns a valid compound of edges, by recreating them"
# this is because the projection algorithm somehow creates wrong shapes.
# they dispay fine, but on loading the file the shape is invalid
# Now with tanderson's fix to ProjectionAlgos, that isn't the case, but this
# can be used for tessellating ellipses and splines for DXF output-DF
oldedges = shape.Edges
newedges = []
for e in oldedges:
@ -1826,15 +1828,18 @@ def cleanProjection(shape,tessellate=False):
else:
newedges.append(e.Curve.toShape())
elif geomType(e) == "Ellipse":
if len(e.Vertexes) > 1:
a = Part.Arc(e.Curve,e.FirstParameter,e.LastParameter).toShape()
newedges.append(a)
if tessellate:
newedges.append(Part.Wire(curvetowire(e, seglength)))
else:
newedges.append(e.Curve.toShape())
if len(e.Vertexes) > 1:
a = Part.Arc(e.Curve,e.FirstParameter,e.LastParameter).toShape()
newedges.append(a)
else:
newedges.append(e.Curve.toShape())
elif geomType(e) == "BSplineCurve" or \
geomType(e) == "BezierCurve":
if tessellate:
newedges.append(Part.Wire(curvetowire(e,e.Curve.NbPoles)))
newedges.append(Part.Wire(curvetowire(e,seglength)))
else:
if isLine(e.Curve):
l = Part.Line(e.Vertexes[0].Point,e.Vertexes[-1].Point).toShape()
@ -1847,6 +1852,36 @@ def cleanProjection(shape,tessellate=False):
print "Debug: error cleaning edge ",e
return Part.makeCompound(newedges)
def curvetosegment(curve,seglen):
points = curve.discretize(seglen)
p0 = points[0]
edgelist = []
for p in points[1:]:
edge = Part.makeLine((p0.x,p0.y,p0.z),(p.x,p.y,p.z))
edgelist.append(edge)
p0 = p
return edgelist
def tessellateProjection(shape,seglen):
''' Returns projection with BSplines and Ellipses broken into line segments.
Useful for exporting projected views to *dxf files.'''
oldedges = shape.Edges
newedges = []
for e in oldedges:
try:
if geomType(e) == "Line":
newedges.append(e.Curve.toShape())
elif geomType(e) == "Circle":
newedges.append(e.Curve.toShape())
elif geomType(e) == "Ellipse":
newedges.append(Part.Wire(curvetosegment(e,seglen)))
elif geomType(e) == "BSplineCurve":
newedges.append(Part.Wire(curvetosegment(e,seglen)))
else:
newedges.append(e)
except:
print "Debug: error cleaning edge ",e
return Part.makeCompound(newedges)
# circle functions *********************************************************

View File

@ -60,7 +60,7 @@
#include <TColgp_Array1OfPnt2d.hxx>
#include <BRep_Tool.hxx>
#include <BRepMesh.hxx>
#include <BRepLib.hxx>
#include <BRepAdaptor_CompCurve.hxx>
#include <Handle_BRepAdaptor_HCompCurve.hxx>
#include <Approx_Curve3d.hxx>
@ -122,6 +122,18 @@ TopoDS_Shape ProjectionAlgos::invertY(const TopoDS_Shape& shape)
}
*/
//added by tanderson. aka blobfish.
//projection algorithms build a 2d curve(pcurve) but no 3d curve.
//this causes problems with meshing algorithms after save and load.
static const TopoDS_Shape& build3dCurves(const TopoDS_Shape &shape)
{
TopExp_Explorer it;
for (it.Init(shape, TopAbs_EDGE); it.More(); it.Next())
BRepLib::BuildCurve3d(TopoDS::Edge(it.Current()));
return shape;
}
void ProjectionAlgos::execute(void)
{
Handle( HLRBRep_Algo ) brep_hlr = new HLRBRep_Algo;
@ -141,17 +153,16 @@ void ProjectionAlgos::execute(void)
// extracting the result sets:
HLRBRep_HLRToShape shapes( brep_hlr );
V = shapes.VCompound ();// hard edge visibly
V1 = shapes.Rg1LineVCompound();// Smoth edges visibly
VN = shapes.RgNLineVCompound();// contour edges visibly
VO = shapes.OutLineVCompound();// contours apparents visibly
VI = shapes.IsoLineVCompound();// isoparamtriques visibly
H = shapes.HCompound ();// hard edge invisibly
H1 = shapes.Rg1LineHCompound();// Smoth edges invisibly
HN = shapes.RgNLineHCompound();// contour edges invisibly
HO = shapes.OutLineHCompound();// contours apparents invisibly
HI = shapes.IsoLineHCompound();// isoparamtriques invisibly
V = build3dCurves(shapes.VCompound ());// hard edge visibly
V1 = build3dCurves(shapes.Rg1LineVCompound());// Smoth edges visibly
VN = build3dCurves(shapes.RgNLineVCompound());// contour edges visibly
VO = build3dCurves(shapes.OutLineVCompound());// contours apparents visibly
VI = build3dCurves(shapes.IsoLineVCompound());// isoparamtriques visibly
H = build3dCurves(shapes.HCompound ());// hard edge invisibly
H1 = build3dCurves(shapes.Rg1LineHCompound());// Smoth edges invisibly
HN = build3dCurves(shapes.RgNLineHCompound());// contour edges invisibly
HO = build3dCurves(shapes.OutLineHCompound());// contours apparents invisibly
HI = build3dCurves(shapes.IsoLineHCompound());// isoparamtriques invisibly
}
std::string ProjectionAlgos::getSVG(ExtractionType type, double scale, double tolerance, double hiddenscale)