import json import FreeCAD as App FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" def quantity_snapshot(value): return { "raw": str(value), "numeric": round(float(value.Value), 9), "unit": str(value.Unit), } def elements_snapshot(measure): return [ {"object": obj.Name, "typeId": obj.TypeId, "subElements": list(sub_elements)} for obj, sub_elements in measure.Elements ] def semantic_snapshot(measure): return { "value": quantity_snapshot(measure.Area), "elements": elements_snapshot(measure), "propertyStatus": [str(item) for item in measure.getPropertyStatus("Area")], "editorMode": [str(item) for item in measure.getEditorMode("Area")], "shape": {"applicable": hasattr(measure, "Shape")}, "objectState": [str(item) for item in measure.State], "statusString": str(measure.getStatusString()), "mustExecute": bool(measure.MustExecute), } def shape_snapshot(obj): shape = obj.Shape bounds = shape.BoundBox return { "name": obj.Name, "typeId": obj.TypeId, "shapeType": shape.ShapeType, "valid": bool(shape.isValid()), "solids": len(shape.Solids), "faces": len(shape.Faces), "edges": len(shape.Edges), "vertices": len(shape.Vertexes), "volume": round(float(shape.Volume), 9), "area": round(float(shape.Area), 9), "bounds": [ round(float(value), 9) for value in (bounds.XMin, bounds.YMin, bounds.ZMin, bounds.XMax, bounds.YMax, bounds.ZMax) ], } def object_snapshot(document): return [{"name": obj.Name, "typeId": obj.TypeId} for obj in document.Objects] def run(): document = App.newDocument("PropertyAreaMutation") try: box = document.addObject("Part::Box", "AreaBox") box.Length = 10 box.Width = 5 box.Height = 2 cylinder = document.addObject("Part::Cylinder", "AreaCylinder") cylinder.Radius = 3 cylinder.Height = 4 measure = document.addObject("Measure::MeasureArea", "AreaProbe") measure.Elements = [(box, ["Face1"])] initial_recompute = int(document.recompute()) before = semantic_snapshot(measure) sources_before = [shape_snapshot(source) for source in (box, cylinder)] objects_before = object_snapshot(document) measure.Elements = [(box, ["Face1", "Face2"]), (cylinder, ["Face1"])] touched_after_edit = { "value": quantity_snapshot(measure.Area), "elements": elements_snapshot(measure), "objectState": [str(item) for item in measure.State], "mustExecute": bool(measure.MustExecute), } edit_recompute = int(document.recompute()) edited = semantic_snapshot(measure) sources_edited = [shape_snapshot(source) for source in (box, cylinder)] measure.Elements = [(box, ["Face1"])] touched_after_restore = { "value": quantity_snapshot(measure.Area), "elements": elements_snapshot(measure), "objectState": [str(item) for item in measure.State], "mustExecute": bool(measure.MustExecute), } restore_recompute = int(document.recompute()) restored = semantic_snapshot(measure) sources_restored = [shape_snapshot(source) for source in (box, cylinder)] objects_restored = object_snapshot(document) return { "schemaVersion": 1, "status": "pass", "baselineId": "freecad-1.1.1-property-area-mutation", "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), "gitCommit": FREECAD_COMMIT, "object": {"name": measure.Name, "typeId": measure.TypeId}, "property": {"name": "Area", "typeId": measure.getTypeIdOfProperty("Area")}, "input": {"name": "Elements", "typeId": measure.getTypeIdOfProperty("Elements")}, "recompute": {"initial": initial_recompute, "edit": edit_recompute, "restore": restore_recompute}, "touchedAfterEdit": touched_after_edit, "touchedAfterRestore": touched_after_restore, "before": before, "edited": edited, "restored": restored, "sources": { "before": sources_before, "edited": sources_edited, "restored": sources_restored, "preserved": sources_before == sources_edited == sources_restored, }, "document": { "objectsBefore": objects_before, "objectsRestored": objects_restored, "objectsPreserved": objects_before == objects_restored, }, "classification": { "inputChanged": before["elements"] != edited["elements"], "derivedValueChanged": before["value"] != edited["value"], "inputRestored": before["elements"] == restored["elements"], "derivedValueRestored": before["value"] == restored["value"], "semanticStateRestored": before == restored, "sourceGeometryPreserved": sources_before == sources_edited == sources_restored, "geometry": "source-shapes-preserved-derived-measurement-has-no-shape", }, } finally: App.closeDocument(document.Name) print("FREECAD_PROPERTY_AREA_MUTATION_RESULT=" + json.dumps(run(), sort_keys=True))