master
John Lauer MPN laser etch on the side face (window kept clear) 1f2f3d4 20d ago
#!/usr/bin/env python3
"""Rotate a STEP about Z through its bbox centre, keeping colours and names (XCAF): used to lay a
laser-etch mark along a part's long axis when the etch service writes across X only.
Usage: rotate_step_xcaf.py <in.step> <out.step> <degrees> [x|y|z, default z] [px,py,pz]
The optional pivot fixes the rotation centre (the side-face etch rotates forward and back about the SAME
point, so a mark that grows the bbox cannot shift the undo); without it the old behaviour is kept."""
import sys, math
from OCP.STEPCAFControl import STEPCAFControl_Reader, STEPCAFControl_Writer
from OCP.STEPControl import STEPControl_AsIs
from OCP.TDocStd import TDocStd_Document
from OCP.TCollection import TCollection_ExtendedString
from OCP.XCAFDoc import XCAFDoc_DocumentTool
from OCP.TDF import TDF_ChildIterator
from OCP.gp import gp_Trsf, gp_Ax1, gp_Pnt, gp_Dir
from OCP.TopLoc import TopLoc_Location
from OCP.Bnd import Bnd_Box
from OCP.BRepBndLib import BRepBndLib
src, out, deg = sys.argv[1], sys.argv[2], float(sys.argv[3])
axis = sys.argv[4] if len(sys.argv) > 4 else "z"
pivot = [float(v) for v in sys.argv[5].split(",")] if len(sys.argv) > 5 else None
doc = TDocStd_Document(TCollection_ExtendedString("doc"))
r = STEPCAFControl_Reader(); r.SetColorMode(True); r.SetNameMode(True); r.SetLayerMode(True)
r.ReadFile(src); r.Transfer(doc)
st = XCAFDoc_DocumentTool.ShapeTool_s(doc.Main())
labs = []
it = TDF_ChildIterator(st.Label(), False)
while it.More():
    l = it.Value()
    if st.IsFree_s(l) and st.IsTopLevel(l): labs.append(l)
    it.Next()
print('free shapes', len(labs))
b = Bnd_Box()
for l in labs: BRepBndLib.Add_s(st.GetShape_s(l), b)
mn, mx = b.CornerMin(), b.CornerMax()
d = {"x": gp_Dir(1, 0, 0), "y": gp_Dir(0, 1, 0), "z": gp_Dir(0, 0, 1)}[axis]
pc = gp_Pnt(*pivot) if pivot else gp_Pnt((mn.X()+mx.X())/2, (mn.Y()+mx.Y())/2, (mn.Z()+mx.Z())/2 if axis != "z" else 0)
t = gp_Trsf(); t.SetRotation(gp_Ax1(pc, d), math.radians(deg))
# wrap the untouched shapes in a new assembly carrying the rotation: the colours stay on the originals
asm = st.NewShape()
for lab in labs:
    st.AddComponent(asm, lab, TopLoc_Location(t))
st.UpdateAssemblies()
w = STEPCAFControl_Writer(); w.SetColorMode(True); w.SetNameMode(True); w.SetLayerMode(True)
w.Transfer(doc, STEPControl_AsIs); w.Write(out)
print(f"rotated {deg} deg about {axis}; in bbox x {mx.X()-mn.X():.3f} y {mx.Y()-mn.Y():.3f}")