| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | """This module contains IFC object definitions""" |
| |
|
| | import FreeCAD |
| | import FreeCADGui |
| |
|
| | translate = FreeCAD.Qt.translate |
| |
|
| |
|
| | |
| | NON_PSETS = [ |
| | "Base", |
| | "IFC", |
| | "", |
| | "Geometry", |
| | "Dimension", |
| | "Linear/radial dimension", |
| | "SectionPlane", |
| | "Axis", |
| | "PhysicalProperties", |
| | "BuildingPart", |
| | "IFC Attributes", |
| | ] |
| |
|
| |
|
| | class ifc_object: |
| | """Base class for all IFC-based objects""" |
| |
|
| | def __init__(self, otype=None): |
| | self.cached = True |
| | self.virgin_placement = True |
| | if otype: |
| | self.Type = otype[0].upper() + otype[1:] |
| | else: |
| | self.Type = "IfcObject" |
| |
|
| | def onBeforeChange(self, obj, prop): |
| | if prop == "Schema": |
| | self.old_schema = obj.Schema |
| | elif prop == "Placement": |
| | self.old_placement = obj.Placement |
| |
|
| | def onChanged(self, obj, prop): |
| | |
| | if prop == "IfcClass" and hasattr(obj, "Class") and obj.Class != obj.IfcClass: |
| | obj.Class = obj.IfcClass |
| | self.rebuild_classlist(obj, setprops=True) |
| | elif prop == "Class" and hasattr(obj, "IfcClass") and obj.Class != obj.IfcClass: |
| | obj.IfcClass = obj.Class |
| | self.rebuild_classlist(obj, setprops=True) |
| | elif prop == "Schema": |
| | self.edit_schema(obj, obj.Schema) |
| | elif prop == "Type": |
| | self.edit_type(obj) |
| | self.assign_classification(obj) |
| | elif prop == "Classification": |
| | self.edit_classification(obj) |
| | elif prop == "Group": |
| | self.edit_group(obj) |
| | elif hasattr(obj, prop) and obj.getGroupOfProperty(prop) == "IFC": |
| | if prop not in ["StepId"]: |
| | self.edit_attribute(obj, prop) |
| | elif prop == "Label": |
| | 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 in ["DisplayLength", "DisplayHeight", "Depth"]: |
| | self.edit_annotation(obj, prop) |
| | elif prop == "Placement": |
| | if getattr(self, "virgin_placement", False): |
| | self.virgin_placement = False |
| | elif obj.Placement != getattr(self, "old_placement", None): |
| | |
| | self.edit_placement(obj) |
| | elif prop == "Modified": |
| | if obj.ViewObject: |
| | obj.ViewObject.signalChangeIcon() |
| | elif hasattr(obj, prop) and obj.getGroupOfProperty(prop) == "Geometry": |
| | self.edit_geometry(obj, prop) |
| | elif hasattr(obj, prop) and obj.getGroupOfProperty(prop) == "Quantities": |
| | self.edit_quantity(obj, prop) |
| | elif hasattr(obj, prop) and obj.getGroupOfProperty(prop) not in NON_PSETS: |
| | |
| | |
| | self.edit_pset(obj, prop) |
| |
|
| | def onDocumentRestored(self, obj): |
| | self.rebuild_classlist(obj) |
| | if hasattr(obj, "IfcFilePath"): |
| | |
| | from PySide import QtCore |
| |
|
| | if obj.OutListRecursive: |
| | for child in obj.OutListRecursive: |
| | if getattr(child, "ShapeMode", None) == "Coin": |
| | child.Proxy.cached = True |
| | child.touch() |
| | else: |
| | obj.Proxy.cached = True |
| | QtCore.QTimer.singleShot(100, obj.touch) |
| | QtCore.QTimer.singleShot(100, obj.Document.recompute) |
| | QtCore.QTimer.singleShot(100, self.fit_all) |
| |
|
| | def assign_classification(self, obj): |
| | """ |
| | Assigns Classification to an IFC object in a case where |
| | the object references a Type that has a Classification property, |
| | so we move copy the Type's property to our actual object. |
| | """ |
| |
|
| | if not getattr(obj, "Type", None): |
| | return |
| |
|
| | type_obj = obj.Type |
| | if getattr(type_obj, "Classification", None): |
| | |
| | |
| | |
| | if getattr(obj, "Classification", None) is None: |
| | obj.addProperty("App::PropertyString", "Classification", "IFC") |
| | obj.Classification = type_obj.Classification |
| | obj.recompute() |
| | elif getattr(obj, "Classification", None): |
| | |
| | |
| | obj.Classification = "" |
| | obj.recompute() |
| |
|
| | def fit_all(self): |
| | """Fits the view""" |
| |
|
| | if FreeCAD.GuiUp: |
| | FreeCADGui.SendMsgToActiveView("ViewFit") |
| |
|
| | def rebuild_classlist(self, obj, setprops=False): |
| | """rebuilds the list of Class enum property according to current class""" |
| |
|
| | from . import ifc_tools |
| |
|
| | obj.Class = [obj.IfcClass] |
| | obj.Class = ifc_tools.get_ifc_classes(obj, obj.IfcClass) |
| | obj.Class = obj.IfcClass |
| | if setprops: |
| | ifc_tools.remove_unused_properties(obj) |
| | ifc_tools.add_properties(obj) |
| |
|
| | def __getstate__(self): |
| | return getattr(self, "Type", None) |
| |
|
| | def __setstate__(self, state): |
| | self.loads(state) |
| |
|
| | def dumps(self): |
| | return getattr(self, "Type", None) |
| |
|
| | def loads(self, state): |
| | if state: |
| | self.Type = state |
| |
|
| | def execute(self, obj): |
| | from . import ifc_generator |
| |
|
| | if obj.isDerivedFrom("Part::Feature"): |
| | cached = getattr(self, "cached", False) |
| | ifc_generator.generate_geometry(obj, cached=cached) |
| | self.cached = False |
| | self.rebuild_classlist(obj) |
| |
|
| | def addObject(self, obj, child): |
| | if child not in obj.Group: |
| | g = obj.Group |
| | g.append(child) |
| | obj.Group = g |
| |
|
| | def removeObject(self, obj, child): |
| | if child in obj.Group: |
| | g = obj.Group |
| | g.remove(child) |
| | obj.Group = g |
| |
|
| | def edit_attribute(self, obj, attribute, value=None): |
| | """Edits an attribute of an underlying IFC object""" |
| |
|
| | from . import ifc_tools |
| |
|
| | if not value: |
| | value = obj.getPropertyByName(attribute) |
| | ifcfile = ifc_tools.get_ifcfile(obj) |
| | elt = ifc_tools.get_ifc_element(obj, ifcfile) |
| | if elt: |
| | result = ifc_tools.set_attribute(ifcfile, elt, attribute, value) |
| | if result: |
| | if hasattr(result, "id") and (result.id() != obj.StepId): |
| | obj.StepId = result.id() |
| |
|
| | def edit_annotation(self, obj, attribute, value=None): |
| | """Edits an attribute of an underlying IFC annotation""" |
| |
|
| | from . import ifc_tools |
| | from . import ifc_export |
| |
|
| | if not value: |
| | if hasattr(obj, attribute): |
| | value = obj.getPropertyByName(attribute) |
| | ifcfile = ifc_tools.get_ifcfile(obj) |
| | elt = ifc_tools.get_ifc_element(obj, ifcfile) |
| | if elt: |
| | if attribute == "Text": |
| | text = ifc_export.get_text(elt) |
| | if text: |
| | 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: |
| | if not hasattr(curve, "Elements"): |
| | |
| | continue |
| | 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) |
| | ifc_tools.set_attribute(ifcfile, points, "CoordList", value) |
| | else: |
| | print("DEBUG: unknown dimension curve type:", sub) |
| | elif attribute in ["DisplayLength", "DisplayHeight", "Depth"]: |
| | l = w = h = 1000.0 |
| | if obj.ViewObject: |
| | if obj.ViewObject.DisplayLength.Value: |
| | l = ifc_export.get_scaled_value(obj.ViewObject.DisplayLength.Value, ifcfile) |
| | if obj.ViewObject.DisplayHeight.Value: |
| | w = ifc_export.get_scaled_value(obj.ViewObject.DisplayHeight.Value, ifcfile) |
| | if obj.Depth.Value: |
| | h = ifc_export.get_scaled_value(obj.Depth.Value, ifcfile) |
| | if elt.Representation.Representations: |
| | for rep in elt.Representation.Representations: |
| | for item in rep.Items: |
| | if item.is_a("IfcCsgSolid"): |
| | if item.TreeRootExpression.is_a("IfcBlock"): |
| | block = item.TreeRootExpression |
| | loc = block.Position.Location |
| | ifc_tools.set_attribute(ifcfile, block, "XLength", l) |
| | ifc_tools.set_attribute(ifcfile, block, "YLength", w) |
| | ifc_tools.set_attribute(ifcfile, block, "ZLength", h) |
| | ifc_tools.set_attribute( |
| | ifcfile, loc, "Coordinates", (-l / 2, -h / 2, -h) |
| | ) |
| |
|
| | def edit_geometry(self, obj, prop): |
| | """Edits a geometry property of an object""" |
| |
|
| | from . import ifc_geometry |
| | from . import ifc_tools |
| |
|
| | result = ifc_geometry.set_geom_property(obj, prop) |
| | if result: |
| | obj.touch() |
| |
|
| | def edit_schema(self, obj, schema): |
| | """Changes the schema of an IFC document""" |
| |
|
| | from . import ifc_tools |
| |
|
| | ifcfile = ifc_tools.get_ifcfile(obj) |
| | if not ifcfile: |
| | return |
| | if not getattr(self, "old_schema", None): |
| | return |
| | if schema != ifcfile.wrapped_data.schema_name(): |
| | |
| | if obj.ViewObject and not getattr(self, "silent", False): |
| | if not obj.ViewObject.Proxy.schema_warning(): |
| | return |
| | ifcfile, migration_table = ifc_tools.migrate_schema(ifcfile, schema) |
| | self.ifcfile = ifcfile |
| | for old_id, new_id in migration_table.items(): |
| | child = [o for o in obj.OutListRecursive if getattr(o, "StepId", None) == old_id] |
| | if len(child) == 1: |
| | child[0].StepId = new_id |
| |
|
| | def edit_placement(self, obj): |
| | """Syncs the internal IFC placement""" |
| |
|
| | from . import ifc_tools |
| |
|
| | ifc_tools.set_placement(obj) |
| |
|
| | def edit_pset(self, obj, prop): |
| | """Edits a Pset value""" |
| |
|
| | from . import ifc_psets |
| |
|
| | ifc_psets.edit_pset(obj, prop) |
| |
|
| | def edit_group(self, obj): |
| | """Edits the children list""" |
| |
|
| | from . import ifc_tools |
| | from . import ifc_layers |
| |
|
| | if obj.Class in [ |
| | "IfcPresentationLayerAssignment", |
| | "IfcPresentationLayerWithStyle", |
| | ]: |
| | ifcfile = ifc_tools.get_ifcfile(obj) |
| | if not ifcfile: |
| | return |
| | newlist = [] |
| | for child in obj.Group: |
| | if not getattr(child, "StepId", None) or ifc_tools.get_ifcfile(child) != ifcfile: |
| | print( |
| | "DEBUG: Not an IFC object. Removing", |
| | child.Label, |
| | "from layer", |
| | obj.Label, |
| | ) |
| | else: |
| | |
| | newlist.append(child) |
| | ifc_layers.add_to_layer(child, obj) |
| | if newlist != obj.Group: |
| | obj.Group = newlist |
| |
|
| | def edit_type(self, obj): |
| | """Edits the type of this object""" |
| |
|
| | from . import ifc_types |
| |
|
| | ifc_types.edit_type(obj) |
| |
|
| | def edit_quantity(self, obj, prop): |
| | """Edits the given quantity""" |
| | pass |
| |
|
| | def get_section_data(self, obj): |
| | """Returns two things: a list of objects and a cut plane""" |
| |
|
| | from . import ifc_tools |
| | import Part |
| |
|
| | if not obj.IfcClass == "IfcAnnotation": |
| | return [], None |
| | if obj.ObjectType != "DRAWING": |
| | return [], None |
| | objs = getattr(obj, "Objects", []) |
| | if not objs: |
| | |
| | objs = [] |
| | proj = ifc_tools.get_project(obj) |
| | if isinstance(proj, FreeCAD.DocumentObject): |
| | objs.append(proj) |
| | objs.extend(ifc_tools.get_freecad_children(proj)) |
| | if objs: |
| | s = [] |
| | for o in objs: |
| | |
| | if o.ShapeMode != "Shape": |
| | s.append(o) |
| | if s: |
| | FreeCAD.Console.PrintLog("DEBUG: Generating shapes. This might take some time...\n") |
| | for o in s: |
| | o.ShapeMode = "Shape" |
| | o.recompute() |
| | l = 1 |
| | h = 1 |
| | if obj.ViewObject: |
| | if hasattr(obj.ViewObject, "DisplayLength"): |
| | l = obj.ViewObject.DisplayLength.Value |
| | h = obj.ViewObject.DisplayHeight.Value |
| | plane = Part.makePlane(l, h, FreeCAD.Vector(l / 2, -h / 2, 0), FreeCAD.Vector(0, 0, 1)) |
| | plane.Placement = obj.Placement |
| | return objs, plane |
| | else: |
| | print("DEBUG: Section plane returned no objects") |
| | return [], None |
| |
|
| | def edit_classification(self, obj): |
| | """Edits the classification of this object""" |
| |
|
| | from . import ifc_classification |
| |
|
| | ifc_classification.edit_classification(obj) |
| |
|
| |
|
| | class document_object: |
| | """Holder for the document's IFC objects""" |
| |
|
| | def __init__(self): |
| | pass |
| |
|