00001
00063 #ifndef MINIMAL_RECTANGLE_2D_H__
00064 #define MINIMAL_RECTANGLE_2D_H__
00065
00066 #include <Eigen/StdVector>
00067 #include <Eigen/Core>
00068 #include <iostream>
00069
00070 namespace cob_3d_mapping
00071 {
00076 class MinimalRectangle2D
00077 {
00078 private:
00079 typedef Eigen::Vector2f PT;
00080
00081 class Line
00082 {
00083 public:
00084 Line(int point, const PT& dir)
00085 : idx(point)
00086 , direction(dir)
00087 , stop(false)
00088 { }
00089
00090 float getDot(const std::vector<PT>& edges)
00091 { return fabs(direction.dot(edges[idx])); }
00092
00093 void rotate(const std::vector<PT>& edges)
00094 {
00095 direction = edges[idx];
00096 ++idx;
00097 if( idx >= edges.size() ) idx = 0;
00098 stop = true;
00099 next->makeOrthogonalTo(direction);
00100 }
00101
00102 void makeOrthogonalTo(const PT& dir)
00103 {
00104 if (stop) { stop = false; return; }
00105 direction[0] = dir[1];
00106 direction[1] = -dir[0];
00107 next->makeOrthogonalTo(direction);
00108 }
00109
00110 int idx;
00111 PT direction;
00112 bool stop;
00113 Line* next;
00114 };
00115
00116 public:
00117 MinimalRectangle2D() { }
00118
00119
00120
00121 template<typename T> void setConvexHull(const T& hull)
00122 {
00123 vertices.push_back(PT(hull[0].x, hull[0].y));
00124 PT tmp;
00125 for(int i=1; i<hull.size(); ++i)
00126 {
00127 tmp = PT(hull[i].x - hull[i-1].x, hull[i].y - hull[i-1].y);
00128 edges.push_back(tmp.normalized());
00129 vertices.push_back(PT(hull[i].x, hull[i].y));
00130 }
00131 tmp = PT(hull[0].x - hull[hull.size()-1].x, hull[0].y - hull[hull.size()-1].y);
00132 edges.push_back(tmp.normalized());
00133 }
00134
00135
00136
00137 template<typename T> void setConvexHullList(const T& hull)
00138 {
00139 vertices.push_back(PT(hull[0][0], hull[0][1]));
00140 PT tmp;
00141 for(int i=1; i<hull.size(); ++i)
00142 {
00143 tmp = PT(hull[i][0] - hull[i-1][0], hull[i][1] - hull[i-1][1]);
00144 edges.push_back(tmp.normalized());
00145 vertices.push_back(PT(hull[i][0], hull[i][1]));
00146 }
00147 tmp = PT(hull[0][0] - hull[hull.size()-1][0], hull[0][1] - hull[hull.size()-1][1]);
00148 edges.push_back(tmp.normalized());
00149 }
00150
00151 inline Line* minAngle(Line* lhs, Line* rhs)
00152 { return ( lhs->getDot(edges) < rhs->getDot(edges) ? rhs : lhs ); }
00153
00154 inline Line* minAngle(Line* i, Line* j, Line* k, Line* l)
00155 { return minAngle( minAngle(i,j), minAngle(k,l) ); }
00156
00157 inline void getIntersection(const Line& l1, const Line& l2, PT& point)
00158 { point = (vertices[l2.idx] - vertices[l1.idx]).dot(l1.direction) * l1.direction + vertices[l1.idx]; }
00159
00160
00161 inline float computeArea(const PT& p1, const PT& p2, const PT& p3)
00162 { return fabs( ((p1[0]-p2[0]) * (p3[1]-p2[1])) - ((p3[0]-p2[0]) * (p1[1]-p2[1])) ); }
00163
00164 void rotatingCalipers(PT& origin, PT& ccw, PT& cw)
00165 {
00166 float xmin = std::numeric_limits<float>::max();
00167 float ymax = - std::numeric_limits<float>::max();
00168 float xmax = - std::numeric_limits<float>::max();
00169 float ymin = std::numeric_limits<float>::max();
00170 float amin = std::numeric_limits<float>::max();
00171
00172 int i, j, k, l;
00173 for (int it=0; it<vertices.size(); ++it)
00174 {
00175 if (vertices[it][0] < xmin) { xmin = vertices[it][0]; i = it; }
00176 else if(vertices[it][0] > xmax) { xmax = vertices[it][0]; k = it; }
00177 if (vertices[it][1] < ymin) { ymin = vertices[it][1]; l = it; }
00178 else if(vertices[it][1] > ymax) { ymax = vertices[it][1]; j = it; }
00179 }
00180
00181
00182 Line vi(i, PT(0,1));
00183 Line vj(j, PT(1,0));
00184 Line vk(k, PT(0,-1));
00185 Line vl(l, PT(-1,0));
00186 vi.next = &vj;
00187 vj.next = &vk;
00188 vk.next = &vl;
00189 vl.next = &vi;
00190
00191 PT ref(0,1);
00192
00193 while(vi.direction.dot(ref) > 0)
00194 {
00195 Line* ls = minAngle(&vi, &vj, &vk, &vl);
00196 ls->rotate(edges);
00197
00198
00199
00200
00201
00202
00203 PT p1, p2, p3;
00204 getIntersection(vl, vi, p1);
00205 getIntersection(vi, vj, p2);
00206 getIntersection(vj, vk, p3);
00207 float area = computeArea(p1, p2, p3);
00208
00209
00210
00211
00212 if (area < amin)
00213 {
00214 amin = area;
00215 origin = p2;
00216 ccw = p1;
00217 cw = p3;
00218 }
00219 }
00220 }
00221
00222 private:
00223 std::vector<PT> edges;
00224 std::vector<PT> vertices;
00225 };
00226 }
00227
00228 #endif // MINIMAL_RECTANGLE_2D_H__