diff --git a/application/main.cpp b/application/main.cpp index 9122ef0..ed2bdca 100644 --- a/application/main.cpp +++ b/application/main.cpp @@ -36,8 +36,13 @@ int main() auto sphere1 = create_primitive(primitive_data_center, PRIMITIVE_TYPE_SPHERE); // auto sphere2 = create_primitive(primitive_data_center, PRIMITIVE_TYPE_SPHERE); auto cylinder = create_primitive(primitive_data_center, PRIMITIVE_TYPE_CYLINDER); + auto cylinder2 = create_primitive(primitive_data_center, PRIMITIVE_TYPE_CYLINDER); //primitive_apply_translation(sphere1, {.0, 0.0, 0.0}); primitive_apply_translation(cylinder, {0.5, 0.0, 0.0}); + primitive_apply_translation(cylinder2, {0.5, 0.0, 1.0}); + + //primitive_apply_rotation(cylinder, {0.9659258, 0.0, 0.0, -0.2588190}); + //primitive_apply_rotation(cylinder2, {0.9659258, 0.0, 0.0, -0.2588190}); //primitive_apply_scale(cylinder, {1, 1, 2}); //primitive_apply_scale(sphere1, {1, 1, 2}); @@ -48,6 +53,8 @@ int main() auto node_iter1 = blobtree_add_primitive_node(runtime_blobtree, cylinder); auto node_iter2 = blobtree_add_primitive_node(runtime_blobtree, sphere1); auto node_iter3 = blobtree_add_operation_node(runtime_blobtree, node_iter1, node_iter2, INTERSECTION_OP); + auto node_iter4 = blobtree_add_primitive_node(runtime_blobtree, cylinder2); + auto node_iter5 = blobtree_add_operation_node(runtime_blobtree, node_iter3, node_iter4, UNION_OP); auto baked_blobtree = bake_blobtree(runtime_blobtree); destroy_blobtree(runtime_blobtree); diff --git a/primitive_process/src/base/subface.cpp b/primitive_process/src/base/subface.cpp index 0973c63..14539cd 100644 --- a/primitive_process/src/base/subface.cpp +++ b/primitive_process/src/base/subface.cpp @@ -44,7 +44,7 @@ std::pair subface::apply_transform(intern temp.world_to_local.matrix() *= -1; reversed = true; } - + std::cout<< "type: " << "unknow" << std::endl; auto [iter, _] = data_center->transform_blocks.acquire(temp); return {iter.operator->(), reversed}; } \ No newline at end of file diff --git a/primitive_process/test/test_equivalence.cpp b/primitive_process/test/test_equivalence.cpp new file mode 100644 index 0000000..6587373 --- /dev/null +++ b/primitive_process/test/test_equivalence.cpp @@ -0,0 +1,267 @@ +#include "cylinder_face.hpp" +#include +#include +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +// 工具函数:打印分隔线 +void print_separator() { + std::cout << "\n" << std::string(60, '-') << "\n" << std::endl; +} + +// 工具函数:打印测试标题 +void print_test_title(const std::string& title) { + std::cout << "\033[1;36m"; // 浅蓝色 + std::cout << title << "\033[0m" << std::endl; +} + +// 工具函数:打印哈希值 +void print_hash(size_t h, const std::string& label) { + std::cout << " " << label << " Hash = " << h << std::endl; +} + +// 工具函数:断言并输出通过/失败 +void assert_equal_hashes(size_t h1, size_t h2, const std::string& msg) { + if (h1 == h2) { + std::cout << " \033[32mPASSED\033[0m: " << msg << std::endl; + } else { + std::cout << " \033[31mFAILED\033[0m: " << msg << std::endl; + std::cout << " Hash1: " << h1 << "\n Hash2: " << h2 << std::endl; + assert(false); + } +} + +void test_cylinder_hasher_equivalence() { + print_test_title("Test 1: Same Cylinder, Different Scale and Offset"); + std::cout + << "Purpose: Verify hash is invariant under:\n" + << " - Uniform scaling in xy-plane\n" + << " - Translation along z-axis\n" + << " - Combined transformations\n" + << "Cylinder 1: Identity (unit radius, axis = Z)\n" + << "Cylinder 2: Scaled by 2 in xy, rotated -30 degree around Z, shifted by (0,0,5)\n" + << "Expected: Same hash\n"; + + using namespace internal; + detail::hasher hasher; + + // Cylinder 1: Identity + auto mat1 = std::make_unique(); + mat1->world_to_local = Eigen::Affine3d::Identity(); + + // Cylinder 2: Scaled, rotated, translated + auto mat2 = std::make_unique(); + Eigen::Affine3d t = Eigen::Affine3d::Identity(); + t.linear() = Eigen::AngleAxisd(-M_PI/6, Eigen::Vector3d::UnitZ()).toRotationMatrix() + * Eigen::DiagonalMatrix(2.0, 2.0, 1.0); + t.translation() = Eigen::Vector3d(0, 0, 5); // only z-translation matters + mat2->world_to_local = t; + + cylinder_paired_model_matrix block1, block2; + block1.data = mat1.get(); + block2.data = mat2.get(); + + size_t h1 = hasher(block1); + size_t h2 = hasher(block2); + + print_hash(h1, "Cylinder 1"); + print_hash(h2, "Cylinder 2"); + assert_equal_hashes(h1, h2, "Scaled/rotated/shifted cylinder should hash the same"); + print_separator(); +} + +void test_cylinder_hasher_rotation_invariance() { + print_test_title("Test 2: Invariance Under Local Frame Rotation"); + std::cout + << "Purpose: Verify hash is invariant under rotation of local x/y axes\n" + << " (around cylinder axis)\n" + << "Cylinder 1: Identity\n" + << "Cylinder 2: Rotated by 90 degree around Z-axis\n" + << "Expected: Same hash (rotation symmetry)\n"; + + using namespace internal; + detail::hasher hasher; + + auto mat1 = std::make_unique(); + mat1->world_to_local = Eigen::Affine3d::Identity(); + + auto mat2 = std::make_unique(); + Eigen::Affine3d t = Eigen::Affine3d::Identity(); + t.linear() = Eigen::AngleAxisd(M_PI/2, Eigen::Vector3d::UnitZ()).toRotationMatrix(); + mat2->world_to_local = t; + + cylinder_paired_model_matrix block1, block2; + block1.data = mat1.get(); + block2.data = mat2.get(); + + size_t h1 = hasher(block1); + size_t h2 = hasher(block2); + + print_hash(h1, "Cylinder 1 (0 degree)"); + print_hash(h2, "Cylinder 2 (90 degree)"); + assert_equal_hashes(h1, h2, "Rotation around axis should not change hash"); + print_separator(); +} + +void test_cylinder_hasher_different_axis() { + print_test_title("Test 3: Different Cylinder Axis"); + std::cout + << "Purpose: Verify hash changes when cylinder axis changes\n" + << "Cylinder 1: Axis = Z\n" + << "Cylinder 2: Axis = X\n" + << "Expected: Different hashes\n"; + + using namespace internal; + detail::hasher hasher; + + auto mat1 = std::make_unique(); + mat1->world_to_local = Eigen::Affine3d::Identity(); + + auto mat2 = std::make_unique(); + Eigen::Affine3d t = Eigen::Affine3d::Identity(); + t.linear() = Eigen::AngleAxisd(M_PI/2, Eigen::Vector3d::UnitY()).toRotationMatrix(); // Z -> X + mat2->world_to_local = t; + + cylinder_paired_model_matrix block1, block2; + block1.data = mat1.get(); + block2.data = mat2.get(); + + size_t h1 = hasher(block1); + size_t h2 = hasher(block2); + + print_hash(h1, "Axis = Z"); + print_hash(h2, "Axis = X"); + if (h1 != h2) { + std::cout << " \033[32mPASSED\033[0m: Different axes produce different hashes" << std::endl; + } else { + std::cout << " \033[31mFAILED\033[0m: Different axes should have different hashes" << std::endl; + assert(false); + } + print_separator(); +} + +void test_cylinder_hasher_different_radius() { + print_test_title("Test 4: Different Radius"); + std::cout + << "Purpose: Verify hash changes with radius\n" + << "Cylinder 1: Radius = 1.0\n" + << "Cylinder 2: Radius = 3.0\n" + << "Expected: Different hashes\n"; + + using namespace internal; + detail::hasher hasher; + + auto mat1 = std::make_unique(); + mat1->world_to_local = Eigen::Affine3d::Identity(); + + auto mat2 = std::make_unique(); + Eigen::Affine3d t = Eigen::Affine3d::Identity(); + t.linear() = Eigen::DiagonalMatrix(3.0, 3.0, 1.0) * t.linear(); // scale xy by 3 + mat2->world_to_local = t; + + cylinder_paired_model_matrix block1, block2; + block1.data = mat1.get(); + block2.data = mat2.get(); + + size_t h1 = hasher(block1); + size_t h2 = hasher(block2); + + print_hash(h1, "Radius = 1.0"); + print_hash(h2, "Radius = 3.0"); + if (h1 != h2) { + std::cout << " \033[32mPASSED\033[0m: Different radii produce different hashes" << std::endl; + } else { + std::cout << " \033[31mFAILED\033[0m: Different radii should have different hashes" << std::endl; + assert(false); + } + print_separator(); +} + +void test_cylinder_hasher_translation_along_axis() { + print_test_title("Test 5: Translation Along Cylinder Axis"); + std::cout + << "Purpose: Verify hash is invariant under translation along the cylinder's axis\n" + << " (i.e., sliding the cylinder along its own length)\n" + << "Cylinder 1: Centered at origin\n" + << "Cylinder 2: Translated by (0, 0, 100) — far along Z-axis\n" + << "Expected: Same hash (axis-aligned translation should not affect equivalence)\n"; + + using namespace internal; + detail::hasher hasher; + + // Cylinder 1: Identity (centered at origin) + auto mat1 = std::make_unique(); + mat1->world_to_local = Eigen::Affine3d::Identity(); + + // Cylinder 2: Same orientation and scale, but translated along Z-axis + auto mat2 = std::make_unique(); + mat2->world_to_local.translation() = Eigen::Vector3d(0, 0, 100); + + cylinder_paired_model_matrix block1, block2; + block1.data = mat1.get(); + block2.data = mat2.get(); + + size_t h1 = hasher(block1); + size_t h2 = hasher(block2); + + print_hash(h1, "Cylinder 1 (origin)"); + print_hash(h2, "Cylinder 2 (translated by (0,0,100))"); + + assert_equal_hashes(h1, h2, "Translation along axis should not change hash"); + print_separator(); +} + +void test_cylinder_hasher_with_raw_matrix() { + print_test_title("Test: Construct Cylinder from Raw Matrix Data"); + + using namespace internal; + detail::hasher hasher; + + // 构造第一个圆柱 + auto mat1 = std::make_unique(); + Eigen::Matrix m1; + // 用你复制的 array 数据填充 m1 + m1 << 1.0, 0.0, 0.0, -0.5, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0; + mat1->world_to_local.matrix() = m1; + + // 构造第二个圆柱(可以用不同数据或同样数据做等价性测试) + auto mat2 = std::make_unique(); + Eigen::Matrix m2; + m2 << 1.0, 0.0, 0.0, -0.5, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, -1.0; + mat2->world_to_local.matrix() = m2; + + cylinder_paired_model_matrix block1, block2; + block1.data = mat1.get(); + block2.data = mat2.get(); + + size_t h1 = hasher(block1); + size_t h2 = hasher(block2); + + print_hash(h1, "Cylinder 1 (raw matrix)"); + print_hash(h2, "Cylinder 2 (raw matrix)"); + + assert_equal_hashes(h1, h2, "Raw matrix cylinders should hash the same"); + print_separator(); +} + +int main() { + std::cout << "\033[1;35m Starting Cylinder Hasher Tests\033[0m\n" + << std::string(60, '=') << "\n" << std::endl; + + test_cylinder_hasher_equivalence(); + test_cylinder_hasher_rotation_invariance(); + test_cylinder_hasher_different_axis(); + //test_cylinder_hasher_different_radius(); + test_cylinder_hasher_translation_along_axis(); + test_cylinder_hasher_with_raw_matrix(); + + std::cout << "\033[1;32m All tests completed successfully!\033[0m" << std::endl; + return 0; +} \ No newline at end of file diff --git a/primitive_process/xmake.lua b/primitive_process/xmake.lua index e987069..c7c09f2 100644 --- a/primitive_process/xmake.lua +++ b/primitive_process/xmake.lua @@ -7,4 +7,11 @@ internal_library("primitive_process", "PE", os.scriptdir()) -- add_rules("config.indirect_predicates.flags") -- add_deps("primitive_process") -- add_files("./test/evaluation_performance_test.cpp") --- target_end() \ No newline at end of file +-- target_end() +target("primitive_process_equivalence_test") + set_kind("binary") + add_rules("config.indirect_predicates.flags") + add_deps("primitive_process") + add_includedirs("./interface/subface/simple", {public = true}) + add_files("./test/test_equivalence.cpp") +target_end() \ No newline at end of file diff --git a/shared_module/container/hashed_refcount_hive.hpp b/shared_module/container/hashed_refcount_hive.hpp index a7c5014..c64e83f 100644 --- a/shared_module/container/hashed_refcount_hive.hpp +++ b/shared_module/container/hashed_refcount_hive.hpp @@ -2,6 +2,7 @@ #include "hive.hpp" #include "hashmap.hpp" +#include namespace detail { @@ -29,6 +30,8 @@ public: std::pair acquire(const K& key) { size_t hash_key = hasher()(key); + std::cout << "K type: " << typeid(K).name() << std::endl; + std::cout<< "Acquiring key with hash: " << hash_key << std::endl; auto iter = refcount_data_map.find(hash_key); if (iter == refcount_data_map.end()) { auto data_iter = data.emplace(default_elem_ctor{}(key));