Skip to content

Commit b7d904f

Browse files
author
corot
committed
Add rotating calipers code file
1 parent f4a1877 commit b7d904f

File tree

2 files changed

+279
-0
lines changed

2 files changed

+279
-0
lines changed

costmap_2d/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ add_library(costmap_2d
9393
src/costmap_math.cpp
9494
src/footprint.cpp
9595
src/costmap_layer.cpp
96+
src/rotating_calipers.cpp
9697
)
9798
add_dependencies(costmap_2d ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
9899
target_link_libraries(costmap_2d
Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
///////////////////////////////////////////////////////////////////////////////////////
2+
//
3+
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4+
//
5+
// By downloading, copying, installing or using the software you agree to this license.
6+
// If you do not agree to this license, do not download, install,
7+
// copy or use the software.
8+
//
9+
//
10+
// License Agreement
11+
// For Open Source Computer Vision Library
12+
//
13+
// Copyright (C) 2000, Intel Corporation, all rights reserved.
14+
// Third party copyrights are property of their respective owners.
15+
//
16+
// Redistribution and use in source and binary forms, with or without modification,
17+
// are permitted provided that the following conditions are met:
18+
//
19+
// * Redistribution's of source code must retain the above copyright notice,
20+
// this list of conditions and the following disclaimer.
21+
//
22+
// * Redistribution's in binary form must reproduce the above copyright notice,
23+
// this list of conditions and the following disclaimer in the documentation
24+
// and/or other materials provided with the distribution.
25+
//
26+
// * The name of OpenCV Foundation may not be used to endorse or promote products
27+
// derived from this software without specific prior written permission.
28+
//
29+
// This software is provided by the copyright holders and contributors "as is" and
30+
// any express or implied warranties, including, but not limited to, the implied
31+
// warranties of merchantability and fitness for a particular purpose are disclaimed.
32+
// In no event shall the OpenCV Foundation or contributors be liable for any direct,
33+
// indirect, incidental, special, exemplary, or consequential damages
34+
// (including, but not limited to, procurement of substitute goods or services;
35+
// loss of use, data, or profits; or business interruption) however caused
36+
// and on any theory of liability, whether in contract, strict liability,
37+
// or tort (including negligence or otherwise) arising in any way out of
38+
// the use of this software, even if advised of the possibility of such damage.
39+
//
40+
//
41+
42+
#include <cfloat>
43+
44+
#include <ros/ros.h>
45+
46+
#include <geometry_msgs/Point.h>
47+
using Point = geometry_msgs::Point;
48+
49+
#include <costmap_2d/footprint.h>
50+
51+
namespace costmap_2d
52+
{
53+
54+
struct MinAreaState
55+
{
56+
int bottom;
57+
int left;
58+
float height;
59+
float width;
60+
float base_a;
61+
float base_b;
62+
};
63+
64+
enum
65+
{
66+
CALIPERS_MAXHEIGHT = 0,
67+
CALIPERS_MINAREARECT = 1,
68+
CALIPERS_MAXDIST = 2
69+
};
70+
71+
/*F///////////////////////////////////////////////////////////////////////////////////////
72+
// Name: rotatingCalipers
73+
// Purpose:
74+
// Rotating calipers algorithm with some applications
75+
//
76+
// Context:
77+
// Parameters:
78+
// points - convex hull vertices ( any orientation )
79+
// n - number of vertices
80+
// mode - concrete application of algorithm
81+
// can be CV_CALIPERS_MAXDIST or
82+
// CV_CALIPERS_MINAREARECT
83+
// left, bottom, right, top - indexes of extremal points
84+
// out - output info.
85+
// In case CV_CALIPERS_MAXDIST it points to float value -
86+
// maximal height of polygon.
87+
// In case CV_CALIPERS_MINAREARECT
88+
// ((CvPoint2D32f*)out)[0] - corner
89+
// ((CvPoint2D32f*)out)[1] - vector1
90+
// ((CvPoint2D32f*)out)[0] - corner2
91+
//
92+
// ^
93+
// |
94+
// vector2 |
95+
// |
96+
// |____________\
97+
// corner /
98+
// vector1
99+
//
100+
// Returns:
101+
// Notes:
102+
//F*/
103+
104+
/* we will use usual cartesian coordinates */
105+
void rotatingCalipers(const std::vector<Point>& points)
106+
{
107+
float min_area = FLT_MAX;
108+
float max_dist = 0;
109+
char buffer[32] = {};
110+
int i, k;
111+
/* modern equivalents
112+
std::vector<float> abuf(points.size() * 3);
113+
std::vector<float>& inv_vect_length = abuf;
114+
std::vector<Point> vect(inv_vect_length + n);
115+
*/
116+
float abuf[points.size() * 3];
117+
float* inv_vect_length = abuf;
118+
Point* vect = (Point*)(inv_vect_length + points.size());
119+
int left = 0, bottom = 0, right = 0, top = 0;
120+
int seq[4] = { -1, -1, -1, -1 };
121+
122+
/* rotating calipers sides will always have coordinates
123+
(a,b) (-b,a) (-a,-b) (b, -a)
124+
*/
125+
/* this is a first base vector (a,b) initialized by (1,0) */
126+
float orientation = 0;
127+
float base_a;
128+
float base_b = 0;
129+
130+
float left_x, right_x, top_y, bottom_y;
131+
Point pt0 = points[0];
132+
133+
left_x = right_x = pt0.x;
134+
top_y = bottom_y = pt0.y;
135+
136+
for (i = 0; i < points.size(); i++)
137+
{
138+
double dx, dy;
139+
140+
if (pt0.x < left_x)
141+
left_x = pt0.x, left = i;
142+
143+
if (pt0.x > right_x)
144+
right_x = pt0.x, right = i;
145+
146+
if (pt0.y > top_y)
147+
top_y = pt0.y, top = i;
148+
149+
if (pt0.y < bottom_y)
150+
bottom_y = pt0.y, bottom = i;
151+
152+
Point pt = points[(i + 1) & (i + 1 < points.size() ? -1 : 0)];
153+
154+
dx = pt.x - pt0.x;
155+
dy = pt.y - pt0.y;
156+
157+
vect[i].x = (float)dx;
158+
vect[i].y = (float)dy;
159+
inv_vect_length[i] = (float)(1. / std::sqrt(dx * dx + dy * dy));
160+
161+
pt0 = pt;
162+
}
163+
164+
// find convex hull orientation
165+
{
166+
double ax = vect[points.size() - 1].x;
167+
double ay = vect[points.size() - 1].y;
168+
169+
for (i = 0; i < points.size(); i++)
170+
{
171+
double bx = vect[i].x;
172+
double by = vect[i].y;
173+
174+
double convexity = ax * by - ay * bx;
175+
176+
if (convexity != 0)
177+
{
178+
orientation = (convexity > 0) ? 1.f : (-1.f);
179+
break;
180+
}
181+
ax = bx;
182+
ay = by;
183+
}
184+
ROS_ASSERT(orientation != 0);
185+
}
186+
base_a = orientation;
187+
188+
/*****************************************************************************************/
189+
/* init calipers position */
190+
seq[0] = bottom;
191+
seq[1] = right;
192+
seq[2] = top;
193+
seq[3] = left;
194+
/*****************************************************************************************/
195+
/* Main loop - evaluate angles and rotate calipers */
196+
197+
/* all of edges will be checked while rotating calipers by 90 degrees */
198+
for (k = 0; k < points.size(); k++)
199+
{
200+
/* sinus of minimal angle */
201+
/*float sinus;*/
202+
203+
/* compute cosine of angle between calipers side and polygon edge */
204+
/* dp - dot product */
205+
float dp0 = base_a * vect[seq[0]].x + base_b * vect[seq[0]].y;
206+
float dp1 = -base_b * vect[seq[1]].x + base_a * vect[seq[1]].y;
207+
float dp2 = -base_a * vect[seq[2]].x - base_b * vect[seq[2]].y;
208+
float dp3 = base_b * vect[seq[3]].x - base_a * vect[seq[3]].y;
209+
210+
float cosalpha = dp0 * inv_vect_length[seq[0]];
211+
float maxcos = cosalpha;
212+
213+
/* number of calipers edges, that has minimal angle with edge */
214+
int main_element = 0;
215+
216+
/* choose minimal angle */
217+
cosalpha = dp1 * inv_vect_length[seq[1]];
218+
maxcos = (cosalpha > maxcos) ? (main_element = 1, cosalpha) : maxcos;
219+
cosalpha = dp2 * inv_vect_length[seq[2]];
220+
maxcos = (cosalpha > maxcos) ? (main_element = 2, cosalpha) : maxcos;
221+
cosalpha = dp3 * inv_vect_length[seq[3]];
222+
maxcos = (cosalpha > maxcos) ? (main_element = 3, cosalpha) : maxcos;
223+
224+
/*rotate calipers*/
225+
{
226+
// get next base
227+
int pindex = seq[main_element];
228+
float lead_x = vect[pindex].x * inv_vect_length[pindex];
229+
float lead_y = vect[pindex].y * inv_vect_length[pindex];
230+
switch (main_element)
231+
{
232+
case 0:
233+
base_a = lead_x;
234+
base_b = lead_y;
235+
break;
236+
case 1:
237+
base_a = lead_y;
238+
base_b = -lead_x;
239+
break;
240+
case 2:
241+
base_a = -lead_x;
242+
base_b = -lead_y;
243+
break;
244+
case 3:
245+
base_a = -lead_y;
246+
base_b = lead_x;
247+
break;
248+
default:
249+
throw ros::Exception("main_element should be 0, 1, 2 or 3");
250+
}
251+
}
252+
/* change base point of main edge */
253+
seq[main_element] += 1;
254+
seq[main_element] = (seq[main_element] == points.size()) ? 0 : seq[main_element];
255+
256+
/* now main element lies on edge aligned to calipers side */
257+
258+
/* find opposite element i.e. transform */
259+
/* 0->2, 1->3, 2->0, 3->1 */
260+
int opposite_el = main_element ^ 2;
261+
262+
float dx = points[seq[opposite_el]].x - points[seq[main_element]].x;
263+
float dy = points[seq[opposite_el]].y - points[seq[main_element]].y;
264+
float dist;
265+
266+
if (main_element & 1)
267+
dist = (float)fabs(dx * base_a + dy * base_b);
268+
else
269+
dist = (float)fabs(dx * (-base_b) + dy * base_a);
270+
271+
if (dist > max_dist)
272+
max_dist = dist;
273+
}
274+
275+
// out[0] = max_dist;
276+
}
277+
278+
} // namespace costmap_2d

0 commit comments

Comments
 (0)