feat: establish reproducible FreeCAD web compatibility baseline
This commit is contained in:
126
scripts/freecad-sketcher-editor-oracle.py
Normal file
126
scripts/freecad-sketcher-editor-oracle.py
Normal file
@@ -0,0 +1,126 @@
|
||||
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))
|
||||
Reference in New Issue
Block a user