BIM: NativeIFC 2D support - axes
This commit is contained in:
committed by
Yorik van Havre
parent
a8b4fb485e
commit
1d6e60f558
@@ -179,13 +179,15 @@ def get_object_type(ifcentity, objecttype=None):
|
||||
objecttype = "dimension"
|
||||
elif get_text(ifcentity):
|
||||
objecttype = "text"
|
||||
elif ifcentity.is_a("IfcGridAxis"):
|
||||
objecttype = "axis"
|
||||
return objecttype
|
||||
|
||||
|
||||
def is_annotation(obj):
|
||||
"""Determines if the given FreeCAD object should be saved as an IfcAnnotation"""
|
||||
|
||||
if getattr(obj, "IfcClass", None) == "IfcAnnotation":
|
||||
if getattr(obj, "IfcClass", None) in ["IfcAnnotation", "IfcGridAxis"]:
|
||||
return True
|
||||
if getattr(obj, "IfcType", None) == "Annotation":
|
||||
return True
|
||||
@@ -270,6 +272,30 @@ def get_sectionplane(annotation):
|
||||
return None
|
||||
|
||||
|
||||
def get_axis(obj):
|
||||
"""Determines if a given IFC entity is an IfcGridAxis. Returns a tuple
|
||||
containing a Placement, a length value in millimeters, and a tag"""
|
||||
|
||||
if obj.is_a("IfcGridAxis"):
|
||||
tag = obj.AxisTag
|
||||
s = ifcopenshell.util.unit.calculate_unit_scale(obj.file) * 1000
|
||||
shape = importIFCHelper.get2DShape(obj.AxisCurve, s, notext=True)
|
||||
if shape:
|
||||
edge = shape[0].Edges[0] # we suppose here the axis shape is a single straight line
|
||||
if obj.SameSense:
|
||||
p0 = edge.Vertexes[0].Point
|
||||
p1 = edge.Vertexes[-1].Point
|
||||
else:
|
||||
p0 = edge.Vertexes[-1].Point
|
||||
p1 = edge.Vertexes[0].Point
|
||||
length = edge.Length
|
||||
placement = FreeCAD.Placement()
|
||||
placement.Base = p0
|
||||
placement.Rotation = FreeCAD.Rotation(FreeCAD.Vector(0,1,0), p1.sub(p0))
|
||||
return (placement, length, tag)
|
||||
return None
|
||||
|
||||
|
||||
def create_annotation(obj, ifcfile):
|
||||
"""Adds an IfcAnnotation from the given object to the given IFC file"""
|
||||
|
||||
|
||||
@@ -465,21 +465,39 @@ def set_representation(vobj, node):
|
||||
"""Sets the correct coin nodes for the given Part object"""
|
||||
|
||||
# node = [colors, verts, faces, edges, parts]
|
||||
if not vobj.RootNode:
|
||||
return
|
||||
if vobj.RootNode.getNumChildren() < 3:
|
||||
return
|
||||
coords = vobj.RootNode.getChild(1) # SoCoordinate3
|
||||
fset = vobj.RootNode.getChild(2).getChild(1).getChild(6) # SoBrepFaceSet
|
||||
eset = (
|
||||
vobj.RootNode.getChild(2).getChild(2).getChild(0).getChild(3)
|
||||
) # SoBrepEdgeSet
|
||||
switch = vobj.RootNode.getChild(2)
|
||||
num_modes = switch.getNumChildren()
|
||||
if num_modes < 3:
|
||||
return
|
||||
# the number of display modes under switch can vary.
|
||||
# the last 4 ones are the ones that are defined for
|
||||
# Part features
|
||||
faces = switch.getChild(num_modes-3)
|
||||
edges = switch.getChild(num_modes-2)
|
||||
fset = None
|
||||
if faces.getNumChildren() >= 7:
|
||||
fset = faces.getChild(6) # SoBrepFaceSet
|
||||
eset = None
|
||||
if edges.getNumChildren() >= 1:
|
||||
if edges.getChild(0).getNumChildren() >= 4:
|
||||
eset = edges.getChild(0).getChild(3) # SoBrepEdgeSet
|
||||
# reset faces and edges
|
||||
fset.coordIndex.deleteValues(0)
|
||||
eset.coordIndex.deleteValues(0)
|
||||
if fset:
|
||||
fset.coordIndex.deleteValues(0)
|
||||
if eset:
|
||||
eset.coordIndex.deleteValues(0)
|
||||
coords.point.deleteValues(0)
|
||||
if not node:
|
||||
return
|
||||
if node[1] and node[3]:
|
||||
if node[1] and node[3] and eset:
|
||||
coords.point.setValues(node[1])
|
||||
eset.coordIndex.setValues(node[3])
|
||||
if node[2] and node[4]:
|
||||
if node[2] and node[4] and fset:
|
||||
fset.coordIndex.setValues(node[2])
|
||||
fset.partIndex.setValues(node[4])
|
||||
|
||||
@@ -553,7 +571,9 @@ def delete_ghost(document):
|
||||
|
||||
|
||||
def get_annotation_shape(annotation, ifcfile, coin=False):
|
||||
"""Returns a shape or a coin node form an IFC annotation"""
|
||||
"""Returns a shape or a coin node form an IFC annotation.
|
||||
Returns [colors, verts, faces, edges], colors and faces
|
||||
being normally None for 2D shapes."""
|
||||
|
||||
import Part
|
||||
from importers import importIFCHelper
|
||||
@@ -562,14 +582,21 @@ def get_annotation_shape(annotation, ifcfile, coin=False):
|
||||
placement = None
|
||||
ifcscale = importIFCHelper.getScaling(ifcfile)
|
||||
shapes2d = []
|
||||
for rep in annotation.Representation.Representations:
|
||||
if rep.RepresentationIdentifier in ["Annotation", "FootPrint", "Axis"]:
|
||||
sh = importIFCHelper.get2DShape(rep, ifcscale, notext=True)
|
||||
if sh:
|
||||
shapes2d.extend(sh)
|
||||
if hasattr(annotation, "Representation"):
|
||||
for rep in annotation.Representation.Representations:
|
||||
if rep.RepresentationIdentifier in ["Annotation", "FootPrint", "Axis"]:
|
||||
sh = importIFCHelper.get2DShape(rep, ifcscale, notext=True)
|
||||
if sh:
|
||||
shapes2d.extend(sh)
|
||||
elif hasattr(annotation, "AxisCurve"):
|
||||
sh = importIFCHelper.get2DShape(annotation.AxisCurve, ifcscale, notext=True)
|
||||
shapes2d.extend(sh)
|
||||
if shapes2d:
|
||||
shape = Part.makeCompound(shapes2d)
|
||||
placement = importIFCHelper.getPlacement(annotation.ObjectPlacement, ifcscale)
|
||||
if hasattr(annotation, "ObjectPlacement"):
|
||||
placement = importIFCHelper.getPlacement(annotation.ObjectPlacement, ifcscale)
|
||||
else:
|
||||
placement = None
|
||||
if coin:
|
||||
iv = shape.writeInventor()
|
||||
iv = iv.replace("\n", "")
|
||||
|
||||
@@ -26,7 +26,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", "SectionPlane", "PhysicalProperties"]
|
||||
NON_PSETS = ["Base", "IFC", "", "Geometry", "Dimension", "Linear/radial dimension",
|
||||
"SectionPlane", "Axis", "PhysicalProperties"]
|
||||
|
||||
class ifc_object:
|
||||
"""Base class for all IFC-based objects"""
|
||||
|
||||
@@ -253,7 +253,7 @@ def create_object(ifcentity, document, ifcfile, shapemode=0, objecttype=None):
|
||||
if exobj:
|
||||
return exobj
|
||||
s = "IFC: Created #{}: {}, '{}'\n".format(
|
||||
ifcentity.id(), ifcentity.is_a(), ifcentity.Name
|
||||
ifcentity.id(), ifcentity.is_a(), getattr(ifcentity, "Name", "")
|
||||
)
|
||||
objecttype = ifc_export.get_object_type(ifcentity, objecttype)
|
||||
FreeCAD.Console.PrintLog(s)
|
||||
@@ -494,6 +494,7 @@ def add_object(document, otype=None, oname="IfcObject"):
|
||||
'text',
|
||||
'dimension',
|
||||
'sectionplane',
|
||||
'axis',
|
||||
or anything else for a standard IFC object"""
|
||||
|
||||
if not document:
|
||||
@@ -501,6 +502,15 @@ def add_object(document, otype=None, oname="IfcObject"):
|
||||
if otype == "sectionplane":
|
||||
obj = Arch.makeSectionPlane()
|
||||
obj.Proxy = ifc_objects.ifc_object(otype)
|
||||
elif otype == "axis":
|
||||
obj = Arch.makeAxis()
|
||||
obj.Proxy = ifc_objects.ifc_object(otype)
|
||||
obj.removeProperty("Angles")
|
||||
obj.removeProperty("Distances")
|
||||
obj.removeProperty("Labels")
|
||||
obj.removeProperty("Limit")
|
||||
if obj.ViewObject:
|
||||
obj.ViewObject.DisplayMode = "Flat Lines"
|
||||
elif otype == "dimension":
|
||||
obj = Draft.make_dimension(FreeCAD.Vector(), FreeCAD.Vector(1,0,0))
|
||||
obj.Proxy = ifc_objects.ifc_object(otype)
|
||||
@@ -666,7 +676,18 @@ def add_properties(
|
||||
if value is not None:
|
||||
setattr(obj, attr, str(value))
|
||||
# annotation properties
|
||||
if ifcentity.is_a("IfcAnnotation"):
|
||||
if ifcentity.is_a("IfcGridAxis"):
|
||||
axisdata = ifc_export.get_axis(ifcentity)
|
||||
if axisdata:
|
||||
if "Placement" not in obj.PropertiesList:
|
||||
obj.addProperty("App::PropertyPlacement", "Placement", "Base")
|
||||
if "CustomText" in obj.PropertiesList:
|
||||
obj.setPropertyStatus("CustomText", "Hidden")
|
||||
obj.setExpression("CustomText", "AxisTag")
|
||||
if "Length" not in obj.PropertiesList:
|
||||
obj.addProperty("App::PropertyLength","Length","Axis")
|
||||
obj.Length = axisdata[1]
|
||||
elif ifcentity.is_a("IfcAnnotation"):
|
||||
sectionplane = ifc_export.get_sectionplane(ifcentity)
|
||||
if sectionplane:
|
||||
if "Placement" not in obj.PropertiesList:
|
||||
@@ -1028,6 +1049,13 @@ def set_placement(obj):
|
||||
if obj.Class in ["IfcProject", "IfcProjectLibrary"]:
|
||||
return
|
||||
element = get_ifc_element(obj)
|
||||
if not hasattr(element, "ObjectPlacement"):
|
||||
# special case: this is a grid axis, it has no placement
|
||||
if element.is_a("IfcGridAxis"):
|
||||
return set_axis_points(obj, element, ifcfile)
|
||||
# other cases of objects without ObjectPlacement?
|
||||
print("DEBUG: object without ObjectPlacement",element)
|
||||
return False
|
||||
placement = FreeCAD.Placement(obj.Placement)
|
||||
placement.Base = FreeCAD.Vector(placement.Base).multiply(get_scale(ifcfile))
|
||||
new_matrix = get_ios_matrix(placement)
|
||||
@@ -1053,6 +1081,29 @@ def set_placement(obj):
|
||||
return False
|
||||
|
||||
|
||||
def set_axis_points(obj, element, ifcfile):
|
||||
"""Sets the points of an axis from placement and length"""
|
||||
|
||||
if element.AxisCurve.is_a("IfcPolyline"):
|
||||
p1 = obj.Placement.Base
|
||||
p2 = obj.Placement.multVec(FreeCAD.Vector(0, obj.Length.Value, 0))
|
||||
api_run(
|
||||
"attribute.edit_attributes",
|
||||
ifcfile,
|
||||
product=element.AxisCurve.Points[0],
|
||||
attributes={"Coordinates": tuple(p1)},
|
||||
)
|
||||
api_run(
|
||||
"attribute.edit_attributes",
|
||||
ifcfile,
|
||||
product=element.AxisCurve.Points[-1],
|
||||
attributes={"Coordinates": tuple(p2)},
|
||||
)
|
||||
return True
|
||||
print("DEBUG: unhandled axis type:",element.AxisCurve.is_a())
|
||||
return False
|
||||
|
||||
|
||||
def save_ifc(obj, filepath=None):
|
||||
"""Saves the linked IFC file of a project, but does not mark it as saved"""
|
||||
|
||||
@@ -1218,6 +1269,7 @@ def create_relationship(old_obj, obj, parent, element, ifcfile, mode=None):
|
||||
parent_element = get_ifc_element(parent)
|
||||
else:
|
||||
parent_element = parent
|
||||
uprel = None
|
||||
# case 4: anything inside group
|
||||
if parent_element.is_a("IfcGroup"):
|
||||
# special case: adding a section plane to a grouo turns it into a drawing
|
||||
@@ -1355,7 +1407,7 @@ def create_relationship(old_obj, obj, parent, element, ifcfile, mode=None):
|
||||
"void.add_opening", ifcfile, opening=element, element=parent_element
|
||||
)
|
||||
# case 3: element aggregated inside other element
|
||||
else:
|
||||
elif element.is_a("IfcProduct"):
|
||||
try:
|
||||
api_run("aggregate.unassign_object", ifcfile, products=[element])
|
||||
except:
|
||||
|
||||
Reference in New Issue
Block a user