import json import os import sys import FreeCAD as App import FreeCADGui as Gui import Part import Sketcher path = os.environ.get("FREECAD_FCSTD_PATH", "") object_name = os.environ.get("FREECAD_FCSTD_OBJECT", "Box") if not path: raise RuntimeError("FREECAD_FCSTD_PATH must point to an FCStd file.") if os.environ.get("FREECAD_FCSTD_CREATE") == "1": generated = App.newDocument("GuiOracleGenerator") generated_object = generated.addObject(os.environ.get("FREECAD_FCSTD_CREATE_TYPEID", "Part::Feature"), object_name) for property_name, property_value in json.loads(os.environ.get("FREECAD_FCSTD_CREATE_PROPERTIES", "{}")).items(): setattr(generated_object, property_name, property_value) generated_brep_path = os.environ.get("FREECAD_BREP_PATH", "") if generated_brep_path: generated_shape = Part.Shape() generated_shape.read(generated_brep_path) generated_object.Shape = generated_shape generated_view = Gui.getDocument(generated.Name).getObject(object_name) generated_view.Visibility = False generated_view.Transparency = 35 generated_view.LineColor = (0x11 / 255.0, 0x22 / 255.0, 0x33 / 255.0) generated_view.PointColor = (0x44 / 255.0, 0x55 / 255.0, 0x66 / 255.0) generated_view.Deviation = 0.2 generated.recompute() generated.saveAs(path) App.closeDocument(generated.Name) if not os.path.isfile(path): raise RuntimeError("FREECAD_FCSTD_PATH does not exist.") document = App.openDocument(path) obj = document.getObject(object_name) if obj is None: raise RuntimeError(f"FCStd object does not exist: {object_name}") if os.environ.get("FREECAD_FCSTD_RECOMPUTE") == "1": document.recompute() view = Gui.getDocument(document.Name).getObject(object_name) if view is None: raise RuntimeError(f"FCStd ViewObject does not exist: {object_name}") resave_path = os.environ.get("FREECAD_FCSTD_RESAVE_PATH", "") if resave_path: document.saveAs(resave_path) shape_result = { "shapeNull": None, "shapeValid": None, "solidCount": None, "faceCount": None, "volume": None, "boundingBox": None, "shapeError": None, } if hasattr(obj, "Shape"): try: shape_result.update({ "shapeNull": bool(obj.Shape.isNull()), "shapeValid": bool(obj.Shape.isValid()) if not obj.Shape.isNull() else None, "solidCount": len(obj.Shape.Solids), "faceCount": len(obj.Shape.Faces), "volume": float(obj.Shape.Volume), "boundingBox": { "min": [float(obj.Shape.BoundBox.XMin), float(obj.Shape.BoundBox.YMin), float(obj.Shape.BoundBox.ZMin)], "max": [float(obj.Shape.BoundBox.XMax), float(obj.Shape.BoundBox.YMax), float(obj.Shape.BoundBox.ZMax)], }, }) except Exception as error: shape_result["shapeError"] = str(error) direct_brep_result = None direct_brep_path = os.environ.get("FREECAD_BREP_PATH", "") if direct_brep_path: direct_brep_result = {"valid": None, "solidCount": None, "faceCount": None, "volume": None, "error": None} try: direct_shape = Part.Shape() direct_shape.read(direct_brep_path) direct_brep_result.update({ "valid": bool(direct_shape.isValid()), "solidCount": len(direct_shape.Solids), "faceCount": len(direct_shape.Faces), "volume": float(direct_shape.Volume), }) except Exception as error: direct_brep_result["error"] = str(error) property_result = {} for property_name in filter(None, os.environ.get("FREECAD_FCSTD_PROPERTIES", "").split(",")): try: property_value = getattr(obj, property_name) if hasattr(property_value, "Value"): property_result[property_name] = float(property_value.Value) elif hasattr(property_value, "Name"): property_result[property_name] = property_value.Name else: property_result[property_name] = property_value except Exception as error: property_result[property_name] = {"error": str(error)} sketch_result = { "geometryCount": None, "constraintCount": None, "constructionGeometry": None, "constraintNames": None, "constraintTypes": None, "externalGeometryCount": None, "externalGeoCount": None, "externalTypes": None, "externalLinks": None, "externalStates": None, "mapMode": None, "attachmentSupport": None, "attachmentOffset": None, } if hasattr(obj, "GeometryCount") and hasattr(obj, "ConstraintCount"): try: sketch_result.update({ "geometryCount": int(obj.GeometryCount), "constraintCount": int(obj.ConstraintCount), "constructionGeometry": [index for index in range(int(obj.GeometryCount)) if obj.getConstruction(index)], "constraintNames": [str(constraint.Name) for constraint in obj.Constraints], "constraintTypes": [str(constraint.Type) for constraint in obj.Constraints], }) except Exception as error: sketch_result["error"] = str(error) if hasattr(obj, "ExternalGeometry") and hasattr(obj, "ExternalGeo"): try: external_links = [] for linked_object, sub_elements in obj.ExternalGeometry: external_links.append({ "objectName": str(linked_object.Name), "subElements": [str(sub_element) for sub_element in sub_elements], }) sketch_result.update({ "externalGeometryCount": len(obj.ExternalGeometry), "externalGeoCount": len(obj.ExternalGeo), "externalTypes": [int(value) for value in obj.ExternalTypes], "externalLinks": external_links, "externalStates": [ { "ref": str(facade.Ref), "id": int(facade.Id), "geometryType": type(geometry).__name__, "flags": sum( (1 << index) if facade.testFlag(flag) else 0 for index, flag in enumerate(("Defining", "Frozen", "Detached", "Missing", "Sync")) ), } for geometry in obj.ExternalGeo for facade in (Sketcher.ExternalGeometryFacade(geometry),) if facade.Ref ], }) except Exception as error: sketch_result["externalError"] = str(error) if hasattr(obj, "MapMode") and hasattr(obj, "AttachmentSupport") and hasattr(obj, "AttachmentOffset"): try: attachment_links = [] for linked_object, sub_elements in obj.AttachmentSupport: attachment_links.append({ "objectName": str(linked_object.Name), "subElements": [str(sub_element) for sub_element in sub_elements], }) offset = obj.AttachmentOffset sketch_result.update({ "mapMode": str(obj.MapMode), "attachmentSupport": attachment_links, "attachmentOffset": { "position": [float(offset.Base.x), float(offset.Base.y), float(offset.Base.z)], "axis": [float(offset.Rotation.Axis.x), float(offset.Rotation.Axis.y), float(offset.Rotation.Axis.z)], "angle": float(offset.Rotation.Angle), }, }) except Exception as error: sketch_result["attachmentError"] = str(error) result = { "schemaVersion": 1, "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), "guiUp": bool(getattr(App, "GuiUp", False)), "objectName": object_name, "visibility": bool(view.Visibility), "transparency": int(view.Transparency), "lineColor": [float(value) for value in view.LineColor], "pointColor": [float(value) for value in view.PointColor], "shapeColor": [float(value) for value in view.ShapeColor], "deviation": float(view.Deviation), "directBrep": direct_brep_result, "properties": property_result, **sketch_result, **shape_result, } App.closeDocument(document.Name) print("FREECAD_FCSTD_GUI_RESULT=" + json.dumps(result, sort_keys=True, separators=(",", ":"))) sys.stdout.flush() sys.exit(0)