import json import FreeCAD as App import Part import Sketcher TOLERANCE = 1e-7 def line(start_x, start_y, end_x, end_y): return Part.LineSegment(App.Vector(start_x, start_y, 0), App.Vector(end_x, end_y, 0)) def point_value(point): return [float(point.x), float(point.y)] def line_value(geometry): return {"start": point_value(geometry.StartPoint), "end": point_value(geometry.EndPoint)} def sketch_state(sketch): return { "geometry": [line_value(geometry) for geometry in sketch.Geometry if hasattr(geometry, "StartPoint")], "construction": [bool(sketch.getConstruction(index)) for index in range(sketch.GeometryCount)], "constraintTypes": [str(constraint.Type) for constraint in sketch.Constraints], "degreesOfFreedom": int(sketch.DoF), "fullyConstrained": bool(sketch.FullyConstrained), } def run_case(case_id, operation): document = App.newDocument("EditorOracle_" + case_id.replace("-", "_")) sketch = document.addObject("Sketcher::SketchObject", "Sketch") sketch.MapMode = "Deactivated" try: details = operation(document, sketch) document.recompute() return {"id": case_id, "passed": True, **details, "final": sketch_state(sketch)} except Exception as error: return {"id": case_id, "passed": False, "errorType": type(error).__name__, "error": str(error)} finally: App.closeDocument(document.Name) def drag_case(document, sketch): sketch.addGeometry(line(0, 0, 5, 1), False) sketch.addConstraint(Sketcher.Constraint("Horizontal", 0)) sketch.solve() before = sketch_state(sketch) sketch.moveGeometry(0, 2, App.Vector(8, 2, 0), False) solve_status = sketch.solve() return {"before": before, "solveStatus": int(solve_status)} def split_case(document, sketch): sketch.addGeometry(line(0, 0, 10, 0), True) sketch.split(0, App.Vector(4, 0, 0)) return {} def extend_case(document, sketch): sketch.addGeometry(line(0, 0, 10, 0), False) sketch.extend(0, 5.0, 2) return {} def trim_case(document, sketch): sketch.addGeometry([line(0, 0, 10, 0), line(7, -2, 7, 2)], False) sketch.trim(0, App.Vector(9, 0, 0)) return {} def construction_case(document, sketch): sketch.addGeometry(line(0, 0, 1, 0), False) sketch.toggleConstruction(0) return {} def transaction_case(document, sketch): document.UndoMode = 1 sketch.addGeometry(line(0, 0, 5, 0), False) document.recompute() document.openTransaction("Move endpoint") sketch.moveGeometry(0, 2, App.Vector(8, 0, 0), False) document.commitTransaction() document.recompute() committed = point_value(sketch.Geometry[0].EndPoint) document.undo() document.recompute() undone = point_value(sketch.Geometry[0].EndPoint) document.redo() document.recompute() redone = point_value(sketch.Geometry[0].EndPoint) return {"committedEnd": committed, "undoneEnd": undone, "redoneEnd": redone} def auto_constraint_case(document, sketch): sketch.addGeometry([line(0, 0, 5, 0.0001), line(5.0001, 0, 5, 4)], False) sketch.addConstraint(Sketcher.Constraint("Coincident", 0, 2, 1, 1)) sketch.addConstraint(Sketcher.Constraint("Horizontal", 0)) solve_status = sketch.solve() return {"solveStatus": int(solve_status)} cases = [ run_case("drag-horizontal", drag_case), run_case("split-line", split_case), run_case("extend-line", extend_case), run_case("trim-at-intersection", trim_case), run_case("toggle-construction", construction_case), run_case("transaction-undo-redo", transaction_case), run_case("auto-constraint", auto_constraint_case), ] report = { "schemaVersion": 1, "baselineId": "freecad-1.1.1-sketcher-editor-oracle", "freecadVersion": ".".join(App.Version()[0:3]), "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", "tolerance": TOLERANCE, "status": "pass" if all(case["passed"] for case in cases) else "failed", "summary": {"cases": len(cases), "passed": sum(1 for case in cases if case["passed"])}, "cases": cases, } print("FREECAD_SKETCHER_EDITOR_ORACLE_RESULT=" + json.dumps(report, sort_keys=True))