From b04bfcf4038da92047ca5259604ddfb8173c4ad9 Mon Sep 17 00:00:00 2001 From: mckay Date: Thu, 4 Sep 2025 15:59:41 +0800 Subject: [PATCH] refactor(cylinder_face): use geometric hash based on world_to_local transform Instead of relying on object identity or raw transform parameters, the hasher now uses intrinsic geometric properties to determine cylinder equivalence. The hash is computed from: - G = R^T * R : encodes the cylinder's cross-sectional metric and axis direction - v = R * d : encodes the axial offset in the radial plane where R is the top-left 2x3 submatrix of the world_to_local linear part, and d is its translation vector. This ensures that two cylinder faces with the same shape, orientation, and central axis (even if parameterized differently) produce the same hash. --- .../interface/subface/simple/cylinder_face.hpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/primitive_process/interface/subface/simple/cylinder_face.hpp b/primitive_process/interface/subface/simple/cylinder_face.hpp index db04f78..5d86b1f 100644 --- a/primitive_process/interface/subface/simple/cylinder_face.hpp +++ b/primitive_process/interface/subface/simple/cylinder_face.hpp @@ -34,8 +34,20 @@ template <> struct hasher { size_t operator()(const internal::cylinder_paired_model_matrix &block) const { - Eigen::Matrix character_rows = block.data->local_to_world.matrix().topRows<2>(); - return XXH3_64bits(character_rows.data(), sizeof(decltype(character_rows))); + const auto& mat = block.data->local_to_world.matrix(); // 3x4 + Eigen::Matrix3d A = mat.block<3,3>(0,0); + Eigen::Vector3d b = mat.col(3); + + Eigen::Matrix3d B = A.inverse(); + Eigen::Matrix R = B.topRows<2>(); + + Eigen::Matrix3d G = R.transpose() * R; + Eigen::Vector2d zero_proj = R * b; + + size_t h = XXH3_64bits(G.data(), sizeof(Eigen::Matrix3d)); + h ^= XXH3_64bits(zero_proj.data(), sizeof(Eigen::Vector2d)); + + return h; } };