FreeCAD / src /Mod /BIM /nativeifc /ifc_geometry.py
AbdulElahGwaith's picture
Upload folder using huggingface_hub
985c397 verified
# SPDX-License-Identifier: LGPL-2.1-or-later
# ***************************************************************************
# * *
# * Copyright (c) 2023 Yorik van Havre <yorik@uncreated.net> *
# * *
# * This file is part of FreeCAD. *
# * *
# * FreeCAD is free software: you can redistribute it and/or modify it *
# * under the terms of the GNU Lesser General Public License as *
# * published by the Free Software Foundation, either version 2.1 of the *
# * License, or (at your option) any later version. *
# * *
# * FreeCAD is distributed in the hope that it will be useful, but *
# * WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
# * Lesser General Public License for more details. *
# * *
# * You should have received a copy of the GNU Lesser General Public *
# * License along with FreeCAD. If not, see *
# * <https://www.gnu.org/licenses/>. *
# * *
# ***************************************************************************
"""This module contains geometry editing and geometry properties-related tools"""
import ifcopenshell
import ifcopenshell.util.unit
import FreeCAD
from . import ifc_tools
def add_geom_properties(obj):
"""Adds geometry properties to a FreeCAD object"""
element = ifc_tools.get_ifc_element(obj)
if not ifc_tools.has_representation(element):
return
ifcfile = ifc_tools.get_ifcfile(obj)
scaling = ifcopenshell.util.unit.calculate_unit_scale(ifcfile)
scaling = scaling * 1000 # given scale is for m, we work in mm
for rep in element.Representation.Representations:
if rep.RepresentationIdentifier == "Body":
if len(rep.Items) == 1:
# Extrusions
if rep.Items[0].is_a("IfcExtrudedAreaSolid"):
ext = rep.Items[0]
if "ExtrusionDepth" not in obj.PropertiesList:
obj.addProperty(
"App::PropertyLength", "ExtrusionDepth", "Geometry", locked=True
)
obj.ExtrusionDepth = ext.Depth * scaling
if "ExtrusionDirection" not in obj.PropertiesList:
obj.addProperty(
"App::PropertyVector", "ExtrusionDirection", "Geometry", locked=True
)
obj.ExtrusionDirection = FreeCAD.Vector(ext.ExtrudedDirection.DirectionRatios)
# Extrusion of a rectangle
if ext.SweptArea.is_a("IfcRectangleProfileDef"):
if "RectangleLength" not in obj.PropertiesList:
obj.addProperty(
"App::PropertyLength", "RectangleLength", "Geometry", locked=True
)
obj.RectangleLength = ext.SweptArea.XDim * scaling
if "RectangleWidth" not in obj.PropertiesList:
obj.addProperty(
"App::PropertyLength", "RectangleWidth", "Geometry", locked=True
)
obj.RectangleWidth = ext.SweptArea.YDim * scaling
# Extrusion of a polyline
elif ext.SweptArea.is_a("IfcArbitraryClosedProfileDef"):
if ext.SweptArea.OuterCurve.is_a("IfcPolyline"):
if "PolylinePoints" not in obj.PropertiesList:
obj.addProperty(
"App::PropertyVectorList",
"PolylinePoints",
"Geometry",
locked=True,
)
points = [p.Coordinates for p in ext.SweptArea.OuterCurve.Points]
points = [p + (0,) for p in points if len(p) < 3]
points = [FreeCAD.Vector(p).multiply(scaling) for p in points]
obj.PolylinePoints = points
# I profile
elif ext.SweptArea.is_a("IfcIShapeProfileDef"):
for p in [
"FilletRadius",
"FlangeEdgeRadius",
"FlangeSlope",
"FlangeThickness",
"OverallDepth",
"OverallWidth",
"WebThickness",
]:
if hasattr(ext.SweptArea, p):
obj.addProperty("App::PropertyLength", p, "Geometry", locked=True)
value = getattr(ext.SweptArea, p)
if not value:
value = 0
value = value * scaling
setattr(obj, p, value)
obj.addProperty(
"App::PropertyString", "ProfileName", "Geometry", locked=True
)
obj.ProfileName = ext.SweptArea.ProfileName
# below is disabled for now... Don't know if it's useful to expose to the user
elif False: # rep.RepresentationIdentifier == "Axis":
# Wall axis consisting on a single line
if len(rep.Items) == 1:
if rep.Items[0].is_a("IfcCompositeCurve"):
if len(rep.Items[0].Segments) == 1:
if rep.Items[0].Segments[0].is_a("IfcCompositeCurveSegment"):
if rep.Items[0].Segments[0].ParentCurve.is_a("IfcPolyline"):
pol = rep.Items[0].Segments[0].ParentCurve
if len(pol.Points) == 2:
if "AxisStart" not in obj.PropertiesList:
obj.addProperty(
"App::PropertyPosition",
"AxisStart",
"Geometry",
locked=True,
)
obj.AxisStart = FreeCAD.Vector(
pol.Points[0].Coordinates
).multiply(scaling)
if "AxisEnd" not in obj.PropertiesList:
obj.addProperty(
"App::PropertyPosition",
"AxisEnd",
"Geometry",
locked=True,
)
obj.AxisEnd = FreeCAD.Vector(
pol.Points[1].Coordinates
).multiply(scaling)
def set_attribute(ifcfile, element, prop, value):
"""Sets an attribute. Returns True if the attribute was changed"""
if value != getattr(element, prop):
ifc_tools.api_run(
"attribute.edit_attributes",
ifcfile,
product=element,
attributes={prop: value},
)
return True
return False
def set_geom_property(obj, prop):
"""Updates the internal IFC file with the given value"""
# TODO verify if values are different than the stored value before changing!
element = ifc_tools.get_ifc_element(obj)
if not ifc_tools.has_representation(element):
return False
ifcfile = ifc_tools.get_ifcfile(obj)
scaling = ifcopenshell.util.unit.calculate_unit_scale(ifcfile)
scaling = 0.001 / scaling
changed = False
if prop == "ExtrusionDepth":
for rep in element.Representation.Representations:
if rep.RepresentationIdentifier == "Body":
if len(rep.Items) == 1:
if rep.Items[0].is_a("IfcExtrudedAreaSolid"):
elem = rep.Items[0]
value = getattr(obj, prop).Value * scaling
changed = set_attribute(ifcfile, elem, "Depth", value)
elif prop == "ExtrusionDirection":
for rep in element.Representation.Representations:
if rep.RepresentationIdentifier == "Body":
if len(rep.Items) == 1:
if rep.Items[0].is_a("IfcExtrudedAreaSolid"):
elem = rep.Items[0].ExtrudedDirection
value = tuple(getattr(obj, prop))
changed = set_attribute(ifcfile, elem, "DirectionRatios", value)
elif prop == "RectangleLength":
for rep in element.Representation.Representations:
if rep.RepresentationIdentifier == "Body":
if len(rep.Items) == 1:
if rep.Items[0].is_a("IfcExtrudedAreaSolid"):
elem = rep.Items[0].SweptArea
if elem.is_a("IfcRectangleProfileDef"):
value = getattr(obj, prop).Value * scaling
changed = set_attribute(ifcfile, elem, "XDim", value)
elif prop == "RectangleWidth":
for rep in element.Representation.Representations:
if rep.RepresentationIdentifier == "Body":
if len(rep.Items) == 1:
if rep.Items[0].is_a("IfcExtrudedAreaSolid"):
elem = rep.Items[0].SweptArea
if elem.is_a("IfcRectangleProfileDef"):
value = getattr(obj, prop).Value * scaling
changed = set_attribute(ifcfile, elem, "YDim", value)
elif prop == "PolylinePoints":
# TODO check values against existing
for rep in element.Representation.Representations:
if rep.RepresentationIdentifier == "Body":
if len(rep.Items) == 1:
if rep.Items[0].is_a("IfcExtrudedAreaSolid"):
if rep.Items[0].SweptArea.is_a("IfcArbitraryClosedProfileDef"):
if rep.Items[0].SweptArea.OuterCurve.is_a("IfcPolyline"):
elem = rep.Items[0].SweptArea.OuterCurve
elem_points = elem.Points
psize = elem_points[0].Dim
points = getattr(obj, prop)
if len(points) > len(elem_points):
for i in range(len(points) - len(elem_points)):
p = ifc_tools.api_run(
"root.create_entity",
ifcfile,
ifc_class="IfcCartesianPoint",
)
elem_points.append(p)
elem.Points = elem_points
elif len(points) < len(elem_points):
rest = []
for i in range(len(elem_points) - len(points)):
rest.append(elem_points.pop())
elem.Points = elem_points
for r in rest:
ifc_tools.api_run("root.remove_product", ifcfile, product=r)
if len(points) == len(elem_points):
for i in range(len(points)):
v = FreeCAD.Vector(points[i]).multiply(scaling)
coord = tuple(v)[:psize]
ifc_tools.api_run(
"attribute.edit_attributes",
ifcfile,
product=elem_points[i],
attributes={"Coordinates": coord},
)
changed = True
elif prop in [
"FilletRadius",
"FlangeEdgeRadius",
"FlangeSlope",
"FlangeThickness",
"OverallDepth",
"OverallWidth",
"WebThickness",
]:
for rep in element.Representation.Representations:
if rep.RepresentationIdentifier == "Body":
if len(rep.Items) == 1:
if rep.Items[0].SweptArea.is_a("IfcIShapeProfileDef"):
elem = rep.Items[0].SweptArea
value = getattr(obj, prop).Value * scaling
if value == 0 and getattr(elem, prop) is None:
value = None
changed = set_attribute(ifcfile, elem, prop, value)
elif prop in ["ProfileName"]:
for rep in element.Representation.Representations:
if rep.RepresentationIdentifier == "Body":
if len(rep.Items) == 1:
if rep.Items[0].SweptArea.is_a("IfcIShapeProfileDef"):
elem = rep.Items[0].SweptArea
value = obj.ProfileName
changed = set_attribute(ifcfile, elem, prop, value)
if changed:
FreeCAD.Console.PrintLog(
"DEBUG: Changing prop"
+ obj.Label
+ ":"
+ str(prop)
+ "to"
+ str(getattr(obj, prop))
+ "\n"
)
return changed