ArchSpace - Correct computed dimensions (floor area and perimeter length) (#14211)
* Arch: Improved ArchComponent.computeAreas function All non vertical faces get projected now. Changed Part.Wire to DraftGeomUtils.findWires * Arch: Removed Area property and add AreaCalculationType to Space object The horizontal area and its perimeter are now calculated in two different ways. Eiter at the centre of mass or as a projection on the XY-plane. The results are filled in the filed horizontal area and perimeter in the Component section. * BIM: Added property Area for Spaces again
This commit is contained in:
@@ -994,6 +994,8 @@ class Component(ArchIFC.IfcProduct):
|
||||
|
||||
import Part
|
||||
import TechDraw
|
||||
import DraftGeomUtils
|
||||
|
||||
fmax = params.get_param_arch("MaxComputeAreas")
|
||||
if len(obj.Shape.Faces) > fmax:
|
||||
obj.VerticalArea = 0
|
||||
@@ -1015,7 +1017,7 @@ class Component(ArchIFC.IfcProduct):
|
||||
else:
|
||||
if (ang > 1.57) and (ang < 1.571):
|
||||
a += f.Area
|
||||
if ang < 1.5707:
|
||||
else:
|
||||
fset.append(f)
|
||||
|
||||
if a and hasattr(obj,"VerticalArea"):
|
||||
@@ -1024,22 +1026,19 @@ class Component(ArchIFC.IfcProduct):
|
||||
if fset and hasattr(obj,"HorizontalArea"):
|
||||
pset = []
|
||||
for f in fset:
|
||||
if f.normalAt(0,0).getAngle(FreeCAD.Vector(0,0,1)) < 0.00001:
|
||||
# already horizontal
|
||||
pset.append(f)
|
||||
try:
|
||||
pf = Part.Face(DraftGeomUtils.findWires(TechDraw.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:
|
||||
try:
|
||||
pf = Part.Face(Part.Wire(TechDraw.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)
|
||||
pset.append(pf)
|
||||
|
||||
|
||||
if pset:
|
||||
self.flatarea = pset.pop()
|
||||
@@ -1049,8 +1048,11 @@ class Component(ArchIFC.IfcProduct):
|
||||
if obj.HorizontalArea.Value != self.flatarea.Area:
|
||||
obj.HorizontalArea = self.flatarea.Area
|
||||
if hasattr(obj,"PerimeterLength") and (len(self.flatarea.Faces) == 1):
|
||||
if obj.PerimeterLength.Value != self.flatarea.Faces[0].OuterWire.Length:
|
||||
obj.PerimeterLength = self.flatarea.Faces[0].OuterWire.Length
|
||||
edges_table = {}
|
||||
for e in self.flatarea.Edges:
|
||||
edges_table.setdefault(e.hashCode(),[]).append(e)
|
||||
border_edges = [pair[0] for pair in edges_table.values() if len(pair) == 1]
|
||||
obj.PerimeterLength = sum([e.Length for e in border_edges])
|
||||
|
||||
def isStandardCase(self,obj):
|
||||
"""Determine if the component is a standard case of its IFC type.
|
||||
|
||||
@@ -145,6 +145,12 @@ ConditioningTypes = [
|
||||
"NaturallyVentedOnly"
|
||||
]
|
||||
|
||||
AreaCalculationType = [
|
||||
"XY-plane projection",
|
||||
"At Center of Mass"
|
||||
]
|
||||
|
||||
|
||||
import FreeCAD
|
||||
import ArchComponent
|
||||
import ArchCommands
|
||||
@@ -213,7 +219,7 @@ class _Space(ArchComponent.Component):
|
||||
if not "Boundaries" in pl:
|
||||
obj.addProperty("App::PropertyLinkSubList","Boundaries", "Space",QT_TRANSLATE_NOOP("App::Property","The objects that make the boundaries of this space object"))
|
||||
if not "Area" in pl:
|
||||
obj.addProperty("App::PropertyArea", "Area", "Space",QT_TRANSLATE_NOOP("App::Property","The computed floor area of this space"))
|
||||
obj.addProperty("App::PropertyArea", "Area", "Space",QT_TRANSLATE_NOOP("App::Property","Identical to Horizontal Area"))
|
||||
if not "FinishFloor" in pl:
|
||||
obj.addProperty("App::PropertyString", "FinishFloor", "Space",QT_TRANSLATE_NOOP("App::Property","The finishing of the floor of this space"))
|
||||
if not "FinishWalls" in pl:
|
||||
@@ -241,8 +247,10 @@ class _Space(ArchComponent.Component):
|
||||
if not "Internal" in pl:
|
||||
obj.addProperty("App::PropertyBool", "Internal", "Space",QT_TRANSLATE_NOOP("App::Property","Specifies if this space is internal or external"))
|
||||
obj.Internal = True
|
||||
if not "AreaCalculationType" in pl:
|
||||
obj.addProperty("App::PropertyEnumeration", "AreaCalculationType", "Space",QT_TRANSLATE_NOOP("App::Property","Defines the calculation type for the horizontal area and its perimeter length"))
|
||||
obj.AreaCalculationType = AreaCalculationType
|
||||
self.Type = "Space"
|
||||
obj.setEditorMode("HorizontalArea",2)
|
||||
|
||||
def onDocumentRestored(self,obj):
|
||||
|
||||
@@ -374,10 +382,14 @@ class _Space(ArchComponent.Component):
|
||||
#print("setting objects shape")
|
||||
shape = shape.Solids[0]
|
||||
self.applyShape(obj,shape,pl)
|
||||
if hasattr(obj.Area,"Value"):
|
||||
a = self.getArea(obj)
|
||||
if obj.Area.Value != a:
|
||||
obj.Area = a
|
||||
if hasattr(obj.HorizontalArea,"Value"):
|
||||
if hasattr(obj,"AreaCalculationType"):
|
||||
if obj.AreaCalculationType == "At Center of Mass":
|
||||
a = self.getArea(obj)
|
||||
obj.HorizontalArea = a
|
||||
if hasattr(obj,"Area"):
|
||||
obj.Area = obj.HorizontalArea
|
||||
|
||||
return
|
||||
|
||||
print("Arch: error computing space boundary for",obj.Label)
|
||||
@@ -392,22 +404,13 @@ class _Space(ArchComponent.Component):
|
||||
if hasattr(obj,"PerimeterLength"):
|
||||
if self.face.OuterWire.Length != obj.PerimeterLength.Value:
|
||||
obj.PerimeterLength = self.face.OuterWire.Length
|
||||
if hasattr(obj,"VerticalArea"):
|
||||
a = 0
|
||||
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 a != obj.VerticalArea.Value:
|
||||
obj.VerticalArea = a
|
||||
#print "area of ",obj.Label," : ",f.Area
|
||||
return self.face.Area
|
||||
else:
|
||||
return 0
|
||||
|
||||
def getFootprint(self,obj):
|
||||
|
||||
"returns a face that represents the footprint of this space"
|
||||
"returns a face that represents the footprint of this space at the center of mass"
|
||||
|
||||
import Part
|
||||
import DraftGeomUtils
|
||||
|
||||
Reference in New Issue
Block a user