#include "path_curve.h" #include #include #define _USE_MATH_DEFINES #include #ifndef M_PI #define M_PI 3.14159265358979323846 #endif void PathCurve::generateLine(const PathPoint& start, const PathPoint& end, int num_points) { path_points_.clear(); path_points_.reserve(num_points); for (int i = 0; i < num_points; ++i) { double t = static_cast(i) / (num_points - 1); PathPoint p; p.x = start.x + t * (end.x - start.x); p.y = start.y + t * (end.y - start.y); p.theta = std::atan2(end.y - start.y, end.x - start.x); p.kappa = 0.0; // 直线曲率为0 path_points_.push_back(p); } } void PathCurve::generateCircleArc(double center_x, double center_y, double radius, double start_angle, double end_angle, int num_points) { path_points_.clear(); path_points_.reserve(num_points); double angle_diff = end_angle - start_angle; // 归一化角度差 while (angle_diff > M_PI) angle_diff -= 2.0 * M_PI; while (angle_diff < -M_PI) angle_diff += 2.0 * M_PI; for (int i = 0; i < num_points; ++i) { double t = static_cast(i) / (num_points - 1); double angle = start_angle + t * angle_diff; PathPoint p; p.x = center_x + radius * std::cos(angle); p.y = center_y + radius * std::sin(angle); // 切线方向垂直于半径方向 if (angle_diff > 0) { p.theta = angle + M_PI / 2.0; } else { p.theta = angle - M_PI / 2.0; } // 圆的曲率是半径的倒数 p.kappa = 1.0 / radius; if (angle_diff < 0) p.kappa = -p.kappa; path_points_.push_back(p); } } void PathCurve::generateCubicBezier(const PathPoint& p0, const PathPoint& p1, const PathPoint& p2, const PathPoint& p3, int num_points) { path_points_.clear(); path_points_.reserve(num_points); for (int i = 0; i < num_points; ++i) { double t = static_cast(i) / (num_points - 1); double t2 = t * t; double t3 = t2 * t; double mt = 1.0 - t; double mt2 = mt * mt; double mt3 = mt2 * mt; // 贝塞尔曲线公式 PathPoint p; p.x = mt3 * p0.x + 3.0 * mt2 * t * p1.x + 3.0 * mt * t2 * p2.x + t3 * p3.x; p.y = mt3 * p0.y + 3.0 * mt2 * t * p1.y + 3.0 * mt * t2 * p2.y + t3 * p3.y; // 一阶导数(切线方向) double dx = 3.0 * mt2 * (p1.x - p0.x) + 6.0 * mt * t * (p2.x - p1.x) + 3.0 * t2 * (p3.x - p2.x); double dy = 3.0 * mt2 * (p1.y - p0.y) + 6.0 * mt * t * (p2.y - p1.y) + 3.0 * t2 * (p3.y - p2.y); p.theta = std::atan2(dy, dx); // 二阶导数(用于计算曲率) double ddx = 6.0 * mt * (p2.x - 2.0 * p1.x + p0.x) + 6.0 * t * (p3.x - 2.0 * p2.x + p1.x); double ddy = 6.0 * mt * (p2.y - 2.0 * p1.y + p0.y) + 6.0 * t * (p3.y - 2.0 * p2.y + p1.y); // 曲率公式 κ = (x'y'' - y'x'') / (x'^2 + y'^2)^(3/2) double velocity_squared = dx * dx + dy * dy; if (velocity_squared > 1e-6) { p.kappa = (dx * ddy - dy * ddx) / std::pow(velocity_squared, 1.5); } else { p.kappa = 0.0; } path_points_.push_back(p); } } void PathCurve::setPathPoints(const std::vector& points) { path_points_ = points; // 计算每个点的切线方向和曲率 for (size_t i = 0; i < path_points_.size(); ++i) { if (i == 0 && path_points_.size() > 1) { // 第一个点 double dx = path_points_[i + 1].x - path_points_[i].x; double dy = path_points_[i + 1].y - path_points_[i].y; path_points_[i].theta = std::atan2(dy, dx); } else if (i == path_points_.size() - 1 && path_points_.size() > 1) { // 最后一个点 double dx = path_points_[i].x - path_points_[i - 1].x; double dy = path_points_[i].y - path_points_[i - 1].y; path_points_[i].theta = std::atan2(dy, dx); } else if (path_points_.size() > 2) { // 中间点 double dx = path_points_[i + 1].x - path_points_[i - 1].x; double dy = path_points_[i + 1].y - path_points_[i - 1].y; path_points_[i].theta = std::atan2(dy, dx); // 计算曲率(使用三点法) if (i > 0 && i < path_points_.size() - 1) { path_points_[i].kappa = computeCurvature( path_points_[i - 1], path_points_[i], path_points_[i + 1]); } } } } PathPoint PathCurve::getPointAt(double t) const { if (path_points_.empty()) { return PathPoint(); } if (path_points_.size() == 1) { return path_points_[0]; } // 限制t在[0, 1]范围内 t = std::max(0.0, std::min(1.0, t)); double index_float = t * (path_points_.size() - 1); size_t index = static_cast(index_float); if (index >= path_points_.size() - 1) { return path_points_.back(); } // 线性插值 double alpha = index_float - index; const PathPoint& p1 = path_points_[index]; const PathPoint& p2 = path_points_[index + 1]; PathPoint result; result.x = p1.x + alpha * (p2.x - p1.x); result.y = p1.y + alpha * (p2.y - p1.y); result.theta = p1.theta + alpha * (p2.theta - p1.theta); result.kappa = p1.kappa + alpha * (p2.kappa - p1.kappa); return result; } double PathCurve::getPathLength() const { double length = 0.0; for (size_t i = 1; i < path_points_.size(); ++i) { double dx = path_points_[i].x - path_points_[i-1].x; double dy = path_points_[i].y - path_points_[i-1].y; length += std::sqrt(dx * dx + dy * dy); } return length; } int PathCurve::findNearestPoint(double x, double y) const { if (path_points_.empty()) { return -1; } int nearest_index = 0; double min_distance = std::numeric_limits::max(); for (size_t i = 0; i < path_points_.size(); ++i) { double dx = x - path_points_[i].x; double dy = y - path_points_[i].y; double distance = std::sqrt(dx * dx + dy * dy); if (distance < min_distance) { min_distance = distance; nearest_index = static_cast(i); } } return nearest_index; } double PathCurve::computeCurvature(const PathPoint& p1, const PathPoint& p2, const PathPoint& p3) const { // 使用三点计算曲率 double dx1 = p2.x - p1.x; double dy1 = p2.y - p1.y; double dx2 = p3.x - p2.x; double dy2 = p3.y - p2.y; double cross = dx1 * dy2 - dy1 * dx2; double d1 = std::sqrt(dx1 * dx1 + dy1 * dy1); double d2 = std::sqrt(dx2 * dx2 + dy2 * dy2); if (d1 < 1e-6 || d2 < 1e-6) { return 0.0; } // Menger曲率公式 double area = std::abs(cross) / 2.0; double d3_sq = (p3.x - p1.x) * (p3.x - p1.x) + (p3.y - p1.y) * (p3.y - p1.y); double d3 = std::sqrt(d3_sq); if (d3 < 1e-6) { return 0.0; } return 4.0 * area / (d1 * d2 * d3); }