BIM: NativeIFC 2D support - dimensions

This commit is contained in:
Yorik van Havre
2024-09-27 11:56:16 +02:00
committed by Yorik van Havre
parent 4fba4abe5f
commit 9c53a024c0
3 changed files with 92 additions and 6 deletions

View File

@@ -121,10 +121,33 @@ def get_text(annotation):
"""Determines if an IfcAnnotation contains an IfcTextLiteral.
Returns the IfcTextLiteral or None"""
for rep in annotation.Representation.Representations:
for item in rep.Items:
if item.is_a("IfcTextLiteral"):
return item
if annotation.is_a("IfcAnnotation"):
for rep in annotation.Representation.Representations:
for item in rep.Items:
if item.is_a("IfcTextLiteral"):
return item
return None
def get_dimension(annotation):
"""Determines if an IfcAnnotation is representing a dimension.
Returns a list containing the representation, two points indicating
the mesured points, and optionally a third point indicating where
the dimension line is located, if available"""
if annotation.is_a("IfcAnnotation"):
if annotation.ObjectType == "DIMENSION":
s = ifcopenshell.util.unit.calculate_unit_scale(annotation.file) * 1000
for rep in annotation.Representation.Representations:
shape = importIFCHelper.get2DShape(rep, s)
if shape and len(shape) == 1:
if len(shape[0].Vertexes) >= 2:
# two-point polyline (BBIM)
res = [rep, shape[0].Vertexes[0].Point, shape[0].Vertexes[-1].Point]
if len(shape[0].Vertexes) > 2:
# 4-point polyline (FreeCAD)
res.append(shape[0].Vertexes[0].Point)
return res
return None
@@ -163,3 +186,15 @@ def get_placement(ifcelement, ifcfile):
s = 0.001 / ifcopenshell.util.unit.calculate_unit_scale(ifcfile)
return importIFCHelper.getPlacement(ifcelement, scaling=s)
def get_scaled_point(point, ifcfile, is2d=False):
"""Returns a scaled 2d or 3d point tuple form a FreeCAD point"""
s = 0.001 / ifcopenshell.util.unit.calculate_unit_scale(ifcfile)
v = FreeCAD.Vector(point)
v.multiply(s)
v = tuple(v)
if is2d:
v = v[:2]
return v

View File

@@ -25,6 +25,8 @@
import FreeCAD
translate = FreeCAD.Qt.translate
# the property groups below should not be treated as psets
NON_PSETS = ["Base", "IFC", "", "Geometry", "Dimension", "Linear/radial dimension", "PhysicalProperties"]
class ifc_object:
"""Base class for all IFC-based objects"""
@@ -66,6 +68,8 @@ class ifc_object:
self.edit_attribute(obj, "Name", obj.Label)
elif prop == "Text":
self.edit_annotation(obj, "Text", "\n".join(obj.Text))
elif prop in ["Start", "End"]:
self.edit_annotation(obj, prop)
elif prop == "Placement":
if getattr(self, "virgin_placement", False):
self.virgin_placement = False
@@ -77,7 +81,7 @@ class ifc_object:
obj.ViewObject.signalChangeIcon()
elif obj.getGroupOfProperty(prop) == "Geometry":
self.edit_geometry(obj, prop)
elif obj.getGroupOfProperty(prop) not in ["Base", "IFC", "", "Geometry", "PhysicalProperties"]:
elif obj.getGroupOfProperty(prop) not in NON_PSETS:
# Treat all property groups outside the default ones as Psets
# print("DEBUG: editinog pset prop",prop)
self.edit_pset(obj, prop)
@@ -186,6 +190,23 @@ class ifc_object:
text = ifc_export.get_text(elt)
if text:
result = ifc_tools.set_attribute(ifcfile, text, "Literal", value)
elif attribute in ["Start", "End"]:
dim = ifc_export.get_dimension(elt)
if dim:
rep = dim[0]
for curve in rep.Items:
for sub in curve.Elements:
if sub.is_a("IfcIndexedPolyCurve"):
points = sub.Points
value = list(points.CoordList)
is2d = "2D" in points.is_a()
if attribute == "Start":
value[0] = ifc_export.get_scaled_point(obj.Start, ifcfile, is2d)
else:
value[-1] = ifc_export.get_scaled_point(obj.End, ifcfile, is2d)
result = ifc_tools.set_attribute(ifcfile, points, "CoordList", value)
else:
print("DEBUG: unknown dimension curve type:",sub)
def edit_geometry(self, obj, prop):
"""Edits a geometry property of an object"""

View File

@@ -259,6 +259,8 @@ def create_object(ifcentity, document, ifcfile, shapemode=0, objecttype=None):
if ifcentity.is_a("IfcAnnotation"):
if ifc_export.get_text(ifcentity):
objecttype = "text"
elif ifc_export.get_dimension(ifcentity):
objecttype = "dimension"
FreeCAD.Console.PrintLog(s)
obj = add_object(document, otype=objecttype)
add_properties(obj, ifcfile, ifcentity, shapemode=shapemode)
@@ -483,11 +485,21 @@ def add_object(document, otype=None, oname="IfcObject"):
'material',
'layer',
'text',
'dimension',
or anything else for a standard IFC object"""
if not document:
return None
if otype == "text":
if otype == "dimension":
obj = Draft.make_dimension(FreeCAD.Vector(), FreeCAD.Vector(1,0,0))
obj.Proxy = ifc_objects.ifc_object(otype)
obj.removeProperty("Diameter")
obj.removeProperty("Distance")
obj.setPropertyStatus("LinkedGeometry", "Hidden")
obj.setGroupOfProperty("Start", "Dimension")
obj.setGroupOfProperty("End", "Dimension")
obj.setGroupOfProperty("Direction", "Dimension")
elif otype == "text":
obj = Draft.make_text("")
obj.Proxy = ifc_objects.ifc_object(otype)
elif otype == "layer":
@@ -653,6 +665,24 @@ def add_properties(
obj.addProperty("App::PropertyStringList", "Text", "Base")
obj.Text = [text.Literal]
obj.Placement = ifc_export.get_placement(ifcentity.ObjectPlacement, ifcfile)
else:
dim = ifc_export.get_dimension(ifcentity)
if dim and len(dim) >= 3:
# the two props below are already taken care of, normally
if "Start" not in obj.PropertiesList:
obj.addProperty("App::PropertyVectorDistance", "Start", "Base")
if "End" not in obj.PropertiesList:
obj.addProperty("App::PropertyVectorDistance", "End", "Base")
if "Dimline" not in obj.PropertiesList:
obj.addProperty("App::PropertyVectorDistance", "Dimline", "Base")
obj.Start = dim[1]
obj.End = dim[2]
if len(dim) > 3:
obj.Dimline = dim[3]
else:
mid = obj.End.sub(obj.Start)
mid.multiply(0.5)
obj.Dimline = obj.Start.add(mid)
# link Label2 and Description
if "Description" in obj.PropertiesList and hasattr(obj, "setExpression"):
obj.setExpression("Label2", "Description")