Files
RCS-3000/src/path_curve.cpp.backup
CaiXiang af65c2425d initial
2025-11-14 16:09:58 +08:00

227 lines
7.1 KiB
Plaintext

#include "path_curve.h"
#include <limits>
#include <algorithm>
#define _USE_MATH_DEFINES
#include <cmath>
#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<double>(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<double>(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<double>(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<PathPoint>& 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<size_t>(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<double>::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<int>(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);
}