1
+ #include " main.h"
2
+
3
+ class CP2DWrap
4
+ {
5
+ public:
6
+ cv::Mat pane;
7
+ std::vector<cv::Point > points;
8
+ std::vector<Line> shortestDistances;
9
+ };
10
+
11
+ int showWithDelay (CP2DWrap &dataWrap, int delay = 0 ) {
12
+ cv::imshow (" Closest pair 2D" , dataWrap.pane );
13
+ return cv::waitKey (delay);
14
+ }
15
+ void drawPoints (cv::Mat &pane, std::vector<cv::Point > &points, int startIndex, int endIndex, int pointType = 0 , bool clearPane = false , bool showIndex = false ) {
16
+ if (clearPane) {
17
+ pane = CL_BACKGROUND;
18
+ }
19
+ cv::Scalar color = pointType == 0 ? CL_GREENBLUE : CL_BLUE_DARK;
20
+ int radius = pointType == 0 ? 5 : 3 ;
21
+ for (int i = startIndex; i <= endIndex; i++)
22
+ {
23
+ cv::circle (pane, points[i], radius, color, -1 );
24
+ if (showIndex) {
25
+ std::stringstream ss;
26
+ ss << (i + 1 );
27
+ cv::putText (pane, ss.str (), cv::Point (points[i].x , points[i].y - 8 ), CV_FONT_HERSHEY_SIMPLEX, 0 .4f , CL_WHITE, 1 );
28
+ }
29
+ }
30
+ }
31
+ void drawPoints (CP2DWrap &dataWrap, int startIndex, int endIndex, int pointType = 0 , bool clearPane = false , bool showIndex = false ) {
32
+ drawPoints (dataWrap.pane , dataWrap.points , startIndex, endIndex, pointType, clearPane, showIndex);
33
+ }
34
+ void drawAllPoints (CP2DWrap &dataWrap, int pointType = 1 , bool clearPane = true , bool showIndex = false ) {
35
+ drawPoints (dataWrap, 0 , dataWrap.points .size () - 1 , pointType, clearPane, showIndex);
36
+ }
37
+ bool sortPointsByX (const cv::Point a, const cv::Point b) { return (a.x < b.x ); }
38
+ bool sortPointsByY (const cv::Point a, const cv::Point b) { return (a.y < b.y ); }
39
+ void drawBoundingBox (CP2DWrap &dataWrap, int startIndex, int endIndex) {
40
+ int minX = startIndex == 0 ? dataWrap.points [startIndex].x - 25 :
41
+ MIDDLE_NUM (dataWrap.points [startIndex].x , dataWrap.points [startIndex - 1 ].x );
42
+ int maxX = endIndex == dataWrap.points .size () - 1 ? dataWrap.points [endIndex].x + 25 :
43
+ MIDDLE_NUM (dataWrap.points [endIndex].x , dataWrap.points [endIndex + 1 ].x );
44
+ cv::rectangle (dataWrap.pane , cv::Point (minX, 25 ), cv::Point (maxX, dataWrap.pane .rows - 25 ), CL_GRAY);
45
+ }
46
+ void drawStoredDistances (CP2DWrap &dataWrap) {
47
+ for (int i = 0 ; i < dataWrap.shortestDistances .size (); i++)
48
+ {
49
+ doubleArrowedLine (dataWrap.pane , dataWrap.shortestDistances [i], CL_GRAY, 2 , 7 );
50
+ }
51
+ }
52
+ void drawStripBase (CP2DWrap &dataWrap, std::vector<cv::Point > &points, int middleX, float stripSize, int startIndex, int endIndex, bool showIndex = false ) {
53
+ drawAllPoints (dataWrap);
54
+ drawBoundingBox (dataWrap, startIndex, endIndex);
55
+
56
+ cv::line (dataWrap.pane , cv::Point (middleX, 15 ), cv::Point (middleX, dataWrap.pane .rows - 25 ), CL_RED_DARK);
57
+ int leftX = std::max<int >((int )(middleX - stripSize), dataWrap.points [startIndex].x );
58
+ cv::line (dataWrap.pane , cv::Point (leftX, 15 ), cv::Point (leftX, dataWrap.pane .rows - 25 ), CL_GRAY);
59
+ int rightX = std::min<int >((int )(middleX + stripSize), dataWrap.points [endIndex].x );
60
+ cv::line (dataWrap.pane , cv::Point (rightX, 15 ), cv::Point (rightX, dataWrap.pane .rows - 25 ), CL_GRAY);
61
+
62
+ drawPoints (dataWrap.pane , points, 0 , points.size () - 1 , 0 , false , showIndex);
63
+ drawStoredDistances (dataWrap);
64
+ }
65
+ void drawBase (CP2DWrap &dataWrap, int startIndex, int endIndex) {
66
+ drawAllPoints (dataWrap);
67
+ drawBoundingBox (dataWrap, startIndex, endIndex);
68
+ drawPoints (dataWrap, startIndex, endIndex);
69
+ drawStoredDistances (dataWrap);
70
+ }
71
+
72
+ /*
73
+ http://www.geeksforgeeks.org/closest-pair-of-points/
74
+ */
75
+
76
+ Line getShortestDistanceBruteForce (CP2DWrap &dataWrap, int startIndex, int endIndex) {
77
+ float smallestDistance = FLT_MAX;
78
+ int p1i = 0 , p2i = 0 ;
79
+ for (int i = startIndex; i <= endIndex; i++)
80
+ {
81
+ for (int j = i + 1 ; j <= endIndex; j++)
82
+ {
83
+ float dist = getLineLength (dataWrap.points [i], dataWrap.points [j]);
84
+
85
+ drawBase (dataWrap, startIndex, endIndex);
86
+ doubleArrowedLine (dataWrap.pane , dataWrap.points [i], dataWrap.points [j], CL_PURPLE_DARK, 2 , 7 );
87
+
88
+ if (dist < smallestDistance) {
89
+ smallestDistance = dist;
90
+ p1i = i;
91
+ p2i = j;
92
+ }
93
+
94
+ doubleArrowedLine (dataWrap.pane , dataWrap.points [p1i], dataWrap.points [p2i], CL_YELLOW, 2 , 7 );
95
+ showWithDelay (dataWrap, 500 );
96
+ }
97
+ }
98
+ dataWrap.shortestDistances .push_back (Line (dataWrap.points [p1i], dataWrap.points [p2i]));
99
+ return Line (dataWrap.points [p1i], dataWrap.points [p2i]);
100
+ }
101
+
102
+ Line getShortestDistanceWithStrip (CP2DWrap &dataWrap, std::vector<cv::Point > &stripPoints, Line closest, int middleX, float stripSize, int startIndex, int endIndex) {
103
+ drawStripBase (dataWrap, stripPoints, middleX, stripSize, startIndex, endIndex, true );
104
+ doubleArrowedLine (dataWrap.pane , closest, CL_YELLOW, 2 , 7 );
105
+ showWithDelay (dataWrap, 500 );
106
+ if (stripPoints.size () < 2 )
107
+ {
108
+ return closest;
109
+ }
110
+
111
+ std::sort (stripPoints.begin (), stripPoints.end (), sortPointsByY);
112
+
113
+ drawStripBase (dataWrap, stripPoints, middleX, stripSize, startIndex, endIndex, true );
114
+ doubleArrowedLine (dataWrap.pane , closest, CL_YELLOW, 2 , 7 );
115
+ showWithDelay (dataWrap, 500 );
116
+
117
+ float closestDistance = getLineLength (closest);
118
+ for (int i = 0 ; i < stripPoints.size () - 1 ; i++)
119
+ {
120
+ for (int j = i+1 ; j < stripPoints.size () &&
121
+ (stripPoints[j].y - stripPoints[i].y < closestDistance); j++)
122
+ {
123
+ drawStripBase (dataWrap, stripPoints, middleX, stripSize, startIndex, endIndex);
124
+ doubleArrowedLine (dataWrap.pane , stripPoints[i], stripPoints[j], CL_PURPLE_DARK, 2 , 7 );
125
+
126
+ if (getLineLength (stripPoints[i], stripPoints[j]) < closestDistance )
127
+ {
128
+ closestDistance = getLineLength (stripPoints[i], stripPoints[j]);
129
+ closest = Line (stripPoints[i], stripPoints[j]);
130
+ }
131
+
132
+ doubleArrowedLine (dataWrap.pane , closest, CL_YELLOW, 2 , 7 );
133
+ showWithDelay (dataWrap, 500 );
134
+ }
135
+ }
136
+ return closest;
137
+ }
138
+
139
+ Line getShortestDistance (CP2DWrap &dataWrap, int startIndex, int endIndex) {
140
+ drawBase (dataWrap, startIndex, endIndex);
141
+ showWithDelay (dataWrap, 500 );
142
+
143
+ if (endIndex - startIndex < 3 )
144
+ {
145
+ return getShortestDistanceBruteForce (dataWrap, startIndex, endIndex);
146
+ }
147
+
148
+ int middleIndex = ((float )(endIndex - startIndex) / 2 .0f ) + startIndex;
149
+ Line closestLeft = getShortestDistance (dataWrap, startIndex, middleIndex);
150
+ Line closestRight = getShortestDistance (dataWrap, middleIndex + 1 , endIndex);
151
+
152
+ drawBase (dataWrap, startIndex, endIndex);
153
+ showWithDelay (dataWrap, 500 );
154
+
155
+ dataWrap.shortestDistances .pop_back ();
156
+ dataWrap.shortestDistances .pop_back ();
157
+
158
+ float fromLeftDistance = getLineLength (closestLeft),
159
+ fromRightDistance = getLineLength (closestRight);
160
+
161
+ Line closestBoth = (fromLeftDistance < fromRightDistance) ? closestLeft : closestRight;
162
+ float closestBothDistance = getLineLength (closestBoth);
163
+
164
+ drawBase (dataWrap, startIndex, endIndex);
165
+ doubleArrowedLine (dataWrap.pane , closestBoth, CL_YELLOW, 2 , 7 );
166
+ showWithDelay (dataWrap, 500 );
167
+
168
+ int middleX = MIDDLE_NUM (dataWrap.points [middleIndex].x , dataWrap.points [middleIndex + 1 ].x );
169
+ std::vector<cv::Point > stripLinePoints;
170
+ for (int i = startIndex; i <= endIndex; i++)
171
+ {
172
+ if (abs (dataWrap.points [i].x - middleX) < closestBothDistance)
173
+ {
174
+ stripLinePoints.push_back (dataWrap.points [i]);
175
+ }
176
+ }
177
+ float stripHalfWidth = (float )(dataWrap.points [endIndex].x - dataWrap.points [startIndex].x ) / 2 .0f ;
178
+ if (closestBothDistance < stripHalfWidth)
179
+ {
180
+ stripHalfWidth = closestBothDistance;
181
+ }
182
+ Line finalClosest = getShortestDistanceWithStrip (dataWrap, stripLinePoints, closestBoth, middleX, stripHalfWidth, startIndex, endIndex);
183
+
184
+ dataWrap.shortestDistances .push_back (finalClosest);
185
+ return finalClosest;
186
+ }
187
+
188
+ void runClosestPair2D () {
189
+ CP2DWrap dataWrap;
190
+ dataWrap.pane = cv::Mat (500 , 1100 , CV_8UC3);
191
+ dataWrap.points = std::vector<cv::Point >(50 );
192
+
193
+ for (int i = 0 ; i < dataWrap.points .size (); i++)
194
+ {
195
+ dataWrap.points [i] = cv::Point2i (getRandom (0 , dataWrap.pane .cols - 100 ) + 50 , getRandom (0 , dataWrap.pane .rows - 100 ) + 50 );
196
+ }
197
+
198
+ drawAllPoints (dataWrap, 0 , true , true );
199
+ showWithDelay (dataWrap, 5000 );
200
+ std::sort (dataWrap.points .begin (), dataWrap.points .end (), sortPointsByX);
201
+ drawAllPoints (dataWrap, 0 , true , true );
202
+ showWithDelay (dataWrap, 1000 );
203
+
204
+ Line shortestDistance = getShortestDistance (dataWrap, 0 , dataWrap.points .size () - 1 );
205
+
206
+ drawAllPoints (dataWrap, 1 );
207
+ std::vector<cv::Point > finalPoints (2 );
208
+ finalPoints[0 ] = shortestDistance.first ;
209
+ finalPoints[1 ] = shortestDistance.second ;
210
+ drawPoints (dataWrap.pane , finalPoints, 0 , 1 );
211
+ doubleArrowedLine (dataWrap.pane , shortestDistance, CL_YELLOW, 2 , 7 );
212
+ showWithDelay (dataWrap, 0 );
213
+ }
0 commit comments