2

计算几何——求简单多边形的重心可视化实现

 1 year ago
source link: https://blog.csdn.net/derbi123123/article/details/106414014
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

计算几何——求简单多边形的重心可视化实现

Luo Xiao C 于 2020-05-28 21:56:41 发布 504
分类专栏: 计算几何

这里首先给出一个公式:
平面多边形 X 可以被剖分为 n个有限的简单图形 X1,X2,…Xn,这些简单图形的重心为 Ci,面积为 Ai,那么这个平面多边形的重心点坐标为 (Cx,Cy):
在这里插入图片描述
一般来说我们可以给多边形进行三角剖分,而n个三角形的面积Ai之和即为多边形的总面积,那么这个公式可以理解为:

多边形重心横坐标 = 多边形剖分的每一个三角形重心的横坐标 * 该三角形的面积之和 / 多边形总面积
多边形重心纵坐标 = 多边形剖分的每一个三角形重心的纵坐标 * 该三角形的面积之和 / 多边形总面积

对于一个三角形,重心坐标就是((x0+x1+x2)/3,(y0+y1+y2)/3),而对于三角形的面积,我们用向量叉积来解决:S=1/2ab*sinC,这里我们采用一个外部的剖分点P。

在这里插入图片描述

三角形ABC的面积= 三角形PBC面积 + 三角形PCA面积 - 三角形PAB面积:
在这里插入图片描述
因为 向量PB 在 向量PA 的顺时针方向,所以向量PB * 向量PA < 0。
假设这四个点的坐标为:P(x0,y0), A(x1,y1), B(x2,y2), C(x3,y3),通过上面的公式进行计算,计算结果:
在这里插入图片描述
我们可以发现,计算结果中没有x0、y0的项,因为它们在计算过程中给消去了,所以我们可以得出一个结论,多边形的面积结果与剖分点的位置是无关的。那么为了计算方便,我们当然选择把这个 P点设置到原点上:现在只用两个点就行了

double curr_area = (polygon[(i + 1) % polygon.size()].x * polygon[i].y - polygon[(i + 1) % polygon.size()].y * polygon[i].x) / 2.0;

只要我们知道多边形的每一个顶点,通过原点进行剖分成多个三角形,然后通过向量的叉乘求出每个三角的面积,最后相加,就可以求出多边形的面积了。

效果:

在这里插入图片描述

最终代码:

#include <iostream>
#include <vector>
#include <map>
#include <stack>
#include <algorithm>
#include <graphics.h>
#include <time.h>
#include <conio.h>
using namespace std;
#define POINTNUM 10
struct Point
{
    double x;    // x坐标
    double y;    // y坐标
    double z;    // z坐标(默认为0,如果需要三维点则给z赋值)
	bool isExtremePoint;//是否为极点
	int next;//下一个极点坐标
    Point(double a = 0, double b = 0, double c = 0) { x = a; y = b; z = c; } // 构造函数
};
struct Triangle
{
    Point v0;
    Point v1;
    Point v2;
    bool is_plane;

    Triangle() {}; // 默认构造函数
    Triangle(Point a, Point b, Point c, bool _is_plane = false) { v0 = a; v1 = b; v2 = c; is_plane = _is_plane; }// 构造函数(默认是三角形)
};
double length(const Point& vec)//向量长度
{
    return (sqrt(pow(vec.x, 2) + pow(vec.y, 2) + pow(vec.z, 2)));
}
Point multiply(const Point& vec1, const Point& vec2)//向量叉乘
{
    Point result;

    result.x = vec1.y * vec2.z - vec2.y * vec1.z;
    result.y = vec1.z * vec2.x - vec2.z * vec1.x;
    result.z = vec1.x * vec2.y - vec2.x * vec1.y;

    return result;
}
Point sub(const Point& lhs, const Point& rhs)//向量减法
{
    Point res;

    res.x = lhs.x - rhs.x;
    res.y = lhs.y - rhs.y;
    res.z = lhs.z - rhs.z;

    return res;
}
Point div(const Point& p, double ratio)//向量除法
{
    Point res;
    
    res.x = p.x / ratio;
    res.y = p.y / ratio;
    res.z = p.z / ratio;

    return res;
}
Point add(const Point& lhs, const Point& rhs)//向量加法
{
    Point res;

    res.x = lhs.x + rhs.x;
    res.y = lhs.y + rhs.y;
    res.z = lhs.z + rhs.z;

    return res;
}
Point mul(const Point& p, double ratio)//向量乘法
{
    Point res;

    res.x = p.x * ratio;
    res.y = p.y * ratio;
    res.z = p.z * ratio;

    return res;
}
double Area2(Point a,Point b,Point c){//利用行列式求面积
	return a.x*b.y-a.y*b.x+b.x*c.y-b.y*c.x+c.x*a.y-c.y*a.x;
}
Point centerOfPolygon(const vector<Point>& polygon)
{
    double polygon_area(0.0);
    Point center;//重心
    Point origin;//原点

    for (int i = 0; i < polygon.size(); ++i)
    {
        Point curr_p = polygon[i];
        Point next_p = polygon[(i + 1) % polygon.size()];
		//double curr_area = (polygon[(i + 1) % polygon.size()].x * polygon[i].y - polygon[(i + 1) % polygon.size()].y * polygon[i].x) / 2.0;
		double curr_area=Area2(origin, curr_p, next_p);
        polygon_area += curr_area;
		//div(add(curr_p, next_p), 3)是curr_p, next_p和原点origin组成的三角形的重心
		center.x += div(add(curr_p, next_p), 3).x*curr_area;
		center.y += div(add(curr_p, next_p), 3).y*curr_area;
    }
	center.x /=polygon_area;
	center.y /=polygon_area;
    return center;
}
int main()
{
	vector<Point> points;
	initgraph(600,600);//创建一个600*600的窗口
	//实验数据
	points.push_back(Point(150,200));
	setlinecolor(RGB(255,0,0));
	setfillcolor(RGB(255,0,0));
	fillcircle(150,200,3);
	points.push_back(Point(300,200));
	setlinecolor(RGB(255,0,0));
	setfillcolor(RGB(255,0,0));
	fillcircle(300,200,3);
	points.push_back(Point(300,400));
	setlinecolor(RGB(255,0,0));
	setfillcolor(RGB(255,0,0));
	fillcircle(300,400,3);
	points.push_back(Point(150,400));
	setlinecolor(RGB(255,0,0));
	setfillcolor(RGB(255,0,0));
	fillcircle(150,400,3);
	points.push_back(Point(100,300));
	setlinecolor(RGB(255,0,0));
	setfillcolor(RGB(255,0,0));
	fillcircle(100,300,3);

	Point result=centerOfPolygon(points);
	//画出结果
	setlinecolor(RGB(0,0,255));
	setfillcolor(RGB(0,0,255));
	fillcircle(result.x,result.y,3);
	getch();
	closegraph();
	return 0;
}
newCodeMoreWhite.png

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK