Arch: Fixed buggy import/export of objects based on rectangles to IFC

This commit is contained in:
Yorik van Havre
2018-11-09 17:59:17 -02:00
parent 3956cee0ac
commit 94a5fd7408
3 changed files with 32 additions and 15 deletions

View File

@@ -1222,9 +1222,10 @@ def rebuildArchShape(objects=None):
FreeCAD.ActiveDocument.recompute()
def getExtrusionData(shape):
"""getExtrusionData(shape): returns a base face and an extrusion vector
if this shape can be described as a perpendicular extrusion, or None if not."""
def getExtrusionData(shape,sortmethod="area"):
"""getExtrusionData(shape,sortmethod): returns a base face and an extrusion vector
if this shape can be described as a perpendicular extrusion, or None if not.
sortmethod can be "area" (default) or "z"."""
if shape.isNull():
return None
if not shape.Solids:
@@ -1264,8 +1265,11 @@ def getExtrusionData(shape):
else:
valids.append([faces[pair[1]][0],faces[pair[0]][0].CenterOfMass.sub(faces[pair[1]][0].CenterOfMass)])
if valids:
# sort by smallest area
valids.sort(key=lambda v: v[0].Area)
if sortmethod == "z":
valids.sort(key=lambda v: v[0].CenterOfMass.z)
else:
# sort by smallest area
valids.sort(key=lambda v: v[0].Area)
return valids[0]
return None

View File

@@ -787,7 +787,8 @@ class _Wall(ArchComponent.Component):
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 obj.Normal != Vector(0,0,0):
normal = face.normalAt(0,0)
if normal.getAngle(Vector(0,0,1)) > math.pi/4:
normal.multiply(width)
base = face.extrude(normal)
@@ -917,6 +918,8 @@ class _Wall(ArchComponent.Component):
placement = FreeCAD.Placement()
if base and placement:
extrusion = normal.multiply(height)
if placement.Rotation.Angle > 0:
extrusion = placement.inverse().Rotation.multVec(extrusion)
return (base,extrusion,placement)
return None

View File

@@ -668,7 +668,11 @@ def insert(filename,docname,skip=[],only=[],root=None):
if DEBUG: print("clone ",end="")
else:
if GET_EXTRUSIONS:
ex = Arch.getExtrusionData(shape) # is this an extrusion?
if ptype in ["IfcWall","IfcWallStandardCase"]:
sortmethod = "z"
else:
sortmethod = "area"
ex = Arch.getExtrusionData(shape,sortmethod) # is this an extrusion?
if ex:
# check for extrusion profile
baseface = None
@@ -701,7 +705,7 @@ def insert(filename,docname,skip=[],only=[],root=None):
if DraftGeomUtils.hasCurves(ex[0]) or len(ex[0].Wires) != 1:
# curves or holes? We just make a Part face
baseface = FreeCAD.ActiveDocument.addObject("Part::Feature",name+"_footprint")
# bug in ifcopenshell? Some faces of a shell may have non-null placement
# bug/feature in ifcopenshell? Some faces of a shell may have non-null placement
# workaround to remove the bad placement: exporting/reimporting as step
if not ex[0].Placement.isNull():
import tempfile
@@ -2521,12 +2525,13 @@ def checkRectangle(edges):
""" checkRectangle(edges=[]): This function checks whether the given form rectangle
or not. It will return True when edges form rectangular shape or return False
when edges not form a rectangular."""
if len(edges) != 4:
return False
angles = [round(getEdgesAngle(edges[0], edges[1])), round(getEdgesAngle(edges[0], edges[2])),
round(getEdgesAngle(edges[0], edges[3]))]
if angles.count(90) == 2 and (angles.count(180) == 1 or angles.count(0) == 1):
return True
else:
return False
return False
def getProfile(ifcfile,p):
@@ -2545,13 +2550,18 @@ def getProfile(ifcfile,p):
# extruded ellipse
profile = ifcfile.createIfcEllipseProfileDef("AREA",None,pt,p.Edges[0].Curve.MajorRadius,p.Edges[0].Curve.MinorRadius)
elif (checkRectangle(p.Edges)):
pxvc = ifcbin.createIfcDirection((1.0,0.0))
# arbitrarily use the first edge as the rectangle orientation
d = vec(p.Edges[0])
d.normalize()
pxvc = ifcbin.createIfcDirection(tuple(d))
povc = ifcbin.createIfcCartesianPoint((0.0,0.0))
pt = ifcbin.createIfcAxis2Placement2D(povc,pxvc)
semiPerimeter = p.Length/2
diff = math.sqrt(semiPerimeter**2 - 4*p.Area)
b = max(abs((semiPerimeter + diff)/2),abs((semiPerimeter - diff)/2))
h = min(abs((semiPerimeter + diff)/2),abs((semiPerimeter - diff)/2))
#semiPerimeter = p.Length/2
#diff = math.sqrt(semiPerimeter**2 - 4*p.Area)
#b = max(abs((semiPerimeter + diff)/2),abs((semiPerimeter - diff)/2))
#h = min(abs((semiPerimeter + diff)/2),abs((semiPerimeter - diff)/2))
b = p.Edges[0].Length
h = p.Edges[1].Length
profile = ifcfile.createIfcRectangleProfileDef("AREA",'rectangular',pt,b,h)
elif (len(p.Faces) == 1) and (len(p.Wires) > 1):
# face with holes