#include #include "vde/core/cam_optimization.h" #include "vde/core/cam_advanced.h" #include "vde/core/cam_strategies.h" #include "vde/core/cam_toolpath.h" #include "vde/brep/brep.h" #include "vde/brep/modeling.h" #include using namespace vde::core; using namespace vde::brep; // =========================================================================== // Helpers // =========================================================================== static BrepModel make_test_box(double w = 50.0, double h = 30.0, double d = 20.0) { return make_box(w, h, d); } static Toolpath make_basic_toolpath() { Toolpath tp; tp.name = "TestBasic"; tp.safe_z = 15.0; PathSegment s1{Point3D(0,0,15), Point3D(10,0,-1), Point3D::Zero(), PathSegmentType::Linear, 500.0, -1.0}; PathSegment s2{Point3D(10,0,-1), Point3D(20,0,-1), Point3D::Zero(), PathSegmentType::Linear, 500.0, -1.0}; PathSegment s3{Point3D(20,0,-1), Point3D(20,10,-1), Point3D::Zero(), PathSegmentType::Linear, 500.0, -1.0}; tp.segments = {s1, s2, s3}; return tp; } // =========================================================================== // chip_thinning_optimization 测试 // =========================================================================== TEST(CamOptimizationTest, ChipThinning_AdjustsFeedForSmallAe) { Toolpath tp = make_basic_toolpath(); Tool tool; tool.diameter = 10.0; // R=5mm, 小径向切深 → 应触发补偿 tool.flutes = 2; auto result = chip_thinning_optimization(tp, tool); EXPECT_EQ(result.segments.size(), tp.segments.size()); EXPECT_GT(result.segments[0].feed_rate, 0); // 名称应有变化 EXPECT_NE(result.name, tp.name); } TEST(CamOptimizationTest, ChipThinning_EmptyToolpath) { Toolpath empty_tp; Tool tool; tool.diameter = 10.0; auto result = chip_thinning_optimization(empty_tp, tool); EXPECT_EQ(result.segments.size(), 0u); } TEST(CamOptimizationTest, ChipThinning_LargeToolNoChange) { // 刀具直径很大,径向切深接近刀具半径 → 不补偿 Toolpath tp = make_basic_toolpath(); Tool tool; tool.diameter = 100.0; // 非常大的刀具 auto result = chip_thinning_optimization(tp, tool); // 大刀具时补偿因子应接近 1 for (size_t i = 0; i < result.segments.size(); ++i) { if (result.segments[i].type == PathSegmentType::Linear) { EXPECT_NEAR(result.segments[i].feed_rate, tp.segments[i].feed_rate, 300.0); } } } // =========================================================================== // trochoidal_turn_milling 测试 // =========================================================================== TEST(CamOptimizationTest, TrochoidalTurnMill_GeneratesSegments) { auto box = make_test_box(30, 30, 15); Tool tool; tool.diameter = 8.0; TurnMillParams params; params.step_down = 5.0; params.trochoid_radius = 2.0; params.safe_z = 15.0; auto tp = trochoidal_turn_milling(box, tool, params); EXPECT_EQ(tp.name, "TrochoidalTurnMill"); EXPECT_GT(tp.segments.size(), 5u) << "Should generate turn-mill toolpath"; EXPECT_DOUBLE_EQ(tp.safe_z, 15.0); } TEST(CamOptimizationTest, TrochoidalTurnMill_IncludesRetract) { auto box = make_test_box(20, 20, 10); Tool tool; tool.diameter = 6.0; TurnMillParams params; params.safe_z = 20.0; params.step_down = 10.0; // 单层 auto tp = trochoidal_turn_milling(box, tool, params); // 最后一段应为提刀 EXPECT_FALSE(tp.segments.empty()); EXPECT_EQ(tp.segments.back().type, PathSegmentType::Rapid); } // =========================================================================== // high_speed_machining 测试 // =========================================================================== TEST(CamOptimizationTest, HighSpeedMachining_IncreasesFeed) { Toolpath tp = make_basic_toolpath(); HSMParams params; params.feed_rate = 2000.0; params.step_down = 0.5; params.trochoidal_corners = false; auto result = high_speed_machining(tp, params); EXPECT_EQ(result.segments.size(), tp.segments.size()); // HSM 应提升进给率 for (size_t i = 0; i < result.segments.size(); ++i) { if (result.segments[i].type == PathSegmentType::Linear) { EXPECT_GE(result.segments[i].feed_rate, params.feed_rate * 0.5); } } } TEST(CamOptimizationTest, HighSpeedMachining_AddsCornerTransitions) { // 创建有拐角的刀路 Toolpath tp; tp.name = "CornerTest"; tp.safe_z = 15.0; PathSegment s1{Point3D(0,0,5), Point3D(10,0,-1), Point3D::Zero(), PathSegmentType::Linear, 500.0, -1.0}; PathSegment s2{Point3D(10,0,-1), Point3D(10,10,-1), Point3D::Zero(), PathSegmentType::Linear, 500.0, -1.0}; // 90° 拐角 tp.segments = {s1, s2}; HSMParams params; params.feed_rate = 2500.0; params.trochoidal_corners = true; params.corner_radius = 2.0; auto result = high_speed_machining(tp, params); // 拐角过渡应增加段数 EXPECT_GT(result.segments.size(), tp.segments.size()); } TEST(CamOptimizationTest, HighSpeedMachining_EmptyToolpath) { Toolpath empty_tp; HSMParams params; auto result = high_speed_machining(empty_tp, params); EXPECT_EQ(result.segments.size(), 0u); } // =========================================================================== // constant_engagement_milling 测试 // =========================================================================== TEST(CamOptimizationTest, ConstantEngagement_GeneratesSpiral) { auto box = make_test_box(40, 40, 10); Tool tool; tool.diameter = 8.0; ConstantEngagementParams params; params.target_engagement = 45.0; params.step_down = 5.0; params.safe_z = 15.0; auto tp = constant_engagement_milling(box, tool, params); EXPECT_EQ(tp.name, "ConstantEngagement"); EXPECT_GT(tp.segments.size(), 10u) << "Should generate multi-ring spiral"; EXPECT_DOUBLE_EQ(tp.safe_z, 15.0); } TEST(CamOptimizationTest, ConstantEngagement_DifferentEngagementAngles) { auto box = make_test_box(30, 30, 10); Tool tool; tool.diameter = 8.0; ConstantEngagementParams low_eng; low_eng.target_engagement = 20.0; low_eng.step_down = 10.0; ConstantEngagementParams high_eng; high_eng.target_engagement = 60.0; high_eng.step_down = 10.0; auto tp_low = constant_engagement_milling(box, tool, low_eng); auto tp_high = constant_engagement_milling(box, tool, high_eng); // 低啮合角 = 更密的螺旋圈 → 更多段 EXPECT_GT(tp_low.segments.size(), 0u); EXPECT_GT(tp_high.segments.size(), 0u); // 低啮合角应有更多段(步距更密) EXPECT_GE(tp_low.segments.size(), tp_high.segments.size() * 0.5); } // =========================================================================== // tool_life_management 测试 // =========================================================================== TEST(CamOptimizationTest, ToolLifeManagement_ReturnsValidResult) { Tool tool; tool.diameter = 10.0; tool.flutes = 4; tool.type = ToolType::ENDMILL; Material mat; mat.name = "Aluminum"; mat.hardness_brinell = 95.0; mat.specific_cutting_force = 800.0; ToolLifeParams params; params.max_cutting_time_min = 60.0; params.max_cutting_length_m = 500.0; auto result = tool_life_management(tool, mat, params); // 铝合金 → 刀具寿命应较长 EXPECT_GT(result.estimated_life_min, 0); EXPECT_GT(result.material_removed_mm3, 0); EXPECT_FALSE(result.needs_replacement); EXPECT_TRUE(result.warning_message.empty() || !result.needs_replacement); } TEST(CamOptimizationTest, ToolLifeManagement_HardMaterialShortLife) { Tool tool; tool.diameter = 6.0; tool.flutes = 2; tool.type = ToolType::BALLNOSE; Material steel; steel.name = "HardenedSteel"; steel.hardness_brinell = 400.0; steel.specific_cutting_force = 4000.0; Material aluminum; aluminum.name = "Aluminum"; aluminum.hardness_brinell = 80.0; aluminum.specific_cutting_force = 600.0; ToolLifeParams params; auto result_steel = tool_life_management(tool, steel, params); auto result_alum = tool_life_management(tool, aluminum, params); // 硬材料的寿命应远小于软材料 EXPECT_LT(result_steel.estimated_life_min, result_alum.estimated_life_min); } TEST(CamOptimizationTest, ToolLifeManagement_WearNearLimit) { Tool tool; tool.diameter = 8.0; tool.flutes = 3; tool.type = ToolType::ENDMILL; Material mat; mat.name = "Steel"; mat.hardness_brinell = 250.0; mat.specific_cutting_force = 2500.0; // 使用较小的临界磨损值来触发报警 ToolLifeParams params; params.critical_flank_wear = 0.05; // 非常小的临界值 params.max_cutting_time_min = 120.0; params.wear_coefficient = 5.0e-5; // 高磨损系数 auto result = tool_life_management(tool, mat, params); // 应该有磨损量记录 EXPECT_GT(result.accumulated_wear_mm, 0); EXPECT_GT(result.current_flank_wear, 0); }