当前位置:   article > 正文

判断多边形的顺逆性_判断多边形的顺逆性_无序线段的形成的封闭多边形,如何找出顺序

判断多边形的顺逆性_无序线段的形成的封闭多边形,如何找出顺序

前言

如果文中数学公式或符号出现乱码,可访问判断多边形的顺逆性

给定一个多边形的所有坐标,如何判断该多边形的点的排列的顺逆性呢?

本文将介绍两种方法解决该问题,并通过C++算法实现。

一、格林公式

设闭区域 D 由分段光滑的简单曲线 L 围成,函数 P(x,y)及 Q(x,y)在 D 上有一阶连续偏导数,则有

格林公式

其中L是D的取正向的边界曲线。

在该公式中取 P ( x , y ) = y P(x,y)=y P(x,y)=y, Q ( x , y ) = 0 Q(x, y)=0 Q(x,y)=0,带入上式可得 − ∬ D d x d y = ∬ y d x -\iint_Ddxdy=\iint ydx Ddxdy=ydx,即 ∬ D d x d y = − ∬ y d x \iint_Ddxdy=-\iint ydx Ddxdy=ydx,左边就代表区域D的面积(记为S),右边 ∬ y d x \iint ydx ydx代表沿着多边形一圈的曲线积分,注意有个负号。

考虑多变形的一条边 P i ( x i , y y ) , P i + 1 ( x i + 1 , y i + 1 ) P_i(x_i,y_y), P_{i+1}(x_{i+1},y_{i+1}) Pi(xi,yy),Pi+1(xi+1,yi+1),参数方程为:

{ x = ( x i + 1 − x i ) t + x i y = ( y i + 1 − y i ) t + y i

{x=(xi+1xi)t+xiy=(yi+1yi)t+yi
{x=(xi+1xi)t+xiy=(yi+1yi)t+yi

带入 S = − ∬ x i x i + 1 y d x S=-\iint{^{x_{i+1}}_{x_i}}ydx S=xixi+1ydx 可得 S i = − 1 2 ( y i + 1 + y i ) ( x i + 1 − x i ) S_i=-\frac {1}{2}(y_{i+1}+y_i)(x_{i+1}-x_i) Si=21(yi+1+yi)(xi+1xi),每条边都可以求出一个 S i S_i Si,求和可以得出多边形的带符号面积,若为正,说明多边形的点为逆时针排列,为负,则说明为顺时针排列。

//自定义 MyPoint类
typedef struct MYPOINT {
	double x;
	double y;
	MYPOINT(double xx, double yy) :x(xx), y(yy) {}
} MyPoint;

bool IsClockwise_1(vector<MyPoint> pts) {
	double d = 0;
	const size_t size = pts.size();
	for (size_t i = 0; i < size - 1; i++) {
		d += -0.5 * (pts[i + 1].y + pts[i].y) * (pts[i + 1].x - pts[i].x);
	}
	
    // 注意,这个容易忽略!最后一个点与第一个点构成的边
	d += -0.5 * (pts[0].y + pts[size - 1].y) * (pts[0].x - pts[size - 1].x);

	if (d < 0)
		return true;
	else
		return false;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

二、叉积法

两个向量的叉积具有正负性,可以判断由第一个向量旋转到第二个向量是顺时针还是逆时针(旋转角 ≤ 18 0 o \leq 180^o 180o)。那么能不能用此方法判断多边形的正负性呢?

考虑下图的情形,多边形ABCDEFG和多边形A′B′C′D′E′F′G′。

Polygon

  1. 对于B点而言,向量 B A ⃗ \vec{BA} BA B C ⃗ \vec{BC} BC B A ⃗ × B C ⃗ \vec{BA} \times \vec{BC} BA ×BC 结果为负数,多边形ABCDEFG的点为顺时针排列。

  2. 对于B′点而言,向量 B ′ A ′ ⃗ × B ′ C ′ ⃗ \vec{B′A′} \times \vec{B′C′} BA ×BC 的结果也为负数,但是四边形A′B′C′D′E′F′G′为逆时针排列。

因此判断B点与相邻两点构成向量的叉积的正负是不可行的,但是有没有哪个点(或者说,哪种类型的点)是符合要求的呢?

现在考虑多边形ABCDEFG最左侧的点F 和 多边形A′B′C′D′E′F′G′最左侧的点E′,

Polygon

  1. 对F点而言, F E ⃗ × F G ⃗ \vec{FE} \times \vec{FG} FE ×FG ,结果为正数,多边形的点为顺时针排列。

  2. 对E′点而言, E ′ D ′ ⃗ × E ′ F ′ ⃗ \vec{E′D′} \times \vec{E′F′} ED ×EF ,结果为负数,多边形的点为逆时针排列。

可以证明,使用多变形的左(右、上、下)侧的一个点,该点与前一个点构成的向量(记为 a ⃗ \vec{a} a ),与后一个点构成的向量(记为 b ⃗ \vec{b} b ),判断 a ⃗ × b ⃗ \vec{a} \times \vec{b} a ×b 的正负,若为正,说明多边形的点为顺时针排列,若为负则为逆时针排列。

bool IsClockwise_2(vector<MyPoint> pts)
{
	//1. 找到横坐标最小的点,该点一定是多边形的最左侧的点,且为凸点
	double min_x = pts[0].x;
	int min_idx = 0;
	size_t size = pts.size();
	for (size_t i = 1; i < size; i++) {
		if (pts[i].x < min_x) {
			min_x = pts[i].x;
			min_idx = i;
		}
	}

	//2. 判断该点与前一个点构成的向量 和 与后一个点构成的向量的叉积的正负
	//2.1 获取该点前一个点和后一个点的下标
	int prev_min_idx = 0, next_min_idx = 0;
	if (0 == min_idx) {		//如果该点是第一个点
		prev_min_idx = size - 1;
		next_min_idx = min_idx + 1;
	}
	else if (size - 1 == min_idx) {	//如果该点是最后一个点
		prev_min_idx = min_idx - 1;
		next_min_idx = 0;
	}
	else {
		prev_min_idx = min_idx - 1;
		next_min_idx = min_idx + 1;
	}

	//2.2 计算叉积
	double cross = (pts[prev_min_idx].x - pts[min_idx].x) * (pts[next_min_idx].y - pts[min_idx].y) -
		(pts[next_min_idx].x - pts[min_idx].x) * (pts[prev_min_idx].y - pts[min_idx].y);

	if (cross > 0)
		return true;
	else 
		return false;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

The End

如有任何疑问,可联系 leopard.c@outlook.com

Thanks for reading!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/42533
推荐阅读
相关标签
  

闽ICP备14008679号