Build and verify the candidate-only FreeCAD naming bridge and OCCT worker path, including three-stage StringHasher restoration. Add Datum, ShapeBinder, attachment-mode, and PartDesign structure oracles plus offline SDK build plans and CI boundary checks.
183 lines
6.5 KiB
Python
183 lines
6.5 KiB
Python
import json
|
|
import os
|
|
import tempfile
|
|
|
|
import FreeCAD as App
|
|
|
|
|
|
def version_text():
|
|
return ".".join(str(value) for value in App.Version()[:3])
|
|
|
|
|
|
def placement_json(placement):
|
|
axis = placement.Rotation.Axis
|
|
base = placement.Base
|
|
return {
|
|
"position": [float(base.x), float(base.y), float(base.z)],
|
|
"axis": [float(axis.x), float(axis.y), float(axis.z)],
|
|
"angleDegrees": float(placement.Rotation.Angle * 180.0 / 3.141592653589793),
|
|
}
|
|
|
|
|
|
def support_json(value):
|
|
result = []
|
|
for obj, sub_elements in value:
|
|
subs = [sub_elements] if isinstance(sub_elements, str) else list(sub_elements)
|
|
result.append({
|
|
"document": obj.Document.Name,
|
|
"object": obj.Name,
|
|
"subElements": [str(sub) for sub in subs if str(sub)],
|
|
})
|
|
return result
|
|
|
|
|
|
def engine_json(obj):
|
|
attacher = obj.Attacher
|
|
implemented = list(attacher.ImplementedModes)
|
|
return {
|
|
"typeId": obj.TypeId,
|
|
"attacherType": attacher.AttacherType,
|
|
"completeModeList": list(attacher.CompleteModeList),
|
|
"implementedModes": implemented,
|
|
"modeInfo": {
|
|
mode: {
|
|
"modeIndex": int(attacher.getModeInfo(mode)["ModeIndex"]),
|
|
"referenceCombinations": attacher.getModeInfo(mode)["ReferenceCombinations"],
|
|
}
|
|
for mode in implemented
|
|
},
|
|
}
|
|
|
|
|
|
def object_state(obj):
|
|
suggestion = obj.Attacher.suggestModes()
|
|
return {
|
|
"typeId": obj.TypeId,
|
|
"mapMode": str(obj.MapMode),
|
|
"support": support_json(obj.AttachmentSupport),
|
|
"placement": placement_json(obj.Placement),
|
|
"state": [str(value) for value in obj.State],
|
|
"status": str(obj.getStatusString()),
|
|
"positionBySupport": bool(obj.positionBySupport()),
|
|
"suggestion": {
|
|
"message": suggestion["message"],
|
|
"bestFitMode": suggestion["bestFitMode"],
|
|
"allApplicableModes": suggestion["allApplicableModes"],
|
|
"referenceTypes": suggestion["references_Types"],
|
|
},
|
|
}
|
|
|
|
|
|
document = App.newDocument("AttachmentModeOracle")
|
|
source_body = document.addObject("PartDesign::Body", "SourceBody")
|
|
source_box = source_body.newObject("PartDesign::AdditiveBox", "SourceBox")
|
|
source_box.Length = 4
|
|
source_box.Width = 5
|
|
source_box.Height = 6
|
|
document.recompute()
|
|
|
|
plane_body = document.addObject("PartDesign::Body", "PlaneBody")
|
|
datum_plane = plane_body.newObject("PartDesign::Plane", "DatumPlane")
|
|
datum_plane.AttachmentSupport = [(source_box, "Face1")]
|
|
datum_plane.MapMode = "FlatFace"
|
|
|
|
line_body = document.addObject("PartDesign::Body", "LineBody")
|
|
datum_line = line_body.newObject("PartDesign::Line", "DatumLine")
|
|
datum_line.AttachmentSupport = [(source_box, ("Vertex1", "Vertex2"))]
|
|
datum_line.MapMode = "TwoPointLine"
|
|
|
|
point_body = document.addObject("PartDesign::Body", "PointBody")
|
|
datum_point = point_body.newObject("PartDesign::Point", "DatumPoint")
|
|
datum_point.AttachmentSupport = [(source_box, "Vertex1")]
|
|
datum_point.MapMode = "Vertex"
|
|
|
|
sketch_body = document.addObject("PartDesign::Body", "SketchBody")
|
|
sketch = sketch_body.newObject("Sketcher::SketchObject", "Sketch")
|
|
sketch.AttachmentSupport = [(source_box, "Face1")]
|
|
sketch.MapMode = "FlatFace"
|
|
|
|
invalid_plane_body = document.addObject("PartDesign::Body", "InvalidPlaneBody")
|
|
invalid_plane = invalid_plane_body.newObject("PartDesign::Plane", "InvalidPlane")
|
|
invalid_plane.AttachmentSupport = [(source_box, "Vertex1")]
|
|
invalid_plane.MapMode = "Vertex"
|
|
|
|
invalid_line_body = document.addObject("PartDesign::Body", "InvalidLineBody")
|
|
invalid_line = invalid_line_body.newObject("PartDesign::Line", "InvalidLine")
|
|
invalid_line.AttachmentSupport = [(source_box, "Face1")]
|
|
invalid_line.MapMode = "FlatFace"
|
|
|
|
invalid_point_body = document.addObject("PartDesign::Body", "InvalidPointBody")
|
|
invalid_point = invalid_point_body.newObject("PartDesign::Point", "InvalidPoint")
|
|
invalid_point.AttachmentSupport = [(source_box, "Face1")]
|
|
invalid_point.MapMode = "FlatFace"
|
|
|
|
document.recompute()
|
|
engine_objects = {
|
|
"plane": datum_plane,
|
|
"line": datum_line,
|
|
"point": datum_point,
|
|
"sketch": sketch,
|
|
}
|
|
engines = {name: engine_json(obj) for name, obj in engine_objects.items()}
|
|
success_initial = {name: object_state(obj) for name, obj in engine_objects.items()}
|
|
failures = {
|
|
obj.Name: {
|
|
"typeId": obj.TypeId,
|
|
"mapMode": str(obj.MapMode),
|
|
"support": support_json(obj.AttachmentSupport),
|
|
"state": [str(value) for value in obj.State],
|
|
"status": str(obj.getStatusString()),
|
|
}
|
|
for obj in [invalid_plane, invalid_line, invalid_point]
|
|
}
|
|
|
|
source_box.Height = 9
|
|
document.recompute()
|
|
success_edited = {name: object_state(obj) for name, obj in engine_objects.items()}
|
|
|
|
with tempfile.TemporaryDirectory(prefix="freecad-attachment-mode-") as temp_dir:
|
|
path = os.path.join(temp_dir, "AttachmentModeOracle.FCStd")
|
|
document.saveAs(path)
|
|
App.closeDocument(document.Name)
|
|
reopened = App.openDocument(path)
|
|
reopened.recompute()
|
|
roundtrip = {
|
|
name: object_state(reopened.getObject(object_name))
|
|
for name, object_name in {
|
|
"plane": "DatumPlane",
|
|
"line": "DatumLine",
|
|
"point": "DatumPoint",
|
|
"sketch": "Sketch",
|
|
}.items()
|
|
}
|
|
roundtrip_failures = {
|
|
object_name: {
|
|
"mapMode": str(reopened.getObject(object_name).MapMode),
|
|
"state": [str(value) for value in reopened.getObject(object_name).State],
|
|
"status": str(reopened.getObject(object_name).getStatusString()),
|
|
}
|
|
for object_name in ["InvalidPlane", "InvalidLine", "InvalidPoint"]
|
|
}
|
|
App.closeDocument(reopened.Name)
|
|
|
|
all_modes = engines["plane"]["completeModeList"]
|
|
implemented_union = sorted({mode for engine in engines.values() for mode in engine["implementedModes"]})
|
|
report = {
|
|
"schemaVersion": 1,
|
|
"baselineId": "freecad-1.1.1-attachment-mode-oracle",
|
|
"freecadVersion": version_text(),
|
|
"gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d",
|
|
"status": "pass",
|
|
"tolerance": 1e-7,
|
|
"registry": {
|
|
"modeCount": len(all_modes),
|
|
"modes": all_modes,
|
|
"implementedUnionCount": len(implemented_union),
|
|
"unimplementedModes": [mode for mode in all_modes if mode not in implemented_union],
|
|
},
|
|
"engines": engines,
|
|
"success": {"initial": success_initial, "edited": success_edited, "roundtrip": roundtrip},
|
|
"failures": {"initial": failures, "roundtrip": roundtrip_failures},
|
|
}
|
|
print("FREECAD_ATTACHMENT_MODE_RESULT=" + json.dumps(report, sort_keys=True, separators=(",", ":")))
|