Arch: Fixed buggy import/export of objects based on rectangles to IFC
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user