- 首先实现下面两个功能:
- 计算点到直线的距离;
- 计算点到线段的距离;
- 然后列举当前代码中 C++ 11 代码规范(希望能养成良好习惯);
C++ 代码实现:
#include <iostream>
#include <cmath>
namespace {
constexpr double kEps = 1e-6;
} // namespace
class Vec2d {
public:
Vec2d() = default;
Vec2d(double x, double y) : x_(x), y_(y) {}
double x() const {
return x_;
}
double y() const {
return y_;
}
Vec2d operator - (const Vec2d& others) const { // 重载减法运算符
return {x_ - others.x(), y_ - others.y()};
}
double Length() const {
return std::sqrt(x_ * x_ + y_ * y_);
}
double CrossProd(const Vec2d &other) const { // 叉乘
return x_ * other.y() - y_ * other.x();
}
double PotProd(const Vec2d &other) const { // 点乘
return x_ * other.x() + y_ * other.y();
}
private:
double x_{0.0};
double y_{0.0};
};
bool CalPointToSegDis(const Vec2d& p, const Vec2d& a,
const Vec2d& b, double* const dis) {
#if 0 // 功能1:计算点到直线的距离
if((a - b).Length() < kEps) {
return false;
}
*dis = std::abs((p - a).CrossProd(p - b)) / (a - b).Length(); // 距离 = 平行四边形面积 / 底边
return true;
#else // 功能2:计算点到线段的距离
const Vec2d ab = b - a;
const Vec2d ap = p - a;
if (ab.Length() < kEps) {
*dis = ap.Length(); // a b 两点重合
return true;
}
const double t = ap.PotProd(ab) / (ab.Length() * ab.Length()); // 计算投影比例 t
if (t < 0.0) {
*dis = ap.Length();
} else if (t > 1.0) {
*dis = (p - b).Length();
} else {
*dis = std::abs(ap.CrossProd(ab)) / ab.Length();
}
return true;
#endif
}
int main() {
Vec2d point{-3.0, 3.0};
Vec2d segment_start{0.0, 0.0};
Vec2d segment_end{2.0, 0};
double distance = 0.0;
if(!CalPointToSegDis(point, segment_start, segment_end, &distance)) {
std::cout << "Error : The Segment is a point" << std::endl;
return -1;
}
std::cout << "The distance from a point to a straight line is : "
<< distance << std::endl;
return 0;
}
C++ 11 代码规范:
列表初始化
-
普通构造函数调用:
Vec2d point(3.0, 5.1961524); -
列表初始化:
Vec2d point{3.0, 5.1961524}; // 调用构造函数 Vec2d(double x, double y)
-
优点:
更安全:
- 避免了窄化转换(narrowing conversion)问题。例如,不允许用花括号初始化将浮点数隐式转换为整数。
int a{3.5}; // 错误:编译时错误,避免浮点数到整数的窄化转换- 传统构造函数调用
int a = 3.5;会直接截断浮点数,产生潜在的错误。支持统一初始化:
- 花括号
{}既可用于类对象初始化,也可以用于内置类型、结构体或数组的初始化。简洁易读:
- 和构造函数调用
Vec2d point(3.0, 5.1961524);相比,列表初始化的形式更简单,并且不容易混淆为函数声明。
传参中的指针常量
指针常量,不能更改指向,可以更改指向内容;
bool CalPointToSegDis(const Vec2d& p, const Vec2d& a,
const Vec2d& b, double* const dis) {}
重载减法运算符
Vec2d operator - (const Vec2d& others) const {
return {x_ - others.x(), y_ - others.y()};
}
constexpr
使用 constexpr 保证这个常量的值在编译时确定,提高性能和安全性,可以减少运行时的计算量;
constexpr double kEps = 1e-6;
匿名命名空间
通过匿名命名空间,限制它的作用范围在当前文件,避免在其他文件中出现命名冲突;
namespace {
constexpr double kEps = 1e-6;
} // namespace
比较浮点数时的精度控制
double kEps = 1e-6;
&spm=1001.2101.3001.5002&articleId=142899066&d=1&t=3&u=6ab621a6b101426a8adad0acae62cb20)
6553

被折叠的 条评论
为什么被折叠?



