Skip to content

Commit 9cbf4f3

Browse files
committed
Point in Polygon and Convex Hull
1 parent 6f0da44 commit 9cbf4f3

8 files changed

+455
-0
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@
33

44
# User-specific files
55
*.suo
6+
*.sln
7+
*.props
68
*.user
79
*.userosscache
810
*.sln.docstates
11+
*.vcxproj
12+
*.filters
913

1014
# User-specific files (MonoDevelop/Xamarin Studio)
1115
*.userprefs

AGU/convexHull.cpp

+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
#include "main.h"
2+
3+
struct ConvexHullPoint
4+
{
5+
cv::Point point;
6+
bool toProcess;
7+
};
8+
9+
void drawPoints(cv::Mat &pane, std::vector<ConvexHullPoint> &points, cv::Point *activePoint = NULL) {
10+
for (int i = 0; i < points.size(); i++)
11+
{
12+
cv::circle(pane, points[i].point, points[i].toProcess ? 2 : 5, points[i].toProcess ? CL_BLUE : CL_RED , -1);
13+
if (activePoint != NULL && points[i].point == *activePoint)
14+
{
15+
cv::circle(pane, points[i].point, 8, CL_RED, 1);
16+
}
17+
/*std::stringstream ss;
18+
ss << i;
19+
cv::putText(pane, ss.str(), cv::Point(polygon[i].x - 10, polygon[i].y - 10), CV_FONT_HERSHEY_SIMPLEX, 0.4f, CL_WHITE, 1);*/
20+
}
21+
}
22+
void drawLineToFindSmallestAngle(cv::Mat &pane, cv::Point sourcePoint, cv::Point destPoint, bool textBeforeEndpoint = false) {
23+
24+
Line line = getInfiniteLinePoints(pane.cols, pane.rows, sourcePoint, destPoint, true);
25+
cv::line(pane, line.first, line.second, CL_RED_DARK);
26+
27+
Vec2f lineVector = getNormalizedVector(destPoint - sourcePoint);
28+
cv::Point2f perpVector = getPerpendicularVector(lineVector);
29+
30+
//cv::line(pane, textPosition, cv::Point(textPosition.x + perpVector.x * 10, textPosition.y + perpVector.y * 10), CL_WHITE);
31+
32+
cv::putText(pane, "p", cv::Point(
33+
destPoint.x + (lineVector.x * 40 * (textBeforeEndpoint ? -1 : 1)) + perpVector.x * 15,
34+
destPoint.y + (lineVector.y * 40 * (textBeforeEndpoint ? -1 : 1)) + perpVector.y * 15
35+
), CV_FONT_HERSHEY_SIMPLEX, 0.6f, CL_GREEN, 1);
36+
37+
}
38+
void drawHullPolygon(cv::Mat &pane, std::vector<cv::Point> &polygon, bool close = false) {
39+
if (polygon.size() < 2) { return; }
40+
int i = 0;
41+
for (; i < polygon.size() - 1; i++)
42+
{
43+
cv::line(pane, polygon[i], polygon[i + 1], CL_YELLOW_DARK, 3);
44+
}
45+
if (close) {
46+
cv::line(pane, polygon[i], polygon[0], CL_YELLOW_DARK, 3);
47+
}
48+
}
49+
50+
int getMostLeftPointIndex(std::vector<ConvexHullPoint> &points) {
51+
int minX = INT_MAX;
52+
int index = 0;
53+
for (int i = 0; i < points.size(); i++) {
54+
if (points[i].point.x < minX)
55+
{
56+
minX = points[i].point.x;
57+
index = i;
58+
}
59+
}
60+
return index;
61+
}
62+
int getPointIndexWithMinimumAngle(std::vector<ConvexHullPoint> &points, cv::Point startLine, cv::Point endLine, cv::Point countInPoint, cv::Mat &pane, std::vector<cv::Point> &polygon) {
63+
Vec2f lineVector = getNormalizedVector(startLine, endLine);
64+
float angleCos = -10;
65+
int index = 0;
66+
int wait = polygon.size() < 3 ? 100 : 20;
67+
for (int i = 0; i < points.size(); i++)
68+
{
69+
if (points[i].point == startLine || points[i].point == endLine) {
70+
continue;
71+
}
72+
Vec2f pointVector = getNormalizedVector(points[i].point - countInPoint);
73+
float angle = lineVector.dot(pointVector);
74+
75+
pane = pane = CL_BACKGROUND;
76+
drawHullPolygon(pane, polygon);
77+
//cv::line(pane, startLine, cv::Point(startLine.x + lineVector.x * 45, startLine.y + lineVector.y * 45), CL_WHITE);
78+
//cv::line(pane, countInPoint, cv::Point(countInPoint.x + pointVector.x * 45, countInPoint.y + pointVector.y * 45), CL_WHITE);
79+
drawLineToFindSmallestAngle(pane, startLine, endLine, polygon.size() == 1);
80+
cv::line(pane, countInPoint, points[i].point, CL_GRAY);
81+
82+
std::cout << "Points: start/doIn/end " << startLine << "/" << countInPoint << "/" << points[i].point << "\n\tlineVec/pointVec " << lineVector << "/" << pointVector << " - angle" << angle;
83+
if (angle > angleCos)
84+
{
85+
angleCos = angle;
86+
index = i;
87+
std::cout << " Change to " << i;
88+
}
89+
90+
cv::line(pane, countInPoint, points[index].point, CL_YELLOW, 2);
91+
drawPoints(pane, points, &countInPoint);
92+
cv::circle(pane, points[i].point, 5, CL_WHITE, 1);
93+
94+
cv::imshow("Convex hull", pane);
95+
cv::waitKey(wait);
96+
97+
std::cout << "\n";
98+
99+
}
100+
101+
std::cout << "Final angle" << angleCos << " Point index " << index << "\n\n";
102+
103+
cv::waitKey(wait);
104+
105+
return index;
106+
}
107+
108+
void runConvexHull() {
109+
110+
cv::Mat pane(500, 700, CV_8UC3);
111+
int padding = 50;
112+
int maxWidth = pane.cols - 2 * padding;
113+
int maxHeight = pane.rows - 2 * padding;
114+
115+
std::vector<ConvexHullPoint> points(50);
116+
std::vector<cv::Point> polygon;
117+
for (int i = 0; i < points.size(); i++)
118+
{
119+
points[i] = ConvexHullPoint{ cv::Point(
120+
(int)(maxWidth * getRandom()) + padding,
121+
(int)(maxHeight * getRandom()) + padding
122+
), true };
123+
}
124+
pane = pane = CL_BACKGROUND;
125+
drawPoints(pane, points);
126+
cv::imshow("Convex hull", pane);
127+
cv::waitKey(0);
128+
// Get start point
129+
int startIndex = getMostLeftPointIndex(points);
130+
points[startIndex].toProcess = false;
131+
cv::Point prevPoint = points[startIndex].point;
132+
pane = pane = CL_BACKGROUND;
133+
drawPoints(pane, points);
134+
cv::imshow("Convex hull", pane);
135+
cv::waitKey(1000);
136+
polygon.push_back(points[startIndex].point);
137+
138+
// Get next point
139+
int nextIndex = getPointIndexWithMinimumAngle(points, prevPoint, cv::Point(points[startIndex].point.x, pane.rows), prevPoint, pane, polygon);
140+
cv::Point nextPoint = points[nextIndex].point;
141+
points[nextIndex].toProcess = false;
142+
polygon.push_back(points[nextIndex].point);
143+
pane = pane = CL_BACKGROUND;
144+
drawHullPolygon(pane, polygon);
145+
drawPoints(pane, points);
146+
cv::imshow("Convex hull", pane);
147+
//cv::waitKey(0);
148+
149+
for (int i = 0; nextIndex != startIndex ; i++)
150+
{
151+
//drawLineToFindSmallestAngle(pane, prevPoint, nextPoint);
152+
cv::imshow("Convex hull", pane);
153+
nextIndex = getPointIndexWithMinimumAngle(points, prevPoint, nextPoint, nextPoint, pane, polygon);
154+
prevPoint = nextPoint;
155+
nextPoint = points[nextIndex].point;
156+
points[nextIndex].toProcess = false;
157+
polygon.push_back(points[nextIndex].point);
158+
159+
/*drawPoints(pane, points);
160+
cv::imshow("Convex hull", pane);
161+
cv::waitKey(5);*/
162+
}
163+
164+
pane = pane = CL_BACKGROUND;
165+
drawHullPolygon(pane, polygon, true);
166+
drawPoints(pane, points);
167+
cv::imshow("Convex hull", pane);
168+
cv::waitKey(0);
169+
170+
}

AGU/main.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include "main.h"
2+
3+
void runConvexHull();
4+
void runPointInsidePolygonCheck();
5+
6+
int main(){
7+
srand(time(NULL));
8+
9+
runPointInsidePolygonCheck();
10+
runConvexHull();
11+
12+
return 0;
13+
}

AGU/main.h

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#pragma once
2+
3+
#include <stdio.h>
4+
#include <tchar.h>
5+
#include <ctime>
6+
#include <algorithm>
7+
#include <opencv2/opencv.hpp>
8+
9+
#define _USE_MATH_DEFINES
10+
#include <math.h>
11+
12+
#include "utils.h"

AGU/pointInsidePolygon.cpp

+144
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
#include "main.h"
2+
3+
void showIm(cv::Mat pane) {
4+
cv::imshow("Point inside polygon", pane);
5+
}
6+
7+
void printStep(int startIndex, int currentIndex, int endIndex, int direction = 0) {
8+
std::string format = "start %d, current %d, end %d = direction %s\n";
9+
if (direction == 0) {
10+
format = "start %d, current %d, end %d\n";
11+
}
12+
std::printf(format.c_str(), startIndex, currentIndex, endIndex, direction < 0 ? "left" : "right");
13+
}
14+
15+
void drawPoint(cv::Mat &pane, cv::Point &point, bool main = false, bool highlight = false) {
16+
cv::Scalar color = CL_BLUE;
17+
if (main) {
18+
color = CL_RED_DARK;
19+
}
20+
if (highlight)
21+
{
22+
color = CL_BLUE_DARK;
23+
}
24+
cv::circle(pane, point, highlight || main ? 6 : 3, color, -1);
25+
}
26+
27+
void drawArrowedLine(cv::Mat &pane, cv::Point &p1, cv::Point &p2, int directionLabel) {
28+
cv::Point middle = getLineMiddle(p1, p2);
29+
cv::Point2f perpVector = getNormalizedVector(getPerpendicularVector(p1, p2, directionLabel > 0));
30+
//cv::line(pane, middle, cv::Point(middle.x + perpVector.x * 10, middle.y + perpVector.y * 10), CL_WHITE);
31+
cv::putText(pane, directionLabel < 0 ? "L" : "R", cv::Point(middle.x + perpVector.x * 15, middle.y + perpVector.y * 15), CV_FONT_HERSHEY_SIMPLEX, 0.4f, CL_GREEN_DARK, 1);
32+
cv::arrowedLine(pane, p1, p2, CL_GREEN_DARK, 2, 8, 0, 0.03);
33+
}
34+
35+
void drawLines(cv::Mat &pane, std::vector<cv::Point> &polygon) {
36+
int i = 0;
37+
for (; i < polygon.size() - 1; i++)
38+
{
39+
cv::line(pane, polygon[i], polygon[i + 1], CL_YELLOW);
40+
}
41+
cv::line(pane, polygon[i], polygon[0], CL_YELLOW);
42+
}
43+
44+
void drawTitledPoints(cv::Mat &pane, std::vector<cv::Point> &polygon, cv::Point &searchPoint) {
45+
for (int i = 0; i < polygon.size(); i++)
46+
{
47+
drawPoint(pane, polygon[i]);
48+
std::stringstream ss;
49+
ss << i;
50+
cv::putText(pane, ss.str(), cv::Point(polygon[i].x - 10, polygon[i].y- 10 ), CV_FONT_HERSHEY_SIMPLEX, 0.4f, CL_WHITE, 1);
51+
}
52+
drawPoint(pane, searchPoint, true);
53+
}
54+
55+
void runPointInsidePolygonCheck() {
56+
int width = 600, height = 400;
57+
cv::Mat pane(height, width, CV_8UC3);
58+
59+
std::vector<cv::Point> polygon;
60+
cv::Point searchPoint;
61+
62+
searchPoint = cv::Point(400, 180);
63+
//searchPoint = cv::Point(350, 40);
64+
//searchPoint = cv::Point(130, 310);
65+
66+
polygon.push_back(cv::Point(60, 200));
67+
polygon.push_back(cv::Point(200, 80));
68+
polygon.push_back(cv::Point(280, 60));
69+
polygon.push_back(cv::Point(450, 100));
70+
polygon.push_back(cv::Point(570, 220));
71+
polygon.push_back(cv::Point(550, 300));
72+
polygon.push_back(cv::Point(490, 350));
73+
polygon.push_back(cv::Point(230, 370));
74+
polygon.push_back(cv::Point(120, 320));
75+
76+
pane = pane = CL_BACKGROUND;
77+
drawLines(pane, polygon);
78+
drawTitledPoints(pane, polygon, searchPoint);
79+
showIm(pane);
80+
cv::waitKey(10000);
81+
82+
int startIndex = 0, currentIndex, endIndex = polygon.size() - 1;
83+
int direction = 0;
84+
while (abs(endIndex - startIndex) > 1)
85+
{
86+
pane = pane = CL_BACKGROUND;
87+
drawLines(pane, polygon);
88+
89+
currentIndex = (endIndex - startIndex + 1) / 2 + startIndex;
90+
direction = getPointSideToLine(polygon[0], polygon[currentIndex], searchPoint);
91+
printStep(startIndex, currentIndex, endIndex, direction);
92+
93+
drawArrowedLine(pane, polygon[0], polygon[currentIndex], direction);
94+
drawTitledPoints(pane, polygon, searchPoint);
95+
showIm(pane);
96+
cv::waitKey(2000);
97+
98+
if (direction < 0)
99+
{
100+
endIndex = currentIndex;
101+
}
102+
else
103+
{
104+
startIndex = currentIndex;
105+
}
106+
}
107+
std::printf("Final: ");
108+
printStep(startIndex, currentIndex, endIndex);
109+
110+
cv::Point p2 = (direction > 0 ? polygon[currentIndex] : polygon[startIndex]),
111+
p3 = (direction > 0 ? polygon[endIndex] : polygon[currentIndex]);
112+
bool isInsidePolygon = isPointInsideTriangle(polygon[0], p2, p3, searchPoint);
113+
114+
pane = pane = CL_BACKGROUND;
115+
drawLines(pane, polygon);
116+
drawTitledPoints(pane, polygon, searchPoint);
117+
drawPoint(pane, polygon[0], false, true);
118+
drawPoint(pane, p2, false, true);
119+
drawPoint(pane, p3, false, true);
120+
showIm(pane);
121+
cv::waitKey(1500);
122+
123+
drawArrowedLine(pane, polygon[0], p2, getPointSideToLine(polygon[0], p2, searchPoint));
124+
showIm(pane);
125+
cv::waitKey(1500);
126+
127+
drawArrowedLine(pane, p2, p3, getPointSideToLine(p2, p3, searchPoint));
128+
showIm(pane);
129+
cv::waitKey(1500);
130+
131+
drawArrowedLine(pane, p3, polygon[0], getPointSideToLine(p3, polygon[0], searchPoint));
132+
showIm(pane);
133+
if (isInsidePolygon) {
134+
std::printf("\nPoint is inside polygon - on the same side of all triangle edges");
135+
}
136+
else
137+
{
138+
std::printf("\nPoint is NOT inside polygon - NOT on the same side of all triangle edges");
139+
}
140+
cv::waitKey(0);
141+
142+
return;
143+
144+
}

0 commit comments

Comments
 (0)