1. Problem description
Two polygons Polygon1 and Polygon2 are known, represented by point sets C1={P1,P2,...,Pm} and C2={Q1,Q2,...,Qn} respectively, and the intersection of these two polygons is found.
2. Algorithm thinking
When two polygons intersect, their vertices are either the intersection of the edges of the two polygons, or are points inside the polygon.
3. Algorithm steps
Computes the intersection between each edge of two polygons.
Computes the points contained within the polygon.
Sort the intersection points and the points inside the polygon counterclockwise (or clockwise) to get the final point set.
4. Code implementation
The basic implementation of the code is as follows:
4.1 Header files
PolygonIntersection.h
#pragma once
#include <iostream>
#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<cv::Point> &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<cv::Point> &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<cv::Point> &poly1, const std::vector<cv::Point> &poly2, std::vector<cv::Point> &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;
}
4.2 Implementation of main function call
main.cpp
#include "PolygonIntersection.h"
int main()
{
std::vector<cv::Point> poly1;
std::vector<cv::Point> 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<cv::Point> 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<count1; i++)
{
cv::Point p1 = poly1[i];
cv::Point p2 = poly1[(i + 1) % count1];
cv::line(result, p1, p2, cv::Scalar(255, 0, 0), 2, 8, 0);
}
int count2 = poly2.size();
for (int i = 0; i < count2; i++)
{
cv::Point p1 = poly2[i];
cv::Point p2 = poly2[(i + 1) % count2];
cv::line(result, p1, p2, cv::Scalar(0, 255, 0), 2, 8, 0);
}
int count3 = interPoly.size();
for (int i = 0; i < count3; i++)
{
cv::Point p1 = interPoly[i];
cv::Point p2 = interPoly[(i + 1) % count3];
cv::line(result, p1, p2, cv::Scalar(0, 0, 255), 2, 8, 0);
}
return 0;
}
4.3 Results
The vertices of the red rectangle are the points where the two polygons intersect