00001 
00059 
00060 
00061 
00062 
00063 
00064 
00065 
00066 #ifndef POLYGON_H_
00067 #define POLYGON_H_
00068 
00069 #include "sub_structures.h"
00070 #include <eigen3/Eigen/Dense>
00071 #include <unsupported/Eigen/NonLinearOptimization>
00072 #include <cob_3d_mapping_msgs/CurvedPolygon.h>
00073 #include <polypartition/polypartition.h>
00074 
00075 namespace Segmentation
00076 {
00077 
00078 #ifdef USE_BOOST_POLYGONS_
00079 #include <boost/polygon/polygon.hpp>
00080 #include <boost/geometry.hpp>
00081 #include <boost/geometry/geometries/geometries.hpp>
00082 #include <boost/geometry/multi/geometries/multi_polygon.hpp>
00083 #include <boost/geometry/algorithms/envelope.hpp>
00084 #include <boost/geometry/geometries/polygon.hpp>
00085 #include <boost/geometry/geometries/point_xy.hpp>
00086   using namespace boost::polygon::operators;
00087 
00088   typedef boost::polygon::polygon_with_holes_data<int> BoostPolygon;
00089   typedef BoostPolygon::point_type BoostPoint;
00090   typedef std::vector<BoostPolygon> BoostPolygonSet;
00091   typedef boost::polygon::polygon_90_set_traits<BoostPolygonSet> BoostTraits;
00092 #endif
00093 
00094   template<int Degree>
00095   struct S_POLYGON {
00096         enum {DEGREE=Degree};
00097         typedef SubStructure::Model<Degree> Model;
00098         
00099     std::vector<std::vector<Eigen::Vector3f> >  segments_;
00100     std::vector<std::vector<Eigen::Vector2i> >  segments2d_;
00101 #ifdef USE_BOOST_POLYGONS_
00102     std::vector<std::vector<BoostPoint> >       segments2d_;
00103 #endif
00104     float weight_; 
00105 #ifdef CHECK_CONNECTIVITY
00106     S_POLYGON_CONNECTIVITY connectivity_;
00107 #endif
00108     SubStructure::Model<Degree> model_;
00109     Eigen::Vector3f middle_;
00110     int mark_;
00111 
00112     typename SubStructure::Param<Degree>::VectorU param_xy_;
00113     sensor_msgs::ImagePtr img_;
00114     float color_[3];
00115 
00116 #ifdef USE_CLASSIFICATION_
00117     Classification::Form::Ptr form_;
00118 #endif
00119 
00120     Eigen::Vector3f feature_;
00121 
00122     S_POLYGON()
00123 #ifdef USE_CLASSIFICATION_
00124     :form_(new Classification::Form)
00125 #endif
00126     {
00127       int color = rand();
00128       color_[0] = ((color>>0)&0xff)/255.f;
00129       color_[1] = ((color>>8)&0xff)/255.f;
00130       color_[2] = ((color>>16)&0xff)/255.f;
00131     }
00132 
00133     bool isLinear() const
00134     {
00135       for(size_t i=3; i<SubStructure::Param<Degree>::NUM; i++)
00136         if(std::abs(model_.p(i))>0.01f) return false;
00137       return true;
00138     }
00139 
00140     void buildForm(const bool debug=false) {
00141       if(segments_.size()<1)
00142         return;
00143 
00144       std::vector<Eigen::Vector3f> pts;
00145       for(size_t i=0; i<segments_[0].size(); i++)
00146       {
00147         Eigen::Vector3f v;
00148 #ifdef USE_BOOST_POLYGONS_
00149         v(0)=segments2d_[0][i].x();
00150         v(1)=segments2d_[0][i].y();
00151 #endif
00152         pts.push_back(v);
00153         
00154       }
00155 
00156 #ifdef USE_CLASSIFICATION_
00157       Classification::Classification cl;
00158       Classification::QuadBB qbb;
00159 
00160       form_->curvature_ = getInvariantCurvature();
00161       cl.setPoints(segments_[0]);
00162       
00163 
00164       int mains[2];
00165       form_->n_=cl.buildLocalTree(debug,&qbb,&form_->compressed_energy_,mains);
00166       form_->outline_ = qbb.getOutline();
00167 
00168       feature_ = project2world(segments_[0][mains[0]].head<2>());
00169       feature_-= project2world(segments_[0][mains[1]].head<2>());
00170       
00171 
00172       if(feature_(0)<0) feature_=-feature_;
00173 #endif
00174     }
00175 
00176     Eigen::Vector2f project2plane(const float x, const float y, const SubStructure::Model<Degree> &model) {
00177       ROS_ERROR("TODO:");
00178       Eigen::Vector2f mv;
00179       mv(0)=x;
00180       mv(1)=y;
00181       float mz;
00182       mz=model.intersect(mv(0), mv(1));
00183       
00184       Eigen::Vector3f v;
00185       v.head<2>() = mz * mv;
00186       v(2) = mz;
00187       
00188       
00189       return mv;
00190     }
00191 
00192 #ifdef USE_BOOST_POLYGONS_
00193     BoostPolygonSet getBoostPolygon2D() const {
00194       
00195       BoostPolygon poly;
00196       BoostPolygonSet r;
00197       if(segments2d_.size()==0) return r;
00198       poly.set(segments2d_[0].begin(), segments2d_[0].end());
00199       
00200       r.push_back(poly);
00201       return r;
00202     }
00203 
00204     BoostPolygonSet getBoostPolygon2D_Centered() const {
00205       
00206       BoostPolygon poly;
00207       BoostPolygonSet r;
00208       if(segments2d_.size()==0) return r;
00209       {
00210         poly.set(segments2d_[0].begin(), segments2d_[0].end());
00211         
00212 
00213         BoostPoint cnt;
00214         boost::polygon::center(cnt,poly);
00215         std::vector<BoostPoint> temp;
00216 
00217         for(size_t i=0; i<segments2d_[0].size(); i++) {
00218           temp.push_back( BoostPoint(segments2d_[0][i].x()-cnt.x(), segments2d_[0][i].y()-cnt.y()));
00219         }
00220 
00221         poly.set(temp.begin(), temp.end());
00222 
00223         r.push_back(poly);
00224       }
00225       return r;
00226     }
00227 #endif
00228 
00229     Eigen::Vector3f project2plane(const float x, const float y, const float mz, const float b) {
00230       ROS_ERROR("TODO:");
00231       return Eigen::Vector3f::Zero();
00232       
00233 
00234 
00235 
00236 
00237 
00238 
00239 
00240 
00241 
00242 
00243 
00244 
00245 
00246 
00247 
00248 
00249 
00250 
00251 
00252     }
00253 
00254     Eigen::Vector3f project2plane(const float x, const float y, const SubStructure::Model<Degree> &model, const float b) {
00255       Eigen::Vector2f mv;
00256       Eigen::Vector3f mv3;
00257       mv(0)=x;
00258       mv(1)=y;
00259       float mz;
00260       mz=model.intersect(mv(0), mv(1));
00261 
00262       mv3(0) = mv(0)*mz;
00263       mv3(1) = mv(1)*mz;
00264       mv3(2) = mz;
00265 
00266       return mv3;
00267     }
00268 
00269     
00270 
00271 
00272 
00273 
00274 
00275 
00276     Eigen::Vector3f project2world(const Eigen::Vector2f &pt) const {
00277       Eigen::Vector3f v;
00278       v.head<2>() = pt;
00279       v(2) = model_.model(pt(0),pt(1));
00280       return v;
00281     }
00282   
00288    inline Eigen::Quaternionf get_orientation() const {
00289            Eigen::Vector2f mid, dir, mean; mid(0) = model_.x(); mid(1) = model_.y();
00290            mean(0) = model_.param.model_(0,1);
00291            mean(1) = model_.param.model_(0,2);
00292            Eigen::SelfAdjointEigenSolver<Eigen::Matrix2f> evd (model_.param.model_.block(1,1, 2,2)-mean*mean.transpose()/model_.param.model_(0,0));
00293            Eigen::Vector3f x = model_.getNormal(model_.x(), model_.y());
00294            dir(0) = evd.eigenvectors().col(1)(1);
00295            dir(1) = evd.eigenvectors().col(1)(0);
00296 
00297            Eigen::Vector3f y = project2world(0.1f*dir+mid)-project2world(mid);
00298            y.normalize();
00299            
00300            Eigen::Matrix3f M;
00301            M.col(0) = -x.cross(y).normalized();
00302            M.col(1) = y;
00303            M.col(2) = x;        
00304            
00305            return Eigen::Quaternionf(M);
00306    }
00307 
00308     Eigen::Vector3f normalAt(const Eigen::Vector2f &v) const {
00309       return model_.getNormal(v(0),v(1));
00310     }
00311 
00312     
00313 
00314 
00315 
00316 
00317 
00318 
00319 
00320 
00321 
00322 
00323 
00324 
00325 
00326 
00327 
00328 
00329 
00330 
00331 
00332 
00333 
00334 
00335 
00336 
00337 
00338 
00339 
00340 
00341 
00342 
00343 
00344 
00345 
00346 
00347 
00348 
00349 
00350     void update() {
00351       Eigen::Vector3f x,y;
00352       x(0)=1.f;
00353       y(1)=1.f;
00354       x(1)=x(2)=y(0)=y(2)=0.f;
00355     }
00356 
00357     void operator=(const SubStructure::Model<Degree> &model) {
00358       feature_.fill(0);
00359       param_xy_ = model.p;
00360       model_ = model;
00361       weight_ = model.param.model_(0,0);
00362 
00363       update();
00364 
00365       middle_(0) = model_.x();
00366       middle_(1) = model_.y();
00367       middle_(2) = model_.z();
00368 
00369       middle_ = project2world(nextPoint(middle_));
00370     }
00371 
00372     void print() {
00373       for(size_t j=0; j<segments_.size(); j++){
00374         std::cout<<"---------------\n";
00375         for(size_t i=0; i<segments_[j].size(); i++)
00376           std::cout<<segments_[j][i]<<"\n";
00377       }
00378     }
00379 
00380     void toRosMsg(cob_3d_mapping_msgs::CurvedPolygon *msg, const ros::Time &time) const
00381     {
00382       static int nextID = 0;
00383       msg->stamp = time;
00384       msg->ID = nextID++;
00385       msg->weight = model_.param.model_(0,0);
00386 
00387       for(int i=0; i<model_.p.rows(); i++)      
00388         msg->parameter[i] = model_.p(i);
00389 
00390       msg->polyline.clear();
00391       if(segments_.size()>0) {
00392         for(size_t i=0; i<segments_[0].size(); i++) {
00393           cob_3d_mapping_msgs::PolylinePoint pt;
00394           pt.x=segments_[0][i](0);
00395           pt.y=segments_[0][i](1);
00396           pt.edge_prob=segments_[0][i](2);
00397           msg->polyline.push_back(pt);
00398         }
00399       }
00400 
00401       cob_3d_mapping_msgs::Feature ft;
00402 
00403       
00404       ft.ID = 1;
00405       Eigen::Vector3f nxtPt = project2world(nextPoint(Eigen::Vector3f::Zero()));
00406       ft.x=nxtPt(0);
00407       ft.y=nxtPt(1);
00408       ft.z=nxtPt(2);
00409       msg->features.push_back(ft);
00410 
00411       
00412       ft.ID = 2;
00413       ft.x=feature_(0);
00414       ft.y=feature_(1);
00415       ft.z=feature_(2);
00416       msg->features.push_back(ft);
00417 
00418       
00419       ft.ID = 3;
00420       ft.x=middle_(0);
00421       ft.y=middle_(1);
00422       ft.z=middle_(2);
00423       msg->features.push_back(ft);
00424 
00425       Eigen::Vector2f ft1,ft2;
00426       Eigen::Vector3f ft3,n=model_.getNormal(middle_(0),middle_(1)),ft1p,ft2p;
00427       
00428 
00429       ft1p(0)=ft1(0);
00430       ft1p(1)=ft1(1);
00431       ft2p(0)=ft2(0);
00432       ft2p(1)=ft2(1);
00433       ft1p(2)=ft2p(2)=0.f;
00434 
00435       
00436       ft.ID = 4;
00437       ft3=ft1p.cross(n);
00438       ft.x = ft3(0);
00439       ft.y = ft3(1);
00440       ft.z = ft3(2);
00441       
00442       msg->features.push_back(ft);
00443 
00444       
00445       ft.ID = 5;
00446       ft3=ft2p.cross(n);
00447       ft.x = ft3(0);
00448       ft.y = ft3(1);
00449       ft.z = ft3(2);
00450       
00451       msg->features.push_back(ft);
00452 
00453     }
00454 
00455 
00457 
00458 
00459 
00460 
00461 
00462 
00463 
00464 
00465 
00466 
00467 
00468 
00469 
00470 
00471 
00472 
00473 
00474 
00475 
00476 
00477 
00478 
00479 
00480 
00481 
00482 
00483 
00484 
00485 
00486 
00487 
00488 
00489 
00490 
00491     struct MyFunctor
00492     {
00493       const SubStructure::Model<Degree> &model;
00494       const float x0,y0,z0;
00495 
00496       int operator()(const Eigen::VectorXf &x, Eigen::VectorXf &fvec) const
00497       {
00498         
00499         fvec(0) = std::pow(model.model(x(0),x(1))-z0,2)+std::pow(x(1)-y0,2)+std::pow(x(0)-x0,2);
00500         fvec(1) = 0;
00501 
00502         
00503         return 0;
00504       }
00505 
00506       int df(const Eigen::VectorXf &x, Eigen::MatrixXf &fjac) const
00507       {
00508         
00509         const float delta = model.model(x(0),x(1))-z0;
00510         const Eigen::Vector3f n = model.getNormal_(x(0),x(1));
00511         fjac(0,0) = n(0)*delta+2*(x(0)-x0);
00512         fjac(0,1) = n(1)*delta+2*(x(1)-y0);
00513         fjac(1,0) = fjac(1,1) = 0;
00514         return 0;
00515       }
00516 
00517       int inputs() const { return 2; }
00518       int values() const { return 2; } 
00519     };
00520 
00522     Eigen::Vector2f _nextPoint(const Eigen::Vector3f &v, Eigen::Vector3f p, const int depth=0) const
00523     {
00524       Eigen::VectorXf r(2);
00525       r = v.head<2>();
00526       MyFunctor functor={model_,
00527                          p(0),p(1),p(2)};
00528       Eigen::LevenbergMarquardt<MyFunctor, float> lm(functor);
00529       lm.parameters.maxfev = 50;
00530       lm.minimize(r);
00531 
00532       return r;
00533     }
00534 
00536     Eigen::Vector2f nextPoint(const Eigen::Vector3f &v) const
00537     {
00538       
00539 
00540 
00541 
00542 
00543 
00544 
00545 
00546 
00547 
00548 
00549 
00550       Eigen::Vector2f r = _nextPoint(v, v);
00551 
00552       float e1 = (v-project2world(v.head<2>())).norm();
00553       float e2 = (v-project2world(r)).norm();
00554 
00555       if(e1<e2)
00556       {
00557         return v.head<2>();
00558       }
00559 
00560       return r;
00561     }
00562 
00563     bool getPose(Eigen::Matrix3f &P, Eigen::Vector3f &origin, float &h, float &w) const {
00564       if(segments_.size()<1)
00565         return false;
00566 
00567       Eigen::Matrix2f A, C;
00568       Eigen::Vector2f B, v1, v2;
00569 
00570       A(0,0) = model_.param.model_(1,1);
00571       A(1,1) = model_.param.model_(3,3);
00572       A(0,1) = A(1,0) = model_.param.model_(1,3); 
00573 
00574       B(0) = model_.param.model_(0,1);
00575       B(1) = model_.param.model_(0,3);
00576 
00577       C = A-C*C.transpose();
00578 
00579       Eigen::EigenSolver<Eigen::Matrix2f> es(C);
00580 
00581 
00582 
00583 
00584       v1 = es.eigenvectors().col(0).real();
00585       v2 = es.eigenvectors().col(1).real();
00586 
00587       v1.normalize();
00588       v2.normalize();
00589 
00590       P.col(0) = project2world(v1)-project2world(Eigen::Vector2f::Zero());
00591       P.col(1) = project2world(v2)-project2world(Eigen::Vector2f::Zero());
00592       P.col(0).normalize();
00593       P.col(1).normalize();
00594       P.col(2) = P.col(0).cross(P.col(1));
00595 
00596       float h_ma = -std::numeric_limits<float>::max(), h_mi = std::numeric_limits<float>::max();
00597       float w_ma = -std::numeric_limits<float>::max(), w_mi = std::numeric_limits<float>::max();
00598 
00599       for(size_t i=0; i<segments_[0].size(); i++)
00600       {
00601         float f=segments_[0][i].head<2>().dot(v1);
00602         h_ma = std::max(h_ma, f);
00603         h_mi = std::min(h_mi, f);
00604 
00605         f=segments_[0][i].head<2>().dot(v2);
00606         w_ma = std::max(w_ma, f);
00607         w_mi = std::min(w_mi, f);
00608       }
00609 
00610       origin = middle_;
00611       w = (project2world(v1*h_ma)-project2world(v1*h_mi)).norm();
00612       h = (project2world(v2*w_ma)-project2world(v2*w_mi)).norm();
00613 
00614 
00615 
00616       return true;
00617     }
00618 
00619     float area() const {
00620 
00621       TPPLPartition pp;
00622       list<TPPLPoly> polys,result;
00623 
00624       
00625       
00626       
00627       for(size_t i=0; i<segments_.size(); i++) {
00628         pcl::PointCloud<pcl::PointXYZ> pc;
00629         TPPLPoly poly;
00630 
00631         poly.Init(segments_[i].size());
00632         poly.SetHole(i!=0);
00633 
00634         for(size_t j=0; j<segments_[i].size(); j++) {
00635           poly[j].x = segments_[i][j](0);
00636           poly[j].y = segments_[i][j](1);
00637         }
00638         if(i!=0)
00639           poly.SetOrientation(TPPL_CW);
00640         else
00641           poly.SetOrientation(TPPL_CCW);
00642 
00643         polys.push_back(poly);
00644       }
00645 
00646       pp.Triangulate_EC(&polys,&result);
00647 
00648       TPPLPoint p1,p2,p3;
00649       Eigen::Vector3f v1,v2,v3;
00650 
00651       float a=0.f;
00652       for(std::list<TPPLPoly>::iterator it=result.begin(); it!=result.end(); it++) {
00653         if(it->GetNumPoints()!=3) continue;
00654 
00655         p1 = it->GetPoint(0);
00656         p2 = it->GetPoint(1);
00657         p3 = it->GetPoint(2);
00658 
00659         v1(0) = p1.x;
00660         v1(1) = p1.y;
00661         v2(0) = p2.x;
00662         v2(1) = p2.y;
00663         v3(0) = p3.x;
00664         v3(1) = p3.y;
00665 
00666         v1 = project2world(v1.head<2>());
00667         v2 = project2world(v2.head<2>());
00668         v3 = project2world(v3.head<2>());
00669 
00670         a += (v2-v1).cross(v3-v1).norm();
00671       }
00672 
00673       return a;
00674     }
00675 
00676   };
00677 
00678 #ifdef QPPF_SPECIALIZATION_2
00679   template< >
00680   struct S_POLYGON<2> {
00681     Eigen::Matrix3f param_;
00682     std::vector<std::vector<Eigen::Vector3f> >  segments_;
00683     std::vector<std::vector<Eigen::Vector2i> >  segments2d_;
00684 #ifdef USE_BOOST_POLYGONS_
00685     std::vector<std::vector<BoostPoint> >       segments2d_;
00686 #endif
00687     float weight_; 
00688 #ifdef CHECK_CONNECTIVITY
00689     S_POLYGON_CONNECTIVITY connectivity_;
00690 #endif
00691     SubStructure::Model<2> model_;
00692     Eigen::Vector3f middle_;
00693     int mark_;
00694 
00695     Eigen::Matrix<float,3,2> proj2plane_;
00696     typename SubStructure::Param<2>::VectorU param_xy_;
00697     sensor_msgs::ImagePtr img_;
00698     float color_[3];
00699 
00700 #ifdef USE_CLASSIFICATION_
00701     Classification::Form::Ptr form_;
00702 #endif
00703 
00704     Eigen::Vector3f feature_;
00705 
00706     S_POLYGON()
00707 #ifdef USE_CLASSIFICATION_
00708     :form_(new Classification::Form)
00709 #endif
00710     {
00711       int color = rand();
00712       color_[0] = ((color>>0)&0xff)/255.f;
00713       color_[1] = ((color>>8)&0xff)/255.f;
00714       color_[2] = ((color>>16)&0xff)/255.f;
00715     }
00716 
00717     bool isLinear() const
00718     {
00719       std::cout<<model_.p<<"\n";
00720       return std::abs(model_.p(2))<0.01f && std::abs(model_.p(4))<0.01f && std::abs(model_.p(5))<0.01f;
00721     }
00722 
00723     void buildForm(const bool debug=false) {
00724       if(segments_.size()<1)
00725         return;
00726 
00727       std::vector<Eigen::Vector3f> pts;
00728       for(size_t i=0; i<segments_[0].size(); i++)
00729       {
00730         Eigen::Vector3f v;
00731 #ifdef USE_BOOST_POLYGONS_
00732         v(0)=segments2d_[0][i].x();
00733         v(1)=segments2d_[0][i].y();
00734 #endif
00735         pts.push_back(v);
00736         
00737       }
00738 
00739 #ifdef USE_CLASSIFICATION_
00740       Classification::Classification cl;
00741       Classification::QuadBB qbb;
00742 
00743       form_->curvature_ = getInvariantCurvature();
00744       cl.setPoints(segments_[0]);
00745       
00746 
00747       int mains[2];
00748       form_->n_=cl.buildLocalTree(debug,&qbb,&form_->compressed_energy_,mains);
00749       form_->outline_ = qbb.getOutline();
00750 
00751       feature_ = project2world(segments_[0][mains[0]].head<2>());
00752       feature_-= project2world(segments_[0][mains[1]].head<2>());
00753       
00754 
00755       if(feature_(0)<0) feature_=-feature_;
00756 #endif
00757     }
00758 
00759     Eigen::Vector2f project2plane(const float x, const float y, const SubStructure::Model<2> &model) {
00760       Eigen::Vector2f mv;
00761       mv(0)=x;
00762       mv(1)=y;
00763       float mz;
00764       mz=model.intersect(mv(0), mv(1));
00765       
00766       Eigen::Vector3f v;
00767       v.head<2>() = mz * mv;
00768       v(2) = mz;
00769       mv(0) = (v-param_.col(0)).dot(proj2plane_.col(0))/proj2plane_.col(0).squaredNorm();
00770       mv(1) = (v-param_.col(0)).dot(proj2plane_.col(1))/proj2plane_.col(1).squaredNorm();
00771 #if DEBUG_LEVEL >70
00772       if(!pcl_isfinite(mv(0))) {
00773         ROS_ERROR("mist");
00774         std::cerr<<x<<","<<y<<","<<mz<<"\nmv:\n";
00775         std::cerr<<mv<<"\np\n";
00776         std::cerr<<model.p<<"\n";
00777         std::cerr<<"mz: "<<mz<<"\nmv:\n";
00778         
00779       }
00780 #endif
00781       return mv;
00782     }
00783 
00784 #ifdef USE_BOOST_POLYGONS_
00785     BoostPolygonSet getBoostPolygon2D() const {
00786       
00787       BoostPolygon poly;
00788       BoostPolygonSet r;
00789       if(segments2d_.size()==0) return r;
00790       poly.set(segments2d_[0].begin(), segments2d_[0].end());
00791       
00792       r.push_back(poly);
00793       return r;
00794     }
00795 
00796     BoostPolygonSet getBoostPolygon2D_Centered() const {
00797       
00798       BoostPolygon poly;
00799       BoostPolygonSet r;
00800       if(segments2d_.size()==0) return r;
00801       {
00802         poly.set(segments2d_[0].begin(), segments2d_[0].end());
00803         
00804 
00805         BoostPoint cnt;
00806         boost::polygon::center(cnt,poly);
00807         std::vector<BoostPoint> temp;
00808 
00809         for(size_t i=0; i<segments2d_[0].size(); i++) {
00810           temp.push_back( BoostPoint(segments2d_[0][i].x()-cnt.x(), segments2d_[0][i].y()-cnt.y()));
00811         }
00812 
00813         poly.set(temp.begin(), temp.end());
00814 
00815         r.push_back(poly);
00816       }
00817       return r;
00818     }
00819 #endif
00820 
00821     Eigen::Vector3f project2plane(const float x, const float y, const float mz, const float b) {
00822       Eigen::Vector2f mv;
00823       Eigen::Vector3f mv3;
00824       mv(0)=x;
00825       mv(1)=y;
00826       mv=mv*mz-getCenter();
00827       
00828       
00829 #if DEBUG_LEVEL >70
00830       if(!pcl_isfinite(mv(0))) {
00831         ROS_ERROR("mistXYZ");
00832         std::cerr<<x<<","<<y<<","<<mz<<"\nmv:\n";
00833         std::cerr<<mv<<"\np\n";
00834         std::cerr<<"mz: "<<mz<<"\nmv:\n";
00835         
00836       }
00837 #endif
00838       mv3(2)=b;
00839       mv3(0)=mv(0);
00840       mv3(1)=mv(1);
00841       return mv3;
00842     }
00843 
00844     Eigen::Vector3f project2plane(const float x, const float y, const SubStructure::Model<2> &model, const float b) {
00845       Eigen::Vector2f mv;
00846       Eigen::Vector3f mv3;
00847       mv(0)=x;
00848       mv(1)=y;
00849       mv3(2)=b;
00850       float mz;
00851       mz=model.intersect(mv(0), mv(1));
00852 
00853       
00854       
00855       
00856 
00857       mv=mv*mz-param_.col(0).head<2>();
00858       
00859       
00860 
00861       
00862 
00863 #if DEBUG_LEVEL >70
00864       if(!pcl_isfinite(mv(0))) {
00865         ROS_ERROR("mist");
00866         std::cerr<<x<<","<<y<<","<<mz<<"\nmv:\n";
00867         std::cerr<<mv<<"\np\n";
00868         std::cerr<<model.p<<"\n";
00869         std::cerr<<"mz: "<<mz<<"\n";
00870         
00871       }
00872 #endif
00873       mv3(0)=mv(0);
00874       mv3(1)=mv(1);
00875       return mv3;
00876     }
00877 
00878     Eigen::Vector2f getCenter() const {
00879       Eigen::Vector2f r;
00880       r(0)=param_(0,0);
00881       r(1)=param_(1,0);
00882       return r;
00883     }
00884 
00885     Eigen::Vector3f project2world(const Eigen::Vector2f &pt) const {
00886       Eigen::Vector3f pt2;
00887       pt2(0)=pt(0)*pt(0);
00888       pt2(1)=pt(1)*pt(1);
00889       pt2(2)=pt(0)*pt(1);
00890 
00891       return param_.col(0) + proj2plane_*pt + proj2plane_.col(0).cross(proj2plane_.col(1)) * (pt2.dot(param_.col(2)) + pt.dot(param_.col(1).head<2>()));
00892     }
00893 
00894     Eigen::Vector3f normalAt(const Eigen::Vector2f &v) const {
00895       Eigen::Vector3f r;
00896 
00897       r(0) = -(param_.col(1)(0) + 2*v(0)*param_.col(2)(0)+v(1)*param_.col(2)(2));
00898       r(1) = -(param_.col(1)(1) + 2*v(1)*param_.col(2)(1)+v(0)*param_.col(2)(2));
00899       r(2) = 1;
00900 
00901       r.normalize();
00902 
00903       Eigen::Matrix3f M;
00904       M.col(0) = proj2plane_.col(0);
00905       M.col(1) = proj2plane_.col(1);
00906       M.col(2) = proj2plane_.col(0).cross(proj2plane_.col(1));
00907 
00908       return M*r;
00909     }
00910 
00911     float getFeature(Eigen::Vector2f &ra,Eigen::Vector2f &rb,Eigen::Vector3f &rc) const {
00912 
00913       rc=feature_;
00914 
00915       float a=param_(0,2), b=param_(1,2), c=param_(2,2);
00916 
00917       float x1 =  sqrtf((a-b)*sqrtf(c*c+b*b-2*a*b+a*a)+c*c+b*b-2*a*b+a*a)/(sqrtf(2)*sqrtf(c*c+b*b-2*a*b+a*a));
00918       float x2 = -sqrtf((b-a)*sqrtf(c*c+b*b-2*a*b+a*a)+c*c+b*b-2*a*b+a*a)/(sqrtf(2)*sqrtf(c*c+b*b-2*a*b+a*a));
00919       float y1=sqrtf(1-x1*x1);
00920       float y2=sqrtf(1-x2*x2);
00921 
00922       ra(0)=x1;
00923       ra(1)=y1;
00924 
00925       rb(0)=x2;
00926       rb(1)=y2;
00927 
00928       Eigen::Vector3f t=getInvariantCurvature();
00929 
00930       return std::max( std::abs(t(0)), std::max(std::abs(t(1)),std::abs(t(2))) );
00931     }
00932 
00933     Eigen::Vector3f getInvariantCurvature() const {
00934       Eigen::Vector3f r;
00935       float a=param_(0,2), b=param_(1,2), c=param_(2,2);
00936 
00937       float x1 =  sqrtf((a-b)*sqrtf(c*c+b*b-2*a*b+a*a)+c*c+b*b-2*a*b+a*a)/(sqrtf(2)*sqrtf(c*c+b*b-2*a*b+a*a));
00938       float x2 = -sqrtf((b-a)*sqrtf(c*c+b*b-2*a*b+a*a)+c*c+b*b-2*a*b+a*a)/(sqrtf(2)*sqrtf(c*c+b*b-2*a*b+a*a));
00939       float y1=sqrtf(1-x1*x1);
00940       float y2=sqrtf(1-x2*x2);
00941 
00942       r(0)=atanf( (a*x1*x1+b*y1*y1+c*x1*y1) /30.f);
00943       r(1)=atanf( (a*x2*x2+b*y2*y2+c*x2*y2) /30.f);
00944       r(2)=0.f;
00945 
00946       return r;
00947     }
00948 
00949     void update() {
00950       Eigen::Vector3f x,y;
00951       x(0)=1.f;
00952       y(1)=1.f;
00953       x(1)=x(2)=y(0)=y(2)=0.f;
00954 
00955       proj2plane_.col(0)=x;
00956       proj2plane_.col(1)=y;
00957 
00958       
00959       
00960 
00961       
00962       
00963       
00964     }
00965 
00966     void operator=(const SubStructure::Model<2> &model) {
00967       feature_.fill(0);
00968       param_xy_ = model.p;
00969       model_ = model;
00970 
00971       
00972       
00973       
00974       
00975       
00976       
00977       
00978       
00979       
00980       
00981       
00982       
00983       
00984       
00985       
00986       
00987       
00988       
00989 
00990       param_.col(0) = Eigen::Vector3f::Zero();
00991       param_.col(0)(2) = model.p(0);
00992 
00993       param_.col(1)(0)=model.p(1);
00994       param_.col(1)(1)=model.p(3);
00995       param_.col(1)(2)=0;
00996       
00997 
00998       param_.col(2)(0)=model.p(2);
00999       param_.col(2)(1)=model.p(4);
01000       param_.col(2)(2)=model.p(5);
01001 
01002       weight_ = model.param.model_(0,0);
01003 
01004       update();
01005 
01006       middle_(0) = model_.x();
01007       middle_(1) = model_.y();
01008       middle_(2) = model_.z();
01009 
01010       middle_ = project2world(nextPoint(middle_));
01011     }
01012 
01013     void print() {
01014       std::cout<<"parameter:\n"<<param_<<"\n";
01015       for(size_t j=0; j<segments_.size(); j++){
01016         std::cout<<"---------------\n";
01017         for(size_t i=0; i<segments_[j].size(); i++)
01018           std::cout<<segments_[j][i]<<"\n";
01019       }
01020     }
01021 
01022     void toRosMsg(cob_3d_mapping_msgs::CurvedPolygon *msg, const ros::Time &time) const
01023     {
01024       static int nextID = 0;
01025       msg->stamp = time;
01026       msg->ID = nextID++;
01027       msg->weight = model_.param.model_(0,0);
01028 
01029       for(int i=0; i<model_.p.rows(); i++)      
01030         msg->parameter[i] = model_.p(i);
01031 
01032       msg->polyline.clear();
01033       if(segments_.size()>0) {
01034         for(size_t i=0; i<segments_[0].size(); i++) {
01035           cob_3d_mapping_msgs::PolylinePoint pt;
01036           pt.x=segments_[0][i](0);
01037           pt.y=segments_[0][i](1);
01038           pt.edge_prob=segments_[0][i](2);
01039           msg->polyline.push_back(pt);
01040         }
01041       }
01042 
01043       cob_3d_mapping_msgs::Feature ft;
01044 
01045       
01046       ft.ID = 1;
01047       Eigen::Vector3f nxtPt = project2world(nextPoint(Eigen::Vector3f::Zero()));
01048       ft.x=nxtPt(0);
01049       ft.y=nxtPt(1);
01050       ft.z=nxtPt(2);
01051       msg->features.push_back(ft);
01052 
01053       
01054       ft.ID = 2;
01055       ft.x=feature_(0);
01056       ft.y=feature_(1);
01057       ft.z=feature_(2);
01058       msg->features.push_back(ft);
01059 
01060       
01061       ft.ID = 3;
01062       ft.x=middle_(0);
01063       ft.y=middle_(1);
01064       ft.z=middle_(2);
01065       msg->features.push_back(ft);
01066 
01067       Eigen::Vector2f ft1,ft2;
01068       Eigen::Vector3f ft3,n=model_.getNormal(middle_(0),middle_(1)),ft1p,ft2p;
01069       getFeature(ft1,ft2,ft3);
01070 
01071       ft1p(0)=ft1(0);
01072       ft1p(1)=ft1(1);
01073       ft2p(0)=ft2(0);
01074       ft2p(1)=ft2(1);
01075       ft1p(2)=ft2p(2)=0.f;
01076 
01077       
01078       ft.ID = 4;
01079       ft3=ft1p.cross(n);
01080       ft.x = ft3(0);
01081       ft.y = ft3(1);
01082       ft.z = ft3(2);
01083       
01084       msg->features.push_back(ft);
01085 
01086       
01087       ft.ID = 5;
01088       ft3=ft2p.cross(n);
01089       ft.x = ft3(0);
01090       ft.y = ft3(1);
01091       ft.z = ft3(2);
01092       
01093       msg->features.push_back(ft);
01094 
01095     }
01096 
01097 
01099 
01100 
01101 
01102 
01103 
01104 
01105 
01106 
01107 
01108 
01109 
01110 
01111 
01112 
01113 
01114 
01115 
01116 
01117 
01118 
01119 
01120 
01121 
01122 
01123 
01124 
01125 
01126 
01127 
01128 
01129 
01130 
01131 
01132 
01133     struct MyFunctor
01134     {
01135       const float a,b,c, d,e;
01136       const float x0,y0,z0;
01137 
01138       int operator()(const Eigen::VectorXf &x, Eigen::VectorXf &fvec) const
01139       {
01140         
01141         fvec(0) = std::pow((-z0+b*x(1)*x(1)+c*x(0)*x(1)+a*x(0)*x(0)+d*x(0)+e*x(1)),2)+std::pow(x(1)-y0,2)+std::pow(x(0)-x0,2);
01142         fvec(1) = 0;
01143 
01144         
01145         return 0;
01146       }
01147 
01148       int df(const Eigen::VectorXf &x, Eigen::MatrixXf &fjac) const
01149       {
01150         
01151         
01152         fjac(0,0) = 2*(c*x(1)+2*a*x(0)+d)*(-z0+b*x(1)*x(1)+c*x(0)*x(1)+a*x(0)*x(0)+d*x(0)+e*x(1))+2*(x(0)-x0);
01153         fjac(0,1) = 2*(2*b*x(1)+c*x(0)+e)*(-z0+b*x(1)*x(1)+c*x(0)*x(1)+a*x(0)*x(0)+d*x(0)+e*x(1))+2*(x(1)-y0);
01154         fjac(1,0) = fjac(1,1) = 0;
01155         return 0;
01156       }
01157 
01158       int inputs() const { return 2; }
01159       int values() const { return 2; } 
01160     };
01161 
01163     Eigen::Vector2f _nextPoint(const Eigen::Vector3f &v, Eigen::Vector3f p, const int depth=0) const
01164     {
01165       Eigen::VectorXf r(2);
01166       r = v.head<2>();
01167       MyFunctor functor={param_.col(2)(0),param_.col(2)(1),param_.col(2)(2),
01168                          param_.col(1)(0),param_.col(1)(1),
01169                          p(0),p(1),p(2)};
01170       Eigen::LevenbergMarquardt<MyFunctor, float> lm(functor);
01171       lm.parameters.maxfev = 50;
01172       lm.minimize(r);
01173 
01174       return r;
01175     }
01176 
01178     Eigen::Vector2f nextPoint(const Eigen::Vector3f &v) const
01179     {
01180       Eigen::Vector3f p;
01181 
01182       p(0) = (v-param_.col(0)).dot(proj2plane_.col(0));
01183       p(1) = (v-param_.col(0)).dot(proj2plane_.col(1));
01184       p(2) = (v-param_.col(0)).dot(proj2plane_.col(0).cross(proj2plane_.col(1)));
01185 
01186       Eigen::Vector2f r = _nextPoint(p, p);
01187 
01188       float e1 = (v-project2world(p.head<2>())).norm();
01189       float e2 = (v-project2world(r)).norm();
01190 
01191       if(e1<e2)
01192       {
01193         return p.head<2>();
01194       }
01195 
01196       return r;
01197     }
01198 
01199     bool getPose(Eigen::Matrix3f &P, Eigen::Vector3f &origin, float &h, float &w) const {
01200       if(segments_.size()<1)
01201         return false;
01202 
01203       Eigen::Matrix2f A, C;
01204       Eigen::Vector2f B, v1, v2;
01205 
01206       A(0,0) = model_.param.model_(1,1);
01207       A(1,1) = model_.param.model_(3,3);
01208       A(0,1) = A(1,0) = model_.param.model_(1,3); 
01209 
01210       B(0) = model_.param.model_(0,1);
01211       B(1) = model_.param.model_(0,3);
01212 
01213       C = A-C*C.transpose();
01214 
01215       Eigen::EigenSolver<Eigen::Matrix2f> es(C);
01216 
01217 
01218 
01219 
01220       v1 = es.eigenvectors().col(0).real();
01221       v2 = es.eigenvectors().col(1).real();
01222 
01223       v1.normalize();
01224       v2.normalize();
01225 
01226       P.col(0) = project2world(v1)-project2world(Eigen::Vector2f::Zero());
01227       P.col(1) = project2world(v2)-project2world(Eigen::Vector2f::Zero());
01228       P.col(0).normalize();
01229       P.col(1).normalize();
01230       P.col(2) = P.col(0).cross(P.col(1));
01231 
01232       float h_ma = -std::numeric_limits<float>::max(), h_mi = std::numeric_limits<float>::max();
01233       float w_ma = -std::numeric_limits<float>::max(), w_mi = std::numeric_limits<float>::max();
01234 
01235       for(size_t i=0; i<segments_[0].size(); i++)
01236       {
01237         float f=segments_[0][i].head<2>().dot(v1);
01238         h_ma = std::max(h_ma, f);
01239         h_mi = std::min(h_mi, f);
01240 
01241         f=segments_[0][i].head<2>().dot(v2);
01242         w_ma = std::max(w_ma, f);
01243         w_mi = std::min(w_mi, f);
01244       }
01245 
01246       origin = middle_;
01247       w = (project2world(v1*h_ma)-project2world(v1*h_mi)).norm();
01248       h = (project2world(v2*w_ma)-project2world(v2*w_mi)).norm();
01249 
01250 
01251 
01252       return true;
01253     }
01254 
01255     float area() const {
01256 
01257       TPPLPartition pp;
01258       list<TPPLPoly> polys,result;
01259 
01260       
01261       
01262       
01263       for(size_t i=0; i<segments_.size(); i++) {
01264         pcl::PointCloud<pcl::PointXYZ> pc;
01265         TPPLPoly poly;
01266 
01267         poly.Init(segments_[i].size());
01268         poly.SetHole(i!=0);
01269 
01270         for(size_t j=0; j<segments_[i].size(); j++) {
01271           poly[j].x = segments_[i][j](0);
01272           poly[j].y = segments_[i][j](1);
01273         }
01274         if(i!=0)
01275           poly.SetOrientation(TPPL_CW);
01276         else
01277           poly.SetOrientation(TPPL_CCW);
01278 
01279         polys.push_back(poly);
01280       }
01281 
01282       pp.Triangulate_EC(&polys,&result);
01283 
01284       TPPLPoint p1,p2,p3;
01285       Eigen::Vector3f v1,v2,v3;
01286 
01287       float a=0.f;
01288       for(std::list<TPPLPoly>::iterator it=result.begin(); it!=result.end(); it++) {
01289         if(it->GetNumPoints()!=3) continue;
01290 
01291         p1 = it->GetPoint(0);
01292         p2 = it->GetPoint(1);
01293         p3 = it->GetPoint(2);
01294 
01295         v1(0) = p1.x;
01296         v1(1) = p1.y;
01297         v2(0) = p2.x;
01298         v2(1) = p2.y;
01299         v3(0) = p3.x;
01300         v3(1) = p3.y;
01301 
01302         v1 = project2world(v1.head<2>());
01303         v2 = project2world(v2.head<2>());
01304         v3 = project2world(v3.head<2>());
01305 
01306         a += (v2-v1).cross(v3-v1).norm();
01307       }
01308 
01309       return a;
01310     }
01311 
01312   };
01313 #endif
01314 }
01315 
01316 #endif 
01317