import json import FreeCAD as App import Part import Sketcher from freecad_mutation_evidence import capture_property_mutation def version_text(): return ".".join(str(value) for value in App.Version()[:3]) def square_sketch(body, name, half_size, z=0.0): sketch = body.newObject("Sketcher::SketchObject", name) points = [(-half_size, -half_size), (half_size, -half_size), (half_size, half_size), (-half_size, half_size)] for index, start in enumerate(points): end = points[(index + 1) % len(points)] sketch.addGeometry(Part.LineSegment(App.Vector(start[0], start[1], 0), App.Vector(end[0], end[1], 0)), False) sketch.Placement.Base.z = z return sketch def shape_result(case_id, document, feature): document.recompute() shape = feature.Shape box = shape.BoundBox if not shape.isNull() else None return { "id": case_id, "passed": not shape.isNull() and shape.isValid(), "status": feature.getStatusString(), "solids": len(shape.Solids) if not shape.isNull() else 0, "faces": len(shape.Faces) if not shape.isNull() else 0, "volume": float(shape.Volume) if not shape.isNull() else 0.0, "bounds": None if box is None else { "min": [float(box.XMin), float(box.YMin), float(box.ZMin)], "max": [float(box.XMax), float(box.YMax), float(box.ZMax)], }, } def tapered_pad(): document = App.newDocument("TaperedPadOracle") body = document.addObject("PartDesign::Body", "Body") sketch = square_sketch(body, "Sketch", 2.0) pad = body.newObject("PartDesign::Pad", "Pad") pad.Profile = sketch pad.Type = "Length" pad.Length = 5.0 pad.TaperAngle = 5.0 mutation = capture_property_mutation(document, pad, "Length", 6.0) result = shape_result("pad-tapered", document, pad) result["mutation"] = mutation App.closeDocument(document.Name) return result def base_and_pocket_document(name, half_size=2.0): document = App.newDocument(name) body = document.addObject("PartDesign::Body", "Body") base = body.newObject("PartDesign::Feature", "Base") base.Shape = Part.makeBox(10, 10, 10, App.Vector(-5, -5, -5)) sketch = square_sketch(body, "Sketch", half_size, 5.0) pocket = body.newObject("PartDesign::Pocket", "Pocket") pocket.Profile = sketch if hasattr(pocket, "BaseFeature"): pocket.BaseFeature = base return document, body, base, sketch, pocket def tapered_pocket(): document, _, _, _, pocket = base_and_pocket_document("TaperedPocketOracle") pocket.Type = "Length" pocket.Length = 10.0 pocket.TaperAngle = 2.0 mutation = capture_property_mutation(document, pocket, "Length", 8.0) result = shape_result("pocket-tapered", document, pocket) result["mutation"] = mutation App.closeDocument(document.Name) return result def through_all_pocket(): document, _, _, _, pocket = base_and_pocket_document("ThroughAllPocketOracle", 1.0) pocket.Type = 1 result = shape_result("pocket-through-all", document, pocket) App.closeDocument(document.Name) return result def up_to_face_pocket(): document, _, base, _, pocket = base_and_pocket_document("UpToFacePocketOracle", 1.0) document.recompute() top_face = min(range(len(base.Shape.Faces)), key=lambda index: base.Shape.Faces[index].CenterOfMass.z) + 1 pocket.Type = 3 pocket.UpToFace = (base, ["Face{}".format(top_face)]) result = shape_result("pocket-up-to-face", document, pocket) result["targetFace"] = top_face App.closeDocument(document.Name) return result def midplane_pad(): document = App.newDocument("MidplanePadOracle") body = document.addObject("PartDesign::Body", "Body") sketch = square_sketch(body, "Sketch", 2.0) pad = body.newObject("PartDesign::Pad", "Pad") pad.Profile = sketch pad.Type = "Length" pad.Length = 6.0 pad.Midplane = True result = shape_result("pad-midplane", document, pad) App.closeDocument(document.Name) return result cases = [tapered_pad(), tapered_pocket(), through_all_pocket(), up_to_face_pocket(), midplane_pad()] version = App.Version() report = { "schemaVersion": 1, "baselineId": "freecad-1.1.1-partdesign-base-oracle", "freecadVersion": version_text(), "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d", "status": "pass" if all(case["passed"] for case in cases) else "failed", "tolerance": 1e-7, "cases": cases, "summary": {"cases": len(cases), "passed": sum(1 for case in cases if case["passed"])}, } print("FREECAD_PARTDESIGN_BASE_RESULT=" + json.dumps(report, sort_keys=True, separators=(",", ":")))