symmetry op• Data kinds: points → primitive
• Call: import fullseye as fs; fs.ledger.detect_reflection_symmetry(points) (to call the implementation directly, import symmetry3d; symmetry3d.detect_reflection_symmetry(points); from the registry, ops3d.get("detect_reflection_symmetry"))
Choose the best mirror-symmetry plane among candidates whose normals are the PCA principal axes (through the centroid).
→ dict{plane_point, plane_normal, score, all_scores, margin}. The smaller the score, the more symmetric.
★ Do not decide acceptance from score alone. Look at margin (added 2026-09-06). margin is the difference between the 2nd- and 1st-place scores: if the candidates are bunched, the answer is a lottery is the warning it gives. Measured (1500 points):
======================= ======== ======== =========
Shape best 2nd margin
======================= ======== ======== =========
Box (3 mirror planes) 0.9397 0.9499 0.0102
Box with a prism 0.9876 0.9918 0.0043
Sphere 1.0490 1.0551 0.0062
Uniform random cube 1.0608 1.3435 0.2828
======================= ======== ======== =========
The more symmetry planes a shape has, the smaller the margin; this is not a bug but information that the shape is like that. A point-cloud registration PoC measures the same structure: the PCA candidates grab a flipped quadrant 83 % of the time on a plain cuboid, and what collapses first then is not the residual but the margin between candidates (0.42 → 0.066 → 0.039). Judge acceptance by margin, not by the residual is the conclusion common to both.
★ score does not approach 0. Even for an exactly symmetric shape, the point spacing creates a floor (the box is at 0.94 in the table above). Instead of asking "is it close to 0", compare with "the value measured on the same shape without reflecting it" or with "the point spacing".
★ The candidates are only the 3 PCA axes. For a shape whose true symmetry plane matches none of the principal axes, the plane is not found, and the op silently returns the best of the 3 anyway. If you need densely sampled candidates, sweep reflection_symmetry_score directly.
• Sample-data catalog (download URLs / licences) — 2-D uses skimage.data (BSD/public domain) plus synthetic images; 3-D lists download URLs for real data sources (Stanford, PDS, …).
• Operator provenance and references — the sources of the research/methods this op family came from.
• dl_mesh_symmetry — py -3.11 examples_3d/dl_mesh_symmetry.py
• itokawa_symmetry_honest — py -3.11 examples_3d/itokawa_symmetry_honest.py
• reflection_symmetry — py -3.11 examples_3d/reflection_symmetry.py
• symmetry — py -3.11 examples_3d/symmetry.py
primitive as input)fuse_to_voxel · angle_between_lines · angle_between_planes · angle_line_plane · distance_point_plane · distance_point_line · distance_line_line · distance_segment_segment
symmetry)detect_rotational_symmetry · reflect_points · reflection_symmetry_score
*Provenance: symmetry3d.py — 3D operator registry. This per-op note is generated by tools/opdocs.py md (do not hand-edit).*
© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.