|
|
|
@ -205,8 +205,10 @@ void polyline_geometry_data::build_as_axis(const polyline_descriptor_t& |
|
|
|
profile_aabb); |
|
|
|
const auto& profile_aabb_min = profile_aabb.min(); |
|
|
|
const auto& profile_aabb_max = profile_aabb.max(); |
|
|
|
aabb = aabb_t(Eigen::Vector3d(profile_aabb_min.y(), 0.0, profile_aabb_min.x()), |
|
|
|
Eigen::Vector3d(profile_aabb_max.y(), 0.0, profile_aabb_max.x())); |
|
|
|
aabb = aabb_t( |
|
|
|
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, |
|
|
|
@ -282,94 +284,26 @@ void polyline_geometry_data::build_as_axis(polyline_descriptor_t&& |
|
|
|
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]; |
|
|
|
|
|
|
|
if (this->thetas[n] <= EPSILON) { |
|
|
|
// 直线段:计算切向量然后获取法向量
|
|
|
|
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()}; |
|
|
|
|
|
|
|
if (should_debug) { |
|
|
|
std::cout << "[DEBUG 直线段] 法向量: (" << normal.x() << ", " << normal.y() << ")" |
|
|
|
<< " 法向量长度: " << normal.norm() << std::endl; |
|
|
|
} |
|
|
|
|
|
|
|
return normal; |
|
|
|
} else { |
|
|
|
// 圆弧段:计算法向量方向
|
|
|
|
const Eigen::Vector2d vec_ca = *iter - *(iter + 1); // a - 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 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 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)); |
|
|
|
|
|
|
|
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; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -389,11 +323,12 @@ void polyline_geometry_data::build_as_axis(polyline_descriptor_t&& |
|
|
|
|
|
|
|
auto make_vertex_3d = [&](const Eigen::Vector2d& v) -> Eigen::Vector3d { |
|
|
|
if (this->is_axis) |
|
|
|
return {v.y(), 0., v.x()}; |
|
|
|
return {v.y(), 0., v.x()}; // Axis: (x,z) -> (z,0,x)
|
|
|
|
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 { |
|
|
|
const auto iter = this->vertices.begin() + this->start_indices[index]; |
|
|
|
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); |
|
|
|
|
|
|
|
// 投影越界时直接返回较近端点
|
|
|
|
// raw_t ≤ 0 说明 P 在起点外侧,无需计算终点距离
|
|
|
|
if (raw_t <= 0) { |
|
|
|
Eigen::Vector3d v = make_vertex_3d(*iter); |
|
|
|
return {v, 0.0, (p - v).norm(), 1., false}; |
|
|
|
} |
|
|
|
// raw_t ≥ len² 说明 P 在终点外侧,无需计算起点距离
|
|
|
|
if (raw_t >= line_vec_length_2) { |
|
|
|
Eigen::Vector3d v = make_vertex_3d(*(iter + 1)); |
|
|
|
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; |
|
|
|
|
|
|
|
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) { |
|
|
|
// 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; |
|
|
|
double dist = (p - closest_point_3d).norm(); |
|
|
|
|
|
|
|
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}; |
|
|
|
}; |
|
|
|
|
|
|
|
// 圆弧段最近点计算
|
|
|
|
auto circle_cpm = [&](auto index) -> comparable_closest_param_t { |
|
|
|
const auto iter = this->vertices.begin() + this->start_indices[index]; |
|
|
|
const auto theta = this->thetas[index]; |
|
|
|
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; |
|
|
|
double cross_bv = base_vec1.x() * base_vec2.y() - base_vec1.y() * base_vec2.x(); |
|
|
|
bool is_cw = (cross_bv < 0); |
|
|
|
|
|
|
|
if (this->is_axis) { |
|
|
|
p_vec = Eigen::Vector2d(p[2], p[0]) - *(iter + 1); |
|
|
|
} 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 r = base_vec1.norm(); // 圆弧半径
|
|
|
|
const double off_plane = this->is_axis ? p[1] : p[2]; |
|
|
|
|
|
|
|
if (p_vec_norm < EPSILON) { |
|
|
|
// 查询点恰好在圆心,选弧段起点
|
|
|
|
const auto closest_point = *iter; |
|
|
|
const auto dis_on_plane = -r; |
|
|
|
return { |
|
|
|
{closest_point.x(), closest_point.y(), 0}, |
|
|
|
0.0, |
|
|
|
std::sqrt(p[2] * p[2] + dis_on_plane * dis_on_plane), |
|
|
|
1., |
|
|
|
false |
|
|
|
}; |
|
|
|
const Eigen::Vector3d closest_point = make_vertex_3d(*iter); |
|
|
|
const auto dis_on_plane = -r; |
|
|
|
return {closest_point, 0.0, std::sqrt(off_plane * off_plane + dis_on_plane * dis_on_plane), 1., false}; |
|
|
|
} |
|
|
|
|
|
|
|
const auto local_x = base_vec1.dot(p_vec); |
|
|
|
const auto local_y = base_vec2.dot(p_vec); |
|
|
|
double phi = std::atan2(local_y, local_x); |
|
|
|
// [DEBUG_CIRCLE_CPM] 对凹弧(CW)打印 phi 分布,验证是否全为负
|
|
|
|
{ |
|
|
|
static std::atomic<int> cw_cnt{0}; |
|
|
|
if (is_cw && ++cw_cnt <= 100) { |
|
|
|
std::cout << "[DEBUG_CIRCLE_CPM] CW弧 #" << cw_cnt << " seg=" << index << " phi=" << phi << " theta=" << theta |
|
|
|
<< " phi_in_range=[" << (-theta) << "," << 0 << "]" |
|
|
|
<< " cross_bv=" << cross_bv << " p_vec=(" << p_vec.x() << "," << p_vec.y() << ")" |
|
|
|
<< " base_vec1=(" << base_vec1.x() << "," << base_vec1.y() << ")" |
|
|
|
<< " base_vec2=(" << base_vec2.x() << "," << base_vec2.y() << ")" |
|
|
|
<< " -> fallback_to_endpoint=" << (phi < -EPSILON || phi > theta + 1e-9 ? "YES" : "NO") << "\n"; |
|
|
|
|
|
|
|
// 根据圆弧转向调整 phi
|
|
|
|
if (!is_cw) { |
|
|
|
// CCW: 有效区间 [0, theta]
|
|
|
|
if (theta > pi + 1e-9) { |
|
|
|
if (phi < -EPSILON) phi += two_pi; |
|
|
|
} else { |
|
|
|
if (phi < -EPSILON) phi = -1.0; // 触发端点回退
|
|
|
|
} |
|
|
|
} |
|
|
|
if (theta > pi + 1e-9) { |
|
|
|
if (phi < -EPSILON) { phi += two_pi; } |
|
|
|
} else { |
|
|
|
// 劣弧:phi 只应在 [0, theta],负值直接视为 gap
|
|
|
|
if (phi < -EPSILON) { |
|
|
|
phi = -1.0; // 强制触发端点回退
|
|
|
|
// CW: 有效区间 [-theta, 0],翻转后统一用 [0, theta] 处理
|
|
|
|
phi = -phi; // 将 CW 的 phi 反号,使有效范围变为 [0, theta]
|
|
|
|
if (theta > pi + 1e-9) { |
|
|
|
if (phi < -EPSILON) phi += two_pi; |
|
|
|
} else { |
|
|
|
if (phi < -EPSILON) phi = -1.0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 弧段越界时返回较近端点
|
|
|
|
if (phi < -1e-9 || phi > theta + 1e-9) { |
|
|
|
const Eigen::Vector3d start_3d = {iter->x(), iter->y(), 0.}; |
|
|
|
const Eigen::Vector3d end_3d = {(iter + 3)->x(), (iter + 3)->y(), 0.}; |
|
|
|
const Eigen::Vector3d start_3d = make_vertex_3d(*iter); |
|
|
|
const Eigen::Vector3d end_3d = make_vertex_3d(*(iter + 3)); |
|
|
|
const double dist_start = (p - start_3d).norm(); |
|
|
|
const double dist_end = (p - end_3d).norm(); |
|
|
|
if (dist_start <= dist_end) |
|
|
|
@ -510,19 +428,20 @@ void polyline_geometry_data::build_as_axis(polyline_descriptor_t&& |
|
|
|
return {end_3d, 1.0, dist_end, 1., false}; |
|
|
|
} |
|
|
|
|
|
|
|
const auto dis_on_plane = p_vec_norm - r; |
|
|
|
const auto closest_point = p_vec / p_vec_norm * r + *(iter + 1); |
|
|
|
const auto dis_on_plane = p_vec_norm - r; |
|
|
|
const Eigen::Vector2d closest_2d = p_vec / p_vec_norm * r + *(iter + 1); |
|
|
|
Eigen::Vector3d closest_3d = make_vertex_3d(closest_2d); |
|
|
|
|
|
|
|
return { |
|
|
|
{closest_point.x(), closest_point.y(), 0}, |
|
|
|
phi / theta, |
|
|
|
std::sqrt(p[2] * p[2] + dis_on_plane * dis_on_plane), |
|
|
|
1., |
|
|
|
closest_3d, |
|
|
|
phi / theta, |
|
|
|
std::sqrt(off_plane * off_plane + dis_on_plane * dis_on_plane), |
|
|
|
1., |
|
|
|
true |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
// 单次遍历
|
|
|
|
// 计算每个线段的最近点
|
|
|
|
std::vector<comparable_closest_param_t> closest_params(this->thetas.size()); |
|
|
|
std::vector<size_t> indices(this->thetas.size()); |
|
|
|
std::iota(indices.begin(), indices.end(), 0); |
|
|
|
@ -533,10 +452,10 @@ void polyline_geometry_data::build_as_axis(polyline_descriptor_t&& |
|
|
|
// 全局最小值:segment 内局部 t ∈ [0,1],加上段索引得到全局 t
|
|
|
|
const auto iter = std::min_element(closest_params.begin(), closest_params.end()); |
|
|
|
iter->t += static_cast<double>(std::distance(closest_params.begin(), iter)); |
|
|
|
return { |
|
|
|
return { |
|
|
|
line_closest_param_t{std::move(iter->point), iter->t, iter->is_peak_value}, |
|
|
|
iter->dist * iter->dist_sign |
|
|
|
}; |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
[[nodiscard]] bool polyline_geometry_data::pmc(const Eigen::Ref<const Eigen::Vector2d>& p, |
|
|
|
|