diff --git a/src/Mod/BIM/importers/exportIFC.py b/src/Mod/BIM/importers/exportIFC.py index 813aa66a7a..8f2dfc1929 100644 --- a/src/Mod/BIM/importers/exportIFC.py +++ b/src/Mod/BIM/importers/exportIFC.py @@ -1676,13 +1676,31 @@ def buildAddress(obj,ifcfile): return addr -def createCurve(ifcfile,wire,scaling=1.0): +def createCurve(ifcfile, wire, scaling=1.0): + """creates an IfcIndexdPolyCurve from a wire + if possible, or defects to createCurveWithArcs""" + + if wire.ShapeType != "Wire": + return createCurveWithArcs(ifcfile, wire, scaling) + for e in wire.Edges: + if isinstance(e.Curve,Part.Circle): + return createCurveWithArcs(ifcfile, wire, scaling) + verts = [v.Point for v in wire.Vertexes] + if scaling != 1: + verts = [v.multiply(scaling) for v in verts] + verts = tuple([tuple(v) for v in verts]) + pts = ifcfile.createIfcCartesianPointList3D(verts) + idc = ifcfile.createIfcIndexedPolyCurve(pts, None, None) + return idc + + +def createCurveWithArcs(ifcfile,wire,scaling=1.0): "creates an IfcCompositeCurve from a shape" segments = [] pol = None last = None - if wire.ShapeType == "edge": + if wire.ShapeType == "Edge": edges = [wire] else: edges = Part.__sortEdges__(wire.Edges) @@ -2512,11 +2530,13 @@ def create_annotation(anno, ifcfile, context, history, preferences): if curves: reps.append(ifcfile.createIfcGeometricCurveSet(curves)) curves = [] + # leftover edges for e in sh.Edges: - if e.hashCode not in ehc: + if e.hashCode() not in ehc: curves.append(createCurve(ifcfile,e)) if curves: reps.append(ifcfile.createIfcGeometricCurveSet(curves)) + # Append text l = FreeCAD.Vector(vp.tbase).multiply(preferences['SCALE_FACTOR']) zdir = None xdir = None diff --git a/src/Mod/BIM/importers/importIFCHelper.py b/src/Mod/BIM/importers/importIFCHelper.py index ceb3cae386..deae2fec19 100644 --- a/src/Mod/BIM/importers/importIFCHelper.py +++ b/src/Mod/BIM/importers/importIFCHelper.py @@ -774,8 +774,9 @@ def getVector(entity,scaling=1000): return v -def get2DShape(representation,scaling=1000): - """Returns a shape from a 2D IfcShapeRepresentation""" +def get2DShape(representation,scaling=1000,notext=False): + """Returns a shape from a 2D IfcShapeRepresentation + if notext is True, no Draft text is created""" import Part import DraftVecUtils @@ -885,9 +886,9 @@ def get2DShape(representation,scaling=1000): [p1, p2, p3] = index2points(s) result.append(Part.Arc(p1, p2, p3)) else: - raise RuntimeError("Illegal IfcIndexedPolyCurve segment") + raise RuntimeError("Illegal IfcIndexedPolyCurve segment: "+s.is_a()) else: - print("getCurveSet: unhandled element: ", el) + print("importIFCHelper.getCurveSet: unhandled element: ", el) return result @@ -909,6 +910,8 @@ def get2DShape(representation,scaling=1000): else: result = preresult elif item.is_a("IfcTextLiteral"): + if notext: + continue pl = getPlacement(item.Placement, scaling) if pl: t = Draft.make_text(item.Literal.split(";"), pl) diff --git a/src/Mod/BIM/nativeifc/ifc_export.py b/src/Mod/BIM/nativeifc/ifc_export.py index 66b7a3fa8d..d957333204 100644 --- a/src/Mod/BIM/nativeifc/ifc_export.py +++ b/src/Mod/BIM/nativeifc/ifc_export.py @@ -139,15 +139,17 @@ def get_dimension(annotation): 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) + shape = importIFCHelper.get2DShape(rep, s, notext=True) 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) + res.append(shape[0].Vertexes[1].Point) return res + else: + print(annotation,"NOT A DIMENSION") return None diff --git a/src/Mod/BIM/nativeifc/ifc_generator.py b/src/Mod/BIM/nativeifc/ifc_generator.py index ab9069bfd6..9c9ea9289b 100644 --- a/src/Mod/BIM/nativeifc/ifc_generator.py +++ b/src/Mod/BIM/nativeifc/ifc_generator.py @@ -564,7 +564,7 @@ def get_annotation_shape(annotation, ifcfile, coin=False): shapes2d = [] for rep in annotation.Representation.Representations: if rep.RepresentationIdentifier in ["Annotation", "FootPrint", "Axis"]: - sh = importIFCHelper.get2DShape(rep, ifcscale) + sh = importIFCHelper.get2DShape(rep, ifcscale, notext=True) if sh: shapes2d.extend(sh) if shapes2d: diff --git a/src/Mod/BIM/nativeifc/ifc_tools.py b/src/Mod/BIM/nativeifc/ifc_tools.py index 05170f6ba8..436fda8d3e 100644 --- a/src/Mod/BIM/nativeifc/ifc_tools.py +++ b/src/Mod/BIM/nativeifc/ifc_tools.py @@ -257,10 +257,10 @@ def create_object(ifcentity, document, ifcfile, shapemode=0, objecttype=None): ) if not objecttype: if ifcentity.is_a("IfcAnnotation"): - if ifc_export.get_text(ifcentity): - objecttype = "text" - elif ifc_export.get_dimension(ifcentity): + if ifc_export.get_dimension(ifcentity): objecttype = "dimension" + elif ifc_export.get_text(ifcentity): + objecttype = "text" FreeCAD.Console.PrintLog(s) obj = add_object(document, otype=objecttype) add_properties(obj, ifcfile, ifcentity, shapemode=shapemode) @@ -656,33 +656,32 @@ def add_properties( setattr(obj, attr, str(value)) # annotation properties if ifcentity.is_a("IfcAnnotation"): - text = ifc_export.get_text(ifcentity) - if text: - # the two props below are already taken care of, normally - if "Placement" not in obj.PropertiesList: - obj.addProperty("App::PropertyPlacement", "Placement", "Base") - if "Text" not in obj.PropertiesList: - obj.addProperty("App::PropertyStringList", "Text", "Base") - obj.Text = [text.Literal] - obj.Placement = ifc_export.get_placement(ifcentity.ObjectPlacement, ifcfile) + dim = ifc_export.get_dimension(ifcentity) + if dim and len(dim) >= 3: + 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) 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) + text = ifc_export.get_text(ifcentity) + if text: + if "Placement" not in obj.PropertiesList: + obj.addProperty("App::PropertyPlacement", "Placement", "Base") + if "Text" not in obj.PropertiesList: + obj.addProperty("App::PropertyStringList", "Text", "Base") + obj.Text = [text.Literal] + obj.Placement = ifc_export.get_placement(ifcentity.ObjectPlacement, ifcfile) + # link Label2 and Description if "Description" in obj.PropertiesList and hasattr(obj, "setExpression"): obj.setExpression("Label2", "Description") @@ -1184,8 +1183,35 @@ def create_relationship(old_obj, obj, parent, element, ifcfile, mode=None): parent_element = get_ifc_element(parent) else: parent_element = parent + # case 4: anything inside group + if parent_element.is_a("IfcGroup"): + # IFC objects can be part of multiple groups but we do the FreeCAD way here + for assignment in getattr(element,"HasAssignments",[]): + if assignment.is_a("IfcRelAssignsToGroup"): + if element in assignment.RelatedObjects: + oldgroup = assignment.RelatingGr + try: + api_run( + "group.unassign_group", + ifcfile, + products=[element], + group=oldgroup + ) + except: + # older version of IfcOpenShell + api_run( + "group.unassign_group", + ifcfile, + product=element, + group=oldgroup + ) + try: + uprel = api_run("group.assign_group", ifcfile, products=[element], group=parent_element) + except: + # older version of IfcOpenShell + uprel = api_run("group.assign_group", ifcfile, product=element, group=parent_element) # case 1: element inside spatiual structure - if parent_element.is_a("IfcSpatialStructureElement") and element.is_a("IfcElement"): + elif parent_element.is_a("IfcSpatialStructureElement") and element.is_a("IfcElement"): # first remove the FreeCAD object from any parent if old_obj: for old_par in old_obj.InList: