计算机图形学的基础之一就是计算几何。它是伴随到计算机和CAD的应用而诞生的一门学科。
它的主要研究内容是几何形体的数学描述和计算机表述。它同计算机辅助几何设计有着十分密切的关系。
在1972年,福雷斯特给其下了正式定义:对几何外形信息的计算机表示,分析和综合。这里的几何外形信息指的是那些用来确定某些几何外形的离散数据点或特征多边形。 按照给定的信息,建立一定的数学模型,再通过计算机进行计算,求得其他所需的信息。这就是计算机表示。之后还需对所建立的数学模型特性及误差等进行分析、综合,以便真实的反映出几何形体。
下面给出二维几何的基础知识。
简单的说,向量(vector)就是有大小和方向的量,如速度、位移等物理量都是向量。
在平面坐标系下,向量和点一样,也用两个数x、y表示。它等于向量的起点到终点的位移。也相当于把起点平移到坐标原点后,终点的坐标。
辅助宏:
const double eps = 1e-10;
const double PI = acos(-1); // π
const double TWO_PI = 2*PI;
const int maxn = 100 + 5;
const int INF = 10000;
点的存储结构定义:
struct Point
{
double x, y;
Point(double x = 0, double y = 0):x(x), y(y){} //构造函数,方便代码编写
};
向量就是有有大小和方向的量,等于起点到终点的位移
typedef Point Vector; //从程序实现上,Vector只是Point的别名
向量+向量=向量 点+向量=点
Vector operator + (Vector A, Vector B)
{
return Vector(A.x + B.x, A.y + B.y);
}
点-点=向量
Vector operator - (Vector A, Vector B)
{
return Vector(A.x - B.x, A.y - B.y);
}
向量乘数=向量.
Vector operator * (Vector A, double p)
{
return Vector(A.x * p, A.y * p);
}
向量/数=向量.
Vector operator / (Vector A, double p)
{
return Vector(A.x / p, A.y / p);
}
三态函数,减少精度问题
int dcmp(double x)
{
if(fabs(x) < eps)
return 0;
else
return x < 0 ? -1:1;
}
向量点积.
两个向量v和w的点积等于二者长度的乘积再乘上它们夹角的余弦。夹角指的是从v逆时针到w的角度,因此当夹角大于90度时点积为负值。如果两向量垂直,点积等于0.
double Dot(Vector A, Vector B)
{
return A.x * B.x + A.y * B.y;
}
利用点积计算向量长度.
double Length(Vector A)
{
return sqrt(Dot(A, A));
}
利用点积计算向量夹角.
double Angle(Vector A, Vector B)
{
return acos(Dot(A, B) / Length(A) / Length(B));
}
叉积
两个向量v和w的叉积等于v和w组成的三角形的有向面积的两倍。顺着第一个向量v看,如果w在左边,那么v和w的叉积大于0,否则小于0.如果两个向量共线(方向相同),那么叉积等于0(三角形退化为线段)。不难发现,叉积不满足交换率,事实上,cross(v,w)=-cross(w,v)
double Cross(Vector A, Vector B)
{
return A.x*B.y - A.y*B.x;
}
求A,B,C三点组成三角形面积的2倍。
double Area2(Point A, Point B, Point C)
{
return Cross(B-A, C-A);
}
两个向量的位置关系:
第一个数是点积的符号,第二个数是叉积的符号,第一个向量v总是水平向右,另一个向量w的各种情况都包含在了图中。比如,当w的终点在下面左上方的第二象限时,点积为负但叉积为正。用(-,+)表示。
-+ 0+ ++
-0 +0
-- 0- +-
向量旋转:
向量可以绕起点旋转:
x' = xcosa - ysina
y' = xsina + ycosa
其中a为逆时针旋转的角。
rad是弧度 -rad为顺时针旋转
Vector Rotate(Vector A, double rad)
{
return Vector(A.x*cos(rad) - A.y*sin(rad), A.x*sin(rad) + A.y*cos(rad));
}
计算向量的单位法线,即左转90以后把长度归一化。
调用前请确保A不是零向量.
Vector Normal(Vector A)
{
double L;
L = Length(A);
return Vector(-A.y/L , A.x/L);
}
向量的极角,即从x轴正半轴旋转到该向量方向所需要的角度,
(x,y)的极角就是atan2(y,x);
double angle(Vector v)
{
return atan2(v.y, v.x);
}
对角进行标准化: floor()为下取整.
double NormalizeAngle(double rad)
{
return rad - TWO_PI*floor(rad / TWO_PI);
}
一点Pa,位移向量va,点Pb,位移向量vb,则相等于Pa不动,Pb位移向量为vb-va。