feat: establish reproducible FreeCAD web compatibility baseline
This commit is contained in:
123
scripts/freecad-partdesign-base-oracle.py
Normal file
123
scripts/freecad-partdesign-base-oracle.py
Normal file
@@ -0,0 +1,123 @@
|
||||
import json
|
||||
|
||||
import FreeCAD as App
|
||||
import Part
|
||||
import Sketcher
|
||||
|
||||
|
||||
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
|
||||
result = shape_result("pad-tapered", document, pad)
|
||||
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
|
||||
result = shape_result("pocket-tapered", document, pocket)
|
||||
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=(",", ":")))
|
||||
Reference in New Issue
Block a user