计算几何摸黑(1)
作为一个刚学完向量的OJ看天选手,看了点计算几何,打算来记两笔。
首先先定义一下π的值:
// 法1:直接define
#define pi 3.14159265358979323846264338327950288
// 这样……可以说好处是直观吧
// 法2:∵cos π == -1 ∴π == arccos -1
const double pi = std::acos(-1);
最基本的构造
定义、输入输出、加法减法赋值和比较的重载和取向量的模
struct Vector // 向量类
{
double x, y;
// 构造方法
Vector(const double a = 0.0, const double b = 0.0)
: x(a), y(b) { }
friend std::istream &operator>>(std::istream &Scanner, Vector &t)
{
Scanner >> t.x >> t.y;
return Scanner;
} // 重定义cin和ifstream
friend std::ostream &operator<<(std::ostream &Printer, const Vector &t)
{
Printer << "(" << t.x << ", " << t.y << ")";
return Printer;
} // 重定义cout和ofstream
inline double getNorm()
{
return std::sqrt(x * x + y * y);
} // 求该向量的模
/* 下面是加法减法和赋值什么的 */
inline Vector operator+(const Vector &t)
{
return Vector(x + t.x, y + t.y);
}
Vector operator+=(const Vector &t)
{
x += t.x;
y += t.y;
return *this;
}
inline Vector operator-(const Vector &t)
{
return Vector(x - t.x, y - t.y);
}
Vector operator-=(const Vector &t)
{
x -= t.x;
y -= t.y;
return *this;
}
Vector operator<(const Vector &t)
{
return x < t.x || (x == t.x && y < t.y);
}
};
typedef Vector Point;
向量的点乘和叉乘
啊就这样,按照点乘和叉乘的定义写,以成员x和y来表示横纵坐标。
double mulDot(const Vector &x, const Vector &y)
{
return x.x * y.x + x.y * y.y;
}
// 向量的点乘
double mulCross(const Vector &x, const Vector &y)
{
return x.x * y.y - x.y * y.x;
}
// 向量的叉乘
向量的夹角
以下是向量点乘的定义,这个可以用求角
通过这个公式,我们可以求a和b的夹角的余弦,进而通过arccos求夹角的值。
double getAngle(Vector &x, Vector &y)
{
return std::acos(mulDot(x, y) / x.getNorm() / y.getNorm());
}
向量的旋转
通过和角公式,我们可以求将α旋转θ度后得到的向量β
所以,我们可以这样实现向量的旋转
Vector Rotate(const Vector &x, const double theta)
{
return Vector(x.x * std::cos(theta) - x.y * std::sin(theta),
x.x * std::sin(theta) + x.y * std::cos(theta));
}
单位法向量
单位法向量就是把模长归一化的法向量,其中法向量就是过此向量起点,并与该向量垂直的向量。
Vector getNormal(const Vector &t)
{
double L = t.getNorm();
return Vector(-t.y / L, t.x / L);
// 这里的原理就是把向量逆时针旋转π / 2,cos (π / 2) == 0, sin(π / 2) == 1代入Rotate(x, theta)的原理可得
}