[AIZU ONLINE JUDGE] 计算几何 CGL_1_C

Counter-Clockwise

For given three points p0,p1,p2, print

COUNTER_CLOCKWISE

if p0,p1,p2 make a counterclockwise turn (1),

CLOCKWISE

if p0,p1,p2 make a clockwise turn (2),

ONLINE_BACK

if p2 is on a line p2,p0,p1 in this order (3),

ONLINE_FRONT

if p2 is on a line p0,p1,p2 in this order (4),

ON_SEGMENT

if p2 is on a segment p0p1 (5).

Input

xp0 yp0 xp1 yp1
q
xp20 yp20
xp21 yp21
...
xp2q−1 yp2q−1

In the first line, integer coordinates of p0 and p1 are given. Then, q queries are given for integer coordinates of p2.

Output

For each query, print the above mentioned status.

Constraints

  • 1 ≤ ≤ 1000
  • −10000 ≤ xiy≤ 10000
  • p0 and p1 are not identical.

Sample Input 1

0 0 2 0
2
-1 1
-1 -1

Sample Output 1

COUNTER_CLOCKWISE
CLOCKWISE

Sample Input 2

0 0 2 0
3
-1 0
0 0
3 0

Sample Output 2

ONLINE_BACK
ON_SEGMENT
ONLINE_FRONT

题目大意:

给定多组数据,分别判断每组中的两个向量对应 5种不同的位置关系(如图)中的哪一种,并输出该种关系对应的名称。

题解:

牵扯到了如何判断向量共线,如何求向量模长以及如何求解两个向量夹角大于0 / 小于0 的知识点

根据叉乘的意义:

\vec{A}\times \vec{B} = \left | A \right | \cdot \left |B \right |\cdot \sin \theta

A, B 夹角大于 0  小于 180° 时 结果为正,此时 B向量 在 A向量 的 “上方” 也就是左边

同理可知当叉乘结果小于0  B向量 在 A向量的 “下方”,也就是右边。

而点乘的结果可以用于判断是否在反方向

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>

using namespace std;

const double eps = 1e-10;

int sign(double x)
{
	if (fabs(x) < eps) return 0;
	else if (x > 0) return 1;
	return -1;
}

struct Point
{
	double x, y;

	Point(double x = 0, double y = 0) : x(x), y(y) { }

	Point operator + (const Point& t) { return Point(x + t.x, y + t.y); }
	Point operator - (const Point& t) { return Point(x - t.x, y - t.y); }
	Point operator * (const double t) { return Point(x * t, y * t); }
	Point operator / (const double t) { return Point(x / t, y / t); }
	bool operator == (const Point& t) { return !sign(x - t.x) && !sign(y - t.y); }
};

typedef Point Vector;
Point O, A, B;

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

double dot(Vector A, Vector B)
{
	return A.x * B.x + A.y * B.y;
}

bool to_left_test(Vector A, Vector B)   // A 是否在 B 的左边
{
	return cross(B, A) > 0;
}

double norm(Vector A)
{
	return sqrt(dot(A, A));
}

int main()
{
	cin >> O.x >> O.y >> A.x >> A.y;

	int p;
	cin >> p;

	while (p--)
	{
		cin >> B.x >> B.y;

		Vector v1 = B - O, v2 = A - O;

		if (sign(cross(B - O, A - O)) == 0)
		{
			if (dot(v1, v2) < -eps) puts("ONLINE_BACK");
			else if (norm(v1) <= norm(v2)) puts("ON_SEGMENT");
			else puts("ONLINE_FRONT");
		}
		else
		{
			if (to_left_test(v1, v2))puts("COUNTER_CLOCKWISE");
			else puts("CLOCKWISE");
		}
	}


	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值