已知两个多边形Polygon1和Polygon2,分别由点集C1={P1,P2,...,Pm}和C2={Q1,Q2,...,Qn}表示,求这两个多边形的交集。
两个多边形相交后,其顶点要么是两个多边形边的交点,要么是在多边形内部的点。
计算两个多边形每条边之间的交点。
计算包含在多边形内部的点。
将交点和多边形内部的点,按逆时针(或顺时针)排序,得出最终的点集。
代码基本实现如下:
PolygonIntersection.h
#pragma once
#include
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
//点集排序
//若点a大于点b,即点a在点b顺时针方向,返回true,否则返回false
bool PointCompare(const cv::Point &a, const cv::Point &b, const cv::Point ¢er)
{
if (a.x >= 0 && b.x < 0)
return true;
if (a.x == 0 && b.x == 0)
return a.y > b.y;
//向量OA和向量OB的叉积
int det = (a.x - center.x) * (b.y - center.y) - (b.x - center.x) * (a.y - center.y);
if (det < 0)
return true;
if (det > 0)
return false;
//向量OA和向量OB共线,以距离判断大小
int d1 = (a.x - center.x) * (a.x - center.x) + (a.y - center.y) * (a.y - center.y);
int d2 = (b.x - center.x) * (b.x - center.y) + (b.y - center.y) * (b.y - center.y);
return d1 > d2;
}
// 顺时针方向排序
void ClockwiseSortPoints(std::vector &vPoints)
{
//计算重心
cv::Point center;
int count_size = vPoints.size();
double x = 0, y = 0;
for (int i = 0; i < count_size; i++)
{
x += vPoints[i].x;
y += vPoints[i].y;
}
center.x = (int)x / count_size;
center.y = (int)y / count_size;
//冒泡排序
for (int i = 0; i < count_size - 1; i++)
{
for (int j = 0; j < count_size - i - 1; j++)
{
if (PointCompare(vPoints[j], vPoints[j + 1], center))
{
cv::Point tmp = vPoints[j];
vPoints[j] = vPoints[j + 1];
vPoints[j + 1] = tmp;
}
}
}
return;
}
//判断点是否在多边形内部/
// The function will return YES if the point x,y is inside the polygon, or
// NO if it is not. If the point is exactly on the edge of the polygon,
// then the function may return YES or NO.
bool IsPointInPolygon(const std::vector &poly, const cv::Point &pt)
{
int i, j;
bool c = false;
int count = poly.size();
for (i = 0, j = count - 1; i < count; j = i++)
{
if ((((poly[i].y <= pt.y) && (pt.y < poly[j].y)) ||
((poly[j].y <= pt.y) && (pt.y < poly[i].y)))
&& (pt.x < (poly[j].x - poly[i].x) * (pt.y - poly[i].y) / (poly[j].y - poly[i].y) + poly[i].x))
{
c = !c;
}
}
return c;
}
///线段相交判断//
//排斥实验
bool IsRectCross(const cv::Point &p1, const cv::Point &p2, const cv::Point &q1, const cv::Point &q2)
{
bool ret = min(p1.x, p2.x) <= max(q1.x, q2.x) &&
min(q1.x, q2.x) <= max(p1.x, p2.x) &&
min(p1.y, p2.y) <= max(q1.y, q2.y) &&
min(q1.y, q2.y) <= max(p1.y, p2.y);
return ret;
}
//跨立判断
bool IsLineSegmentCross(const cv::Point &pFirst1, const cv::Point &pFirst2, const cv::Point &pSecond1, const cv::Point &pSecond2)
{
long line1, line2;
line1 = pFirst1.x * (pSecond1.y - pFirst2.y) +
pFirst2.x * (pFirst1.y - pSecond1.y) +
pSecond1.x * (pFirst2.y - pFirst1.y);
line2 = pFirst1.x * (pSecond2.y - pFirst2.y) +
pFirst2.x * (pFirst1.y - pSecond2.y) +
pSecond2.x * (pFirst2.y - pFirst1.y);
if (((line1 ^ line2) >= 0) && !(line1 == 0 && line2 == 0))
return false;
line1 = pSecond1.x * (pFirst1.y - pSecond2.y) +
pSecond2.x * (pSecond1.y - pFirst1.y) +
pFirst1.x * (pSecond2.y - pSecond1.y);
line2 = pSecond1.x * (pFirst2.y - pSecond2.y) +
pSecond2.x * (pSecond1.y - pFirst2.y) +
pFirst2.x * (pSecond2.y - pSecond1.y);
if (((line1 ^ line2) >= 0) && !(line1 == 0 && line2 == 0))
return false;
return true;
}
bool GetCrossPoint(const cv::Point &p1, const cv::Point &p2, const cv::Point &q1, const cv::Point &q2, long &x, long &y)
{
if (IsRectCross(p1, p2, q1, q2))
{
if (IsLineSegmentCross(p1, p2, q1, q2))
{
//求交点
long tmpLeft, tmpRight;
tmpLeft = (q2.x - q1.x) * (p1.y - p2.y) - (p2.x - p1.x) * (q1.y - q2.y);
tmpRight = (p1.y - q1.y) * (p2.x - p1.x) * (q2.x - q1.x) + q1.x * (q2.y - q1.y) * (p2.x - p1.x) - p1.x * (p2.y - p1.y) * (q2.x - q1.x);
x = (int)((double)tmpRight / (double)tmpLeft);
tmpLeft = (p1.x - p2.x) * (q2.y - q1.y) - (p2.y - p1.y) * (q1.x - q2.x);
tmpRight = p2.y * (p1.x - p2.x) * (q2.y - q1.y) + (q2.x - p2.x) * (q2.y - q1.y) * (p1.y - p2.y) - q2.y * (q1.x - q2.x) * (p2.y - p1.y);
y = (int)((double)tmpRight / (double)tmpLeft);
return true;
}
}
return false;
}
///线段相交结束//
//多边形交集
bool PolygonClip(const std::vector &poly1, const std::vector &poly2, std::vector &interPoly)
{
if (poly1.size() < 3 || poly2.size() < 3)
{
return false;
}
long x, y;
//计算多边形交点
int count1 = poly1.size();
int count2 = poly2.size();
for (int i = 0; i < count1; i++)
{
int poly1_next_idx = (i + 1) % count1;
for (int j = 0; j < count2; j++)
{
int poly2_next_idx = (j + 1) % count2;
if (GetCrossPoint(poly1[i], poly1[poly1_next_idx],
poly2[j], poly2[poly2_next_idx],
x, y))
{
interPoly.push_back(cv::Point(x, y));
}
}
}
//计算多边形内部点
for (int i = 0; i < count1; i++)
{
if ( IsPointInPolygon(poly2, poly1[i]) )
{
interPoly.push_back(poly1[i]);
}
}
for (int i = 0; i < count2; i++)
{
if ( IsPointInPolygon(poly1, poly2[i]) )
{
interPoly.push_back(poly2[i]);
}
}
if (interPoly.size() <= 0)
return false;
//点集排序
ClockwiseSortPoints(interPoly);
return true;
}
main.cpp
#include "PolygonIntersection.h"
int main()
{
std::vector poly1;
std::vector poly2;
// 多边形1 点集赋值
poly1.push_back(cv::Point(50,30));
poly1.push_back(cv::Point(100, 30));
poly1.push_back(cv::Point(100, 130));
poly1.push_back(cv::Point(50, 130));
// 多边形2 点集赋值
poly2.push_back(cv::Point(75, 80));
poly2.push_back(cv::Point(125, 80));
poly2.push_back(cv::Point(125, 180));
poly2.push_back(cv::Point(75, 180));
std::vector interPoly;
bool status = PolygonClip(poly1, poly2, interPoly);
cv::Mat result = cv::Mat::zeros(300, 300, CV_8UC3);
int count1 = poly1.size();
for (int i = 0; i
红色矩形框的顶点就是两个多边形相交的点
https://www.cnblogs.com/dwdxdy/p/3232110.html