BIM: NativeIFC 2D support - optimized export of FreeCAD dimensions

This commit is contained in:
Yorik van Havre
2024-09-27 14:08:26 +02:00
committed by Yorik van Havre
parent 43b2411996
commit c0d452f6c5
5 changed files with 91 additions and 40 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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:

View File

@@ -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: