Browse Source

fix: Improve 'insert_polyline_corner_fillets' function and fix the mapping issue in 'polyline_geometry_data::calculate_closest_param'

main
linchforever 5 days ago
parent
commit
da3efa945c
  1. 6
      primitive_process/src/subface/geometry/extrude_helixline_geometry.cpp
  2. 77
      primitive_process/src/subface/geometry/extrude_polyline_geometry.cpp
  3. 159
      primitive_process/src/subface/geometry/geometry_data.cpp
  4. 119
      primitive_process/src/subface/geometry/polyline_fillet.cpp
  5. 6
      primitive_process/src/subface/simple/extrude_helixline_side_face.cpp

6
primitive_process/src/subface/geometry/extrude_helixline_geometry.cpp

@ -15,8 +15,10 @@ void extrude_helixline_geometry_t::build()
// 对 profile 各衔接顶点插入微小圆角弧 // 对 profile 各衔接顶点插入微小圆角弧
std::vector<vector3d> filleted_pts; std::vector<vector3d> filleted_pts;
std::vector<double> filleted_bgs; std::vector<double> filleted_bgs;
const fillet_config_t fillet_cfg{/*segment_ratio=*/3.0, const fillet_config_t fillet_cfg{/*segment_ratio=*/0.05,
/*min_turn_angle_deg=*/0.5}; /*min_turn_angle_deg=*/0.5,
/*min_fillet_radius=*/0.0, // profile 自身不需要最小半径约束
/*is_axis=*/true};
insert_polyline_corner_fillets(profile_desc, filleted_pts, filleted_bgs, fillet_cfg); insert_polyline_corner_fillets(profile_desc, filleted_pts, filleted_bgs, fillet_cfg);
polyline_descriptor_t filleted_desc{}; polyline_descriptor_t filleted_desc{};

77
primitive_process/src/subface/geometry/extrude_polyline_geometry.cpp

@ -1,24 +1,60 @@
#include <subface/geometry/extrude_polyline_geometry.hpp> #include <subface/geometry/extrude_polyline_geometry.hpp>
#include <subface/geometry/polyline_fillet.hpp> #include <subface/geometry/polyline_fillet.hpp>
#include <cmath>
namespace internal namespace internal
{ {
/// 计算 profile 截面的最大半径(原点到各顶点的最大距离)。
/// 用于确保 axis 圆角半径 > profile 半径,防止挤出体内侧自相交。
static double compute_profile_max_radius(const polyline_descriptor_t& profile_desc)
{
if (profile_desc.point_number == 0 || profile_desc.points == nullptr) return 0.0;
double max_r2 = 0.0;
for (uint32_t i = 0; i < profile_desc.point_number; ++i) {
const double x = profile_desc.points[i].x;
const double y = profile_desc.points[i].y;
max_r2 = std::max(max_r2, x * x + y * y);
}
// 如果有 bulge 圆弧,圆弧中点可能更远,粗略扩大 10%
if (profile_desc.bulges != nullptr) {
double arc_extra = 0.0;
for (uint32_t i = 0; i < profile_desc.point_number; ++i) {
const double b = profile_desc.bulges[i];
if (std::abs(b) < 1e-12) continue;
// 圆弧中点偏离弦的距离 = chord/2 * |b|
const uint32_t j = (i + 1) % profile_desc.point_number;
const double dx = profile_desc.points[j].x - profile_desc.points[i].x;
const double dy = profile_desc.points[j].y - profile_desc.points[i].y;
arc_extra = std::max(arc_extra, 0.5 * std::sqrt(dx * dx + dy * dy) * std::abs(b));
}
return std::sqrt(max_r2) + arc_extra;
}
return std::sqrt(max_r2);
}
void extrude_polyline_geometry_t::build() void extrude_polyline_geometry_t::build()
{ {
const auto& profile_desc = this->descriptor.profiles[0]; const auto& profile_desc = this->descriptor.profiles[0];
const auto& axis_desc = this->descriptor.axis; const auto& axis_desc = this->descriptor.axis;
// 对 axis 折线插入微小圆角弧 const double profile_max_radius = compute_profile_max_radius(profile_desc);
std::cout << "[extrude_polyline_geometry_t::build]: inserting tiny curve for axis" const double axis_min_fillet_radius = profile_max_radius * 0.01;
<< " segment_ratio=" << 0.1 << ", min_turn_angle_deg=" << 0.0 << "\n";
std::cout << "[extrude_polyline_geometry_t::build] profile_max_radius=" << profile_max_radius
<< ", axis_min_fillet_radius=" << axis_min_fillet_radius << "\n";
std::vector<vector3d> filleted_axis_pts; std::vector<vector3d> filleted_axis_pts;
std::vector<double> filleted_axis_bgs; std::vector<double> filleted_axis_bgs;
const fillet_config_t axis_fillet_cfg{/*segment_ratio=*/0.1, const fillet_config_t axis_fillet_cfg{
/*min_turn_angle_deg=*/0.0}; /*segment_ratio=*/0.15,
/*min_turn_angle_deg=*/0.5,
/*min_fillet_radius=*/axis_min_fillet_radius,
/*is_axis=*/true};
insert_polyline_corner_fillets(axis_desc, filleted_axis_pts, filleted_axis_bgs, axis_fillet_cfg); insert_polyline_corner_fillets(axis_desc, filleted_axis_pts, filleted_axis_bgs, axis_fillet_cfg);
// 构建圆角后的 axis 临时描述符
polyline_descriptor_t filleted_axis_desc{}; polyline_descriptor_t filleted_axis_desc{};
filleted_axis_desc.point_number = static_cast<uint32_t>(filleted_axis_pts.size()); filleted_axis_desc.point_number = static_cast<uint32_t>(filleted_axis_pts.size());
filleted_axis_desc.points = filleted_axis_pts.data(); filleted_axis_desc.points = filleted_axis_pts.data();
@ -28,20 +64,23 @@ void extrude_polyline_geometry_t::build()
filleted_axis_desc.is_close = axis_desc.is_close; filleted_axis_desc.is_close = axis_desc.is_close;
std::cout << "[extrude_polyline_geometry_t::build] " std::cout << "[extrude_polyline_geometry_t::build] "
<< "original axis points: " << axis_desc.point_number << ", after fillet: " << filleted_axis_desc.point_number << "axis: " << axis_desc.point_number << " pts → " << filleted_axis_desc.point_number << " pts (after fillet)\n";
<< "\n";
axis_geom.build_as_axis(filleted_axis_desc, // 改为 filleted_axis_desc axis_geom.build_as_axis(filleted_axis_desc, profile_desc.reference_normal, axis_to_world, polyline_aabb);
profile_desc.reference_normal,
axis_to_world,
polyline_aabb);
std::cout << "[extrude_polyline_geometry_t::build]: inserting tiny curve for profile" for (uint32_t k = 0; k < axis_desc.point_number; ++k) {
<< " segment_ratio=" << 0.05 << ", min_turn_angle_deg=" << 0.0 << "\n"; polyline_aabb.extend(Eigen::Vector3d(axis_desc.points[k].x, axis_desc.points[k].y, axis_desc.points[k].z));
}
polyline_aabb.min().array() -= profile_max_radius;
polyline_aabb.max().array() += profile_max_radius;
// 对 profile 截面插入圆角(不需要最小半径约束)
std::vector<vector3d> filleted_profile_pts; std::vector<vector3d> filleted_profile_pts;
std::vector<double> filleted_profile_bgs; std::vector<double> filleted_profile_bgs;
const fillet_config_t profile_fillet_cfg{/*segment_ratio=*/0.1, const fillet_config_t profile_fillet_cfg{/*segment_ratio=*/0.05,
/*min_turn_angle_deg=*/0.0}; /*min_turn_angle_deg=*/0.5,
/*min_fillet_radius=*/0.0, // profile 自身不需要最小半径约束
/*is_axis=*/false};
insert_polyline_corner_fillets(profile_desc, filleted_profile_pts, filleted_profile_bgs, profile_fillet_cfg); insert_polyline_corner_fillets(profile_desc, filleted_profile_pts, filleted_profile_bgs, profile_fillet_cfg);
polyline_descriptor_t filleted_profile_desc{}; polyline_descriptor_t filleted_profile_desc{};
@ -53,10 +92,8 @@ void extrude_polyline_geometry_t::build()
filleted_profile_desc.is_close = profile_desc.is_close; filleted_profile_desc.is_close = profile_desc.is_close;
std::cout << "[extrude_polyline_geometry_t::build] " std::cout << "[extrude_polyline_geometry_t::build] "
<< "original profile points: " << profile_desc.point_number << "profile: " << profile_desc.point_number << " pts → " << filleted_profile_desc.point_number
<< ", after fillet: " << filleted_profile_desc.point_number << " pts (after fillet)\n";
<< "\n";
// 从 axis_to_world 中提取投影方向 // 从 axis_to_world 中提取投影方向
const Eigen::Vector3d proj_x = axis_to_world.matrix().col(0).head<3>(); // Binormal const Eigen::Vector3d proj_x = axis_to_world.matrix().col(0).head<3>(); // Binormal

159
primitive_process/src/subface/geometry/geometry_data.cpp

@ -205,8 +205,10 @@ void polyline_geometry_data::build_as_axis(const polyline_descriptor_t&
profile_aabb); profile_aabb);
const auto& profile_aabb_min = profile_aabb.min(); const auto& profile_aabb_min = profile_aabb.min();
const auto& profile_aabb_max = profile_aabb.max(); const auto& profile_aabb_max = profile_aabb.max();
aabb = aabb_t(Eigen::Vector3d(profile_aabb_min.y(), 0.0, profile_aabb_min.x()), aabb = aabb_t(
Eigen::Vector3d(profile_aabb_max.y(), 0.0, profile_aabb_max.x())); Eigen::Vector3d(profile_aabb_min.y(), 0.0, profile_aabb_min.x()),
Eigen::Vector3d(profile_aabb_max.y(), 0.0, profile_aabb_max.x())
);
} }
void polyline_geometry_data::build_as_axis(polyline_descriptor_t&& desc, void polyline_geometry_data::build_as_axis(polyline_descriptor_t&& desc,
@ -282,94 +284,26 @@ void polyline_geometry_data::build_as_axis(polyline_descriptor_t&&
frac = 1.0; frac = 1.0;
} }
// 调试控制:每1000次调用打印一次调试信息
static int debug_counter = 0;
constexpr int DEBUG_INTERVAL = 10000;
bool should_debug = (++debug_counter % DEBUG_INTERVAL == 0);
if (should_debug) {
std::cout << "[DEBUG calculate_normal] 调用#" << debug_counter << " t=" << t << " n=" << n << " frac=" << frac
<< " 总段数=" << this->start_indices.size() << " 类型=" << (this->thetas[n] <= EPSILON ? "直线" : "圆弧")
<< std::endl;
}
const auto iter = this->vertices.begin() + this->start_indices[n]; const auto iter = this->vertices.begin() + this->start_indices[n];
if (this->thetas[n] <= EPSILON) { if (this->thetas[n] <= EPSILON) {
// 直线段:计算切向量然后获取法向量 // 直线段:计算切向量然后获取法向量
const auto temp = (*(iter + 1) - *iter).normalized(); const auto temp = (*(iter + 1) - *iter).normalized();
if (should_debug) {
std::cout << "[DEBUG 直线段] 起点: (" << iter->x() << ", " << iter->y() << ")"
<< " 终点: (" << (iter + 1)->x() << ", " << (iter + 1)->y() << ")"
<< " 切向量: (" << temp.x() << ", " << temp.y() << ")"
<< " 切向量长度: " << temp.norm() << std::endl;
}
Eigen::Vector2d normal = {-temp.y(), temp.x()}; Eigen::Vector2d normal = {-temp.y(), temp.x()};
if (should_debug) {
std::cout << "[DEBUG 直线段] 法向量: (" << normal.x() << ", " << normal.y() << ")"
<< " 法向量长度: " << normal.norm() << std::endl;
}
return normal; return normal;
} else { } else {
// 圆弧段:计算法向量方向 // 圆弧段:计算法向量方向
const Eigen::Vector2d vec_ca = *iter - *(iter + 1); // a - c const Eigen::Vector2d vec_ca = *iter - *(iter + 1); // a - c
const Eigen::Vector2d vec_cd = *(iter + 2) - *(iter + 1); // d - c const Eigen::Vector2d vec_cd = *(iter + 2) - *(iter + 1); // d - c
if (should_debug) {
std::cout << "[DEBUG 圆弧段] 起点A: (" << iter->x() << ", " << iter->y() << ")"
<< " 圆心C: (" << (iter + 1)->x() << ", " << (iter + 1)->y() << ")"
<< " 中间点D: (" << (iter + 2)->x() << ", " << (iter + 2)->y() << ")"
<< " 终点B: (" << (iter + 3)->x() << ", " << (iter + 3)->y() << ")" << std::endl;
std::cout << "[DEBUG 圆弧段] vec_ca: (" << vec_ca.x() << ", " << vec_ca.y() << ") 长度: " << vec_ca.norm()
<< " vec_cd: (" << vec_cd.x() << ", " << vec_cd.y() << ") 长度: " << vec_cd.norm() << std::endl;
}
const double cross = vec_ca.x() * vec_cd.y() - vec_ca.y() * vec_cd.x(); const double cross = vec_ca.x() * vec_cd.y() - vec_ca.y() * vec_cd.x();
const double bulge_sign = (cross > 1e-12) ? 1.0 : -1.0; const double bulge_sign = (cross > 1e-12) ? 1.0 : -1.0;
if (should_debug) {
std::cout << "[DEBUG 圆弧段] 叉积=" << cross << " 方向sign=" << bulge_sign << " theta=" << this->thetas[n] << "("
<< (this->thetas[n] * 180.0 / pi) << "°)"
<< " 半径=" << vec_ca.norm() << std::endl;
}
const auto alpha = std::cos(frac * this->thetas[n]); const auto alpha = std::cos(frac * this->thetas[n]);
const auto beta = std::sin(frac * this->thetas[n]); const auto beta = std::sin(frac * this->thetas[n]);
if (should_debug) {
std::cout << "[DEBUG 圆弧段] 参数计算: frac*theta=" << (frac * this->thetas[n]) << "("
<< (frac * this->thetas[n] * 180.0 / pi) << "°)"
<< " alpha=cos=" << alpha << " beta=sin=" << beta << std::endl;
}
// 计算法向量 // 计算法向量
Eigen::Vector2d normal = bulge_sign * ((alpha + beta) * *(iter + 1) - alpha * *iter - beta * *(iter + 2)); Eigen::Vector2d normal = bulge_sign * ((alpha + beta) * *(iter + 1) - alpha * *iter - beta * *(iter + 2));
if (should_debug) {
std::cout << "[DEBUG 圆弧段] 法向量: (" << normal.x() << ", " << normal.y() << ")"
<< " 长度: " << normal.norm() << std::endl;
// 检查法向量长度是否正常
double norm_length = normal.norm();
if (norm_length < 0.5 || norm_length > 2.0) {
std::cout << "[DEBUG 警告] 法向量长度异常: " << norm_length << std::endl;
// 输出详细分量信息用于调试
Eigen::Vector2d comp1 = (alpha + beta) * *(iter + 1);
Eigen::Vector2d comp2 = -alpha * *iter;
Eigen::Vector2d comp3 = -beta * *(iter + 2);
Eigen::Vector2d sum = comp1 + comp2 + comp3;
std::cout << "[DEBUG 分量详情] comp1=(" << comp1.x() << "," << comp1.y() << ")"
<< " comp2=(" << comp2.x() << "," << comp2.y() << ")"
<< " comp3=(" << comp3.x() << "," << comp3.y() << ")"
<< " 未缩放向量=(" << sum.x() << "," << sum.y() << ")" << std::endl;
}
}
return normal; return normal;
} }
} }
@ -389,11 +323,12 @@ void polyline_geometry_data::build_as_axis(polyline_descriptor_t&&
auto make_vertex_3d = [&](const Eigen::Vector2d& v) -> Eigen::Vector3d { auto make_vertex_3d = [&](const Eigen::Vector2d& v) -> Eigen::Vector3d {
if (this->is_axis) if (this->is_axis)
return {v.y(), 0., v.x()}; return {v.y(), 0., v.x()}; // Axis: (x,z) -> (z,0,x)
else else
return {v.x(), v.y(), 0.}; return {v.x(), v.y(), 0.}; // Profile: (x,y) -> (x,y,0)
}; };
// 直线段最近点计算
auto line_cpm = [&](auto index) -> comparable_closest_param_t { auto line_cpm = [&](auto index) -> comparable_closest_param_t {
const auto iter = this->vertices.begin() + this->start_indices[index]; const auto iter = this->vertices.begin() + this->start_indices[index];
const auto line_vec = *(iter + 1) - *iter; const auto line_vec = *(iter + 1) - *iter;
@ -412,48 +347,36 @@ void polyline_geometry_data::build_as_axis(polyline_descriptor_t&&
const auto raw_t = line_vec.dot(p_dir); const auto raw_t = line_vec.dot(p_dir);
// 投影越界时直接返回较近端点 // 投影越界时直接返回较近端点
// raw_t ≤ 0 说明 P 在起点外侧,无需计算终点距离
if (raw_t <= 0) { if (raw_t <= 0) {
Eigen::Vector3d v = make_vertex_3d(*iter); Eigen::Vector3d v = make_vertex_3d(*iter);
return {v, 0.0, (p - v).norm(), 1., false}; return {v, 0.0, (p - v).norm(), 1., false};
} }
// raw_t ≥ len² 说明 P 在终点外侧,无需计算起点距离
if (raw_t >= line_vec_length_2) { if (raw_t >= line_vec_length_2) {
Eigen::Vector3d v = make_vertex_3d(*(iter + 1)); Eigen::Vector3d v = make_vertex_3d(*(iter + 1));
return {v, 1.0, (p - v).norm(), 1., false}; return {v, 1.0, (p - v).norm(), 1., false};
} }
const auto p_dir_length_2 = p_dir.squaredNorm();
const auto t = raw_t / line_vec_length_2; const auto t = raw_t / line_vec_length_2;
Eigen::Vector3d closest_point_3d; // 计算最近点
double dist; const Eigen::Vector2d closest_2d = *iter + t * line_vec;
Eigen::Vector3d closest_point_3d = make_vertex_3d(closest_2d);
if (this->is_axis) { double dist = (p - closest_point_3d).norm();
// Axis
closest_point_3d.x() = (1 - t) * iter->y() + t * (iter + 1)->y();
closest_point_3d.y() = 0;
closest_point_3d.z() = (1 - t) * iter->x() + t * (iter + 1)->x();
dist = (p - closest_point_3d).norm();
} else {
// Profile
closest_point_3d.x() = (1 - t) * iter->x() + t * (iter + 1)->x();
closest_point_3d.y() = (1 - t) * iter->y() + t * (iter + 1)->y();
closest_point_3d.z() = 0;
dist = std::sqrt(p_dir_length_2 - raw_t * raw_t / line_vec_length_2 + p[2] * p[2]);
}
return {closest_point_3d, t, dist, 1., true}; return {closest_point_3d, t, dist, 1., true};
}; };
// 圆弧段最近点计算
auto circle_cpm = [&](auto index) -> comparable_closest_param_t { auto circle_cpm = [&](auto index) -> comparable_closest_param_t {
const auto iter = this->vertices.begin() + this->start_indices[index]; const auto iter = this->vertices.begin() + this->start_indices[index];
const auto theta = this->thetas[index]; const auto theta = this->thetas[index];
const auto base_vec1 = *iter - *(iter + 1); // 起点 - 圆心 const auto base_vec1 = *iter - *(iter + 1); // 起点 - 圆心
const auto base_vec2 = *(iter + 2) - *(iter + 1); // 切线辅助点 d - 圆心 c(非弧终点 b const auto base_vec2 = *(iter + 2) - *(iter + 1); // 切线辅助点 d - 圆心 c
Eigen::Vector2d p_vec; Eigen::Vector2d p_vec;
double cross_bv = base_vec1.x() * base_vec2.y() - base_vec1.y() * base_vec2.x(); double cross_bv = base_vec1.x() * base_vec2.y() - base_vec1.y() * base_vec2.x();
bool is_cw = (cross_bv < 0); bool is_cw = (cross_bv < 0);
if (this->is_axis) { if (this->is_axis) {
p_vec = Eigen::Vector2d(p[2], p[0]) - *(iter + 1); p_vec = Eigen::Vector2d(p[2], p[0]) - *(iter + 1);
} else { } else {
@ -462,46 +385,41 @@ void polyline_geometry_data::build_as_axis(polyline_descriptor_t&&
const auto p_vec_norm = p_vec.norm(); // 查询点到圆心的距离 const auto p_vec_norm = p_vec.norm(); // 查询点到圆心的距离
const auto r = base_vec1.norm(); // 圆弧半径 const auto r = base_vec1.norm(); // 圆弧半径
const double off_plane = this->is_axis ? p[1] : p[2];
if (p_vec_norm < EPSILON) { if (p_vec_norm < EPSILON) {
// 查询点恰好在圆心,选弧段起点 // 查询点恰好在圆心,选弧段起点
const auto closest_point = *iter; const Eigen::Vector3d closest_point = make_vertex_3d(*iter);
const auto dis_on_plane = -r; const auto dis_on_plane = -r;
return { return {closest_point, 0.0, std::sqrt(off_plane * off_plane + dis_on_plane * dis_on_plane), 1., false};
{closest_point.x(), closest_point.y(), 0},
0.0,
std::sqrt(p[2] * p[2] + dis_on_plane * dis_on_plane),
1.,
false
};
} }
const auto local_x = base_vec1.dot(p_vec); const auto local_x = base_vec1.dot(p_vec);
const auto local_y = base_vec2.dot(p_vec); const auto local_y = base_vec2.dot(p_vec);
double phi = std::atan2(local_y, local_x); double phi = std::atan2(local_y, local_x);
// [DEBUG_CIRCLE_CPM] 对凹弧(CW)打印 phi 分布,验证是否全为负
{ // 根据圆弧转向调整 phi
static std::atomic<int> cw_cnt{0}; if (!is_cw) {
if (is_cw && ++cw_cnt <= 100) { // CCW: 有效区间 [0, theta]
std::cout << "[DEBUG_CIRCLE_CPM] CW弧 #" << cw_cnt << " seg=" << index << " phi=" << phi << " theta=" << theta if (theta > pi + 1e-9) {
<< " phi_in_range=[" << (-theta) << "," << 0 << "]" if (phi < -EPSILON) phi += two_pi;
<< " cross_bv=" << cross_bv << " p_vec=(" << p_vec.x() << "," << p_vec.y() << ")" } else {
<< " base_vec1=(" << base_vec1.x() << "," << base_vec1.y() << ")" if (phi < -EPSILON) phi = -1.0; // 触发端点回退
<< " base_vec2=(" << base_vec2.x() << "," << base_vec2.y() << ")"
<< " -> fallback_to_endpoint=" << (phi < -EPSILON || phi > theta + 1e-9 ? "YES" : "NO") << "\n";
}
} }
} else {
// CW: 有效区间 [-theta, 0],翻转后统一用 [0, theta] 处理
phi = -phi; // 将 CW 的 phi 反号,使有效范围变为 [0, theta]
if (theta > pi + 1e-9) { if (theta > pi + 1e-9) {
if (phi < -EPSILON) { phi += two_pi; } if (phi < -EPSILON) phi += two_pi;
} else { } else {
// 劣弧:phi 只应在 [0, theta],负值直接视为 gap if (phi < -EPSILON) phi = -1.0;
if (phi < -EPSILON) {
phi = -1.0; // 强制触发端点回退
} }
} }
// 弧段越界时返回较近端点 // 弧段越界时返回较近端点
if (phi < -1e-9 || phi > theta + 1e-9) { if (phi < -1e-9 || phi > theta + 1e-9) {
const Eigen::Vector3d start_3d = {iter->x(), iter->y(), 0.}; const Eigen::Vector3d start_3d = make_vertex_3d(*iter);
const Eigen::Vector3d end_3d = {(iter + 3)->x(), (iter + 3)->y(), 0.}; const Eigen::Vector3d end_3d = make_vertex_3d(*(iter + 3));
const double dist_start = (p - start_3d).norm(); const double dist_start = (p - start_3d).norm();
const double dist_end = (p - end_3d).norm(); const double dist_end = (p - end_3d).norm();
if (dist_start <= dist_end) if (dist_start <= dist_end)
@ -511,18 +429,19 @@ void polyline_geometry_data::build_as_axis(polyline_descriptor_t&&
} }
const auto dis_on_plane = p_vec_norm - r; const auto dis_on_plane = p_vec_norm - r;
const auto closest_point = p_vec / p_vec_norm * r + *(iter + 1); const Eigen::Vector2d closest_2d = p_vec / p_vec_norm * r + *(iter + 1);
Eigen::Vector3d closest_3d = make_vertex_3d(closest_2d);
return { return {
{closest_point.x(), closest_point.y(), 0}, closest_3d,
phi / theta, phi / theta,
std::sqrt(p[2] * p[2] + dis_on_plane * dis_on_plane), std::sqrt(off_plane * off_plane + dis_on_plane * dis_on_plane),
1., 1.,
true true
}; };
}; };
// 单次遍历 // 计算每个线段的最近点
std::vector<comparable_closest_param_t> closest_params(this->thetas.size()); std::vector<comparable_closest_param_t> closest_params(this->thetas.size());
std::vector<size_t> indices(this->thetas.size()); std::vector<size_t> indices(this->thetas.size());
std::iota(indices.begin(), indices.end(), 0); std::iota(indices.begin(), indices.end(), 0);

119
primitive_process/src/subface/geometry/polyline_fillet.cpp

@ -1,6 +1,5 @@
#include <subface/geometry/polyline_fillet.hpp> #include <subface/geometry/polyline_fillet.hpp>
#include <math/math_defs.hpp> #include <math/math_defs.hpp>
//#include <algorithm>
namespace internal namespace internal
{ {
@ -105,7 +104,8 @@ inline void push_point(std::vector<vector3d>& out_points,
} // anonymous namespace } // anonymous namespace
void insert_polyline_corner_fillets(const polyline_descriptor_t& profile,
void insert_polyline_corner_fillets(const polyline_descriptor_t& desc,
std::vector<vector3d>& out_points, std::vector<vector3d>& out_points,
std::vector<double>& out_bulges, std::vector<double>& out_bulges,
const fillet_config_t& cfg) const fillet_config_t& cfg)
@ -113,107 +113,80 @@ void insert_polyline_corner_fillets(const polyline_descriptor_t& profile,
out_points.clear(); out_points.clear();
out_bulges.clear(); out_bulges.clear();
const uint32_t n = profile.point_number; const uint32_t n = desc.point_number;
const bool closed = profile.is_close; const bool closed = desc.is_close;
std::function<Eigen::Vector2d(const vector3d&)> to_2d;
std::function<vector3d(const Eigen::Vector2d&, double)> to_3d;
if (cfg.is_axis) {
// axis:XZ 平面
to_2d = [](const vector3d& p) -> Eigen::Vector2d {return {p.x, p.z};};
to_3d = [](const Eigen::Vector2d& q, double fixed_y) -> vector3d { return {q.x(), fixed_y, q.y()};};
} else {
// profile:XY 平面
to_2d = [](const vector3d& p) -> Eigen::Vector2d {return {p.x, p.y};};
to_3d = [](const Eigen::Vector2d& q, double fixed_z) -> vector3d {return {q.x(), q.y(), fixed_z};};
}
// ── 退化情况:点数过少,无内部衔接顶点可处理 ──────────────────────── // 退化情况
// 闭合:至少需要 3 点才有顶点(含衔接)
// 不闭合:至少需要 3 点才有内部顶点(至少 1 个 interior vertex)
if (n < 3) { if (n < 3) {
for (uint32_t i = 0; i < n; ++i) { for (uint32_t i = 0; i < n; ++i) {
out_points.push_back(profile.points[i]); out_points.push_back(desc.points[i]);
// 只有前n-1个顶点需要凸度(开放折线) if (i < n - 1) out_bulges.push_back(desc.bulges ? desc.bulges[i] : 0.0);
if (i < n - 1) { out_bulges.push_back(profile.bulges ? profile.bulges[i] : 0.0); }
} }
return; return;
} }
std::vector<Eigen::Vector2d> pts(n); std::vector<Eigen::Vector2d> pts(n);
std::vector<double> bulges(n); std::vector<double> bulges(n);
// fixed_coord:axis→y分量(恒=0),profile→z分量(恒=0)
std::vector<double> fixed_coords(n);
for (uint32_t i = 0; i < n; ++i) { for (uint32_t i = 0; i < n; ++i) {
pts[i] = {profile.points[i].x, profile.points[i].y}; pts[i] = to_2d(desc.points[i]);
bulges[i] = profile.bulges ? profile.bulges[i] : 0.0; bulges[i] = desc.bulges ? desc.bulges[i] : 0.0;
fixed_coords[i] = cfg.is_axis ? desc.points[i].y // axis:保留 y(=0)
: desc.points[i].z; // profile:保留 z(=0)
} }
// ── 逐顶点计算圆角 ──────────────────────────────────────────────────── // 计算每个顶点的圆角
// 闭合:处理全部 n 个顶点(首尾环形相连)
// 不闭合:仅处理内部顶点 [1, n-2](首尾为端点,无入/出射配对)
std::vector<Corner> corners(n); std::vector<Corner> corners(n);
if (closed) { if (closed) {
for (uint32_t i = 0; i < n; ++i) { for (uint32_t i = 0; i < n; ++i) corners[i] = compute_corner(pts, bulges, i, (i + n - 1) % n, (i + 1) % n, cfg);
const uint32_t prev = (i + n - 1) % n;
const uint32_t next = (i + 1) % n;
corners[i] = compute_corner(pts, bulges, i, prev, next, cfg);
}
} else { } else {
// corners[0] 和 corners[n-1] 保持默认 inactive for (uint32_t i = 1; i <= n - 2; ++i) corners[i] = compute_corner(pts, bulges, i, i - 1, i + 1, cfg);
for (uint32_t i = 1; i <= n - 2; ++i) { corners[i] = compute_corner(pts, bulges, i, i - 1, i + 1, cfg); }
} }
auto push_pt = [&](const Eigen::Vector2d& p2d, double fixed, double bulge) {
out_points.push_back(to_3d(p2d, fixed));
out_bulges.push_back(bulge);
};
out_points.reserve(n * 2); out_points.reserve(n * 2);
out_bulges.reserve(n * 2); out_bulges.reserve(n * 2);
if (closed) { if (closed) {
// 闭合:环形迭代,输出隐式首尾相连
//
// 对每段 i(pts[i]→pts[next],bulge=bulges[i]):
// 1.段起点:corners[i].active ? trim_out[i] : pts[i]
// 2.若 corners[next].active:插入 trim_in[next](附 fillet_bulge[next])
// 下一迭代自然从 trim_out[next] 开始
for (uint32_t i = 0; i < n; ++i) { for (uint32_t i = 0; i < n; ++i) {
const uint32_t next = (i + 1) % n; const uint32_t next = (i + 1) % n;
const double z_i = profile.points[i].z; const auto& seg_start = corners[i].active ? corners[i].trim_out : pts[i];
const double z_nxt = profile.points[next].z; push_pt(seg_start, fixed_coords[i], bulges[i]);
if (corners[next].active) push_pt(corners[next].trim_in, fixed_coords[next], corners[next].fillet_bulge);
const Eigen::Vector2d& seg_start = corners[i].active ? corners[i].trim_out : pts[i];
push_point(out_points, out_bulges, seg_start, z_i, bulges[i]);
if (corners[next].active) {
push_point(out_points, out_bulges, corners[next].trim_in, z_nxt, corners[next].fillet_bulge);
}
} }
} else { } else {
// 不闭合:线性迭代,明确保留首尾端点
//
// 对每段 i(0..n-2),输出段起点;若 next 顶点有圆角(且非末点),
// 则额外插入 trim_in[next](附 fillet_bulge[next])作为本段实际终点,
// 下一迭代从 trim_out[next] 开始。
for (uint32_t i = 0; i < n - 1; ++i) { for (uint32_t i = 0; i < n - 1; ++i) {
const uint32_t next = i + 1; const uint32_t next = i + 1;
const double z_i = profile.points[i].z; const auto& seg_start = (i == 0) ? pts[0] : corners[i].active ? corners[i].trim_out : pts[i];
const double z_nxt = profile.points[next].z; push_pt(seg_start, fixed_coords[i], bulges[i]);
if (next < n - 1 && corners[next].active)
// 段起点: push_pt(corners[next].trim_in, fixed_coords[next], corners[next].fillet_bulge);
// i==0 → 始终为 pts[0](端点,没有圆角)
// corners[i].active → trim_out[i](由上一迭代的圆角偏移得到)
// 否则 → pts[i]
const Eigen::Vector2d& seg_start = (i == 0) ? pts[0] : corners[i].active ? corners[i].trim_out : pts[i];
// 若 next 有圆角(且 next 不是末点,末点无圆角):
// 本段实际终点为 trim_in[next],之后插入圆弧,
// 下一迭代从 trim_out[next] 开始
if (next < n - 1 && corners[next].active) {
push_point(out_points, out_bulges, seg_start, z_i, bulges[i]);
push_point(out_points, out_bulges, corners[next].trim_in, z_nxt, corners[next].fillet_bulge);
} else {
// next 无圆角(或 next 是末点):正常输出段起点
push_point(out_points, out_bulges, seg_start, z_i, bulges[i]);
} }
out_points.push_back(desc.points[n - 1]); // 末点原样保留
} }
// 末点:始终为 pts[n-1](端点,没有圆角) if (closed)
out_points.push_back(profile.points[n - 1]);
//out_bulges.push_back(0.0);
}
if (closed) {
assert(out_points.size() == out_bulges.size()); assert(out_points.size() == out_bulges.size());
} else { else
assert(out_bulges.size() + 1 == out_points.size()); // 开放折线:凸度数量 = 点数 - 1 assert(out_bulges.size() + 1 == out_points.size());
}
} }
} // namespace internal } // namespace internal

6
primitive_process/src/subface/simple/extrude_helixline_side_face.cpp

@ -210,12 +210,6 @@ std::tuple<Eigen::Vector4d, double, double> extrude_helixline_side_function_impl
Eigen::Vector3d axis_normal = face->get_axis_geom().calculate_normal(t_axis); Eigen::Vector3d axis_normal = face->get_axis_geom().calculate_normal(t_axis);
Eigen::Vector3d B = axis_normal.cross(axis_tangent).normalized(); Eigen::Vector3d B = axis_normal.cross(axis_tangent).normalized();
//Eigen::Transform<double, 3, Eigen::Isometry> TBN;
//TBN.matrix().col(0).head<3>() = B;
//TBN.matrix().col(1).head<3>() = axis_normal;
//TBN.matrix().col(2).head<3>() = axis_tangent;
//TBN.matrix().col(3).head<3>() = axis_point;
//TBN.matrix()(3, 3) = 1.0;
auto TBN = get_local_TBN_helixline(face->get_axis_geom(), axis_point, t_axis); auto TBN = get_local_TBN_helixline(face->get_axis_geom(), axis_point, t_axis);
// ==================== 处理 Profile 参数 ==================== // ==================== 处理 Profile 参数 ====================

Loading…
Cancel
Save