Arch: massive rewrite of extrusion-based Arch objects and IFC export
This commit is contained in:
parent
bd8a296be6
commit
65aaf16201
|
@ -432,14 +432,25 @@ def getShapeFromMesh(mesh,fast=True,tolerance=0.001,flat=False,cut=True):
|
|||
try:
|
||||
f = Part.Face(Part.makePolygon(pts))
|
||||
except:
|
||||
pass
|
||||
print "getShapeFromMesh: error building face from polygon"
|
||||
#pass
|
||||
else:
|
||||
faces.append(f)
|
||||
shell = Part.makeShell(faces)
|
||||
solid = Part.Solid(shell)
|
||||
solid = solid.removeSplitter()
|
||||
return solid
|
||||
|
||||
try:
|
||||
solid = Part.Solid(shell)
|
||||
except Part.OCCError:
|
||||
print "getShapeFromMesh: error creating solid"
|
||||
else:
|
||||
try:
|
||||
solid = solid.removeSplitter()
|
||||
except Part.OCCError:
|
||||
print "getShapeFromMesh: error removing splitter"
|
||||
#pass
|
||||
return solid
|
||||
|
||||
#if not mesh.isSolid():
|
||||
# print "getShapeFromMesh: non-solid mesh, using slow method"
|
||||
faces = []
|
||||
segments = mesh.getPlanarSegments(tolerance)
|
||||
#print len(segments)
|
||||
|
@ -462,9 +473,11 @@ def getShapeFromMesh(mesh,fast=True,tolerance=0.001,flat=False,cut=True):
|
|||
if flat:
|
||||
return se
|
||||
except Part.OCCError:
|
||||
print "getShapeFromMesh: error removing splitter"
|
||||
try:
|
||||
cp = Part.makeCompound(faces)
|
||||
except Part.OCCError:
|
||||
print "getShapeFromMesh: error creating compound"
|
||||
return None
|
||||
else:
|
||||
return cp
|
||||
|
@ -472,6 +485,7 @@ def getShapeFromMesh(mesh,fast=True,tolerance=0.001,flat=False,cut=True):
|
|||
try:
|
||||
solid = Part.Solid(se)
|
||||
except Part.OCCError:
|
||||
print "getShapeFromMesh: error creating solid"
|
||||
return se
|
||||
else:
|
||||
return solid
|
||||
|
@ -673,7 +687,7 @@ def pruneIncluded(objectslist,strict=False):
|
|||
if obj.isDerivedFrom("Part::Feature"):
|
||||
if not (Draft.getType(obj) in ["Window","Clone","Pipe"]):
|
||||
for parent in obj.InList:
|
||||
if parent.isDerivedFrom("Part::Feature"):
|
||||
if parent.isDerivedFrom("Part::Feature") and not (Draft.getType(parent) in ["Facebinder"]):
|
||||
if not parent.isDerivedFrom("Part::Part2DObject"):
|
||||
# don't consider 2D objects based on arch elements
|
||||
if hasattr(parent,"CloneOf"):
|
||||
|
@ -936,8 +950,12 @@ def getExtrusionData(shape):
|
|||
return None
|
||||
# build faces list with normals
|
||||
faces = []
|
||||
import Part
|
||||
for f in shape.Faces:
|
||||
faces.append([f,f.normalAt(0,0)])
|
||||
try:
|
||||
faces.append([f,f.normalAt(0,0)])
|
||||
except Part.OCCError:
|
||||
return None
|
||||
# find opposite normals pairs
|
||||
pairs = []
|
||||
for i1, f1 in enumerate(faces):
|
||||
|
|
|
@ -31,7 +31,7 @@ Roles = ['Undefined','Beam','Chimney','Column','Covering','Curtain Wall',
|
|||
'Member','Plate','Railing','Ramp','Ramp Flight','Rebar','Pile','Roof','Shading Device','Slab','Space',
|
||||
'Stair','Stair Flight','Tendon','Wall','Wall Layer','Window']
|
||||
|
||||
import FreeCAD,Draft,ArchCommands
|
||||
import FreeCAD,Draft,ArchCommands,math
|
||||
from FreeCAD import Vector
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
|
@ -363,195 +363,43 @@ 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 Draft.getType(obj) == "Precast":
|
||||
return None
|
||||
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[0].isClosed():
|
||||
return obj.Base.Shape.copy()
|
||||
elif not(obj.Base.Shape.Solids):
|
||||
if hasattr(obj.Base.Shape,"CenterOfMass"):
|
||||
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 = []
|
||||
if Draft.getType(obj) == "Precast":
|
||||
return wires
|
||||
n,l,w,h = self.getDefaultValues(obj)
|
||||
def getExtrusionData(self,obj):
|
||||
"returns (shape,extrusion vector,placement) or None"
|
||||
if hasattr(obj,"CloneOf"):
|
||||
if obj.CloneOf:
|
||||
data = obj.CloneOf.Proxy.getExtrusionData(obj.CloneOf)
|
||||
if data:
|
||||
return data
|
||||
if obj.Base:
|
||||
if obj.Base.isDerivedFrom("Part::Extrusion"):
|
||||
if obj.Base.Base:
|
||||
base = obj.Base.Base.Shape.copy()
|
||||
#if noplacement:
|
||||
# base.Placement = FreeCAD.Placement()
|
||||
return [base]
|
||||
elif obj.Base.isDerivedFrom("Part::Feature"):
|
||||
if obj.Base.Shape:
|
||||
base = obj.Base.Shape.copy()
|
||||
if noplacement:
|
||||
base.Placement = FreeCAD.Placement()
|
||||
if not base.Solids:
|
||||
if base.Faces:
|
||||
import DraftGeomUtils
|
||||
if not DraftGeomUtils.isCoplanar(base.Faces):
|
||||
return []
|
||||
return [base]
|
||||
|
||||
basewires = []
|
||||
if not base.Wires:
|
||||
if len(base.Edges) == 1:
|
||||
import Part
|
||||
basewires = [Part.Wire(base.Edges)]
|
||||
else:
|
||||
basewires = base.Wires
|
||||
if basewires:
|
||||
import DraftGeomUtils,DraftVecUtils,Part
|
||||
for wire in basewires:
|
||||
e = wire.Edges[0]
|
||||
if isinstance(e.Curve,Part.Circle):
|
||||
dvec = e.Vertexes[0].Point.sub(e.Curve.Center)
|
||||
else:
|
||||
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(Part.__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(Part.__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:
|
||||
wires.append(wire)
|
||||
elif Draft.getType(obj) in ["Wall","Structure"]:
|
||||
if (Draft.getType(obj) == "Structure") and (l > h) and (obj.Role != "Slab"):
|
||||
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) == "Precast":
|
||||
return FreeCAD.Vector()
|
||||
if obj.Base:
|
||||
if obj.Base.isDerivedFrom("Part::Extrusion"):
|
||||
return FreeCAD.Vector(obj.Base.Dir)
|
||||
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)
|
||||
base,placement = self.rebase(obj.Base.Base.Shape)
|
||||
extrusion = obj.Base.Dir
|
||||
if extrusion.Length == 0:
|
||||
extrusion = FreeCAD.Vector(0,0,1)
|
||||
if hasattr(obj.Base,"LengthForward"):
|
||||
if obj.Base.LengthForward.Value:
|
||||
extrusion = extrusion.multiply(obj.Base.LengthForward.Value)
|
||||
return (base,extrusion,placement)
|
||||
return None
|
||||
|
||||
def rebase(self,shape):
|
||||
import DraftGeomUtils,math
|
||||
if hasattr(shape,"CenterOfMass"):
|
||||
v = shape.CenterOfMass
|
||||
else:
|
||||
normal = default
|
||||
return normal,length,width,height
|
||||
|
||||
def getPlacement(self,obj):
|
||||
"returns a total placement for the profile of this component"
|
||||
v = shape.BoundBox.Center
|
||||
n = DraftGeomUtils.getNormal(shape)
|
||||
r = FreeCAD.Rotation(FreeCAD.Vector(0,0,1),n)
|
||||
if round(r.Angle,8) == round(math.pi,8):
|
||||
r = FreeCAD.Rotation()
|
||||
shape = shape.copy()
|
||||
shape.translate(v.negative())
|
||||
shape.rotate(FreeCAD.Vector(0,0,0),r.inverted().Axis,math.degrees(r.inverted().Angle))
|
||||
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
|
||||
p.Base = v
|
||||
p.Rotation = r
|
||||
return (shape,p)
|
||||
|
||||
def hideSubobjects(self,obj,prop):
|
||||
"Hides subobjects when a subobject lists change"
|
||||
|
@ -701,33 +549,42 @@ class Component:
|
|||
return
|
||||
if not obj.Shape.Faces:
|
||||
return
|
||||
import Drawing,Part
|
||||
a = 0
|
||||
fset = []
|
||||
for f in obj.Shape.Faces:
|
||||
ang = f.normalAt(0,0).getAngle(FreeCAD.Vector(0,0,1))
|
||||
if (ang > 1.57) and (ang < 1.571):
|
||||
a += f.Area
|
||||
if ang < 1.5707:
|
||||
fset.append(f)
|
||||
for i,f in enumerate(obj.Shape.Faces):
|
||||
try:
|
||||
ang = f.normalAt(0,0).getAngle(FreeCAD.Vector(0,0,1))
|
||||
except Part.OCCError:
|
||||
print "Debug: Error computing areas for ",obj.Label,": normalAt() Face ",i
|
||||
return
|
||||
else:
|
||||
if (ang > 1.57) and (ang < 1.571):
|
||||
a += f.Area
|
||||
if ang < 1.5707:
|
||||
fset.append(f)
|
||||
if a and hasattr(obj,"VerticalArea"):
|
||||
if obj.VerticalArea.Value != a:
|
||||
obj.VerticalArea = a
|
||||
if fset and hasattr(obj,"HorizontalArea"):
|
||||
import Drawing,Part
|
||||
pset = []
|
||||
for f in fset:
|
||||
try:
|
||||
pf = Part.Face(Part.Wire(Drawing.project(f,FreeCAD.Vector(0,0,1))[0].Edges))
|
||||
except Part.OCCError:
|
||||
# error in computing the areas. Better set them to zero than show a wrong value
|
||||
if obj.HorizontalArea.Value != 0:
|
||||
print "Error computing areas for ",obj.Label
|
||||
obj.HorizontalArea = 0
|
||||
if hasattr(obj,"PerimeterLength"):
|
||||
if obj.PerimeterLength.Value != 0:
|
||||
obj.PerimeterLength = 0
|
||||
if f.normalAt(0,0).getAngle(FreeCAD.Vector(0,0,1)) < 0.00001:
|
||||
# already horizontal
|
||||
pset.append(f)
|
||||
else:
|
||||
pset.append(pf)
|
||||
try:
|
||||
pf = Part.Face(Part.Wire(Drawing.project(f,FreeCAD.Vector(0,0,1))[0].Edges))
|
||||
except Part.OCCError:
|
||||
# error in computing the areas. Better set them to zero than show a wrong value
|
||||
if obj.HorizontalArea.Value != 0:
|
||||
print "Debug: Error computing areas for ",obj.Label,": unable to project face: ",str([v.Point for v in f.Vertexes])," (face normal:",f.normalAt(0,0),")"
|
||||
obj.HorizontalArea = 0
|
||||
if hasattr(obj,"PerimeterLength"):
|
||||
if obj.PerimeterLength.Value != 0:
|
||||
obj.PerimeterLength = 0
|
||||
else:
|
||||
pset.append(pf)
|
||||
if pset:
|
||||
self.flatarea = pset.pop()
|
||||
for f in pset:
|
||||
|
|
|
@ -162,6 +162,7 @@ class _ArchPipe(ArchComponent.Component):
|
|||
|
||||
ArchComponent.Component.__init__(self,obj)
|
||||
self.Type = "Pipe"
|
||||
obj.Role = ["Pipe Segment"]
|
||||
obj.addProperty("App::PropertyLength", "Diameter", "Arch", QT_TRANSLATE_NOOP("App::Property","The diameter of this pipe, if not based on a profile"))
|
||||
obj.addProperty("App::PropertyLength", "Length", "Arch", QT_TRANSLATE_NOOP("App::Property","The length of this pipe, if not based on an edge"))
|
||||
obj.addProperty("App::PropertyLink", "Profile", "Arch", QT_TRANSLATE_NOOP("App::Property","An optional closed profile to base this pipe on"))
|
||||
|
@ -275,6 +276,7 @@ class _ArchPipeConnector(ArchComponent.Component):
|
|||
|
||||
ArchComponent.Component.__init__(self,obj)
|
||||
self.Type = "PipeConnector"
|
||||
obj.Role = ["Pipe Fitting"]
|
||||
obj.addProperty("App::PropertyLength", "Radius", "Arch", QT_TRANSLATE_NOOP("App::Property","The curvature radius of this connector"))
|
||||
obj.addProperty("App::PropertyLinkList", "Pipes", "Arch", QT_TRANSLATE_NOOP("App::Property","The pipes linked by this connector"))
|
||||
obj.addProperty("App::PropertyEnumeration", "ConnectorType", "Arch", QT_TRANSLATE_NOOP("App::Property","The type of this connector"))
|
||||
|
|
|
@ -44,9 +44,9 @@ else:
|
|||
class _Precast(ArchComponent.Component):
|
||||
|
||||
"The base Precast class"
|
||||
|
||||
|
||||
def __init__(self,obj):
|
||||
|
||||
|
||||
ArchComponent.Component.__init__(self,obj)
|
||||
obj.addProperty("App::PropertyDistance","Length","Arch",QT_TRANSLATE_NOOP("App::Property","The length of this element"))
|
||||
obj.addProperty("App::PropertyDistance","Width","Arch",QT_TRANSLATE_NOOP("App::Property","The width of this element"))
|
||||
|
@ -55,25 +55,19 @@ class _Precast(ArchComponent.Component):
|
|||
obj.addProperty("App::PropertyVectorList","Nodes","Arch",QT_TRANSLATE_NOOP("App::Property","The structural nodes of this element"))
|
||||
self.Type = "Precast"
|
||||
obj.Role = ["Beam","Column","Panel","Slab","Stairs"]
|
||||
|
||||
def getProfile(self,obj,noplacement=True):
|
||||
return []
|
||||
|
||||
def getExtrusionVector(self,obj,noplacement=True):
|
||||
return FreeCAD.Vector()
|
||||
|
||||
|
||||
def execute(self,obj):
|
||||
|
||||
|
||||
if self.clone(obj):
|
||||
return
|
||||
|
||||
|
||||
class _PrecastBeam(_Precast):
|
||||
|
||||
|
||||
"The Precast Beam"
|
||||
|
||||
|
||||
def __init__(self,obj):
|
||||
|
||||
|
||||
_Precast.__init__(self,obj)
|
||||
obj.addProperty("App::PropertyDistance","Chamfer","Arch",QT_TRANSLATE_NOOP("App::Property","The size of the chamfer of this element"))
|
||||
obj.addProperty("App::PropertyDistance","DentLength","Arch",QT_TRANSLATE_NOOP("App::Property","The dent length of this element"))
|
||||
|
@ -82,7 +76,7 @@ class _PrecastBeam(_Precast):
|
|||
obj.Role = ["Beam"]
|
||||
|
||||
def execute(self,obj):
|
||||
|
||||
|
||||
if self.clone(obj):
|
||||
return
|
||||
|
||||
|
@ -94,12 +88,12 @@ class _PrecastBeam(_Precast):
|
|||
dentlength = obj.DentLength.Value
|
||||
dentheight = obj.DentHeight.Value
|
||||
dents = obj.Dents
|
||||
|
||||
|
||||
if (length == 0) or (width == 0) or (height == 0):
|
||||
return
|
||||
if (chamfer >= width/2) or (chamfer >= height/2):
|
||||
return
|
||||
|
||||
|
||||
import Part
|
||||
p = []
|
||||
if chamfer > 0:
|
||||
|
@ -174,18 +168,18 @@ class _PrecastBeam(_Precast):
|
|||
|
||||
|
||||
class _PrecastIbeam(_Precast):
|
||||
|
||||
|
||||
"The Precast Ibeam"
|
||||
|
||||
|
||||
def __init__(self,obj):
|
||||
|
||||
|
||||
_Precast.__init__(self,obj)
|
||||
obj.addProperty("App::PropertyDistance","Chamfer","Arch",QT_TRANSLATE_NOOP("App::Property","The chamfer length of this element"))
|
||||
obj.addProperty("App::PropertyDistance","BeamBase","Arch",QT_TRANSLATE_NOOP("App::Property","The base length of this element"))
|
||||
obj.Role = ["Beam"]
|
||||
|
||||
def execute(self,obj):
|
||||
|
||||
|
||||
if self.clone(obj):
|
||||
return
|
||||
|
||||
|
@ -195,12 +189,12 @@ class _PrecastIbeam(_Precast):
|
|||
height = obj.Height.Value
|
||||
base = obj.BeamBase.Value
|
||||
slant = obj.Chamfer.Value
|
||||
|
||||
|
||||
if (length == 0) or (width == 0) or (height == 0):
|
||||
return
|
||||
if (slant*2 >= width) or (base*2+slant*2 >= height):
|
||||
return
|
||||
|
||||
|
||||
import Part
|
||||
p = []
|
||||
p.append(Vector(0,0,0))
|
||||
|
@ -225,11 +219,11 @@ class _PrecastIbeam(_Precast):
|
|||
|
||||
|
||||
class _PrecastPillar(_Precast):
|
||||
|
||||
|
||||
"The Precast Pillar"
|
||||
|
||||
|
||||
def __init__(self,obj):
|
||||
|
||||
|
||||
_Precast.__init__(self,obj)
|
||||
obj.addProperty("App::PropertyDistance","Chamfer","Arch",QT_TRANSLATE_NOOP("App::Property","The size of the chamfer of this element"))
|
||||
obj.addProperty("App::PropertyDistance","GrooveDepth","Arch",QT_TRANSLATE_NOOP("App::Property","The groove depth of this element"))
|
||||
|
@ -240,10 +234,10 @@ class _PrecastPillar(_Precast):
|
|||
obj.Role = ["Column"]
|
||||
|
||||
def execute(self,obj):
|
||||
|
||||
|
||||
if self.clone(obj):
|
||||
return
|
||||
|
||||
|
||||
pl = obj.Placement
|
||||
length = obj.Length.Value
|
||||
width = obj.Width.Value
|
||||
|
@ -259,7 +253,7 @@ class _PrecastPillar(_Precast):
|
|||
return
|
||||
if (chamfer >= width/2) or (chamfer >= length/2):
|
||||
return
|
||||
|
||||
|
||||
import Part
|
||||
p = []
|
||||
if chamfer > 0:
|
||||
|
@ -341,17 +335,17 @@ class _PrecastPillar(_Precast):
|
|||
dentshape.translate(Vector(dentoffset,0,0))
|
||||
dentshape.translate(Vector(0,0,dentlevel))
|
||||
shape = shape.fuse(dentshape)
|
||||
|
||||
|
||||
shape = self.processSubShapes(obj,shape,pl)
|
||||
self.applyShape(obj,shape,pl)
|
||||
|
||||
|
||||
class _PrecastPanel(_Precast):
|
||||
|
||||
|
||||
"The Precast Panel"
|
||||
|
||||
|
||||
def __init__(self,obj):
|
||||
|
||||
|
||||
_Precast.__init__(self,obj)
|
||||
obj.addProperty("App::PropertyDistance","Chamfer","Arch",QT_TRANSLATE_NOOP("App::Property","The size of the chamfer of this element"))
|
||||
obj.addProperty("App::PropertyDistance","DentWidth","Arch",QT_TRANSLATE_NOOP("App::Property","The dent width of this element"))
|
||||
|
@ -359,10 +353,10 @@ class _PrecastPanel(_Precast):
|
|||
obj.Role = ["Plate"]
|
||||
|
||||
def execute(self,obj):
|
||||
|
||||
|
||||
if self.clone(obj):
|
||||
return
|
||||
|
||||
|
||||
pl = obj.Placement
|
||||
length = obj.Length.Value
|
||||
width = obj.Width.Value
|
||||
|
@ -370,12 +364,12 @@ class _PrecastPanel(_Precast):
|
|||
chamfer = obj.Chamfer.Value
|
||||
dentheight = obj.DentHeight.Value
|
||||
dentwidth = obj.DentWidth.Value
|
||||
|
||||
|
||||
if (length == 0) or (width == 0) or (height == 0):
|
||||
return
|
||||
if ((chamfer+dentwidth) >= width) or (dentheight >= height):
|
||||
return
|
||||
|
||||
|
||||
import Part
|
||||
p = []
|
||||
p.append(Vector(0,0,0))
|
||||
|
@ -436,17 +430,17 @@ class _PrecastPanel(_Precast):
|
|||
shape = shape.cut(s)
|
||||
s.translate(Vector(0,0,height))
|
||||
shape = shape.fuse(s)
|
||||
|
||||
|
||||
shape = self.processSubShapes(obj,shape,pl)
|
||||
self.applyShape(obj,shape,pl)
|
||||
|
||||
|
||||
class _PrecastSlab(_Precast):
|
||||
|
||||
|
||||
"The Precast Slab"
|
||||
|
||||
|
||||
def __init__(self,obj):
|
||||
|
||||
|
||||
_Precast.__init__(self,obj)
|
||||
obj.addProperty("App::PropertyEnumeration","SlabType","Arch",QT_TRANSLATE_NOOP("App::Property","The type of this slab"))
|
||||
obj.addProperty("App::PropertyDistance","SlabBase","Arch",QT_TRANSLATE_NOOP("App::Property","The size of the base of this element"))
|
||||
|
@ -458,7 +452,7 @@ class _PrecastSlab(_Precast):
|
|||
obj.SlabType = ["Champagne","Hat"]
|
||||
|
||||
def execute(self,obj):
|
||||
|
||||
|
||||
if self.clone(obj):
|
||||
return
|
||||
|
||||
|
@ -472,9 +466,9 @@ class _PrecastSlab(_Precast):
|
|||
holemajor = obj.HoleMajor.Value
|
||||
holeminor = obj.HoleMinor.Value
|
||||
holespacing = obj.HoleSpacing.Value
|
||||
|
||||
|
||||
slant = (height-base) / 3 # this gives the inclination of the vertical walls
|
||||
|
||||
|
||||
if (length == 0) or (width == 0) or (height == 0):
|
||||
return
|
||||
if base >= height:
|
||||
|
@ -486,7 +480,7 @@ class _PrecastSlab(_Precast):
|
|||
if holemajor < holeminor:
|
||||
return
|
||||
import Part
|
||||
|
||||
|
||||
p = []
|
||||
if slabtype == "Champagne":
|
||||
p.append(Vector(0,0,0))
|
||||
|
@ -512,7 +506,7 @@ class _PrecastSlab(_Precast):
|
|||
p = Part.makePolygon(p)
|
||||
f = Part.Face(p)
|
||||
shape = f.extrude(Vector(length,0,0))
|
||||
|
||||
|
||||
if holenumber > 0:
|
||||
holespan = holenumber * holeminor + (holenumber - 1) * holespacing
|
||||
holestart = (width/2 - holespan/2) + holeminor/2
|
||||
|
@ -529,17 +523,17 @@ class _PrecastSlab(_Precast):
|
|||
s = tube.copy()
|
||||
s.translate(Vector(0,x,height/2))
|
||||
shape = shape.cut(s)
|
||||
|
||||
|
||||
shape = self.processSubShapes(obj,shape,pl)
|
||||
self.applyShape(obj,shape,pl)
|
||||
|
||||
|
||||
class _PrecastStairs(_Precast):
|
||||
|
||||
|
||||
"The Precast Stairs"
|
||||
|
||||
|
||||
def __init__(self,obj):
|
||||
|
||||
|
||||
_Precast.__init__(self,obj)
|
||||
obj.addProperty("App::PropertyDistance","DownLength","Arch",QT_TRANSLATE_NOOP("App::Property","The length of the down floor of this element"))
|
||||
obj.addProperty("App::PropertyInteger","RiserNumber","Arch",QT_TRANSLATE_NOOP("App::Property","The number of risers in this element"))
|
||||
|
@ -548,7 +542,7 @@ class _PrecastStairs(_Precast):
|
|||
obj.Role = ["Stairs"]
|
||||
|
||||
def execute(self,obj):
|
||||
|
||||
|
||||
if self.clone(obj):
|
||||
return
|
||||
|
||||
|
@ -573,7 +567,7 @@ class _PrecastStairs(_Precast):
|
|||
return
|
||||
if length < tread:
|
||||
length = tread # minimum
|
||||
|
||||
|
||||
import math,Part
|
||||
|
||||
p = [Vector(0,0,0)] # relative moves
|
||||
|
@ -628,7 +622,7 @@ class _ViewProviderPrecast(ArchComponent.ViewProviderComponent):
|
|||
if self.Object.CloneOf:
|
||||
return ":/icons/Arch_Structure_Clone.svg"
|
||||
return ":/icons/Arch_Structure_Tree.svg"
|
||||
|
||||
|
||||
def setEdit(self,vobj,mode):
|
||||
if mode == 0:
|
||||
import FreeCADGui
|
||||
|
@ -643,7 +637,7 @@ class _ViewProviderPrecast(ArchComponent.ViewProviderComponent):
|
|||
FreeCADGui.Control.showDialog(taskd)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def unsetEdit(self,vobj,mode):
|
||||
import FreeCADGui
|
||||
if hasattr(self,"dentd"):
|
||||
|
@ -654,18 +648,18 @@ class _ViewProviderPrecast(ArchComponent.ViewProviderComponent):
|
|||
|
||||
|
||||
class _PrecastTaskPanel:
|
||||
|
||||
|
||||
'''The TaskPanel for precast creation'''
|
||||
|
||||
|
||||
def __init__(self):
|
||||
|
||||
|
||||
import FreeCADGui
|
||||
from PySide import QtCore,QtGui,QtSvg
|
||||
self.form = QtGui.QWidget()
|
||||
self.grid = QtGui.QGridLayout(self.form)
|
||||
self.PrecastTypes = ["Beam","I-Beam","Pillar","Panel","Slab","Stairs"]
|
||||
self.SlabTypes = ["Champagne","Hat"]
|
||||
|
||||
|
||||
# image display
|
||||
self.preview = QtSvg.QSvgWidget(":/ui/ParametersBeam.svg")
|
||||
self.preview.setMaximumWidth(200)
|
||||
|
@ -679,67 +673,67 @@ class _PrecastTaskPanel:
|
|||
self.valueSlabType.setCurrentIndex(0)
|
||||
self.grid.addWidget(self.labelSlabType,1,0,1,1)
|
||||
self.grid.addWidget(self.valueSlabType,1,1,1,1)
|
||||
|
||||
|
||||
self.labelChamfer = QtGui.QLabel()
|
||||
self.valueChamfer = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.grid.addWidget(self.labelChamfer,2,0,1,1)
|
||||
self.grid.addWidget(self.valueChamfer,2,1,1,1)
|
||||
|
||||
|
||||
self.labelDentLength = QtGui.QLabel()
|
||||
self.valueDentLength = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.grid.addWidget(self.labelDentLength,3,0,1,1)
|
||||
self.grid.addWidget(self.valueDentLength,3,1,1,1)
|
||||
|
||||
|
||||
self.labelDentWidth = QtGui.QLabel()
|
||||
self.valueDentWidth = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.grid.addWidget(self.labelDentWidth,4,0,1,1)
|
||||
self.grid.addWidget(self.valueDentWidth,4,1,1,1)
|
||||
|
||||
|
||||
self.labelDentHeight = QtGui.QLabel()
|
||||
self.valueDentHeight = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.grid.addWidget(self.labelDentHeight,5,0,1,1)
|
||||
self.grid.addWidget(self.valueDentHeight,5,1,1,1)
|
||||
|
||||
|
||||
self.labelBase = QtGui.QLabel()
|
||||
self.valueBase = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.grid.addWidget(self.labelBase,6,0,1,1)
|
||||
self.grid.addWidget(self.valueBase,6,1,1,1)
|
||||
|
||||
|
||||
self.labelHoleNumber = QtGui.QLabel()
|
||||
self.valueHoleNumber = QtGui.QSpinBox()
|
||||
self.grid.addWidget(self.labelHoleNumber,7,0,1,1)
|
||||
self.grid.addWidget(self.valueHoleNumber,7,1,1,1)
|
||||
|
||||
|
||||
self.labelHoleMajor = QtGui.QLabel()
|
||||
self.valueHoleMajor = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.grid.addWidget(self.labelHoleMajor,8,0,1,1)
|
||||
self.grid.addWidget(self.valueHoleMajor,8,1,1,1)
|
||||
|
||||
|
||||
self.labelHoleMinor = QtGui.QLabel()
|
||||
self.valueHoleMinor = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.grid.addWidget(self.labelHoleMinor,9,0,1,1)
|
||||
self.grid.addWidget(self.valueHoleMinor,9,1,1,1)
|
||||
|
||||
|
||||
self.labelHoleSpacing = QtGui.QLabel()
|
||||
self.valueHoleSpacing = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.grid.addWidget(self.labelHoleSpacing,10,0,1,1)
|
||||
self.grid.addWidget(self.valueHoleSpacing,10,1,1,1)
|
||||
|
||||
|
||||
self.labelGrooveNumber = QtGui.QLabel()
|
||||
self.valueGrooveNumber = QtGui.QSpinBox()
|
||||
self.grid.addWidget(self.labelGrooveNumber,11,0,1,1)
|
||||
self.grid.addWidget(self.valueGrooveNumber,11,1,1,1)
|
||||
|
||||
|
||||
self.labelGrooveDepth = QtGui.QLabel()
|
||||
self.valueGrooveDepth = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.grid.addWidget(self.labelGrooveDepth,12,0,1,1)
|
||||
self.grid.addWidget(self.valueGrooveDepth,12,1,1,1)
|
||||
|
||||
|
||||
self.labelGrooveHeight = QtGui.QLabel()
|
||||
self.valueGrooveHeight = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.grid.addWidget(self.labelGrooveHeight,13,0,1,1)
|
||||
self.grid.addWidget(self.valueGrooveHeight,13,1,1,1)
|
||||
|
||||
|
||||
self.labelGrooveSpacing = QtGui.QLabel()
|
||||
self.valueGrooveSpacing = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.grid.addWidget(self.labelGrooveSpacing,14,0,1,1)
|
||||
|
@ -749,17 +743,17 @@ class _PrecastTaskPanel:
|
|||
self.valueRiserNumber = QtGui.QSpinBox()
|
||||
self.grid.addWidget(self.labelRiserNumber,15,0,1,1)
|
||||
self.grid.addWidget(self.valueRiserNumber,15,1,1,1)
|
||||
|
||||
|
||||
self.labelDownLength = QtGui.QLabel()
|
||||
self.valueDownLength = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.grid.addWidget(self.labelDownLength,16,0,1,1)
|
||||
self.grid.addWidget(self.valueDownLength,16,1,1,1)
|
||||
|
||||
|
||||
self.labelRiser = QtGui.QLabel()
|
||||
self.valueRiser = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.grid.addWidget(self.labelRiser,17,0,1,1)
|
||||
self.grid.addWidget(self.valueRiser,17,1,1,1)
|
||||
|
||||
|
||||
self.labelTread = QtGui.QLabel()
|
||||
self.valueTread = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.grid.addWidget(self.labelTread,18,0,1,1)
|
||||
|
@ -782,7 +776,7 @@ class _PrecastTaskPanel:
|
|||
QtCore.QObject.connect(self.valueTread,QtCore.SIGNAL("valueChanged(double)"),self.setTread)
|
||||
self.retranslateUi(self.form)
|
||||
self.form.hide()
|
||||
|
||||
|
||||
def getValues(self):
|
||||
d = {}
|
||||
d["SlabType"] = self.SlabTypes[self.valueSlabType.currentIndex()]
|
||||
|
@ -806,49 +800,49 @@ class _PrecastTaskPanel:
|
|||
if hasattr(self,"Dents"):
|
||||
d["Dents"] = self.Dents.getValues()
|
||||
return d
|
||||
|
||||
|
||||
def setChamfer(self,value):
|
||||
self.Chamfer = value
|
||||
|
||||
|
||||
def setDentLength(self,value):
|
||||
self.DentLength = value
|
||||
|
||||
|
||||
def setDentWidth(self,value):
|
||||
self.DentWidth = value
|
||||
|
||||
|
||||
def setDentHeight(self,value):
|
||||
self.DentHeight = value
|
||||
|
||||
|
||||
def setBase(self,value):
|
||||
self.Base = value
|
||||
|
||||
|
||||
def setHoleMajor(self,value):
|
||||
self.HoleMajor = value
|
||||
|
||||
|
||||
def setHoleMinor(self,value):
|
||||
self.HoleMinor = value
|
||||
|
||||
|
||||
def setHoleSpacing(self,value):
|
||||
self.HoleSpacing = value
|
||||
|
||||
|
||||
def setGrooveDepth(self,value):
|
||||
self.GrooveDepth = value
|
||||
|
||||
|
||||
def setGrooveHeight(self,value):
|
||||
self.GrooveHeight = value
|
||||
|
||||
|
||||
def setGrooveSpacing(self,value):
|
||||
self.GrooveSpacing = value
|
||||
|
||||
def setDownLength(self,value):
|
||||
self.DownLength = value
|
||||
|
||||
|
||||
def setRiser(self,value):
|
||||
self.Riser = value
|
||||
|
||||
|
||||
def setTread(self,value):
|
||||
self.Tread = value
|
||||
|
||||
|
||||
def retranslateUi(self, dialog):
|
||||
from PySide import QtGui
|
||||
self.form.setWindowTitle(QtGui.QApplication.translate("Arch", "Precast elements", None, QtGui.QApplication.UnicodeUTF8))
|
||||
|
@ -1106,62 +1100,62 @@ class _PrecastTaskPanel:
|
|||
|
||||
|
||||
class _DentsTaskPanel:
|
||||
|
||||
|
||||
'''The TaskPanel for dent creation'''
|
||||
|
||||
|
||||
def __init__(self):
|
||||
|
||||
|
||||
import FreeCADGui
|
||||
from PySide import QtCore,QtGui,QtSvg
|
||||
self.form = QtGui.QWidget()
|
||||
self.grid = QtGui.QGridLayout(self.form)
|
||||
self.Rotations = ["N","S","E","O"]
|
||||
self.RotationAngles = [90,270,0,180]
|
||||
|
||||
|
||||
# dents list
|
||||
self.labelDents = QtGui.QLabel()
|
||||
self.listDents = QtGui.QListWidget()
|
||||
self.grid.addWidget(self.labelDents,0,0,1,2)
|
||||
self.grid.addWidget(self.listDents,1,0,1,2)
|
||||
|
||||
|
||||
# buttons
|
||||
self.buttonAdd = QtGui.QPushButton()
|
||||
self.buttonRemove = QtGui.QPushButton()
|
||||
self.grid.addWidget(self.buttonAdd,2,0,1,1)
|
||||
self.grid.addWidget(self.buttonRemove,2,1,1,1)
|
||||
|
||||
|
||||
# image display
|
||||
self.preview = QtSvg.QSvgWidget(":/ui/ParametersDent.svg")
|
||||
self.preview.setMaximumWidth(200)
|
||||
self.preview.setMinimumHeight(120)
|
||||
self.grid.addWidget(self.preview,3,0,1,2)
|
||||
|
||||
# parameters
|
||||
# parameters
|
||||
self.labelLength = QtGui.QLabel()
|
||||
self.valueLength = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.grid.addWidget(self.labelLength,4,0,1,1)
|
||||
self.grid.addWidget(self.valueLength,4,1,1,1)
|
||||
|
||||
|
||||
self.labelWidth = QtGui.QLabel()
|
||||
self.valueWidth = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.grid.addWidget(self.labelWidth,5,0,1,1)
|
||||
self.grid.addWidget(self.valueWidth,5,1,1,1)
|
||||
|
||||
|
||||
self.labelHeight = QtGui.QLabel()
|
||||
self.valueHeight = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.grid.addWidget(self.labelHeight,6,0,1,1)
|
||||
self.grid.addWidget(self.valueHeight,6,1,1,1)
|
||||
|
||||
|
||||
self.labelSlant = QtGui.QLabel()
|
||||
self.valueSlant = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.grid.addWidget(self.labelSlant,7,0,1,1)
|
||||
self.grid.addWidget(self.valueSlant,7,1,1,1)
|
||||
|
||||
|
||||
self.labelLevel = QtGui.QLabel()
|
||||
self.valueLevel = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.grid.addWidget(self.labelLevel,8,0,1,1)
|
||||
self.grid.addWidget(self.valueLevel,8,1,1,1)
|
||||
|
||||
|
||||
self.labelRotation = QtGui.QLabel()
|
||||
self.valueRotation = QtGui.QComboBox()
|
||||
self.valueRotation.addItems(self.Rotations)
|
||||
|
@ -1173,7 +1167,7 @@ class _DentsTaskPanel:
|
|||
self.valueOffset = FreeCADGui.UiLoader().createWidget("Gui::InputField")
|
||||
self.grid.addWidget(self.labelOffset,10,0,1,1)
|
||||
self.grid.addWidget(self.valueOffset,10,1,1,1)
|
||||
|
||||
|
||||
# signals/slots
|
||||
QtCore.QObject.connect(self.valueLength,QtCore.SIGNAL("valueChanged(double)"),self.setLength)
|
||||
QtCore.QObject.connect(self.valueWidth,QtCore.SIGNAL("valueChanged(double)"),self.setWidth)
|
||||
|
@ -1187,31 +1181,31 @@ class _DentsTaskPanel:
|
|||
QtCore.QObject.connect(self.listDents,QtCore.SIGNAL("itemClicked(QListWidgetItem*)"),self.editDent)
|
||||
self.retranslateUi(self.form)
|
||||
self.form.hide()
|
||||
|
||||
|
||||
def setLength(self,value):
|
||||
self.Length = value
|
||||
self.setDent()
|
||||
|
||||
|
||||
def setWidth(self,value):
|
||||
self.Width = value
|
||||
self.setDent()
|
||||
|
||||
|
||||
def setHeight(self,value):
|
||||
self.Height = value
|
||||
self.setDent()
|
||||
|
||||
|
||||
def setSlant(self,value):
|
||||
self.Slant = value
|
||||
self.setDent()
|
||||
|
||||
|
||||
def setLevel(self,value):
|
||||
self.Level = value
|
||||
self.setDent()
|
||||
|
||||
|
||||
def setOffset(self,value):
|
||||
self.Offset = value
|
||||
self.setDent()
|
||||
|
||||
|
||||
def fillDents(self,dents):
|
||||
self.listDents.clear()
|
||||
i = 1
|
||||
|
@ -1219,14 +1213,14 @@ class _DentsTaskPanel:
|
|||
s = "Dent "+str(i)+" :"+d
|
||||
self.listDents.addItem(s)
|
||||
i += 1
|
||||
|
||||
|
||||
def setDent(self,i=0):
|
||||
if self.listDents.currentItem():
|
||||
num = str(self.listDents.currentRow()+1)
|
||||
rot = self.RotationAngles[self.valueRotation.currentIndex()]
|
||||
s = "Dent "+num+" :"+str(self.Length)+";"+str(self.Width)+";"+str(self.Height)+";"+str(self.Slant)+";"+str(self.Level)+";"+str(rot)+";"+str(self.Offset)
|
||||
self.listDents.currentItem().setText(s)
|
||||
|
||||
|
||||
def addDent(self):
|
||||
num = str(self.listDents.count()+1)
|
||||
rot = self.RotationAngles[self.valueRotation.currentIndex()]
|
||||
|
@ -1234,11 +1228,11 @@ class _DentsTaskPanel:
|
|||
self.listDents.addItem(s)
|
||||
self.listDents.setCurrentRow(self.listDents.count()-1)
|
||||
self.editDent()
|
||||
|
||||
|
||||
def removeDent(self):
|
||||
if self.listDents.currentItem():
|
||||
self.listDents.takeItem(self.listDents.currentRow())
|
||||
|
||||
|
||||
def editDent(self,item=None):
|
||||
if self.listDents.currentItem():
|
||||
s = self.listDents.currentItem().text()
|
||||
|
@ -1251,7 +1245,7 @@ class _DentsTaskPanel:
|
|||
self.valueLevel.setText(FreeCAD.Units.Quantity(float(s[4]),FreeCAD.Units.Length).UserString)
|
||||
self.valueRotation.setCurrentIndex(self.RotationAngles.index(int(s[5])))
|
||||
self.valueOffset.setText(FreeCAD.Units.Quantity(float(s[6]),FreeCAD.Units.Length).UserString)
|
||||
|
||||
|
||||
def retranslateUi(self, dialog):
|
||||
from PySide import QtGui
|
||||
self.form.setWindowTitle(QtGui.QApplication.translate("Arch", "Precast options", None, QtGui.QApplication.UnicodeUTF8))
|
||||
|
@ -1265,19 +1259,19 @@ class _DentsTaskPanel:
|
|||
self.labelLevel.setText(QtGui.QApplication.translate("Arch", "Level", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.labelRotation.setText(QtGui.QApplication.translate("Arch", "Rotation", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.labelOffset.setText(QtGui.QApplication.translate("Arch", "Offset", None, QtGui.QApplication.UnicodeUTF8))
|
||||
|
||||
|
||||
def getValues(self):
|
||||
l = []
|
||||
for i in range(self.listDents.count()):
|
||||
s = self.listDents.item(i).text()
|
||||
l.append(s.split(":")[1])
|
||||
return l
|
||||
|
||||
|
||||
|
||||
def makePrecast(precasttype=None,length=0,width=0,height=0,slabtype="",chamfer=0,dentlength=0,dentwidth=0,dentheight=0,dents=[],base=0,holenumber=0,holemajor=0,holeminor=0,holespacing=0,groovenumber=0,groovedepth=0,grooveheight=0,groovespacing=0,risernumber=0,downlength=0,riser=0,tread=0):
|
||||
|
||||
|
||||
"creates one of the precast objects in the current document"
|
||||
|
||||
|
||||
if precasttype == "Beam":
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Beam")
|
||||
_PrecastBeam(obj)
|
||||
|
@ -1345,4 +1339,4 @@ def makePrecast(precasttype=None,length=0,width=0,height=0,slabtype="",chamfer=0
|
|||
if FreeCAD.GuiUp:
|
||||
_ViewProviderPrecast(obj.ViewObject)
|
||||
return obj
|
||||
|
||||
|
||||
|
|
|
@ -307,7 +307,7 @@ class _Space(ArchComponent.Component):
|
|||
if obj.Base:
|
||||
if obj.Base.isDerivedFrom("Part::Feature"):
|
||||
if obj.Base.Shape.Solids:
|
||||
shape = obj.Base.Shape.Solids[0].copy()
|
||||
shape = obj.Base.Shape.copy()
|
||||
shape = shape.removeSplitter()
|
||||
|
||||
# 2: if not, add all bounding boxes of considered objects and build a first shape
|
||||
|
|
|
@ -374,7 +374,9 @@ class _CommandStructure:
|
|||
|
||||
|
||||
class _Structure(ArchComponent.Component):
|
||||
|
||||
"The Structure object"
|
||||
|
||||
def __init__(self,obj):
|
||||
ArchComponent.Component.__init__(self,obj)
|
||||
obj.addProperty("App::PropertyLink","Tool","Arch",QT_TRANSLATE_NOOP("App::Property","An optional extrusion path for this element"))
|
||||
|
@ -386,7 +388,9 @@ class _Structure(ArchComponent.Component):
|
|||
obj.addProperty("App::PropertyVectorList","Nodes","Arch",QT_TRANSLATE_NOOP("App::Property","The structural nodes of this element"))
|
||||
obj.addProperty("App::PropertyString","Profile","Arch",QT_TRANSLATE_NOOP("App::Property","A description of the standard profile this element is based upon"))
|
||||
obj.addProperty("App::PropertyDistance","NodesOffset","Arch",QT_TRANSLATE_NOOP("App::Property","Offset distance between the centerline and the nodes line"))
|
||||
obj.addProperty("App::PropertyEnumeration","FaceMaker","Arch",QT_TRANSLATE_NOOP("App::Property","The facemaker type to use to build the profile of this object"))
|
||||
self.Type = "Structure"
|
||||
obj.FaceMaker = ["None","Simple","Cheese","Bullseye"]
|
||||
obj.Role = Roles
|
||||
|
||||
def execute(self,obj):
|
||||
|
@ -397,11 +401,22 @@ class _Structure(ArchComponent.Component):
|
|||
if self.clone(obj):
|
||||
return
|
||||
|
||||
normal,length,width,height = self.getDefaultValues(obj)
|
||||
|
||||
# creating base shape
|
||||
pl = obj.Placement
|
||||
import Part, DraftGeomUtils
|
||||
base = None
|
||||
pl = obj.Placement
|
||||
extdata = self.getExtrusionData(obj)
|
||||
if extdata:
|
||||
base = extdata[0]
|
||||
base.Placement = extdata[2].multiply(base.Placement)
|
||||
extv = extdata[2].Rotation.multVec(extdata[1])
|
||||
if obj.Tool:
|
||||
try:
|
||||
base = obj.Tool.Shape.copy().makePipe(obj.Base.Shape.copy())
|
||||
except Part.OCCError:
|
||||
FreeCAD.Console.PrintError(translate("Arch","Error: The base shape couldn't be extruded along this tool object")+"\n")
|
||||
return
|
||||
else:
|
||||
base = base.extrude(extv)
|
||||
if obj.Base:
|
||||
if obj.Base.isDerivedFrom("Part::Feature"):
|
||||
if obj.Base.Shape.isNull():
|
||||
|
@ -410,42 +425,8 @@ class _Structure(ArchComponent.Component):
|
|||
if not obj.Base.Shape.Solids:
|
||||
# let pass invalid objects if they have solids...
|
||||
return
|
||||
if hasattr(obj,"Tool"):
|
||||
if obj.Tool:
|
||||
try:
|
||||
base = obj.Tool.Shape.copy().makePipe(obj.Base.Shape.copy())
|
||||
except Part.OCCError:
|
||||
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):
|
||||
if len(obj.Base.Shape.Faces) > 0 :
|
||||
normal=obj.Base.Shape.Faces[0].normalAt(.5,.5)
|
||||
else:
|
||||
normal = DraftGeomUtils.getNormal(obj.Base.Shape)
|
||||
if not normal:
|
||||
normal = FreeCAD.Vector(0,0,1)
|
||||
#p = FreeCAD.Placement(obj.Base.Placement)
|
||||
#normal = p.Rotation.multVec(normal)
|
||||
else:
|
||||
normal = Vector(obj.Normal)
|
||||
normal = normal.multiply(height)
|
||||
elif obj.Base.Shape.Solids:
|
||||
base = obj.Base.Shape.copy()
|
||||
if base.Solids:
|
||||
pass
|
||||
elif base.Faces:
|
||||
base = base.extrude(normal)
|
||||
elif (len(base.Wires) == 1):
|
||||
if base.Wires[0].isClosed():
|
||||
try:
|
||||
base = Part.Face(base.Wires[0])
|
||||
base = base.extrude(normal)
|
||||
except Part.OCCError:
|
||||
FreeCAD.Console.PrintError(obj.Label+" : "+str(translate("Arch","Unable to extrude the base shape\n")))
|
||||
return
|
||||
|
||||
elif obj.Base.isDerivedFrom("Mesh::Feature"):
|
||||
if obj.Base.Mesh.isSolid():
|
||||
if obj.Base.Mesh.countComponents() == 1:
|
||||
|
@ -453,54 +434,133 @@ class _Structure(ArchComponent.Component):
|
|||
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")))
|
||||
FreeCAD.Console.PrintWarning(translate("Arch","This mesh is an invalid solid")+"\n")
|
||||
obj.Base.ViewObject.show()
|
||||
else:
|
||||
base = self.getProfiles(obj)
|
||||
if base:
|
||||
if length > height:
|
||||
normal = normal.multiply(length)
|
||||
else:
|
||||
normal = normal.multiply(height)
|
||||
base = Part.Face(base[0])
|
||||
base = base.extrude(normal)
|
||||
if not base:
|
||||
FreeCAD.Console.PrintError(translate("Arch","Error: Invalid base object")+"\n")
|
||||
return
|
||||
|
||||
base = self.processSubShapes(obj,base,pl)
|
||||
self.applyShape(obj,base,pl)
|
||||
|
||||
def getExtrusionData(self,obj):
|
||||
"""returns (shape,extrusion vector,placement) or None"""
|
||||
import Part,DraftGeomUtils
|
||||
data = ArchComponent.Component.getExtrusionData(self,obj)
|
||||
if data:
|
||||
return data
|
||||
length = obj.Length.Value
|
||||
width = obj.Width.Value
|
||||
height = obj.Height.Value
|
||||
normal = None
|
||||
if not height:
|
||||
for p in obj.InList:
|
||||
if Draft.getType(p) == "Floor":
|
||||
if p.Height.Value:
|
||||
height = p.Height.Value
|
||||
base = None
|
||||
placement = None
|
||||
if obj.Base:
|
||||
if obj.Base.isDerivedFrom("Part::Feature"):
|
||||
if obj.Base.Shape:
|
||||
if obj.Base.Shape.Solids:
|
||||
return None
|
||||
elif obj.Base.Shape.Faces:
|
||||
if not DraftGeomUtils.isCoplanar(obj.Base.Shape.Faces):
|
||||
return None
|
||||
else:
|
||||
base,placement = self.rebase(obj.Base.Shape)
|
||||
normal = obj.Base.Shape.Faces[0].normalAt(0,0)
|
||||
elif obj.Base.Shape.Wires:
|
||||
baseface = None
|
||||
if hasattr(obj,"FaceMaker"):
|
||||
if obj.FaceMaker != "None":
|
||||
try:
|
||||
baseface = Part.makeFace(obj.Base.Shape.Wires,"Part::FaceMaker"+str(obj.FaceMaker))
|
||||
except:
|
||||
FreeCAD.Console.PrintError(translate("Arch","Facemaker returned an error")+"\n")
|
||||
return None
|
||||
normal = baseface.normalAt(0,0)
|
||||
if not baseface:
|
||||
for w in obj.Base.Shape.Wires:
|
||||
w.fix(0.1,0,1) # fixes self-intersecting wires
|
||||
f = Part.Face(sh)
|
||||
if baseface:
|
||||
baseface = baseface.fuse(f)
|
||||
else:
|
||||
baseface = f
|
||||
normal = f.normalAt(0,0)
|
||||
base,placement = self.rebase(baseface)
|
||||
elif (len(obj.Base.Shape.Edges) == 1) and (len(obj.Base.Shape.Vertexes) == 1):
|
||||
# closed edge
|
||||
w = Part.Wire(obj.Base.Shape.Edges[0])
|
||||
baseface = Part.Face(w)
|
||||
base,placement = self.rebase(baseface)
|
||||
elif length and width and height:
|
||||
if (length > height) and (obj.Role != "Slab"):
|
||||
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)
|
||||
import Part
|
||||
baseface = Part.Face(Part.makePolygon([v1,v2,v3,v4,v1]))
|
||||
base,placement = self.rebase(baseface)
|
||||
if base and placement:
|
||||
if obj.Normal == Vector(0,0,0):
|
||||
if not normal:
|
||||
normal = Vector(0,0,1)
|
||||
else:
|
||||
normal = Vector(obj.Normal)
|
||||
if (length > height) and (obj.Role != "Slab"):
|
||||
extrusion = normal.multiply(length)
|
||||
else:
|
||||
extrusion = normal.multiply(height)
|
||||
return (base,extrusion,placement)
|
||||
return None
|
||||
|
||||
def onChanged(self,obj,prop):
|
||||
self.hideSubobjects(obj,prop)
|
||||
if prop in ["Shape","ResetNodes","NodesOffset"]:
|
||||
# ResetNodes is not a property but it allows us to use this function to force reset the nodes
|
||||
if hasattr(obj,"Nodes"):
|
||||
# update structural nodes
|
||||
offset = FreeCAD.Vector()
|
||||
if hasattr(obj,"NodesOffset"):
|
||||
offset = FreeCAD.Vector(0,0,obj.NodesOffset.Value)
|
||||
if obj.Nodes and (prop != "ResetNodes"):
|
||||
if hasattr(self,"nodes"):
|
||||
if self.nodes:
|
||||
if obj.Nodes != self.nodes:
|
||||
# nodes are set manually: don't touch them
|
||||
return
|
||||
nodes = None
|
||||
extdata = self.getExtrusionData(obj)
|
||||
if extdata:
|
||||
nodes = extdata[0]
|
||||
nodes.Placement = nodes.Placement.multiply(extdata[2])
|
||||
if obj.Role not in ["Slab"]:
|
||||
if obj.Tool:
|
||||
nodes = obj.Tool.Shape
|
||||
else:
|
||||
# nodes haven't been calculated yet, but are set (file load)
|
||||
# we calculate the nodes now but don't change the property
|
||||
if obj.Role in ["Slab"]:
|
||||
nodes = self.getProfiles(obj)[0]
|
||||
else:
|
||||
nodes = self.getAxis(obj)
|
||||
if nodes:
|
||||
self.nodes = [v.Point.add(offset) for v in nodes.Vertexes]
|
||||
import Part
|
||||
nodes = Part.Line(nodes.CenterOfMass,nodes.CenterOfMass.add(extdata[1])).toShape()
|
||||
offset = FreeCAD.Vector()
|
||||
if hasattr(obj,"NodesOffset"):
|
||||
offset = FreeCAD.Vector(0,0,obj.NodesOffset.Value)
|
||||
if obj.Nodes and (prop != "ResetNodes"):
|
||||
if hasattr(self,"nodes"):
|
||||
if self.nodes:
|
||||
if obj.Nodes != self.nodes:
|
||||
# nodes are set manually: don't touch them
|
||||
return
|
||||
# we calculate and set the nodes
|
||||
if obj.Role in ["Slab"]:
|
||||
nodes = self.getProfiles(obj)[0]
|
||||
else:
|
||||
nodes = self.getAxis(obj)
|
||||
if nodes:
|
||||
self.nodes = [v.Point.add(offset) for v in nodes.Vertexes]
|
||||
obj.Nodes = self.nodes
|
||||
# nodes haven't been calculated yet, but are set (file load)
|
||||
# we set the nodes now but don't change the property
|
||||
if nodes:
|
||||
self.nodes = [v.Point.add(offset) for v in nodes.Vertexes]
|
||||
return
|
||||
# we set the nodes
|
||||
if nodes:
|
||||
self.nodes = [v.Point.add(offset) for v in nodes.Vertexes]
|
||||
obj.Nodes = self.nodes
|
||||
|
||||
def getNodeEdges(self,obj):
|
||||
"returns a list of edges from stuctural nodes"
|
||||
|
|
|
@ -429,13 +429,15 @@ class _Wall(ArchComponent.Component):
|
|||
return
|
||||
|
||||
import Part, DraftGeomUtils
|
||||
pl = obj.Placement
|
||||
normal,length,width,height = self.getDefaultValues(obj)
|
||||
base = None
|
||||
face = None
|
||||
|
||||
pl = obj.Placement
|
||||
extdata = self.getExtrusionData(obj)
|
||||
if extdata:
|
||||
base = extdata[0]
|
||||
base.Placement = extdata[2].multiply(base.Placement)
|
||||
extv = extdata[2].Rotation.multVec(extdata[1])
|
||||
base = base.extrude(extv)
|
||||
if obj.Base:
|
||||
# computing a shape from a base object
|
||||
if obj.Base.isDerivedFrom("Part::Feature"):
|
||||
if obj.Base.Shape.isNull():
|
||||
return
|
||||
|
@ -443,51 +445,8 @@ class _Wall(ArchComponent.Component):
|
|||
if not obj.Base.Shape.Solids:
|
||||
# let pass invalid objects if they have solids...
|
||||
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
|
||||
if not obj.Base.Shape.Faces:
|
||||
# set the length property
|
||||
if hasattr(obj.Base.Shape,"Length"):
|
||||
l = obj.Base.Shape.Length
|
||||
if obj.Length != l:
|
||||
obj.Length = l
|
||||
profiles = self.getProfiles(obj)
|
||||
if profiles:
|
||||
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
|
||||
else:
|
||||
base = None
|
||||
FreeCAD.Console.PrintError(str(translate("Arch","Error: Invalid base object")))
|
||||
|
||||
elif obj.Base.isDerivedFrom("Mesh::Feature"):
|
||||
if obj.Base.Mesh.isSolid():
|
||||
if obj.Base.Mesh.countComponents() == 1:
|
||||
|
@ -495,16 +454,25 @@ class _Wall(ArchComponent.Component):
|
|||
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")))
|
||||
FreeCAD.Console.PrintWarning(translate("Arch","This mesh is an invalid solid")+"\n")
|
||||
obj.Base.ViewObject.show()
|
||||
else:
|
||||
# computing a shape from scratch
|
||||
if length and width and height:
|
||||
base = Part.makeBox(length,width,height)
|
||||
if not base:
|
||||
FreeCAD.Console.PrintError(translate("Arch","Error: Invalid base object")+"\n")
|
||||
return
|
||||
|
||||
base = self.processSubShapes(obj,base,pl)
|
||||
self.applyShape(obj,base,pl)
|
||||
|
||||
# set the length property
|
||||
if obj.Base:
|
||||
if obj.Base.isDerivedFrom("Part::Feature"):
|
||||
if obj.Base.Shape.Edges:
|
||||
if not obj.Base.Shape.Faces:
|
||||
if hasattr(obj.Base.Shape,"Length"):
|
||||
l = obj.Base.Shape.Length
|
||||
if obj.Length.Value != l:
|
||||
obj.Length = l
|
||||
|
||||
def onChanged(self,obj,prop):
|
||||
self.hideSubobjects(obj,prop)
|
||||
ArchComponent.Component.onChanged(self,obj,prop)
|
||||
|
@ -517,7 +485,115 @@ class _Wall(ArchComponent.Component):
|
|||
if abs(abs(f.CenterOfMass.z) - abs(obj.Shape.BoundBox.ZMin)) < 0.001:
|
||||
faces.append(f)
|
||||
return faces
|
||||
|
||||
|
||||
def getExtrusionData(self,obj):
|
||||
"""returns (shape,extrusion vector,placement) or None"""
|
||||
import Part,DraftGeomUtils
|
||||
data = ArchComponent.Component.getExtrusionData(self,obj)
|
||||
if data:
|
||||
return data
|
||||
length = obj.Length.Value
|
||||
width = obj.Width.Value
|
||||
height = obj.Height.Value
|
||||
if not height:
|
||||
for p in obj.InList:
|
||||
if Draft.getType(p) == "Floor":
|
||||
if p.Height.Value:
|
||||
height = p.Height.Value
|
||||
if obj.Normal == Vector(0,0,0):
|
||||
normal = Vector(0,0,1)
|
||||
else:
|
||||
normal = Vector(obj.Normal)
|
||||
base = None
|
||||
placement = None
|
||||
basewires = None
|
||||
if obj.Base:
|
||||
if obj.Base.isDerivedFrom("Part::Feature"):
|
||||
if obj.Base.Shape:
|
||||
if obj.Base.Shape.Solids:
|
||||
return None
|
||||
elif obj.Face > 0:
|
||||
if len(obj.Base.Shape.Faces) >= obj.Face:
|
||||
face = obj.Base.Shape.Faces[obj.Face-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)
|
||||
base,placement = self.rebase(base)
|
||||
return (base,normal,placement)
|
||||
elif obj.Base.Shape.Faces:
|
||||
if not DraftGeomUtils.isCoplanar(obj.Base.Shape.Faces):
|
||||
return None
|
||||
else:
|
||||
base,placement = self.rebase(obj.Base.Shape)
|
||||
elif obj.Base.Shape.Wires:
|
||||
basewires = obj.Base.Shape.Wires
|
||||
elif len(obj.Base.Shape.Edges) == 1:
|
||||
basewires = [Part.Wire(obj.Base.Shape.Edges)]
|
||||
if basewires and width:
|
||||
baseface = None
|
||||
for wire in basewires:
|
||||
e = wire.Edges[0]
|
||||
if isinstance(e.Curve,Part.Circle):
|
||||
dvec = e.Vertexes[0].Point.sub(e.Curve.Center)
|
||||
else:
|
||||
dvec = DraftGeomUtils.vec(wire.Edges[0]).cross(normal)
|
||||
if not DraftVecUtils.isNull(dvec):
|
||||
dvec.normalize()
|
||||
sh = None
|
||||
if obj.Align == "Left":
|
||||
dvec.multiply(width)
|
||||
if obj.Offset.Value:
|
||||
dvec2 = DraftVecUtils.scaleTo(dvec,obj.Offset.Value)
|
||||
wire = DraftGeomUtils.offsetWire(wire,dvec2)
|
||||
w2 = DraftGeomUtils.offsetWire(wire,dvec)
|
||||
w1 = Part.Wire(Part.__sortEdges__(wire.Edges))
|
||||
sh = DraftGeomUtils.bind(w1,w2)
|
||||
elif obj.Align == "Right":
|
||||
dvec.multiply(width)
|
||||
dvec = dvec.negative()
|
||||
if obj.Offset.Value:
|
||||
dvec2 = DraftVecUtils.scaleTo(dvec,obj.Offset.Value)
|
||||
wire = DraftGeomUtils.offsetWire(wire,dvec2)
|
||||
w2 = DraftGeomUtils.offsetWire(wire,dvec)
|
||||
w1 = Part.Wire(Part.__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)
|
||||
if sh:
|
||||
sh.fix(0.1,0,1) # fixes self-intersecting wires
|
||||
f = Part.Face(sh)
|
||||
if baseface:
|
||||
baseface = baseface.fuse(f)
|
||||
else:
|
||||
baseface = f
|
||||
if baseface:
|
||||
base,placement = self.rebase(baseface)
|
||||
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.Face(Part.makePolygon([v1,v2,v3,v4,v1]))
|
||||
placement = FreeCAD.Placement()
|
||||
if base and placement:
|
||||
extrusion = normal.multiply(height)
|
||||
return (base,extrusion,placement)
|
||||
return None
|
||||
|
||||
class _ViewProviderWall(ArchComponent.ViewProviderComponent):
|
||||
"A View Provider for the Wall object"
|
||||
|
|
|
@ -33,18 +33,20 @@ if open.__module__ == '__builtin__':
|
|||
pyopen = open # because we'll redefine open below
|
||||
|
||||
# which IFC type must create which FreeCAD type
|
||||
typesmap = { "Site": ["IfcSite"],
|
||||
"Building": ["IfcBuilding"],
|
||||
"Floor": ["IfcBuildingStorey"],
|
||||
"Structure": ["IfcBeam", "IfcBeamStandardCase", "IfcColumn", "IfcColumnStandardCase", "IfcSlab", "IfcFooting", "IfcPile", "IfcTendon"],
|
||||
"Wall": ["IfcWall", "IfcWallStandardCase", "IfcCurtainWall"],
|
||||
"Window": ["IfcWindow", "IfcWindowStandardCase", "IfcDoor", "IfcDoorStandardCase"],
|
||||
"Roof": ["IfcRoof"],
|
||||
"Stairs": ["IfcStair", "IfcStairFlight", "IfcRamp", "IfcRampFlight"],
|
||||
"Space": ["IfcSpace"],
|
||||
"Rebar": ["IfcReinforcingBar"],
|
||||
"Panel": ["IfcPlate"],
|
||||
"Equipment": ["IfcFurnishingElement","IfcSanitaryTerminal","IfcFlowTerminal","IfcElectricAppliance"]
|
||||
typesmap = { "Site": ["IfcSite"],
|
||||
"Building": ["IfcBuilding"],
|
||||
"Floor": ["IfcBuildingStorey"],
|
||||
"Structure": ["IfcBeam", "IfcBeamStandardCase", "IfcColumn", "IfcColumnStandardCase", "IfcSlab", "IfcFooting", "IfcPile", "IfcTendon"],
|
||||
"Wall": ["IfcWall", "IfcWallStandardCase", "IfcCurtainWall"],
|
||||
"Window": ["IfcWindow", "IfcWindowStandardCase", "IfcDoor", "IfcDoorStandardCase"],
|
||||
"Roof": ["IfcRoof"],
|
||||
"Stairs": ["IfcStair", "IfcStairFlight", "IfcRamp", "IfcRampFlight"],
|
||||
"Space": ["IfcSpace"],
|
||||
"Rebar": ["IfcReinforcingBar"],
|
||||
"Panel": ["IfcPlate"],
|
||||
"Equipment": ["IfcFurnishingElement","IfcSanitaryTerminal","IfcFlowTerminal","IfcElectricAppliance"],
|
||||
"Pipe": ["IfcPipeSegment"],
|
||||
"PipeConnector":["IfcPipeFitting"]
|
||||
}
|
||||
|
||||
# which IFC entity (product) is a structural object
|
||||
|
@ -55,7 +57,7 @@ structuralifcobjects = (
|
|||
"IfcStructuralLinearAction", "IfcStructuralLinearActionVarying", "IfcStructuralPlanarAction"
|
||||
)
|
||||
|
||||
# specific name translations
|
||||
# specific FreeCAD <-> IFC slang translations
|
||||
translationtable = { "Foundation":"Footing",
|
||||
"Floor":"BuildingStorey",
|
||||
"Rebar":"ReinforcingBar",
|
||||
|
@ -63,7 +65,9 @@ translationtable = { "Foundation":"Footing",
|
|||
"ElectricEquipment":"ElectricAppliance",
|
||||
"Furniture":"FurnishingElement",
|
||||
"Stair Flight":"StairFlight",
|
||||
"Curtain Wall":"CurtainWall"
|
||||
"Curtain Wall":"CurtainWall",
|
||||
"Pipe Segment":"PipeSegment",
|
||||
"Pipe Fitting":"PipeFitting"
|
||||
}
|
||||
|
||||
ifctemplate = """ISO-10303-21;
|
||||
|
@ -785,7 +789,7 @@ def insert(filename,docname,skip=[],only=[],root=None):
|
|||
else:
|
||||
if DEBUG: print "no group name specified for entity: #", ifcfile[host].id(), ", entity type is used!"
|
||||
grp_name = ifcfile[host].is_a() + "_" + str(ifcfile[host].id())
|
||||
grp = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup",grp_name)
|
||||
grp = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup",grp_name.encode("utf8"))
|
||||
objects[host] = grp
|
||||
for child in children:
|
||||
if child in objects.keys():
|
||||
|
@ -962,7 +966,7 @@ def export(exportList,filename):
|
|||
of.write(template.encode("utf8"))
|
||||
of.close()
|
||||
os.close(templatefilehandle)
|
||||
global ifcfile, surfstyles, clones, sharedobjects
|
||||
global ifcfile, surfstyles, clones, sharedobjects, profiledefs, shapedefs
|
||||
ifcfile = ifcopenshell.open(templatefile)
|
||||
history = ifcfile.by_type("IfcOwnerHistory")[0]
|
||||
context = ifcfile.by_type("IfcGeometricRepresentationContext")[0]
|
||||
|
@ -985,6 +989,8 @@ def export(exportList,filename):
|
|||
sharedobjects = {} # { BaseName: IfcRepresentationMap }
|
||||
count = 1
|
||||
groups = {} # { Host: [Child,Child,...] }
|
||||
profiledefs = {} # { ProfileDefString:profiledef,...}
|
||||
shapedefs = {} # { ShapeDefString:[shapes],... }
|
||||
|
||||
# build clones table
|
||||
if CREATE_CLONES:
|
||||
|
@ -1318,6 +1324,7 @@ def export(exportList,filename):
|
|||
# 2D objects
|
||||
|
||||
if EXPORT_2D:
|
||||
curvestyles = {}
|
||||
if annotations and DEBUG: print "exporting 2D objects..."
|
||||
for anno in annotations:
|
||||
xvc = ifcfile.createIfcDirection((1.0,0.0,0.0))
|
||||
|
@ -1342,6 +1349,22 @@ def export(exportList,filename):
|
|||
tpl = ifcfile.createIfcAxis2Placement3D(pos,None,None)
|
||||
txt = ifcfile.createIfcTextLiteral(";".join(anno.LabelText).encode("utf8"),tpl,"LEFT")
|
||||
reps = [txt]
|
||||
|
||||
for coldef in ["LineColor","TextColor","ShapeColor"]:
|
||||
if hasattr(obj.ViewObject,coldef):
|
||||
rgb = getattr(obj.ViewObject,coldef)[:3]
|
||||
if rgb in curvestyles:
|
||||
psa = curvestyles[rgb]
|
||||
else:
|
||||
col = ifcfile.createIfcColourRgb(None,rgb[0],rgb[1],rgb[2])
|
||||
cvf = ifcfile.createIfcDraughtingPredefinedCurveFont("CONTINUOUS")
|
||||
ics = ifcfile.createIfcCurveStyle('Line',cvf,None,col)
|
||||
psa = ifcfile.createIfcPresentationStyleAssignment([ics])
|
||||
curvestyles[rgb] = psa
|
||||
for rep in reps:
|
||||
isi = ifcfile.createIfcStyledItem(rep,[psa],None)
|
||||
break
|
||||
|
||||
shp = ifcfile.createIfcShapeRepresentation(context,'Annotation','Annotation2D',reps)
|
||||
rep = ifcfile.createIfcProductDefinitionShape(None,None,[shp])
|
||||
ann = ifcfile.createIfcAnnotation(ifcopenshell.guid.compress(uuid.uuid1().hex),history,anno.Label.encode('utf8'),'',None,gpl,rep)
|
||||
|
@ -1390,7 +1413,7 @@ def createCurve(ifcfile,wire):
|
|||
if da > 0:
|
||||
follow = not(follow)
|
||||
xvc = ifcfile.createIfcDirection((1.0,0.0))
|
||||
ovc = ifcfile.createIfcCartesianPoint(tuple(e.Curve.Center)[:2])
|
||||
ovc = ifcfile.createIfcCartesianPoint(tuple(e.Curve.Center))
|
||||
plc = ifcfile.createIfcAxis2Placement2D(ovc,xvc)
|
||||
cir = ifcfile.createIfcCircle(plc,e.Curve.Radius)
|
||||
curve = ifcfile.createIfcTrimmedCurve(cir,[ifcfile.createIfcParameterValue(p1)],[ifcfile.createIfcParameterValue(p2)],follow,"PARAMETER")
|
||||
|
@ -1404,7 +1427,7 @@ def createCurve(ifcfile,wire):
|
|||
last = e.Vertexes[-1].Point
|
||||
else:
|
||||
last = e.Vertexes[-1].Point
|
||||
pts = [ifcfile.createIfcCartesianPoint(tuple(v)[:2]) for v in verts]
|
||||
pts = [ifcfile.createIfcCartesianPoint(tuple(v)) for v in verts]
|
||||
curve = ifcfile.createIfcPolyline(pts)
|
||||
segment = ifcfile.createIfcCompositeCurveSegment("CONTINUOUS",True,curve)
|
||||
segments.append(segment)
|
||||
|
@ -1422,6 +1445,7 @@ def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tess
|
|||
productdef = None
|
||||
shapetype = "no shape"
|
||||
tostore = False
|
||||
subplacement = None
|
||||
|
||||
# check for clones
|
||||
if (not subtraction) and (not forcebrep):
|
||||
|
@ -1447,67 +1471,62 @@ def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tess
|
|||
if (not shapes) and (not forcebrep):
|
||||
profile = None
|
||||
if hasattr(obj,"Proxy"):
|
||||
if hasattr(obj.Proxy,"getProfiles"):
|
||||
p = obj.Proxy.getProfiles(obj,noplacement=True)
|
||||
extrusionv = obj.Proxy.getExtrusionVector(obj,noplacement=True)
|
||||
if not DraftVecUtils.isNull(extrusionv):
|
||||
extrusionv.multiply(0.001) # to meters
|
||||
if (len(p) == 1) and extrusionv:
|
||||
p = p[0].copy()
|
||||
p.scale(0.001) # to meters
|
||||
r = obj.Proxy.getPlacement(obj)
|
||||
r.Base = r.Base.multiply(0.001) # to meters
|
||||
d = DraftGeomUtils.getNormal(p.Wires[0])
|
||||
if r.isNull() and ( (p.CenterOfMass.z > 0.001) or ( (d.getAngle(FreeCAD.Vector(0,0,1)) > 0.001) and (d.getAngle(FreeCAD.Vector(0,0,1)) < 3.14159) ) ):
|
||||
# the object placement is null, but the profile is not in the XY plane.
|
||||
npla = FreeCAD.Placement()
|
||||
npla.Base = p.Vertexes[0].Point
|
||||
nrot = FreeCAD.Rotation(FreeCAD.Vector(0,0,1),d)
|
||||
npla.Rotation = nrot
|
||||
r = npla
|
||||
# p.Placement = p.Placement.multiply(npla.inverse()) # move the profile to origin - not working??
|
||||
p.translate(p.Vertexes[0].Point.negative())
|
||||
p.rotate(FreeCAD.Vector(0,0,0),nrot.inverted().Axis,math.degrees(nrot.inverted().Angle))
|
||||
extrusionv = nrot.inverted().multVec(extrusionv) # move the extrusion vector to Z axis, mandatory in IFC
|
||||
|
||||
if hasattr(obj.Proxy,"getExtrusionData"):
|
||||
extdata = obj.Proxy.getExtrusionData(obj)
|
||||
if extdata:
|
||||
# convert to meters
|
||||
p = extdata[0]
|
||||
p.scale(0.001)
|
||||
ev = extdata[1]
|
||||
ev.multiply(0.001)
|
||||
pl = extdata[2]
|
||||
pl.Base = pl.Base.multiply(0.001)
|
||||
pstr = str([v.Point for v in extdata[0].Vertexes])
|
||||
if pstr in profiledefs:
|
||||
profile = profiledefs[pstr]
|
||||
shapetype = "reusing profile"
|
||||
else:
|
||||
if len(p.Edges) == 1:
|
||||
|
||||
pxvc = ifcfile.createIfcDirection((1.0,0.0))
|
||||
povc = ifcfile.createIfcCartesianPoint((0.0,0.0))
|
||||
pt = ifcfile.createIfcAxis2Placement2D(povc,pxvc)
|
||||
|
||||
# extruded circle
|
||||
if isinstance(p.Edges[0].Curve,Part.Circle):
|
||||
# extruded circle
|
||||
profile = ifcfile.createIfcCircleProfileDef("AREA",None,pt, p.Edges[0].Curve.Radius)
|
||||
|
||||
# extruded ellipse
|
||||
elif isinstance(p.Edges[0].Curve,Part.Ellipse):
|
||||
# extruded ellipse
|
||||
profile = ifcfile.createIfcEllipseProfileDef("AREA",None,pt, p.Edges[0].Curve.MajorRadius, p.Edges[0].Curve.MinorRadius)
|
||||
|
||||
else:
|
||||
curves = False
|
||||
for e in p.Edges:
|
||||
if isinstance(e.Curve,Part.Circle):
|
||||
curves = True
|
||||
|
||||
# extruded polyline
|
||||
if not curves:
|
||||
w = Part.Wire(Part.__sortEdges__(p.Edges))
|
||||
# extruded polyline
|
||||
w = Part.Wire(Part.__sortEdges__(p.Wires[0].Edges))
|
||||
pts = [ifcfile.createIfcCartesianPoint(tuple(v.Point)[:2]) for v in w.Vertexes+[w.Vertexes[0]]]
|
||||
pol = ifcfile.createIfcPolyline(pts)
|
||||
|
||||
# extruded composite curve
|
||||
else:
|
||||
# extruded composite curve
|
||||
pol = createCurve(ifcfile,p)
|
||||
profile = ifcfile.createIfcArbitraryClosedProfileDef("AREA",None,pol)
|
||||
if profile:
|
||||
profiledefs[pstr] = profile
|
||||
|
||||
if profile and not(DraftVecUtils.isNull(extrusionv)):
|
||||
xvc = ifcfile.createIfcDirection(tuple(r.Rotation.multVec(FreeCAD.Vector(1,0,0))))
|
||||
zvc = ifcfile.createIfcDirection(tuple(r.Rotation.multVec(FreeCAD.Vector(0,0,1))))
|
||||
ovc = ifcfile.createIfcCartesianPoint(tuple(r.Base))
|
||||
if profile and not(DraftVecUtils.isNull(ev)):
|
||||
#ev = pl.Rotation.inverted().multVec(ev)
|
||||
#print "ev:",ev
|
||||
if not tostore:
|
||||
# add the object placement to the profile placement. Otherwise it'll be done later at map insert
|
||||
pl2 = FreeCAD.Placement(obj.Placement)
|
||||
pl2.Base = pl2.Base.multiply(0.001)
|
||||
pl = pl2.multiply(pl)
|
||||
xvc = ifcfile.createIfcDirection(tuple(pl.Rotation.multVec(FreeCAD.Vector(1,0,0))))
|
||||
zvc = ifcfile.createIfcDirection(tuple(pl.Rotation.multVec(FreeCAD.Vector(0,0,1))))
|
||||
ovc = ifcfile.createIfcCartesianPoint(tuple(pl.Base))
|
||||
lpl = ifcfile.createIfcAxis2Placement3D(ovc,zvc,xvc)
|
||||
edir = ifcfile.createIfcDirection(tuple(FreeCAD.Vector(extrusionv).normalize()))
|
||||
shape = ifcfile.createIfcExtrudedAreaSolid(profile,lpl,edir,extrusionv.Length)
|
||||
edir = ifcfile.createIfcDirection(tuple(FreeCAD.Vector(ev).normalize()))
|
||||
shape = ifcfile.createIfcExtrudedAreaSolid(profile,lpl,edir,ev.Length)
|
||||
shapes.append(shape)
|
||||
solidType = "SweptSolid"
|
||||
shapetype = "extrusion"
|
||||
|
@ -1521,113 +1540,131 @@ def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tess
|
|||
if hasattr(obj.Proxy,"getSubVolume"):
|
||||
fcshape = obj.Proxy.getSubVolume(obj)
|
||||
if not fcshape:
|
||||
if hasattr(obj,"Shape"):
|
||||
if obj.Shape:
|
||||
if not obj.Shape.isNull():
|
||||
fcshape = obj.Shape
|
||||
elif hasattr(obj,"Terrain"):
|
||||
if obj.Terrain:
|
||||
if hasattr(obj.Terrain,"Shape"):
|
||||
if obj.Terrain.Shape:
|
||||
if not obj.Terrain.Shape.isNull():
|
||||
fcshape = obj.Terrain.Shape
|
||||
if obj.isDerivedFrom("Part::Feature"):
|
||||
if False: # below is buggy. No way to duplicate shapes that way?
|
||||
#if hasattr(obj,"Base") and hasattr(obj,"Additions")and hasattr(obj,"Subtractions"):
|
||||
if obj.Base and (not obj.Additions) and not(obj.Subtractions):
|
||||
if obj.Base.isDerivedFrom("Part::Feature"):
|
||||
if obj.Base.Shape:
|
||||
if obj.Base.Shape.Solids:
|
||||
fcshape = obj.Base.Shape
|
||||
subplacement = FreeCAD.Placement(obj.Placement)
|
||||
if not fcshape:
|
||||
if obj.Shape:
|
||||
if not obj.Shape.isNull():
|
||||
fcshape = obj.Shape
|
||||
if fcshape:
|
||||
solids = []
|
||||
if fcshape.Solids:
|
||||
dataset = fcshape.Solids
|
||||
shapedef = str([v.Point for v in fcshape.Vertexes])
|
||||
if shapedef in shapedefs:
|
||||
shapes = shapedefs[shapedef]
|
||||
shapetype = "reusing brep"
|
||||
else:
|
||||
dataset = fcshape.Shells
|
||||
if DEBUG: print "Warning! object contains no solids"
|
||||
|
||||
# if this is a clone, place back the shapes in null position
|
||||
if tostore:
|
||||
for shape in dataset:
|
||||
shape.Placement = FreeCAD.Placement()
|
||||
|
||||
# new ifcopenshell serializer
|
||||
from ifcopenshell import geom
|
||||
if hasattr(geom,"serialise") and obj.isDerivedFrom("Part::Feature") and SERIALIZE:
|
||||
p = geom.serialise(obj.Shape.exportBrepToString())
|
||||
productdef = ifcfile.add(p)
|
||||
for rep in productdef.Representations:
|
||||
rep.ContextOfItems = context
|
||||
xvc = ifcfile.createIfcDirection((1.0,0.0,0.0))
|
||||
zvc = ifcfile.createIfcDirection((0.0,0.0,1.0))
|
||||
ovc = ifcfile.createIfcCartesianPoint((0.0,0.0,0.0))
|
||||
gpl = ifcfile.createIfcAxis2Placement3D(ovc,zvc,xvc)
|
||||
placement = ifcfile.createIfcLocalPlacement(None,gpl)
|
||||
shapetype = "advancedbrep"
|
||||
shapes = None
|
||||
else:
|
||||
# old method
|
||||
for fcsolid in dataset:
|
||||
fcsolid.scale(0.001) # to meters
|
||||
faces = []
|
||||
curves = False
|
||||
shapetype = "brep"
|
||||
for fcface in fcsolid.Faces:
|
||||
for e in fcface.Edges:
|
||||
if DraftGeomUtils.geomType(e) != "Line":
|
||||
try:
|
||||
if e.curvatureAt(e.FirstParameter+(e.LastParameter-e.FirstParameter)/2) > 0.0001:
|
||||
curves = True
|
||||
break
|
||||
except Part.OCCError:
|
||||
pass
|
||||
if curves:
|
||||
joinfacets = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetBool("ifcJoinCoplanarFacets",False)
|
||||
usedae = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetBool("ifcUseDaeOptions",False)
|
||||
if not joinfacets:
|
||||
shapetype = "triangulated"
|
||||
if usedae:
|
||||
import importDAE
|
||||
tris = importDAE.triangulate(fcsolid)
|
||||
else:
|
||||
tris = fcsolid.tessellate(tessellation)
|
||||
for tri in tris[1]:
|
||||
pts = [ifcfile.createIfcCartesianPoint(tuple(tris[0][i])) for i in tri]
|
||||
loop = ifcfile.createIfcPolyLoop(pts)
|
||||
bound = ifcfile.createIfcFaceOuterBound(loop,True)
|
||||
face = ifcfile.createIfcFace([bound])
|
||||
faces.append(face)
|
||||
fcsolid = Part.Shape() # empty shape so below code is not executed
|
||||
else:
|
||||
fcsolid = Arch.removeCurves(fcsolid,dae=usedae)
|
||||
if not fcsolid:
|
||||
if DEBUG: print "Error: Unable to triangulate shape"
|
||||
fcsolid = Part.Shape()
|
||||
|
||||
for fcface in fcsolid.Faces:
|
||||
loops = []
|
||||
verts = [v.Point for v in Part.Wire(Part.__sortEdges__(fcface.OuterWire.Edges)).Vertexes]
|
||||
c = fcface.CenterOfMass
|
||||
v1 = verts[0].sub(c)
|
||||
v2 = verts[1].sub(c)
|
||||
n = fcface.normalAt(0,0)
|
||||
if DraftVecUtils.angle(v2,v1,n) >= 0:
|
||||
verts.reverse() # inverting verts order if the direction is couterclockwise
|
||||
pts = [ifcfile.createIfcCartesianPoint(tuple(v)) for v in verts]
|
||||
loop = ifcfile.createIfcPolyLoop(pts)
|
||||
bound = ifcfile.createIfcFaceOuterBound(loop,True)
|
||||
loops.append(bound)
|
||||
for wire in fcface.Wires:
|
||||
if wire.hashCode() != fcface.OuterWire.hashCode():
|
||||
verts = [v.Point for v in Part.Wire(Part.__sortEdges__(wire.Edges)).Vertexes]
|
||||
v1 = verts[0].sub(c)
|
||||
v2 = verts[1].sub(c)
|
||||
if DraftVecUtils.angle(v2,v1,DraftVecUtils.neg(n)) >= 0:
|
||||
verts.reverse()
|
||||
pts = [ifcfile.createIfcCartesianPoint(tuple(v)) for v in verts]
|
||||
loop = ifcfile.createIfcPolyLoop(pts)
|
||||
bound = ifcfile.createIfcFaceBound(loop,True)
|
||||
loops.append(bound)
|
||||
face = ifcfile.createIfcFace(loops)
|
||||
faces.append(face)
|
||||
|
||||
if faces:
|
||||
shell = ifcfile.createIfcClosedShell(faces)
|
||||
shape = ifcfile.createIfcFacetedBrep(shell)
|
||||
shapes.append(shape)
|
||||
# new ifcopenshell serializer
|
||||
from ifcopenshell import geom
|
||||
serialized = False
|
||||
if hasattr(geom,"serialise") and obj.isDerivedFrom("Part::Feature") and SERIALIZE:
|
||||
if obj.Shape.Faces:
|
||||
sh = obj.Shape.copy()
|
||||
sh.scale(0.001) # to meters
|
||||
p = geom.serialise(sh.exportBrepToString())
|
||||
if p:
|
||||
productdef = ifcfile.add(p)
|
||||
for rep in productdef.Representations:
|
||||
rep.ContextOfItems = context
|
||||
xvc = ifcfile.createIfcDirection((1.0,0.0,0.0))
|
||||
zvc = ifcfile.createIfcDirection((0.0,0.0,1.0))
|
||||
ovc = ifcfile.createIfcCartesianPoint((0.0,0.0,0.0))
|
||||
gpl = ifcfile.createIfcAxis2Placement3D(ovc,zvc,xvc)
|
||||
placement = ifcfile.createIfcLocalPlacement(None,gpl)
|
||||
shapetype = "advancedbrep"
|
||||
shapes = None
|
||||
serialized = True
|
||||
if not serialized:
|
||||
# old method
|
||||
solids = []
|
||||
if fcshape.Solids:
|
||||
dataset = fcshape.Solids
|
||||
else:
|
||||
dataset = fcshape.Shells
|
||||
#if DEBUG: print "Warning! object contains no solids"
|
||||
|
||||
# if this is a clone, place back the shapes in null position
|
||||
if tostore:
|
||||
for shape in dataset:
|
||||
shape.Placement = FreeCAD.Placement()
|
||||
|
||||
for fcsolid in dataset:
|
||||
fcsolid.scale(0.001) # to meters
|
||||
faces = []
|
||||
curves = False
|
||||
shapetype = "brep"
|
||||
for fcface in fcsolid.Faces:
|
||||
for e in fcface.Edges:
|
||||
if DraftGeomUtils.geomType(e) != "Line":
|
||||
try:
|
||||
if e.curvatureAt(e.FirstParameter+(e.LastParameter-e.FirstParameter)/2) > 0.0001:
|
||||
curves = True
|
||||
break
|
||||
except Part.OCCError:
|
||||
pass
|
||||
if curves:
|
||||
joinfacets = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetBool("ifcJoinCoplanarFacets",False)
|
||||
usedae = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetBool("ifcUseDaeOptions",False)
|
||||
if joinfacets:
|
||||
result = Arch.removeCurves(fcsolid,dae=usedae)
|
||||
if result:
|
||||
fcsolid = result
|
||||
else:
|
||||
# fall back to standard triangulation
|
||||
joinfacets = False
|
||||
if not joinfacets:
|
||||
shapetype = "triangulated"
|
||||
if usedae:
|
||||
import importDAE
|
||||
tris = importDAE.triangulate(fcsolid)
|
||||
else:
|
||||
tris = fcsolid.tessellate(tessellation)
|
||||
for tri in tris[1]:
|
||||
pts = [ifcfile.createIfcCartesianPoint(tuple(tris[0][i])) for i in tri]
|
||||
loop = ifcfile.createIfcPolyLoop(pts)
|
||||
bound = ifcfile.createIfcFaceOuterBound(loop,True)
|
||||
face = ifcfile.createIfcFace([bound])
|
||||
faces.append(face)
|
||||
fcsolid = Part.Shape() # empty shape so below code is not executed
|
||||
|
||||
for fcface in fcsolid.Faces:
|
||||
loops = []
|
||||
verts = [v.Point for v in fcface.OuterWire.OrderedVertexes]
|
||||
c = fcface.CenterOfMass
|
||||
v1 = verts[0].sub(c)
|
||||
v2 = verts[1].sub(c)
|
||||
n = fcface.normalAt(0,0)
|
||||
if DraftVecUtils.angle(v2,v1,n) >= 0:
|
||||
verts.reverse() # inverting verts order if the direction is couterclockwise
|
||||
pts = [ifcfile.createIfcCartesianPoint(tuple(v)) for v in verts]
|
||||
loop = ifcfile.createIfcPolyLoop(pts)
|
||||
bound = ifcfile.createIfcFaceOuterBound(loop,True)
|
||||
loops.append(bound)
|
||||
for wire in fcface.Wires:
|
||||
if wire.hashCode() != fcface.OuterWire.hashCode():
|
||||
verts = [v.Point for v in wire.OrderedVertexes]
|
||||
v1 = verts[0].sub(c)
|
||||
v2 = verts[1].sub(c)
|
||||
if DraftVecUtils.angle(v2,v1,DraftVecUtils.neg(n)) >= 0:
|
||||
verts.reverse()
|
||||
pts = [ifcfile.createIfcCartesianPoint(tuple(v)) for v in verts]
|
||||
loop = ifcfile.createIfcPolyLoop(pts)
|
||||
bound = ifcfile.createIfcFaceBound(loop,True)
|
||||
loops.append(bound)
|
||||
face = ifcfile.createIfcFace(loops)
|
||||
faces.append(face)
|
||||
|
||||
if faces:
|
||||
shell = ifcfile.createIfcClosedShell(faces)
|
||||
shape = ifcfile.createIfcFacetedBrep(shell)
|
||||
shapes.append(shape)
|
||||
|
||||
shapedefs[shapedef] = shapes
|
||||
|
||||
if shapes:
|
||||
|
||||
|
@ -1638,7 +1675,7 @@ def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tess
|
|||
ovc = ifcfile.createIfcCartesianPoint((0.0,0.0,0.0))
|
||||
gpl = ifcfile.createIfcAxis2Placement3D(ovc,zvc,xvc)
|
||||
repmap = ifcfile.createIfcRepresentationMap(gpl,subrep)
|
||||
pla = FreeCAD.ActiveDocument.getObject(tostore).Placement
|
||||
pla = obj.Placement
|
||||
axis1 = ifcfile.createIfcDirection(tuple(pla.Rotation.multVec(FreeCAD.Vector(1,0,0))))
|
||||
axis2 = ifcfile.createIfcDirection(tuple(pla.Rotation.multVec(FreeCAD.Vector(0,1,0))))
|
||||
origin = ifcfile.createIfcCartesianPoint(tuple(FreeCAD.Vector(pla.Base).multiply(0.001)))
|
||||
|
|
Loading…
Reference in New Issue
Block a user