diff --git a/src/Mod/BIM/nativeifc/ifc_export.py b/src/Mod/BIM/nativeifc/ifc_export.py index 569a4cc4f2..66b7a3fa8d 100644 --- a/src/Mod/BIM/nativeifc/ifc_export.py +++ b/src/Mod/BIM/nativeifc/ifc_export.py @@ -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 diff --git a/src/Mod/BIM/nativeifc/ifc_objects.py b/src/Mod/BIM/nativeifc/ifc_objects.py index d67610dd2e..71ef0de337 100644 --- a/src/Mod/BIM/nativeifc/ifc_objects.py +++ b/src/Mod/BIM/nativeifc/ifc_objects.py @@ -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""" diff --git a/src/Mod/BIM/nativeifc/ifc_tools.py b/src/Mod/BIM/nativeifc/ifc_tools.py index c17caf2901..05170f6ba8 100644 --- a/src/Mod/BIM/nativeifc/ifc_tools.py +++ b/src/Mod/BIM/nativeifc/ifc_tools.py @@ -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")