Arch: Big cleanup - fixes #1524
* Removed redundant code in Arch objects * Supports wandererfan's Units code in Draft module * Cleanup of the IFC exporter * Better support of extruded profiles in IFC export
This commit is contained in:
parent
068452f0ac
commit
2798de1afa
|
@ -593,26 +593,14 @@ def check(objectslist,includehidden=False):
|
|||
bad.append([o,translate("Arch","contains faces that are not part of any solid")])
|
||||
return bad
|
||||
|
||||
|
||||
def addFixture(fixture,baseobject):
|
||||
'''addFixture(fixture,baseobject): adds the given object as a
|
||||
fixture to the given base object'''
|
||||
if hasattr(baseobject,"Fixtures"):
|
||||
f = baseobject.Fixtures
|
||||
f.append(fixture)
|
||||
baseobject.Fixtures = f
|
||||
if baseobject.ViewObject.DisplayMode != "Detailed":
|
||||
fixture.ViewObject.hide()
|
||||
else:
|
||||
FreeCAD.Console.PrintMessage(translate("Arch","This object has no support for fixtures"))
|
||||
|
||||
def getTuples(data,scale=1,placement=None,normal=None,close=True,flatten=False):
|
||||
"""getTuples(data,[scale,placement,normal,flatten]): returns a tuple or a list of tuples from a vector
|
||||
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"""
|
||||
import Part
|
||||
if isinstance(data,FreeCAD.Vector):
|
||||
if placement:
|
||||
data = placement.multVec(data)
|
||||
data = DraftVecUtils.rounded(data)
|
||||
return (data.x*scale,data.y*scale,data.z*scale)
|
||||
elif isinstance(data,Part.Shape):
|
||||
t = []
|
||||
|
@ -632,21 +620,21 @@ def getTuples(data,scale=1,placement=None,normal=None,close=True,flatten=False):
|
|||
for v in verts:
|
||||
pt = v.Point
|
||||
if placement:
|
||||
pt = placement.multVec(pt)
|
||||
if flatten:
|
||||
t.append((pt.x*scale,pt.y*scale,0))
|
||||
else:
|
||||
t.append((pt.x*scale,pt.y*scale,pt.z*scale))
|
||||
if close:
|
||||
t.append(t[0]) # for IFC verts lists must be closed
|
||||
if not placement.isNull():
|
||||
pt = placement.multVec(pt)
|
||||
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 getExtrusionData(obj,scale=1,flatten=True):
|
||||
"""getExtrusionData(obj,[scale,flatten]): returns a closed path (a list of tuples) and a tuple expressing an extrusion
|
||||
vector, or None, if a base loop and an extrusion direction cannot be extracted. Scale can indicate a scale factor.
|
||||
if flatten is True (default), the profile stays in the XY plane (IFC default)"""
|
||||
def getExtrusionData(obj,scale=1):
|
||||
"""getExtrusionData(obj,[scale]): 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:
|
||||
# provisorily treat objs with additions as breps
|
||||
|
@ -656,16 +644,24 @@ def getExtrusionData(obj,scale=1,flatten=True):
|
|||
# provisorily treat objs with subtractions as breps
|
||||
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
|
||||
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,flatten=flatten), obj.Proxy.BaseProfile.Edges[0].Curve.Radius*scale, getTuples(obj.Proxy.ExtrusionVector,scale,r)
|
||||
return "polyline", getTuples(obj.Proxy.BaseProfile,scale,pl,flatten=flatten), getTuples(obj.Proxy.ExtrusionVector,scale,r)
|
||||
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):
|
||||
return "circle", [getTuples(p.Edges[0].Curve.Center,scale), p.Edges[0].Curve.Radius*scale], getTuples(v,scale), d
|
||||
return "polyline", getTuples(p,scale), getTuples(v,scale), d
|
||||
return None
|
||||
|
||||
def getBrepFacesData(obj,scale=1):
|
||||
|
@ -719,7 +715,9 @@ def pruneIncluded(objectslist):
|
|||
if not (Draft.getType(obj) in ["Window","Clone"]):
|
||||
for parent in obj.InList:
|
||||
if parent.isDerivedFrom("Part::Feature"):
|
||||
toplevel = False
|
||||
if not parent.isDerivedFrom("Part::Part2DObject"):
|
||||
# don't consider 2D objects based on arch elements
|
||||
toplevel = False
|
||||
if toplevel:
|
||||
newlist.append(obj)
|
||||
return newlist
|
||||
|
@ -784,8 +782,6 @@ def survey(callback=False):
|
|||
if not found:
|
||||
newsels.append(o)
|
||||
if newsels:
|
||||
from pivy import coin
|
||||
pr = Draft.getParam("dimPrecision",2)
|
||||
for o in newsels:
|
||||
if o.Object.isDerivedFrom("Part::Feature"):
|
||||
n = o.Object.Label
|
||||
|
@ -796,15 +792,18 @@ def survey(callback=False):
|
|||
FreeCAD.SurveyObserver.labels.append(anno.Name)
|
||||
t = ""
|
||||
if o.Object.Shape.Solids:
|
||||
t = str(round(o.Object.Shape.Volume,pr))
|
||||
t = FreeCAD.Units.Quantity(o.Object.Shape.Volume,FreeCAD.Units.Volume)
|
||||
t = t.getUserPreferred()[0]
|
||||
anno.LabelText = "v " + t
|
||||
FreeCAD.Console.PrintMessage("Object: " + n + ", Element: Whole, Volume: " + t + "\n")
|
||||
elif o.Object.Shape.Faces:
|
||||
t = str(round(o.Object.Shape.Area,pr))
|
||||
t = FreeCAD.Units.Quantity(o.Object.Shape.Area,FreeCAD.Units.Area)
|
||||
t = t.getUserPreferred()[0]
|
||||
anno.LabelText = "a " + t
|
||||
FreeCAD.Console.PrintMessage("Object: " + n + ", Element: Whole, Area: " + t + "\n")
|
||||
else:
|
||||
t = str(round(o.Object.Shape.Length,pr))
|
||||
t = FreeCAD.Units.Quantity(o.Object.Shape.Length,FreeCAD.Units.Length)
|
||||
t = t.getUserPreferred()[0]
|
||||
anno.LabelText = "l " + t
|
||||
FreeCAD.Console.PrintMessage("Object: " + n + ", Element: Whole, Length: " + t + "\n")
|
||||
if FreeCAD.GuiUp and t:
|
||||
|
@ -821,15 +820,18 @@ def survey(callback=False):
|
|||
FreeCAD.SurveyObserver.labels.append(anno.Name)
|
||||
t = ""
|
||||
if "Face" in el:
|
||||
t = str(round(e.Area,pr))
|
||||
t = FreeCAD.Units.Quantity(e.Area,FreeCAD.Units.Area)
|
||||
t = t.getUserPreferred()[0]
|
||||
anno.LabelText = "a " + t
|
||||
FreeCAD.Console.PrintMessage("Object: " + n + ", Element: " + el + ", Area: "+ t + "\n")
|
||||
elif "Edge" in el:
|
||||
t = str(round(e.Length,pr))
|
||||
t = FreeCAD.Units.Quantity(e.Length,FreeCAD.Units.Length)
|
||||
t = t.getUserPreferred()[0]
|
||||
anno.LabelText = "l " + t
|
||||
FreeCAD.Console.PrintMessage("Object: " + n + ", Element: " + el + ", Length: " + t + "\n")
|
||||
elif "Vertex" in el:
|
||||
t = str(round(e.Z,pr))
|
||||
t = FreeCAD.Units.Quantity(e.Z,FreeCAD.Units.Length)
|
||||
t = t.getUserPreferred()[0]
|
||||
anno.LabelText = "z " + t
|
||||
FreeCAD.Console.PrintMessage("Object: " + n + ", Element: " + el + ", Zcoord: " + t + "\n")
|
||||
if FreeCAD.GuiUp and t:
|
||||
|
@ -1092,31 +1094,6 @@ class _CommandSurvey:
|
|||
FreeCADGui.doCommand("Arch.survey()")
|
||||
|
||||
|
||||
class _CommandFixture:
|
||||
# OBSOLETE - To be removed
|
||||
"the Arch Fixture command definition"
|
||||
def GetResources(self):
|
||||
return {'Pixmap' : 'Arch_Fixture',
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("Arch_Fixture","Add fixture"),
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_Fixture","Adds the selected components as fixtures to the active object")}
|
||||
|
||||
def IsActive(self):
|
||||
if len(FreeCADGui.Selection.getSelection()) > 1:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def Activated(self):
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Grouping")))
|
||||
host = sel.pop()
|
||||
for o in sel:
|
||||
FreeCADGui.doCommand("import Arch")
|
||||
FreeCADGui.doCommand("Arch.addFixture(FreeCAD.ActiveDocument."+o.Name+",FreeCAD.ActiveDocument."+host.Name+")")
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('Arch_Add',_CommandAdd())
|
||||
FreeCADGui.addCommand('Arch_Remove',_CommandRemove())
|
||||
|
@ -1128,4 +1105,3 @@ if FreeCAD.GuiUp:
|
|||
FreeCADGui.addCommand('Arch_Check',_CommandCheck())
|
||||
FreeCADGui.addCommand('Arch_IfcExplorer',_CommandIfcExplorer())
|
||||
FreeCADGui.addCommand('Arch_Survey',_CommandSurvey())
|
||||
#FreeCADGui.addCommand('Arch_Fixture',_CommandFixture())
|
||||
|
|
|
@ -285,6 +285,8 @@ class Component:
|
|||
obj.addProperty("App::PropertyLink","Base","Arch","The base object this component is built upon")
|
||||
obj.addProperty("App::PropertyLinkList","Additions","Arch","Other shapes that are appended to this object")
|
||||
obj.addProperty("App::PropertyLinkList","Subtractions","Arch","Other shapes that are subtracted from this object")
|
||||
obj.addProperty("App::PropertyString","Description","Arch","An optional description for this component")
|
||||
obj.addProperty("App::PropertyString","Tag","Arch","An optional tag for this component")
|
||||
obj.Proxy = self
|
||||
self.Type = "Component"
|
||||
self.Subvolume = None
|
||||
|
@ -317,6 +319,163 @@ class Component:
|
|||
siblings.append(o)
|
||||
return siblings
|
||||
|
||||
def getAxis(self,obj):
|
||||
"Returns an open wire which is the axis of this component, if applicable"
|
||||
if obj.Base:
|
||||
if obj.Base.isDerivedFrom("Part::Feature"):
|
||||
if obj.Base.Shape:
|
||||
if (len(obj.Base.Shape.Wires) == 1) and not(obj.Base.Shape.Faces):
|
||||
if not obj.Base.Shape.Wires.isClosed():
|
||||
return obj.Base.Shape.copy()
|
||||
elif not(obj.Base.Shape.Solids):
|
||||
p1 = obj.Base.Shape.CenterOfMass
|
||||
v = self.getExtrusionVector(obj)
|
||||
if v:
|
||||
p2 = p1.add(v)
|
||||
import Part
|
||||
return Part.Line(p1,p2).toShape()
|
||||
else:
|
||||
p1 = FreeCAD.Vector()
|
||||
v = self.getExtrusionVector(obj)
|
||||
if v:
|
||||
p2 = p1.add(v)
|
||||
import Part
|
||||
return Part.Line(p1,p2).toShape()
|
||||
return None
|
||||
|
||||
def getProfiles(self,obj,noplacement=False):
|
||||
"Returns the base profile(s) of this component, if applicable"
|
||||
wires = []
|
||||
n,l,w,h = self.getDefaultValues(obj)
|
||||
if obj.Base:
|
||||
if obj.Base.isDerivedFrom("Part::Feature"):
|
||||
if obj.Base.Shape:
|
||||
base = obj.Base.Shape.copy()
|
||||
if noplacement:
|
||||
base.Placement = FreeCAD.Placement()
|
||||
if not base.Solids:
|
||||
if base.Faces:
|
||||
return [base]
|
||||
elif base.Wires:
|
||||
import DraftGeomUtils,DraftVecUtils,Part
|
||||
for wire in base.Wires:
|
||||
dvec = DraftGeomUtils.vec(wire.Edges[0]).cross(n)
|
||||
if not DraftVecUtils.isNull(dvec):
|
||||
dvec.normalize()
|
||||
sh = None
|
||||
if hasattr(obj,"Align"):
|
||||
if obj.Align == "Left":
|
||||
dvec.multiply(w)
|
||||
if hasattr(obj,"Offset"):
|
||||
if obj.Offset.Value:
|
||||
dvec2 = DraftVecUtils.scaleTo(dvec,obj.Offset.Value)
|
||||
wire = DraftGeomUtils.offsetWire(wire,dvec2)
|
||||
w2 = DraftGeomUtils.offsetWire(wire,dvec)
|
||||
w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges))
|
||||
sh = DraftGeomUtils.bind(w1,w2)
|
||||
elif obj.Align == "Right":
|
||||
dvec.multiply(w)
|
||||
dvec = dvec.negative()
|
||||
if hasattr(obj,"Offset"):
|
||||
if obj.Offset.Value:
|
||||
dvec2 = DraftVecUtils.scaleTo(dvec,obj.Offset.Value)
|
||||
wire = DraftGeomUtils.offsetWire(wire,dvec2)
|
||||
w2 = DraftGeomUtils.offsetWire(wire,dvec)
|
||||
w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges))
|
||||
sh = DraftGeomUtils.bind(w1,w2)
|
||||
elif obj.Align == "Center":
|
||||
dvec.multiply(w/2)
|
||||
w1 = DraftGeomUtils.offsetWire(wire,dvec)
|
||||
dvec = dvec.negative()
|
||||
w2 = DraftGeomUtils.offsetWire(wire,dvec)
|
||||
sh = DraftGeomUtils.bind(w1,w2)
|
||||
if sh:
|
||||
wires.append(sh)
|
||||
else:
|
||||
if (Draft.getType(obj) == "Structure") and (l > h):
|
||||
if noplacement:
|
||||
h2 = h/2 or 0.5
|
||||
w2 = w/2 or 0.5
|
||||
v1 = Vector(-h2,-w2,0)
|
||||
v2 = Vector(h2,-w2,0)
|
||||
v3 = Vector(h2,w2,0)
|
||||
v4 = Vector(-h2,w2,0)
|
||||
else:
|
||||
h2 = h/2 or 0.5
|
||||
w2 = w/2 or 0.5
|
||||
v1 = Vector(0,-w2,-h2)
|
||||
v2 = Vector(0,-w2,h2)
|
||||
v3 = Vector(0,w2,h2)
|
||||
v4 = Vector(0,w2,-h2)
|
||||
else:
|
||||
l2 = l/2 or 0.5
|
||||
w2 = w/2 or 0.5
|
||||
v1 = Vector(-l2,-w2,0)
|
||||
v2 = Vector(l2,-w2,0)
|
||||
v3 = Vector(l2,w2,0)
|
||||
v4 = Vector(-l2,w2,0)
|
||||
import Part
|
||||
base = Part.makePolygon([v1,v2,v3,v4,v1])
|
||||
return [base]
|
||||
return wires
|
||||
|
||||
def getExtrusionVector(self,obj,noplacement=False):
|
||||
"Returns an extrusion vector of this component, if applicable"
|
||||
n,l,w,h = self.getDefaultValues(obj)
|
||||
if Draft.getType(obj) == "Structure":
|
||||
if l > h:
|
||||
v = n.multiply(l)
|
||||
if noplacement:
|
||||
import DraftVecUtils
|
||||
v = DraftVecUtils.rounded(FreeCAD.Rotation(FreeCAD.Vector(0,1,0),-90).multVec(v))
|
||||
return v
|
||||
return n.multiply(h)
|
||||
|
||||
def getDefaultValues(self,obj):
|
||||
"returns normal,length,width,height values from this component"
|
||||
length = 0
|
||||
if hasattr(obj,"Length"):
|
||||
if obj.Length.Value:
|
||||
length = obj.Length.Value
|
||||
width = 0
|
||||
if hasattr(obj,"Width"):
|
||||
if obj.Width.Value:
|
||||
width = obj.Width.Value
|
||||
height = 0
|
||||
if hasattr(obj,"Height"):
|
||||
if obj.Height.Value:
|
||||
height = obj.Height.Value
|
||||
else:
|
||||
for p in obj.InList:
|
||||
if Draft.getType(p) == "Floor":
|
||||
if p.Height.Value:
|
||||
height = p.Height.Value
|
||||
default = Vector(0,0,1)
|
||||
if Draft.getType(obj) == "Structure":
|
||||
if length > height:
|
||||
default = Vector(1,0,0)
|
||||
if hasattr(obj,"Normal"):
|
||||
if obj.Normal == Vector(0,0,0):
|
||||
normal = default
|
||||
else:
|
||||
normal = Vector(obj.Normal)
|
||||
else:
|
||||
normal = default
|
||||
return normal,length,width,height
|
||||
|
||||
def getPlacement(self,obj):
|
||||
"returns a total placement for the profile of this component"
|
||||
p = FreeCAD.Placement()
|
||||
if obj.Base:
|
||||
p = obj.Base.Placement.multiply(p)
|
||||
else:
|
||||
if Draft.getType(obj) == "Structure":
|
||||
n,l,w,h = self.getDefaultValues(obj)
|
||||
if l > h:
|
||||
p.Rotation = FreeCAD.Rotation(FreeCAD.Vector(0,1,0),90)
|
||||
p = obj.Placement.multiply(p)
|
||||
return p
|
||||
|
||||
def hideSubobjects(self,obj,prop):
|
||||
"Hides subobjects when a subobject lists change"
|
||||
if prop in ["Additions","Subtractions"]:
|
||||
|
@ -328,17 +487,17 @@ class Component:
|
|||
continue
|
||||
o.ViewObject.hide()
|
||||
|
||||
def processSubShapes(self,obj,base,pl=None):
|
||||
def processSubShapes(self,obj,base,placement=None):
|
||||
"Adds additions and subtractions to a base shape"
|
||||
import Draft,Part
|
||||
#print "Processing subshapes of ",obj.Label, " : ",obj.Additions
|
||||
|
||||
if pl:
|
||||
if pl.isNull():
|
||||
pl = None
|
||||
if placement:
|
||||
if placement.isNull():
|
||||
placement = None
|
||||
else:
|
||||
pl = FreeCAD.Placement(pl)
|
||||
pl = pl.inverse()
|
||||
placement = FreeCAD.Placement(placement)
|
||||
placement = placement.inverse()
|
||||
|
||||
# treat additions
|
||||
for o in obj.Additions:
|
||||
|
@ -356,16 +515,16 @@ class Component:
|
|||
js = ArchWall.mergeShapes(o,obj)
|
||||
if js:
|
||||
add = js.cut(base)
|
||||
if pl:
|
||||
add.Placement = add.Placement.multiply(pl)
|
||||
if placement:
|
||||
add.Placement = add.Placement.multiply(placement)
|
||||
base = base.fuse(add)
|
||||
|
||||
elif (Draft.getType(o) == "Window") or (Draft.isClone(o,"Window")):
|
||||
f = o.Proxy.getSubVolume(o)
|
||||
if f:
|
||||
if base.Solids and f.Solids:
|
||||
if pl:
|
||||
f.Placement = f.Placement.multiply(pl)
|
||||
if placemen:
|
||||
f.Placement = f.Placement.multiply(placement)
|
||||
base = base.cut(f)
|
||||
|
||||
elif o.isDerivedFrom("Part::Feature"):
|
||||
|
@ -373,8 +532,8 @@ class Component:
|
|||
if not o.Shape.isNull():
|
||||
if o.Shape.Solids:
|
||||
s = o.Shape.copy()
|
||||
if pl:
|
||||
s.Placement = s.Placement.multiply(pl)
|
||||
if placement:
|
||||
s.Placement = s.Placement.multiply(placement)
|
||||
if base:
|
||||
if base.Solids:
|
||||
try:
|
||||
|
@ -397,8 +556,8 @@ class Component:
|
|||
f = o.Proxy.getSubVolume(o)
|
||||
if f:
|
||||
if base.Solids and f.Solids:
|
||||
if pl:
|
||||
f.Placement = f.Placement.multiply(pl)
|
||||
if placement:
|
||||
f.Placement = f.Placement.multiply(placement)
|
||||
base = base.cut(f)
|
||||
|
||||
elif (Draft.getType(o) == "Roof") or (Draft.isClone(o,"Roof")):
|
||||
|
@ -413,13 +572,29 @@ class Component:
|
|||
if not o.Shape.isNull():
|
||||
if o.Shape.Solids and base.Solids:
|
||||
s = o.Shape.copy()
|
||||
if pl:
|
||||
s.Placement = s.Placement.multiply(pl)
|
||||
if placement:
|
||||
s.Placement = s.Placement.multiply(placement)
|
||||
try:
|
||||
base = base.cut(s)
|
||||
except:
|
||||
print "Arch: unable to cut object ",o.Name, " from ", obj.Name
|
||||
return base
|
||||
|
||||
def applyShape(self,obj,shape,placement):
|
||||
"checks and cleans the given shape, and apply it to the object"
|
||||
if shape:
|
||||
if not shape.isNull():
|
||||
if shape.isValid() and shape.Solids:
|
||||
if shape.Volume < 0:
|
||||
shape.reverse()
|
||||
if shape.Volume < 0:
|
||||
FreeCAD.Console.PrintError(translate("Arch","Error computing the shape of this object"))
|
||||
return
|
||||
shape = shape.removeSplitter()
|
||||
obj.Shape = shape
|
||||
if not placement.isNull():
|
||||
obj.Placement = placement
|
||||
|
||||
|
||||
class ViewProviderComponent:
|
||||
"A default View Provider for Component objects"
|
||||
|
|
|
@ -35,6 +35,8 @@ __title__="FreeCAD Arch Frame"
|
|||
__author__ = "Yorik van Havre"
|
||||
__url__ = "http://www.freecadweb.org"
|
||||
|
||||
# Possible roles for frames
|
||||
Roles = ['Covering','Member','Railing','Shading Device','Tendon']
|
||||
|
||||
def makeFrame(base,profile,name=translate("Arch","Frame")):
|
||||
"""makeFrame(base,profile,[name]): creates a frame object from a base sketch (or any other object
|
||||
|
@ -75,7 +77,9 @@ class _Frame(ArchComponent.Component):
|
|||
obj.addProperty("App::PropertyBool","Align","Arch","Specifies if the profile must be aligned with the extrusion wires")
|
||||
obj.addProperty("App::PropertyVector","Offset","Arch","An offset vector between the base sketch and the frame")
|
||||
obj.addProperty("App::PropertyAngle","Rotation","Arch","The rotation of the profile around its extrusion axis")
|
||||
obj.addProperty("App::PropertyEnumeration","Role","Arch","The role of this wall")
|
||||
self.Type = "Frame"
|
||||
obj.Role = Roles
|
||||
|
||||
def execute(self,obj):
|
||||
if not obj.Base:
|
||||
|
|
|
@ -41,7 +41,7 @@ if FreeCAD.GuiUp:
|
|||
QtCore.QT_TRANSLATE_NOOP("Arch","Steel")
|
||||
|
||||
# Possible roles for structural elements
|
||||
Roles = ["Beam","Column","Slab","Wall","Containment wall","Roof","Foundation"]
|
||||
Roles = ["Beam","Column","Slab","Wall","Curtain Wall","Roof","Foundation","Pile","Tendon"]
|
||||
|
||||
# Presets in the form: Class, Name, Width, Height, [Web thickness, Flange thickness]
|
||||
Presets = [None,
|
||||
|
@ -287,11 +287,12 @@ Presets = [None,
|
|||
|
||||
]
|
||||
|
||||
def makeStructure(baseobj=None,length=0,width=0,height=0,name=translate("Arch","Structure")):
|
||||
def makeStructure(baseobj=None,length=None,width=None,height=None,name=translate("Arch","Structure")):
|
||||
'''makeStructure([obj],[length],[width],[heigth],[swap]): creates a
|
||||
structure element based on the given profile object and the given
|
||||
extrusion height. If no base object is given, you can also specify
|
||||
length and width for a cubic object.'''
|
||||
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch")
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name)
|
||||
_Structure(obj)
|
||||
_ViewProviderStructure(obj.ViewObject)
|
||||
|
@ -300,10 +301,19 @@ def makeStructure(baseobj=None,length=0,width=0,height=0,name=translate("Arch","
|
|||
obj.Base.ViewObject.hide()
|
||||
if width:
|
||||
obj.Width = width
|
||||
else:
|
||||
obj.Width = p.GetFloat("StructureWidth",100)
|
||||
if height:
|
||||
obj.Height = height
|
||||
else:
|
||||
obj.Height = p.GetFloat("StructureHeight",1000)
|
||||
if length:
|
||||
obj.Length = length
|
||||
else:
|
||||
if not baseobj:
|
||||
# don't set the length if we have a base object, otherwise the lenght X height calc
|
||||
# gets wrong
|
||||
obj.Length = p.GetFloat("StructureLength",100)
|
||||
if height > length:
|
||||
obj.Role = "Column"
|
||||
obj.ViewObject.ShapeColor = ArchCommands.getDefaultColor("Structure")
|
||||
|
@ -362,7 +372,8 @@ class _CommandStructure:
|
|||
self.Profile = 0
|
||||
self.continueCmd = False
|
||||
self.DECIMALS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Units").GetInt("Decimals",2)
|
||||
self.FORMAT = "%." + str(self.DECIMALS) + "f mm"
|
||||
import DraftGui
|
||||
self.FORMAT = DraftGui.makeFormatSpec(self.DECIMALS,'Length')
|
||||
sel = FreeCADGui.Selection.getSelection()
|
||||
if sel:
|
||||
st = Draft.getObjectsOfType(sel,"Structure")
|
||||
|
@ -412,6 +423,7 @@ class _CommandStructure:
|
|||
# horizontal
|
||||
FreeCADGui.doCommand('s = Arch.makeStructure(p,height='+str(self.Length)+')')
|
||||
FreeCADGui.doCommand('s.Placement.Rotation = FreeCAD.Rotation(-0.5,0.5,-0.5,0.5)')
|
||||
FreeCADGui.doCommand('s.Profile = "'+pr[1]+'"')
|
||||
else:
|
||||
FreeCADGui.doCommand('s = Arch.makeStructure(length='+str(self.Length)+',width='+str(self.Width)+',height='+str(self.Height)+')')
|
||||
FreeCADGui.doCommand('s.Placement.Base = '+DraftVecUtils.toString(point))
|
||||
|
@ -537,10 +549,8 @@ class _Structure(ArchComponent.Component):
|
|||
obj.addProperty("App::PropertyVector","Normal","Arch",translate("Arch","The normal extrusion direction of this object (keep (0,0,0) for automatic normal)"))
|
||||
obj.addProperty("App::PropertyEnumeration","Role","Arch",translate("Arch","The role of this structural element"))
|
||||
obj.addProperty("App::PropertyVectorList","Nodes","Arch",translate("Arch","The structural nodes of this element"))
|
||||
obj.addProperty("App::PropertyString","Profile","Arch","A description of the standard profile this element is based upon")
|
||||
self.Type = "Structure"
|
||||
obj.Length = 1
|
||||
obj.Width = 1
|
||||
obj.Height = 1
|
||||
obj.Role = Roles
|
||||
|
||||
def execute(self,obj):
|
||||
|
@ -548,24 +558,7 @@ class _Structure(ArchComponent.Component):
|
|||
|
||||
import Part, DraftGeomUtils
|
||||
|
||||
# getting default values
|
||||
length = 1
|
||||
width = 1
|
||||
height = 1
|
||||
if hasattr(obj,"Length"):
|
||||
if obj.Length.Value:
|
||||
length = obj.Length.Value
|
||||
if hasattr(obj,"Width"):
|
||||
if obj.Width.Value:
|
||||
width = obj.Width.Value
|
||||
if hasattr(obj,"Height"):
|
||||
if obj.Height.Value:
|
||||
height = obj.Height.Value
|
||||
else:
|
||||
for p in obj.InList:
|
||||
if Draft.getType(p) == "Floor":
|
||||
if p.Height.Value:
|
||||
height = p.Height.Value
|
||||
normal,length,width,height = self.getDefaultValues(obj)
|
||||
|
||||
# creating base shape
|
||||
pl = obj.Placement
|
||||
|
@ -574,6 +567,8 @@ class _Structure(ArchComponent.Component):
|
|||
if obj.Base.isDerivedFrom("Part::Feature"):
|
||||
if obj.Base.Shape.isNull():
|
||||
return
|
||||
if not obj.Base.Shape.isValid():
|
||||
return
|
||||
if hasattr(obj,"Tool"):
|
||||
if obj.Tool:
|
||||
try:
|
||||
|
@ -582,9 +577,11 @@ class _Structure(ArchComponent.Component):
|
|||
FreeCAD.Console.PrintError(translate("Arch","Error: The base shape couldn't be extruded along this tool object"))
|
||||
return
|
||||
if not base:
|
||||
if not height:
|
||||
return
|
||||
if obj.Normal == Vector(0,0,0):
|
||||
p = FreeCAD.Placement(obj.Base.Placement)
|
||||
normal = p.Rotation.multVec(Vector(0,0,1))
|
||||
normal = p.Rotation.multVec(normal)
|
||||
else:
|
||||
normal = Vector(obj.Normal)
|
||||
normal = normal.multiply(height)
|
||||
|
@ -592,64 +589,33 @@ class _Structure(ArchComponent.Component):
|
|||
if base.Solids:
|
||||
pass
|
||||
elif base.Faces:
|
||||
self.BaseProfile = base
|
||||
self.ExtrusionVector = normal
|
||||
base = base.extrude(normal)
|
||||
elif (len(base.Wires) == 1):
|
||||
if base.Wires[0].isClosed():
|
||||
base = Part.Face(base.Wires[0])
|
||||
self.BaseProfile = base
|
||||
self.ExtrusionVector = normal
|
||||
base = base.extrude(normal)
|
||||
|
||||
elif obj.Base.isDerivedFrom("Mesh::Feature"):
|
||||
if obj.Base.Mesh.isSolid():
|
||||
if obj.Base.Mesh.countComponents() == 1:
|
||||
sh = ArchCommands.getShapeFromMesh(obj.Base.Mesh)
|
||||
if sh.isClosed() and sh.isValid() and sh.Solids:
|
||||
if sh.isClosed() and sh.isValid() and sh.Solids and (not sh.isNull()):
|
||||
base = sh
|
||||
else:
|
||||
FreeCAD.Console.PrintWarning(str(translate("Arch","This mesh is an invalid solid")))
|
||||
obj.Base.ViewObject.show()
|
||||
else:
|
||||
if obj.Normal == Vector(0,0,0):
|
||||
base = self.getProfiles(obj)
|
||||
if base:
|
||||
if length > height:
|
||||
normal = Vector(1,0,0).multiply(length)
|
||||
normal = normal.multiply(length)
|
||||
else:
|
||||
normal = Vector(0,0,1).multiply(height)
|
||||
else:
|
||||
normal = Vector(obj.Normal).multiply(height)
|
||||
self.ExtrusionVector = normal
|
||||
if length > height:
|
||||
h2 = height/2 or 0.5
|
||||
w2 = width/2 or 0.5
|
||||
v1 = Vector(0,-w2,-h2)
|
||||
v2 = Vector(0,-w2,h2)
|
||||
v3 = Vector(0,w2,h2)
|
||||
v4 = Vector(0,w2,-h2)
|
||||
else:
|
||||
l2 = length/2 or 0.5
|
||||
w2 = width/2 or 0.5
|
||||
v1 = Vector(-l2,-w2,0)
|
||||
v2 = Vector(l2,-w2,0)
|
||||
v3 = Vector(l2,w2,0)
|
||||
v4 = Vector(-l2,w2,0)
|
||||
base = Part.makePolygon([v1,v2,v3,v4,v1])
|
||||
base = Part.Face(base)
|
||||
self.BaseProfile = base
|
||||
base = base.extrude(self.ExtrusionVector)
|
||||
normal = normal.multiply(height)
|
||||
base = Part.Face(base[0])
|
||||
base = base.extrude(normal)
|
||||
|
||||
base = self.processSubShapes(obj,base,pl)
|
||||
|
||||
if base:
|
||||
if not base.isNull():
|
||||
if base.isValid() and base.Solids:
|
||||
if base.Volume < 0:
|
||||
base.reverse()
|
||||
if base.Volume < 0:
|
||||
FreeCAD.Console.PrintError(translate("Arch","Couldn't compute a shape"))
|
||||
return
|
||||
base = base.removeSplitter()
|
||||
obj.Shape = base
|
||||
if not pl.isNull():
|
||||
obj.Placement = pl
|
||||
self.applyShape(obj,base,pl)
|
||||
|
||||
def onChanged(self,obj,prop):
|
||||
self.hideSubobjects(obj,prop)
|
||||
|
@ -665,16 +631,14 @@ class _Structure(ArchComponent.Component):
|
|||
else:
|
||||
# nodes haven't been calculated yet, but are set (file load)
|
||||
# we calculate the nodes now but don't change the property
|
||||
if hasattr(self,"BaseProfile") and hasattr(self,"ExtrusionVector"):
|
||||
p1 = self.BaseProfile.CenterOfMass
|
||||
p2 = p1.add(self.ExtrusionVector)
|
||||
self.nodes = [p1,p2]
|
||||
axis = self.getAxis(obj)
|
||||
if axis:
|
||||
self.nodes = [v.Point for v in axis.Vertexes]
|
||||
return
|
||||
if hasattr(self,"BaseProfile") and hasattr(self,"ExtrusionVector"):
|
||||
p1 = self.BaseProfile.CenterOfMass
|
||||
p2 = p1.add(self.ExtrusionVector)
|
||||
self.nodes = [p1,p2]
|
||||
#print "calculating nodes: ",self.nodes
|
||||
# we calculate and set the nodes
|
||||
axis = self.getAxis(obj)
|
||||
if axis:
|
||||
self.nodes = [v.Point for v in axis.Vertexes]
|
||||
obj.Nodes = self.nodes
|
||||
|
||||
|
||||
|
|
|
@ -35,6 +35,9 @@ __title__="FreeCAD Wall"
|
|||
__author__ = "Yorik van Havre"
|
||||
__url__ = "http://www.freecadweb.org"
|
||||
|
||||
# Possible roles for walls
|
||||
Roles = ['Wall','Wall Layer','Beam','Column','Curtain Wall']
|
||||
|
||||
def makeWall(baseobj=None,length=None,width=None,height=None,align="Center",face=None,name=translate("Arch","Wall")):
|
||||
'''makeWall([obj],[length],[width],[height],[align],[face],[name]): creates a wall based on the
|
||||
given object, which can be a sketch, a draft object, a face or a solid, or no object at
|
||||
|
@ -157,7 +160,8 @@ class _CommandWall:
|
|||
self.JOIN_WALLS_SKETCHES = p.GetBool("joinWallSketches",False)
|
||||
self.AUTOJOIN = p.GetBool("autoJoinWalls",True)
|
||||
self.DECIMALS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Units").GetInt("Decimals",2)
|
||||
self.FORMAT = "%." + str(self.DECIMALS) + "f mm"
|
||||
import DraftGui
|
||||
self.FORMAT = DraftGui.makeFormatSpec(self.DECIMALS,'Length')
|
||||
sel = FreeCADGui.Selection.getSelectionEx()
|
||||
done = False
|
||||
self.existing = []
|
||||
|
@ -387,15 +391,12 @@ class _Wall(ArchComponent.Component):
|
|||
obj.addProperty("App::PropertyLength","Height","Arch",translate("Arch","The height of this wall. Keep 0 for automatic. Not used if this wall is based on a solid"))
|
||||
obj.addProperty("App::PropertyEnumeration","Align","Arch",translate("Arch","The alignment of this wall on its base object, if applicable"))
|
||||
obj.addProperty("App::PropertyVector","Normal","Arch",translate("Arch","The normal extrusion direction of this object (keep (0,0,0) for automatic normal)"))
|
||||
obj.addProperty("App::PropertyBool","ForceWire","Arch",translate("Arch","If True, if this wall is based on a face, it will use its border wire as trace, and disconsider the face."))
|
||||
obj.addProperty("App::PropertyInteger","Face","Arch",translate("Arch","The face number of the base object used to build this wall"))
|
||||
obj.addProperty("App::PropertyLength","Offset","Arch",translate("Arch","The offset between this wall and its baseline (only for left and right alignments)"))
|
||||
obj.addProperty("App::PropertyEnumeration","Role","Arch",translate("Arch","The role of this wall"))
|
||||
obj.Align = ['Left','Right','Center']
|
||||
obj.ForceWire = False
|
||||
obj.Role = Roles
|
||||
self.Type = "Wall"
|
||||
obj.Width = 1
|
||||
obj.Height = 1
|
||||
obj.Length = 1
|
||||
|
||||
def execute(self,obj):
|
||||
"builds the wall shape"
|
||||
|
@ -404,62 +405,50 @@ class _Wall(ArchComponent.Component):
|
|||
pl = obj.Placement
|
||||
normal,length,width,height = self.getDefaultValues(obj)
|
||||
base = None
|
||||
|
||||
# computing a shape from scratch
|
||||
if not obj.Base:
|
||||
if length and width and height:
|
||||
base = Part.makeBox(length,width,height)
|
||||
else:
|
||||
FreeCAD.Console.PrintError(str(translate("Arch","Error: Unable to compute a base shape")))
|
||||
return
|
||||
else:
|
||||
face = None
|
||||
|
||||
if obj.Base:
|
||||
# computing a shape from a base object
|
||||
if obj.Base.isDerivedFrom("Part::Feature"):
|
||||
if not obj.Base.Shape.isNull():
|
||||
if obj.Base.Shape.isValid():
|
||||
base = obj.Base.Shape.copy()
|
||||
face = None
|
||||
if hasattr(obj,"Face"):
|
||||
if obj.Face:
|
||||
if len(base.Faces) >= obj.Face:
|
||||
face = base.Faces[obj.Face-1]
|
||||
if face:
|
||||
# wall is based on a face
|
||||
normal = face.normalAt(0,0)
|
||||
if normal.getAngle(Vector(0,0,1)) > math.pi/4:
|
||||
normal.multiply(width)
|
||||
base = face.extrude(normal)
|
||||
if obj.Align == "Center":
|
||||
base.translate(normal.negative().multiply(0.5))
|
||||
elif obj.Align == "Right":
|
||||
base.translate(normal.negative())
|
||||
else:
|
||||
normal.multiply(height)
|
||||
base = face.extrude(normal)
|
||||
elif base.Solids:
|
||||
pass
|
||||
elif (len(base.Faces) == 1) and (not obj.ForceWire):
|
||||
if height:
|
||||
normal.multiply(height)
|
||||
base = base.extrude(normal)
|
||||
elif len(base.Wires) >= 1:
|
||||
temp = None
|
||||
for wire in obj.Base.Shape.Wires:
|
||||
sh = self.getBase(obj,wire,normal,width,height)
|
||||
if temp:
|
||||
temp = temp.fuse(sh)
|
||||
else:
|
||||
temp = sh
|
||||
base = temp
|
||||
elif base.Edges:
|
||||
wire = Part.Wire(base.Edges)
|
||||
if wire:
|
||||
sh = self.getBase(obj,wire,normal,width,height)
|
||||
if sh:
|
||||
base = sh
|
||||
else:
|
||||
base = None
|
||||
FreeCAD.Console.PrintError(str(translate("Arch","Error: Invalid base object")))
|
||||
if obj.Base.Shape.isNull():
|
||||
return
|
||||
if not obj.Base.Shape.isValid():
|
||||
return
|
||||
|
||||
if hasattr(obj,"Face"):
|
||||
if obj.Face > 0:
|
||||
if len(obj.Base.Shape.Faces) >= obj.Face:
|
||||
face = obj.Base.Shape.Faces[obj.Face-1]
|
||||
if face:
|
||||
# case 1: this wall is based on a specific face of its base object
|
||||
normal = face.normalAt(0,0)
|
||||
if normal.getAngle(Vector(0,0,1)) > math.pi/4:
|
||||
normal.multiply(width)
|
||||
base = face.extrude(normal)
|
||||
if obj.Align == "Center":
|
||||
base.translate(normal.negative().multiply(0.5))
|
||||
elif obj.Align == "Right":
|
||||
base.translate(normal.negative())
|
||||
else:
|
||||
normal.multiply(height)
|
||||
base = face.extrude(normal)
|
||||
elif obj.Base.Shape.Solids:
|
||||
# case 2: the base is already a solid
|
||||
base = obj.Base.Shape.copy()
|
||||
elif obj.Base.Shape.Edges:
|
||||
# case 3: the base is flat, we need to extrude it
|
||||
profiles = self.getProfiles(obj)
|
||||
normal.multiply(height)
|
||||
base = profiles.pop()
|
||||
base.fix(0.1,0,1)
|
||||
base = base.extrude(normal)
|
||||
for p in profiles:
|
||||
p.fix(0.1,0,1)
|
||||
p = p.extrude(normal)
|
||||
base = base.fuse(p)
|
||||
else:
|
||||
base = None
|
||||
FreeCAD.Console.PrintError(str(translate("Arch","Error: Invalid base object")))
|
||||
|
||||
elif obj.Base.isDerivedFrom("Mesh::Feature"):
|
||||
if obj.Base.Mesh.isSolid():
|
||||
|
@ -470,24 +459,13 @@ class _Wall(ArchComponent.Component):
|
|||
else:
|
||||
FreeCAD.Console.PrintWarning(str(translate("Arch","This mesh is an invalid solid")))
|
||||
obj.Base.ViewObject.show()
|
||||
else:
|
||||
# computing a shape from scratch
|
||||
if length and width and height:
|
||||
base = Part.makeBox(length,width,height)
|
||||
|
||||
base = self.processSubShapes(obj,base,pl)
|
||||
|
||||
if base:
|
||||
if not base.isNull():
|
||||
if base.isValid() and base.Solids:
|
||||
if base.Volume < 0:
|
||||
base.reverse()
|
||||
if base.Volume < 0:
|
||||
FreeCAD.Console.PrintError(str(translate("Arch","Couldn't compute the wall shape")))
|
||||
return
|
||||
try:
|
||||
base = base.removeSplitter()
|
||||
except:
|
||||
FreeCAD.Console.PrintError(str(translate("Arch","Error removing splitter from wall shape")))
|
||||
obj.Shape = base
|
||||
if not pl.isNull():
|
||||
obj.Placement = pl
|
||||
self.applyShape(obj,base,pl)
|
||||
|
||||
def onChanged(self,obj,prop):
|
||||
self.hideSubobjects(obj,prop)
|
||||
|
@ -503,77 +481,6 @@ class _Wall(ArchComponent.Component):
|
|||
if (Draft.getType(o) == "Window") or Draft.isClone(o,"Window"):
|
||||
o.Placement.move(delta)
|
||||
ArchComponent.Component.onChanged(self,obj,prop)
|
||||
|
||||
def getDefaultValues(self,obj):
|
||||
"returns normal,width,height values from this wall"
|
||||
length = 1
|
||||
if hasattr(obj,"Length"):
|
||||
if obj.Length.Value:
|
||||
length = obj.Length.Value
|
||||
width = 1
|
||||
if hasattr(obj,"Width"):
|
||||
if obj.Width.Value:
|
||||
width = obj.Width.Value
|
||||
height = 1
|
||||
if hasattr(obj,"Height"):
|
||||
if obj.Height.Value:
|
||||
height = obj.Height.Value
|
||||
else:
|
||||
for p in obj.InList:
|
||||
if Draft.getType(p) == "Floor":
|
||||
if p.Height.Value:
|
||||
height = p.Height.Value
|
||||
normal = None
|
||||
if hasattr(obj,"Normal"):
|
||||
if obj.Normal == Vector(0,0,0):
|
||||
normal = Vector(0,0,1)
|
||||
else:
|
||||
normal = Vector(obj.Normal)
|
||||
else:
|
||||
normal = Vector(0,0,1)
|
||||
return normal,length,width,height
|
||||
|
||||
def getBase(self,obj,wire,normal,width,height):
|
||||
"returns a full shape from a base wire"
|
||||
import DraftGeomUtils,Part
|
||||
flat = False
|
||||
if hasattr(obj.ViewObject,"DisplayMode"):
|
||||
flat = (obj.ViewObject.DisplayMode == "Flat 2D")
|
||||
dvec = DraftGeomUtils.vec(wire.Edges[0]).cross(normal)
|
||||
if not DraftVecUtils.isNull(dvec):
|
||||
dvec.normalize()
|
||||
if obj.Align == "Left":
|
||||
dvec.multiply(width)
|
||||
if hasattr(obj,"Offset"):
|
||||
if obj.Offset.Value:
|
||||
dvec2 = DraftVecUtils.scaleTo(dvec,obj.Offset.Value)
|
||||
wire = DraftGeomUtils.offsetWire(wire,dvec2)
|
||||
w2 = DraftGeomUtils.offsetWire(wire,dvec)
|
||||
w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges))
|
||||
sh = DraftGeomUtils.bind(w1,w2)
|
||||
elif obj.Align == "Right":
|
||||
dvec.multiply(width)
|
||||
dvec = dvec.negative()
|
||||
if hasattr(obj,"Offset"):
|
||||
if obj.Offset.Value:
|
||||
dvec2 = DraftVecUtils.scaleTo(dvec,obj.Offset.Value)
|
||||
wire = DraftGeomUtils.offsetWire(wire,dvec2)
|
||||
w2 = DraftGeomUtils.offsetWire(wire,dvec)
|
||||
w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges))
|
||||
sh = DraftGeomUtils.bind(w1,w2)
|
||||
elif obj.Align == "Center":
|
||||
dvec.multiply(width/2)
|
||||
w1 = DraftGeomUtils.offsetWire(wire,dvec)
|
||||
dvec = dvec.negative()
|
||||
w2 = DraftGeomUtils.offsetWire(wire,dvec)
|
||||
sh = DraftGeomUtils.bind(w1,w2)
|
||||
# fixing self-intersections
|
||||
sh.fix(0.1,0,1)
|
||||
self.BaseProfile = sh
|
||||
if height and (not flat):
|
||||
self.ExtrusionVector = Vector(normal).multiply(height)
|
||||
sh = sh.extrude(self.ExtrusionVector)
|
||||
return sh
|
||||
|
||||
|
||||
class _ViewProviderWall(ArchComponent.ViewProviderComponent):
|
||||
|
|
|
@ -383,7 +383,8 @@ class _CommandWindow:
|
|||
self.baseFace = None
|
||||
self.wparams = ["Width","Height","H1","H2","H3","W1","W2","O1","O2"]
|
||||
self.DECIMALS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Units").GetInt("Decimals",2)
|
||||
self.FORMAT = "%." + str(self.DECIMALS) + "f mm"
|
||||
import DraftGui
|
||||
self.FORMAT = DraftGui.makeFormatSpec(self.DECIMALS,'Length')
|
||||
|
||||
# auto mode
|
||||
if sel:
|
||||
|
@ -810,7 +811,8 @@ class _ArchWindowTaskPanel:
|
|||
|
||||
self.obj = None
|
||||
self.DECIMALS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Units").GetInt("Decimals",2)
|
||||
self.FORMAT = "%." + str(self.DECIMALS) + "f mm"
|
||||
import DraftGui
|
||||
self.FORMAT = DraftGui.makeFormatSpec(self.DECIMALS,'Length')
|
||||
self.form = QtGui.QWidget()
|
||||
self.form.setObjectName("TaskPanel")
|
||||
self.grid = QtGui.QGridLayout(self.form)
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -299,23 +299,6 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_14">
|
||||
<item>
|
||||
<widget class="Gui::PrefCheckBox" name="checkBox_4">
|
||||
<property name="text">
|
||||
<string>Aggregate windows to their host objects</string>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>ifcAggregateWindows</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Arch</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
@ -397,14 +397,17 @@ class IfcDocument(object):
|
|||
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):
|
||||
def addPlacement(self,reference=None,origin=(0,0,0),xaxis=(1,0,0),zaxis=(0,0,1),local=True,flat=False):
|
||||
"""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
|
||||
placement is returned, otherwise a local one."""
|
||||
xvc = create(self._fileobject,"IfcDirection",getTuple(xaxis))
|
||||
zvc = create(self._fileobject,"IfcDirection",getTuple(zaxis))
|
||||
ovc = create(self._fileobject,"IfcCartesianPoint",getTuple(origin))
|
||||
gpl = create(self._fileobject,"IfcAxis2Placement3D",[ovc,zvc,xvc])
|
||||
if flat:
|
||||
gpl = create(self._fileobject,"IfcAxis2Placement2D",[ovc,xvc])
|
||||
else:
|
||||
gpl = create(self._fileobject,"IfcAxis2Placement3D",[ovc,zvc,xvc])
|
||||
if local:
|
||||
lpl = create(self._fileobject,"IfcLocalPlacement",[reference,gpl])
|
||||
return lpl
|
||||
|
@ -450,72 +453,53 @@ class IfcDocument(object):
|
|||
else:
|
||||
create(self._fileobject,"IfcRelAggregates",[uid(),self._owner,'Relationship','',container,entities])
|
||||
|
||||
def addWall(self,shapes,storey=None,placement=None,name="Default wall",description=None,standard=False):
|
||||
"""addWall(shapes,[storey,placement,name,description]): creates a wall from the given representation shape(s)"""
|
||||
def addProduct(self,elttype,shapes,storey=None,placement=None,name="Unnamed element",description=None,extra=None):
|
||||
"""addProduct(elttype,representations,[storey,placement,name,description,extra]): creates an element of the given type
|
||||
(IfcWall, IfcBeam, etc...) with the given attributes, plus the given extra attributes."""
|
||||
if not extra:
|
||||
extra = []
|
||||
if not description:
|
||||
description = None
|
||||
if not placement:
|
||||
placement = self.addPlacement()
|
||||
if not isinstance(shapes,list):
|
||||
shapes = [shapes]
|
||||
if standard:
|
||||
solidType = "SweptSolid"
|
||||
else:
|
||||
solidType = "Brep"
|
||||
reps = [create(self._fileobject,"IfcShapeRepresentation",[self._repcontext,'Body',solidType,[shape]]) for shape in shapes]
|
||||
prd = create(self._fileobject,"IfcProductDefinitionShape",[None,None,reps])
|
||||
if standard:
|
||||
wal = create(self._fileobject,"IfcWallStandardCase",[uid(),self._owner,name,description,None,placement,prd,None])
|
||||
else:
|
||||
wal = create(self._fileobject,"IfcWall",[uid(),self._owner,name,description,None,placement,prd,None])
|
||||
self.BuildingProducts.append(wal)
|
||||
representations = self.addRepresentations(shapes)
|
||||
prd = create(self._fileobject,"IfcProductDefinitionShape",[None,None,representations])
|
||||
try:
|
||||
elt = create(self._fileobject,elttype,[uid(),self._owner,name,description,None,placement,prd,None]+extra)
|
||||
except:
|
||||
print "unable to create an ",elttype, " with attributes: ",[uid(),self._owner,name,description,None,placement,prd,None]+extra
|
||||
print "supported attributes are: "
|
||||
o = IfcImport.Entity(elttype)
|
||||
print getPropertyNames(o)
|
||||
raise
|
||||
self.BuildingProducts.append(elt)
|
||||
if not storey:
|
||||
if self.Storeys:
|
||||
storey = self.Storeys[0]
|
||||
else:
|
||||
storey = self.addStorey()
|
||||
self._relate(storey,wal)
|
||||
return wal
|
||||
|
||||
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()
|
||||
self._relate(storey,elt)
|
||||
return elt
|
||||
|
||||
def addRepresentations(self,shapes):
|
||||
"""addRepresentations(shapes,[solidType]): creates a representation from the given shape"""
|
||||
solidType = "Brep"
|
||||
if not isinstance(shapes,list):
|
||||
if shapes.is_a("IfcExtrudedAreaSolid"):
|
||||
solidType = "SweptSolid"
|
||||
shapes = [shapes]
|
||||
if extrusion:
|
||||
solidType = "SweptSolid"
|
||||
else:
|
||||
solidType = "Brep"
|
||||
reps = [create(self._fileobject,"IfcShapeRepresentation",[self._repcontext,'Body',solidType,[shape]]) for shape in shapes]
|
||||
prd = create(self._fileobject,"IfcProductDefinitionShape",[None,None,reps])
|
||||
if ifctype in ["IfcSlab","IfcFooting"]:
|
||||
stt = create(self._fileobject,ifctype,[uid(),self._owner,name,description,None,placement,prd,None,"NOTDEFINED"])
|
||||
else:
|
||||
stt = create(self._fileobject,ifctype,[uid(),self._owner,name,description,None,placement,prd,None])
|
||||
self.BuildingProducts.append(stt)
|
||||
if not storey:
|
||||
if self.Storeys:
|
||||
storey = self.Storeys[0]
|
||||
else:
|
||||
storey = self.addStorey()
|
||||
self._relate(storey,stt)
|
||||
return stt
|
||||
|
||||
def addWindow(self,ifctype,width,height,shapes,host=None,placement=None,name="Default Window",description=None):
|
||||
"""addWindow(ifctype,width,height,shapes,[host,placement,name,description]): creates a window
|
||||
from the given representation shape(s). Ifctype is the type of window object (IfcWindow, IfcDoor, etc)"""
|
||||
if not placement:
|
||||
placement = self.addPlacement()
|
||||
if not isinstance(shapes,list):
|
||||
shapes = [shapes]
|
||||
reps = [create(self._fileobject,"IfcShapeRepresentation",[self._repcontext,'Body','SolidModel',[shape]]) for shape in shapes]
|
||||
prd = create(self._fileobject,"IfcProductDefinitionShape",[None,None,reps])
|
||||
win = create(self._fileobject,ifctype,[uid(),self._owner,name,description,None,placement,prd,None,float(height),float(width)])
|
||||
self.BuildingProducts.append(win)
|
||||
if host:
|
||||
self._relate(host,win)
|
||||
return win
|
||||
|
||||
return reps
|
||||
|
||||
def addColor(self,rgb,rep):
|
||||
"""addColor(rgb,rep): adds a RGB color definition tuple (float,float,float) to a given representation"""
|
||||
col = create(self._fileobject,"IfcColourRgb",[None]+list(rgb))
|
||||
ssr = create(self._fileobject,"IfcSurfaceStyleRendering",[col,None,None,None,None,None,None,None,"FLAT"])
|
||||
iss = create(self._fileobject,"IfcSurfaceStyle",[None,"BOTH",[ssr]])
|
||||
psa = create(self._fileobject,"IfcPresentationStyleAssignment",[[iss]])
|
||||
isi = create(self._fileobject,"IfcStyledItem",[rep,[psa],None])
|
||||
return isi
|
||||
|
||||
def addPolyline(self,points):
|
||||
"""addPolyline(points): creates a polyline from the given points"""
|
||||
pts = [create(self._fileobject,"IfcCartesianPoint",getTuple(p)) for p in points]
|
||||
|
@ -525,7 +509,7 @@ class IfcDocument(object):
|
|||
|
||||
def addCircle(self,radius):
|
||||
"""addCircle(radius): creates a polyline from the given points"""
|
||||
lpl = self.addPlacement()
|
||||
lpl = self.addPlacement(flat=True)
|
||||
cir = create(self._fileobject,"IfcCircleProfileDef",["AREA",None,lpl,float(radius)])
|
||||
return cir
|
||||
|
||||
|
@ -539,20 +523,24 @@ class IfcDocument(object):
|
|||
solid = create(self._fileobject,"IfcExtrudedAreaSolid",[profile,placement,edir,value])
|
||||
return solid
|
||||
|
||||
def addExtrudedPolyline(self,points,extrusion,placement=None):
|
||||
"""addExtrudedPolyline(points,extrusion,[placement]): makes an extruded polyline
|
||||
def addExtrudedPolyline(self,points,extrusion,placement=None,color=None):
|
||||
"""addExtrudedPolyline(points,extrusion,[placement,color]): makes an extruded polyline
|
||||
from the given points and the given extrusion vector"""
|
||||
pol = self.addPolyline(points)
|
||||
exp = self.addExtrusion(pol,extrusion,placement)
|
||||
if color:
|
||||
self.addColor(color,exp)
|
||||
return exp
|
||||
|
||||
def addExtrudedCircle(self,center,radius,extrusion,placement=None):
|
||||
"""addExtrudedCircle(radius,extrusion,[placement]): makes an extruded circle
|
||||
def addExtrudedCircle(self,center,radius,extrusion,placement=None,color=None):
|
||||
"""addExtrudedCircle(radius,extrusion,[placement,color]): 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)
|
||||
if color:
|
||||
self.addColor(color,exp)
|
||||
return exp
|
||||
|
||||
def addFace(self,face):
|
||||
|
@ -584,8 +572,8 @@ class IfcDocument(object):
|
|||
iface = create(self._fileobject,"IfcFace",[ifb])
|
||||
return iface
|
||||
|
||||
def addFacetedBrep(self,faces):
|
||||
"""addFacetedBrep(self,faces): creates a faceted brep object from the given list
|
||||
def addFacetedBrep(self,faces,color=None):
|
||||
"""addFacetedBrep(self,faces,[color]): creates a faceted brep object from the given list
|
||||
of faces (each face is a list of lists of points, inner wires are reversed)"""
|
||||
self.fpoints = []
|
||||
self.frefs = []
|
||||
|
@ -594,6 +582,8 @@ class IfcDocument(object):
|
|||
ifaces = [self.addFace(face) for face in faces]
|
||||
sh = create(self._fileobject,"IfcClosedShell",[ifaces])
|
||||
brp = create(self._fileobject,"IfcFacetedBrep",[sh])
|
||||
if color:
|
||||
self.addColor(color,brp)
|
||||
return brp
|
||||
|
||||
|
||||
|
@ -641,18 +631,18 @@ def example2():
|
|||
ifc.Name = "Test Project"
|
||||
ifc.Owner = "Yorik van Havre"
|
||||
ifc.Organization = "FreeCAD"
|
||||
w1 = ifc.addWall( ifc.addExtrudedPolyline([(0,0,0),(0,200,0),(5000,200,0),(5000,0,0),(0,0,0)], (0,0,3500)) )
|
||||
ifc.addWall( ifc.addExtrudedPolyline([(0,200,0),(0,2000,0),(200,2000,0),(200,200,0),(0,200,0)],(0,0,3500)) )
|
||||
ifc.addWall( ifc.addExtrudedPolyline([(0,2000,0),(0,2200,0),(5000,2200,0),(5000,2000,0),(0,2000,0)],(0,0,3500)) )
|
||||
ifc.addWall( ifc.addExtrudedPolyline([(5000,200,0),(5000,2000,0),(4800,2000,0),(4800,200,0),(5000,200,0)],(0,0,3500)) )
|
||||
ifc.addWall( ifc.addFacetedBrep([[[(0,0,0),(100,0,0),(100,-1000,0),(0,-1000,0)]],
|
||||
w1 = ifc.addProduct( "IfcWall", ifc.addExtrudedPolyline([(0,0,0),(0,200,0),(5000,200,0),(5000,0,0),(0,0,0)], (0,0,3500)) )
|
||||
ifc.addProduct( "IfcWall", ifc.addExtrudedPolyline([(0,200,0),(0,2000,0),(200,2000,0),(200,200,0),(0,200,0)],(0,0,3500)) )
|
||||
ifc.addProduct( "IfcWall", ifc.addExtrudedPolyline([(0,2000,0),(0,2200,0),(5000,2200,0),(5000,2000,0),(0,2000,0)],(0,0,3500)) )
|
||||
ifc.addProduct( "IfcWall", ifc.addExtrudedPolyline([(5000,200,0),(5000,2000,0),(4800,2000,0),(4800,200,0),(5000,200,0)],(0,0,3500)) )
|
||||
ifc.addProduct( "IfcWall", ifc.addFacetedBrep([[[(0,0,0),(100,0,0),(100,-1000,0),(0,-1000,0)]],
|
||||
[[(0,0,0),(100,0,0),(100,0,1000),(0,0,1000)]],
|
||||
[[(0,0,0),(0,0,1000),(0,-1000,1000),(0,-1000,0)]],
|
||||
[[(0,-1000,0),(0,-1000,1000),(100,-1000,1000),(100,-1000,0)]],
|
||||
[[(100,-1000,0),(100,-1000,1000),(100,0,1000),(100,0,0)]],
|
||||
[[(0,0,1000),(0,-1000,1000),(100,-1000,1000),(100,0,1000)]]]) )
|
||||
ifc.addStructure( "IfcColumn", ifc.addExtrudedPolyline([(0,0,0),(0,-200,0),(-500,-200,0),(-500,0,0),(0,0,0)], (0,0,3500)) )
|
||||
ifc.addWindow( "IfcDoor", 200, 200, ifc.addExtrudedPolyline([(200,200,0),(200,400,0),(400,400,0),(400,200,0),(200,200,0)], (0,0,200)), w1 )
|
||||
ifc.addProduct( "IfcColumn", ifc.addExtrudedPolyline([(0,0,0),(0,-200,0),(-500,-200,0),(-500,0,0),(0,0,0)], (0,0,3500)) )
|
||||
ifc.addProduct( "IfcDoor", ifc.addExtrudedPolyline([(200,200,0),(200,400,0),(400,400,0),(400,200,0),(200,200,0)], (0,0,200)), w1, [200, 200] )
|
||||
ifc.write()
|
||||
|
||||
print dir(ifc._fileobject)
|
||||
|
|
|
@ -30,13 +30,23 @@ __url__ = "http://www.freecadweb.org"
|
|||
|
||||
# config
|
||||
subtractiveTypes = ["IfcOpeningElement"] # elements that must be subtracted from their parents
|
||||
SCHEMA = "http://www.steptools.com/support/stdev_docs/express/ifc2x3/ifc2x3_tc1.exp" # only for internal prser
|
||||
SCHEMA = "http://www.steptools.com/support/stdev_docs/ifcbim/ifc4.exp" # only for internal prser
|
||||
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
|
||||
|
||||
# supported ifc products (export only):
|
||||
supportedIfcTypes = ["IfcSite", "IfcBuilding", "IfcBuildingStorey", "IfcBeam", "IfcBeamStandardCase",
|
||||
"IfcChimney", "IfcColumn", "IfcColumnStandardCase", "IfcCovering", "IfcCurtainWall",
|
||||
"IfcDoor", "IfcDoorStandardCase", "IfcMember", "IfcMemberStandardCase", "IfcPlate",
|
||||
"IfcPlateStandardCase", "IfcRailing", "IfcRamp", "IfcRampFlight", "IfcRoof",
|
||||
"IfcSlab", "IfcStair", "IfcStairFlight", "IfcWall",
|
||||
"IfcWallStandardCase", "IfcWindow", "IfcWindowStandardCase", "IfcBuildingElementProxy",
|
||||
"IfcPile", "IfcFooting", "IfcReinforcingBar", "IfcTendon"]
|
||||
|
||||
# TODO : shading device not supported?
|
||||
|
||||
if open.__module__ == '__builtin__':
|
||||
pyopen = open # because we'll redefine open below
|
||||
|
||||
|
@ -915,12 +925,14 @@ def export(exportList,filename):
|
|||
try:
|
||||
import IfcImport
|
||||
except:
|
||||
FreeCAD.Console.PrintError(translate("Arch","Error: IfcOpenShell is not installed\n"))
|
||||
print """importIFC: ifcOpenShell is not installed. IFC export is unavailable.
|
||||
Note: IFC export currently requires an experimental version of IfcOpenShell
|
||||
available from https://github.com/aothms/IfcOpenShell"""
|
||||
return
|
||||
else:
|
||||
if not hasattr(IfcImport,"IfcFile"):
|
||||
FreeCAD.Console.PrintError(translate("Arch","Error: your IfcOpenShell version is too old\n"))
|
||||
print """importIFC: The version of ifcOpenShell installed on this system doesn't
|
||||
have IFC export capabilities. IFC export currently requires an experimental
|
||||
version of IfcOpenShell available from https://github.com/aothms/IfcOpenShell"""
|
||||
|
@ -948,12 +960,6 @@ def export(exportList,filename):
|
|||
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 = []
|
||||
|
@ -970,164 +976,112 @@ def export(exportList,filename):
|
|||
|
||||
# process objects
|
||||
for obj in objectslist:
|
||||
|
||||
otype = Draft.getType(obj)
|
||||
name = str(obj.Label)
|
||||
parent = Arch.getHost(obj)
|
||||
gdata = None
|
||||
|
||||
if otype in ["Group"]:
|
||||
# unsupported objects. TODO: support
|
||||
continue
|
||||
|
||||
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 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"
|
||||
fdata = None
|
||||
placement = None
|
||||
color = None
|
||||
representation = None
|
||||
descr = None
|
||||
extra = None
|
||||
|
||||
# setting the IFC type
|
||||
if hasattr(obj,"Role"):
|
||||
ifctype = obj.Role.replace(" ","")
|
||||
else:
|
||||
if DEBUG: print " Extrusion"
|
||||
ifctype = otype
|
||||
if ifctype == "Foundation":
|
||||
ifctype = "Footing"
|
||||
elif ifctype == "Rebar":
|
||||
ifctype = "ReinforcingBar"
|
||||
|
||||
# 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)
|
||||
if DEBUG: print "adding " + obj.Label + " as Ifc" + ifctype
|
||||
|
||||
# writing text log
|
||||
spacer = ""
|
||||
for i in range(36-len(obj.Label)):
|
||||
spacer += " "
|
||||
if otype in ["Structure","Window"]:
|
||||
if hasattr(obj,"Role"):
|
||||
tp = obj.Role
|
||||
else:
|
||||
tp = otype
|
||||
else:
|
||||
tp = otype
|
||||
txt.append(obj.Label + spacer + tp)
|
||||
txt.append(obj.Label + spacer + ifctype)
|
||||
|
||||
# writing IFC data
|
||||
if otype == "Building":
|
||||
ifc.addBuilding( name=name )
|
||||
# writing IFC data
|
||||
if obj.isDerivedFrom("App::DocumentObjectGroup"):
|
||||
|
||||
elif otype == "Floor":
|
||||
# getting parent building
|
||||
if parent:
|
||||
parent = ifc.findByName("IfcBuilding",str(parent.Label))
|
||||
ifc.addStorey( building=parent, name=name )
|
||||
|
||||
elif otype == "Wall":
|
||||
if parent:
|
||||
parent = ifc.findByName("IfcBuildingStorey",str(parent.Label))
|
||||
if gdata:
|
||||
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:
|
||||
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"
|
||||
if hasattr(obj,"Role"):
|
||||
if obj.Role == "Column":
|
||||
role = "IfcColumn"
|
||||
elif obj.Role == "Slab":
|
||||
role = "IfcSlab"
|
||||
elif obj.Role == "Foundation":
|
||||
role = "IfcFooting"
|
||||
if gdata:
|
||||
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:
|
||||
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 AGGREGATE_WINDOWS:
|
||||
if parent:
|
||||
p = ifc.findByName("IfcWallStandardCase",str(parent.Label))
|
||||
if not p:
|
||||
p = ifc.findByName("IfcWall",str(parent.Label))
|
||||
if not p:
|
||||
p = ifc.findByName("IfcColumn",str(parent.Label))
|
||||
if not p:
|
||||
p = ifc.findByName("IfcBeam",str(parent.Label))
|
||||
if not p:
|
||||
p = ifc.findByName("IfcSlab",str(parent.Label))
|
||||
parent = p
|
||||
if otype == "Building":
|
||||
ifc.addBuilding( name=name )
|
||||
elif otype == "Floor":
|
||||
ifc.addStorey( building=parent, name=name )
|
||||
else:
|
||||
if parent:
|
||||
p = Arch.getHost(parent)
|
||||
if p:
|
||||
parent = ifc.findByName("IfcBuildingStorey",str(p.Label))
|
||||
else:
|
||||
parent = None
|
||||
print " Skipping (not implemented yet)"
|
||||
|
||||
role = "IfcWindow"
|
||||
if hasattr(obj,"Role"):
|
||||
if obj.Role == "Door":
|
||||
role = "IfcDoor"
|
||||
elif obj.isDerivedFrom("Part::Feature"):
|
||||
|
||||
# get color
|
||||
if FreeCAD.GuiUp:
|
||||
color = obj.ViewObject.ShapeColor[:3]
|
||||
|
||||
# get parent floor
|
||||
if parent:
|
||||
parent = ifc.findByName("IfcBuildingStorey",str(parent.Label))
|
||||
|
||||
# get representation
|
||||
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 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"
|
||||
if gdata:
|
||||
placement = ifc.addPlacement(origin=gdata[3][0],xaxis=gdata[3][1],zaxis=gdata[3][2])
|
||||
if gdata[0] == "polyline":
|
||||
ifc.addWindow( role, obj.Width*scaling, obj.Height*scaling, ifc.addExtrudedPolyline(gdata[1], gdata[2]), host=parent, name=name )
|
||||
representation = ifc.addExtrudedPolyline(gdata[1], gdata[2], color=color)
|
||||
elif gdata[0] == "circle":
|
||||
representation = ifc.addExtrudedCircle(gdata[1][0], gdata[1][1], gdata[2], color=color)
|
||||
else:
|
||||
print "debug: unknow extrusion type"
|
||||
elif fdata:
|
||||
if JOINSOLIDS:
|
||||
ifc.addWindow( role, obj.Width*scaling, obj.Height*scaling, ifc.union([ifc.addFacetedBrep(f) for f in fdata]), host=parent, name=name )
|
||||
representation = ifc.join([ifc.addFacetedBrep(f, color=color) for f in fdata])
|
||||
else:
|
||||
ifc.addWindow( role, obj.Width*scaling, obj.Height*scaling, [ifc.addFacetedBrep(f) for f in fdata], host=parent, name=name )
|
||||
representation = [ifc.addFacetedBrep(f, color=color) for f in fdata]
|
||||
|
||||
# create ifc object
|
||||
ifctype = "Ifc" + ifctype
|
||||
if hasattr(obj,"Description"):
|
||||
descr = obj.Description
|
||||
if otype == "Wall":
|
||||
if gdata:
|
||||
if gdata[0] == "polyline":
|
||||
ifctype = "IfcWallStandardCase"
|
||||
elif otype == "Structure":
|
||||
if ifctype in ["IfcSlab","IfcFooting"]:
|
||||
extra = ["NOTDEFINED"]
|
||||
elif otype == "Window":
|
||||
extra = [obj.Width.Value*scaling, obj.Height.Value*scaling]
|
||||
if not ifctype in supportedIfcTypes:
|
||||
if DEBUG: print " Type ",ifctype," is not supported by the current version of IfcOpenShell. Exporting as IfcBuildingElementProxy instead"
|
||||
ifctype = "IfcBuildingElementProxy"
|
||||
extra = ["ELEMENT"]
|
||||
ifc.addProduct( ifctype, representation, storey=parent, placement=placement, name=name, description=descr, extra=extra )
|
||||
else:
|
||||
print "IFC export: object type ", otype, " is not supported yet."
|
||||
if DEBUG: print "IFC export: object type ", otype, " is not supported yet."
|
||||
|
||||
|
||||
ifc.write()
|
||||
|
||||
|
@ -1169,4 +1123,4 @@ def explore(filename=None):
|
|||
ifcReader.DEBUG = DEBUG
|
||||
d = ifcReader.explorer(filename,schema)
|
||||
d.show()
|
||||
return d
|
||||
return d
|
||||
|
|
|
@ -326,7 +326,7 @@ def getGroupContents(objectslist,walls=False,addgroups=False):
|
|||
#print "adding ",obj.Name
|
||||
newlist.append(obj)
|
||||
if walls:
|
||||
if getType(obj) == "Wall":
|
||||
if getType(obj) in ["Wall","Structure"]:
|
||||
for o in obj.OutList:
|
||||
if (getType(o) == "Window") or isClone(o,"Window"):
|
||||
newlist.append(o)
|
||||
|
|
|
@ -168,6 +168,8 @@ def getRotation(vector,reference=Vector(1,0,0)):
|
|||
representing a quaternion rotation between the reference
|
||||
(or X axis if omitted) and the vector'''
|
||||
c = vector.cross(reference)
|
||||
if isNull(c):
|
||||
return (0,0,0,1.0)
|
||||
c.normalize()
|
||||
return (c.x,c.y,c.z,math.sqrt((vector.Length ** 2) * (reference.Length ** 2)) + vector.dot(reference))
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user