Study - 几何计算总结

本文详细介绍了二维空间中点与向量的相关概念和运算,包括两点之间的距离计算、向量的加减乘除运算、点积与叉积及其应用,如判断向量夹角、平行性以及计算三角形面积。此外,还讨论了点与直线、线段的位置关系及点到直线的距离、投影和对称点的计算方法。
摘要由CSDN通过智能技术生成


一、点与向量

在二维坐标系中,我们可以将点的坐标转换为向量的坐标;假设坐标原点 O ( 0 , 0 ) O(0, 0) O(0,0) , 如 P ( x , y ) P(x, y) P(x,y)
P ( x , y ) = O P → , O P → = ( x , y ) P(x, y) = \overrightarrow{OP}, \overrightarrow{OP} = (x, y) P(x,y)=OP ,OP =(x,y)

1.1. 两点之间的距离

  • 二维平面的点用坐标 P ( x , y ) P(x, y) P(x,y)表示:
struct Point
{
	float x,y;
	Point(){}
	Point(float x,float y):x(x),y(y){}
};
  • 两点间的距离
  1. 用库函数hypot()计算三角形 [A,B与原点O组成的三角形] 的斜边长; 需要添加头文件#include <math.h>
float Distance(Point A, Point B)
{
    return hypot(A.x - B.x, A.y - B.y);
}
  • 直接两点间的距离公式 A ( x 1 , y 1 ) , B ( x 2 , y 2 ) A(x_1, y_1),B(x_2, y_2) A(x1,y1),B(x2,y2)
    A B ⃗ = O B ⃗ − O A ⃗ , ∣ A B ⃗ ∣ 2 = ( x 2 − x 1 ) 2 + ( y 2 − y 1 ) 2 \vec{AB} = \vec{OB} - \vec{OA} , | \vec{AB} |^2 = (x_2 - x_1)^2 + (y_2 - y_1)^2 AB =OB OA ,AB 2=(x2x1)2+(y2y1)2

struct Point
{
	float x,y;
	Point(){}
	Point(float x,float y):x(x),y(y){}
	float Distance(Point A, Point B)
	{
    	return hypot(A.x - B.x, A.y - B.y);
	}
};

1.2. 向量的运算

我们把向量也用点表示,但需注意,向量可以平移。

typedef Point Vector;

两个点确定一个向量

Point (Point A,Point B)
{
	return Point(A.x - B.x, A.y - B.y);
}

向量运算需要对运算符进行重载。

  • 加法
Point operator +(Point B)
{
	return Point(x + B.x, y + B.y);
}
  • 减法
Point operator -(Point B)
{
	return Point(x - B.x, y - B.y);
}
  • 乘法和除法用来等比例放大或缩小向量
Point operator *(float k)
{
	return Point (x * k, y * k);
}
Point operator /(float k)
{
	return Point (x / k, y / k);
}
  • 判等
    判等涉及到运算的精度,所以需要先定义浮点数的判等函数。
const float eps=1e-8;    //偏差值,有时用1e-10
int sgn(float x)		//判断x是否等于0:0为等于,1为大于,-1为小于
{
	if(abs(x)<eps)
		return 0;
	else
		return x < 0 ? -1 : 1;
}
int dcmp(float x, float y)	//判断x是否等于y:0为等于,1为大于,-1为小于
{
	if(abs(x-y)<eps)
		return 0;
	else
		return x < y ? -1 : 1;
}

所以向量的判等可以调用上面的sgn()函数或dcmp()函数。

bool operator ==(Point B)
{
	return sgn(x - B.x) == 0 && sgn(y - B.y) == 0;
}

typedef Point Vector
struct Point
{
	float x,y;
	Point(){}
	Point(float x,float y):x(x),y(y){}
	Point (Point A,Point B){return Point(A.x - B.x, A.y - B.y);}
	float Distance(Point A, Point B)
	{
    	return hypot(A.x - B.x, A.y - B.y);
	}
	const float eps=1e-8;    //偏差值,有时用1e-10
	int sgn(float x)		//判断x是否等于0:0为等于,1为大于,-1为小于
	{
		if(abs(x)<eps)
			return 0;
		else
			return x < 0 ? -1 : 1;
	}
	int dcmp(float x, float y)	//判断x是否等于y:0为等于,1为大于,-1为小于
	{
		if(abs(x - y)<eps)
			return 0;
		else
			return x < y ? -1 : 1;
	}

	Point operator +(Point B){return Point(x + B.x, y + B.y);}
	Point operator -(Point B){return Point(x - B.x, y - B.y);}
	Point operator *(double k){return Point (x * k, y * k);}
	Point operator /(double k){return Point (x / k, y / k);}
	bool operator ==(Point B){return sgn(x - B.x) == 0 && sgn(y - B.y) == 0;}
};

1.3. 向量的点积与叉积

  1. 点积
    数学公式:
    A ⋅ B = ∣ A ∣ ∣ B ∣ cos ⁡ θ = A . x ⋅ B . x + A . y ⋅ B . y \mathbf{A·B} =\left | A \right | \left | B \right | \cos \theta =A.x\cdot B.x+A.y\cdot B.y AB=ABcosθ=A.xB.x+A.yB.y
    代码如下:
double Dot(Vector A,Vector B)
{
	return A.x * B.x + A.y * B.y;
}

点积的正负可判断向量的夹角是锐角还是钝角.
点积为0代表向量垂直.


  1. 叉积
    数学公式:
    A × B = ∣ A ∣ ∣ B ∣ sin ⁡ θ = A . x ⋅ B . y − A . y ⋅ B . x \mathbf{A} \times \mathbf{B}=\left | A \right | \left | B \right | \sin \theta =A.x\cdot B.y-A.y\cdot B.x A×B=ABsinθ=A.xB.yA.yB.x

代码如下:

double Cross(Vector A,Vector B)
{
	return A.x * B.y - A.y * B.x;
}

A与B逆时针叉乘为正数,反之为负数。
如果叉积为0,则向量共线,可能同向,也可能反向。


1.4. 叉积的应用

  • 计算三角形面积
    我们知道,三角形的面积公式可表示为 S = 1 2 a b sin ⁡ C S= \dfrac{1}{2} ab \sin{C} S=21absinC
    a × b = ∣ a ∣ ∣ b ∣ s i n C a × b=|a| |b| sinC a×b=a∣∣bsinC
    所以 S = 1 2 ( a × b ) S=\dfrac{1}{2} (a×b) S=21(a×b)

  • 判断两个向量是否平行
    叉积为0代表向量平行
bool Parallel(Vector A,Vector B)
{
	return sgn(Cross(A, B)) == 0;
}

  • 向量旋转
    假如我们需要将向量 ( x , y ) (x,y) (x,y)旋转 θ θ θ度,则数学关系表达式为:
    x ′ = x c o s θ − y s i n θ , y ′ = x s i n θ + y c o s θ x' = x cosθ - y sinθ, y' = x sinθ + y cosθ x=xcosθysinθ,y=xsinθ+ycosθ
Vector Rotate(Vector A, float rad)
{
	return Vector (A.x * cos(rad) - A.y * sin(rad), A.x * sin(rad) + y *cos(rad));
}

二、点与线

2.1. 直线的表达方式

直线表达形式有很多,重点说一般式斜截式

  • 一般式: a x + b y + c = 0 ax + by + c = 0 ax+by+c=0
  • 斜截式: y = k x + b y = kx + b y=kx+b

两点确定一条直线,所以我们将直线用两个点表示

struct Line
{
    Point p1, p2;
    Line() {}
    Line(Point p1, Point p2) :p1(p1), p2(p2) {}
    Line(Point p, double angle) //0<=angle<pi
    {
        p1 = p;
        if (sgn(angle - pi / 2) == 0)
        {
            p2 = p1 + Point(0, 1);
        }
        else
        {
            p2 = (p1 + Point(1, tan(angle)));
        }
    }
    //ax+by+c=0
    Line(double a, double b, double c)     
    {
        if (sgn(a) == 0)
        {
            p1 = Point(0, -c / b);
            p2 = Point(1, -c / b);
        }
        else if (sgn(b) == 0)
        {
            p1 = Point(-c / a, 0);
            p2 = Point(-c / a, 1);
        }
        else
        {
            p1 = Point(0, -c / b);
            p2 = Point(1, (-c - a) / b);
        }
    }
};

  • 点与直线的位置关系
    我们把点与直线的关系分为点在直线的左侧右侧在直线上
int Point_line_relation(Point p,Line v)
{
	int c=sgn(Cross(p - v.p1,v.p2-v.p1));  //计算叉积的正负从而加以判断
	if (c < 0) return -1;		//p在v左侧
	if (c  >0) return 1;		//p在v右侧
	return 0;				//p在v上
}

  • 点到直线的距离
    可把点和线补成平行四边形或者三角形,这所求距离即为平行四边形或三角形的高
double Dis_point_line(Point p,Line v)
{
	return Cross(p - v.p1, v.p2 - v.p1) / distance(v.p1, v.p2);
}

  • 点在直线上的投影
double Point_line_proj(Point p, Line v)
{
	double k = Dot(v.p2 - v.p1, p - v.p1) / Len2(v.p2 - v.p1);
	//Len2为求p1p2长度的平方的函数(自定义),前面并未给出
	return v.p1 + (v.p2 - v.p1) * k;
}

  • 点关于直线的对称点
    我们先借助上面的函数球场投影,再求出对称点
Point Point_line_symmetry()
{
	Point q = Point_line_proj(p.v);
	return Point(2 * q.x - p.x, 2 * q.y - p.y);		//两点中点坐标公式变形
}

2.2. 线段的表示

typedef Line Segment;		//与直线扩展到向量类似

  • 点与线段的位置关系
    判断点P在直线v上,首先,用叉积判断是否共线,但这还不过,可能出现一下特殊情况:

此时,就需要再加一条判断条件: P P P v v v的两个端点夹角是否为钝角(180°)

bool Point_on_seg(Point p,Line v)
{
	return sgn(Cross(p - v.p1, v.p2 - v.p1)) == 0 && sgn(Dot(p - v.p1, v.p2 - v.p1)) <= 0;
}

  • 点到线段的距离
    如果p1,p2在P两侧,则最短距离为点到线段的垂直距离;
    但如果p1,p2在P同侧,则不存在垂直距离。

所以需先判断p1,p2是否在P同侧,再根据不同情况利用距离公式计算

Point Dis_point_seg(Point p,Segment v)
{
	if (sgn(Dot(v.p2 - v.p1, p - v.p1)) < 0 || sgn(Dot(p - v.p2, v.p1 - v.p2)) < 0)
		return min(Distance(p.v1, p), Distance(p.v2, p));
	return Dis_point_line(p, v);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值