contrib/gel/vsol/vsol_polygon_3d.cxx
Go to the documentation of this file.
00001 // This is gel/vsol/vsol_polygon_3d.cxx
00002 #include "vsol_polygon_3d.h"
00003 //:
00004 // \file
00005 #include <vcl_cassert.h>
00006 #include <vcl_iostream.h>
00007 #include <vcl_cmath.h>
00008 #include <vsl/vsl_vector_io.h>
00009 #include <vsol/vsol_point_3d.h>
00010 #include <vgl/vgl_vector_3d.h>
00011 #include <vgl/vgl_homg_point_3d.h>
00012 #include <vgl/algo/vgl_fit_plane_3d.h>
00013 
00014 //***************************************************************************
00015 // Initialization
00016 //***************************************************************************
00017 void vsol_polygon_3d::compute_plane()
00018 {
00019   vcl_vector<vgl_homg_point_3d<double> > pts;
00020   for (vcl_vector<vsol_point_3d_sptr>::iterator pit = storage_->begin();
00021        pit != storage_->end(); ++pit)
00022     pts.push_back(vgl_homg_point_3d<double>((*pit)->x(),(*pit)->y(),(*pit)->z(),1.0));
00023   vgl_fit_plane_3d<double> fp(pts);
00024   fp.fit(0.1, &vcl_cerr);
00025   plane_ = fp.get_plane();
00026   plane_.normalize();
00027 }
00028 
00029 //----------------------------------------------------------------
00030 // Default constructor
00031 //----------------------------------------------------------------
00032 vsol_polygon_3d::vsol_polygon_3d()
00033 : storage_(0)
00034 {
00035 }
00036 
00037 //---------------------------------------------------------------------------
00038 //: Constructor from a vcl_vector (not a geometric vector but a list of points).
00039 // Require: new_vertices.size()>=3 and valid_vertices(new_vertices)
00040 //---------------------------------------------------------------------------
00041 vsol_polygon_3d::vsol_polygon_3d(vcl_vector<vsol_point_3d_sptr> const& new_vertices)
00042 {
00043   // require
00044   assert(new_vertices.size()>=3);
00045   assert(valid_vertices(new_vertices));
00046 
00047   storage_=new vcl_vector<vsol_point_3d_sptr>(new_vertices);
00048   this->compute_plane();
00049 }
00050 
00051 //---------------------------------------------------------------------------
00052 // Copy constructor
00053 //---------------------------------------------------------------------------
00054 vsol_polygon_3d::vsol_polygon_3d(vsol_polygon_3d const& other)
00055   : vsol_region_3d(other)
00056 {
00057   //vsol_point_3d_sptr p;
00058 
00059   storage_=new vcl_vector<vsol_point_3d_sptr>(*other.storage_);
00060   for (unsigned int i=0;i<storage_->size();++i)
00061     (*storage_)[i]=new vsol_point_3d(*((*other.storage_)[i]));
00062   plane_ = other.plane_;
00063 }
00064 
00065 //---------------------------------------------------------------------------
00066 // Destructor
00067 //---------------------------------------------------------------------------
00068 vsol_polygon_3d::~vsol_polygon_3d()
00069 {
00070   delete storage_;
00071 }
00072 
00073 //---------------------------------------------------------------------------
00074 //: Clone `this': creation of a new object and initialization.
00075 // See Prototype pattern
00076 //---------------------------------------------------------------------------
00077 vsol_spatial_object_3d* vsol_polygon_3d::clone(void) const
00078 {
00079   return new vsol_polygon_3d(*this);
00080 }
00081 
00082 //***************************************************************************
00083 // Access
00084 //***************************************************************************
00085 
00086 //---------------------------------------------------------------------------
00087 //: Return vertex `i'.
00088 // Require: valid_index(i)
00089 //---------------------------------------------------------------------------
00090 vsol_point_3d_sptr vsol_polygon_3d::vertex(const int i) const
00091 {
00092   // require
00093   assert(valid_index(i));
00094 
00095   return (*storage_)[i];
00096 }
00097 
00098 //***************************************************************************
00099 // Comparison
00100 //***************************************************************************
00101 
00102 //---------------------------------------------------------------------------
00103 //: Has `this' the same points than `other' in the same order ?
00104 //---------------------------------------------------------------------------
00105 bool vsol_polygon_3d::operator==(vsol_polygon_3d const& other) const
00106 {
00107   bool result = (this==&other);
00108 
00109   if (!result)
00110   {
00111     result = (storage_->size()==other.storage_->size());
00112 
00113     if (result)
00114     {
00115       vsol_point_3d_sptr p=(*storage_)[0];
00116 
00117       unsigned int i=0;
00118       for (result=false;i<storage_->size()&&!result;++i)
00119         result = (*p==*(*other.storage_)[i]);
00120       if (result)
00121       {
00122         for (unsigned int j=1;j<size()&&result;++i,++j)
00123         {
00124           if (i>=storage_->size()) i=0;
00125           result = ((*storage_)[i]==(*storage_)[j]);
00126         }
00127       }
00128     }
00129   }
00130   return result;
00131 }
00132 
00133 //---------------------------------------------------------------------------
00134 //: spatial object equality
00135 //---------------------------------------------------------------------------
00136 bool vsol_polygon_3d::operator==(vsol_spatial_object_3d const& obj) const
00137 {
00138   return
00139     obj.cast_to_region() && obj.cast_to_region()->cast_to_polygon() &&
00140     *this == *obj.cast_to_region()->cast_to_polygon();
00141 }
00142 
00143 //---------------------------------------------------------------------------
00144 //: Compute the bounding box of `this'
00145 //---------------------------------------------------------------------------
00146 void vsol_polygon_3d::compute_bounding_box(void) const
00147 {
00148   set_bounding_box((*storage_)[0]->x(),
00149                    (*storage_)[0]->y(),
00150                    (*storage_)[0]->z());
00151   for (unsigned int i=1;i<storage_->size();++i)
00152     add_to_bounding_box((*storage_)[i]->x(),
00153                         (*storage_)[i]->y(),
00154                         (*storage_)[i]->z());
00155 }
00156 
00157 //---------------------------------------------------------------------------
00158 //: Return the area of `this'
00159 //---------------------------------------------------------------------------
00160 double vsol_polygon_3d::area(void) const
00161 {
00162   // TO DO
00163   vcl_cerr << "Warning: vsol_polygon_3d::area() has not been implemented yet\n";
00164   return -1;
00165 }
00166 
00167 //---------------------------------------------------------------------------
00168 //: Is `this' convex ?
00169 // A polygon is convex if it is planar and if moreover the direction of
00170 // "turning" at every vertex is the same.  This is checked by calculating
00171 // the cross product of two consecutive edges and verifying that these
00172 // all have the same direction, i.e., that their pairwise dot products
00173 // are all nonnegative (which proves the "turning") and equal to the
00174 // product of their lengths (which proves coplanarity).
00175 //---------------------------------------------------------------------------
00176 bool vsol_polygon_3d::is_convex(void) const
00177 {
00178    if (storage_->size()==3) return true; // A triangle is always convex
00179 
00180    // First find a non-zero cross product.  This is certainly present,
00181    // unless the polygon collapses to a line segment.
00182    // Note that cross-product=0 means that two edges are parallel, which
00183    // is perfectly valid, but the other "turnings" should still all be in
00184    // the same direction.  An earlier implementation allowed for turning
00185    // in the other direction after a cross-product=0.
00186 
00187    vgl_vector_3d<double> n = vgl_vector_3d<double>(0.0,0.0,0.0);
00188    for (unsigned int i=0; i<storage_->size(); ++i)
00189    {
00190      int j = (i>1) ? i-2 : i-2+storage_->size();
00191      int k = (i>0) ? i-1 : i-1+storage_->size();
00192      vsol_point_3d_sptr p0=(*storage_)[k];
00193      vsol_point_3d_sptr p1=(*storage_)[j];
00194      vsol_point_3d_sptr p2=(*storage_)[i];
00195      vgl_vector_3d<double> v1=p0->to_vector(*p1);
00196      vgl_vector_3d<double> v2=p1->to_vector(*p2);
00197      n = cross_product(v1,v2);
00198      if (n != vgl_vector_3d<double>(0.0,0.0,0.0))
00199        break;
00200    }
00201    if (n == vgl_vector_3d<double>(0.0,0.0,0.0))
00202      return true;
00203 
00204    for (unsigned int i=0; i<storage_->size(); ++i)
00205    {
00206      int j = (i>1) ? i-2 : i-2+storage_->size();
00207      int k = (i>0) ? i-1 : i-1+storage_->size();
00208      vsol_point_3d_sptr p0=(*storage_)[k];
00209      vsol_point_3d_sptr p1=(*storage_)[j];
00210      vsol_point_3d_sptr p2=(*storage_)[i];
00211      vgl_vector_3d<double> v1=p0->to_vector(*p1);
00212      vgl_vector_3d<double> v2=p1->to_vector(*p2);
00213      vgl_vector_3d<double> n2 = cross_product(v1,v2);
00214      if (dot_product(n2,n) < 0)
00215        return false; // turns in the other direction
00216      if (!parallel(n2,n,1e-6))
00217        return false; // non-planar
00218    }
00219    return true;
00220 }
00221 
00222 //---------------------------------------------------------------------------
00223 //: Are `new_vertices' valid vertices to build a polygon of the current type?
00224 //  That is are all vertices in the same plane ?
00225 //---------------------------------------------------------------------------
00226 bool vsol_polygon_3d::valid_vertices(const vcl_vector<vsol_point_3d_sptr> new_vertices) const
00227 {
00228   double tol = 1e-06;
00229   if (new_vertices.size() <= 3) return true; // a triangle is always in a plane
00230 
00231   vsol_point_3d_sptr p0=new_vertices[0];
00232   vsol_point_3d_sptr p1=new_vertices[1];
00233   vsol_point_3d_sptr p2=new_vertices[2];
00234 
00235   vgl_vector_3d<double> v1 (p1->x()-p0->x(),
00236                             p1->y()-p0->y(),
00237                             p1->z()-p0->z());
00238 
00239   vgl_vector_3d<double> v2 (p2->x()-p0->x(),
00240                             p2->y()-p0->y(),
00241                             p2->z()-p0->z());
00242   vgl_vector_3d<double> n = normalized(cross_product(v1,v2));// normal to the plane made by the vertices
00243 
00244   for (unsigned int i=3;i<new_vertices.size();++i)
00245   {
00246     p2=new_vertices[i];
00247     v2=vgl_vector_3d<double>(p2->x()-p0->x(),
00248                              p2->y()-p0->y(),
00249                              p2->z()-p0->z());
00250 #if 0
00251     if (dot_product(n,v2)!=0)
00252       return false;
00253 #endif
00254     double dp = vcl_fabs(dot_product(n,v2));
00255     if (dp>tol)
00256       return false;
00257   }
00258 
00259   return true;
00260 }
00261 
00262 //***************************************************************************
00263 // Basic operations
00264 //***************************************************************************
00265 
00266 //---------------------------------------------------------------------------
00267 //: Is `p' in `this' ?
00268 // \todo not yet implemented
00269 //---------------------------------------------------------------------------
00270 bool vsol_polygon_3d::in(vsol_point_3d_sptr const& ) const
00271 {
00272   vcl_cerr << "Warning: vsol_polygon_3d::in() has not been implemented yet\n";
00273   return false;
00274 }
00275 
00276 //---------------------------------------------------------------------------
00277 //: Return the unit normal vector at point `p'.
00278 //---------------------------------------------------------------------------
00279 vgl_vector_3d<double>
00280 vsol_polygon_3d::normal_at_point(vsol_point_3d_sptr const& /*no p needed*/) const
00281 {
00282   return plane_.normal();
00283 }
00284 //---------------------------------------------------------------------------
00285 //: Return the unit normal vector
00286 //---------------------------------------------------------------------------
00287 vgl_vector_3d<double> vsol_polygon_3d::normal() const
00288 {
00289   return plane_.normal();
00290 }
00291 
00292 //***************************************************************************
00293 // Implementation
00294 //***************************************************************************
00295 
00296 
00297 inline void vsol_polygon_3d::describe(vcl_ostream &strm, int blanking) const
00298 {
00299   if (blanking < 0) blanking = 0; while (blanking--) strm << ' ';
00300   if (size() == 0)
00301     strm << "[vsol_polygon_3d null]";
00302   else {
00303     strm << "[vsol_polygon_3d Nverts=" << size()
00304          << " Area=" << area();
00305     for (unsigned int i=0; i<size(); ++i)
00306       strm << " p" << i << ':' << *(vertex(i));
00307     strm << ']';
00308   }
00309   strm << vcl_endl;
00310 }
00311 
00312 //----------------------------------------------------------------
00313 // ================   Binary I/O Methods ========================
00314 //----------------------------------------------------------------
00315 
00316 //: Binary save self to stream.
00317 void vsol_polygon_3d::b_write(vsl_b_ostream &os) const
00318 {
00319   vsl_b_write(os, version());
00320   vsol_spatial_object_3d::b_write(os);
00321   if (!storage_)
00322     vsl_b_write(os, false); // Indicate null pointer stored
00323   else
00324   {
00325     vsl_b_write(os, true); // Indicate non-null pointer stored
00326     vsl_b_write(os, *storage_);
00327   }
00328 }
00329 
00330 //: Binary load self from stream (not typically used)
00331 void vsol_polygon_3d::b_read(vsl_b_istream &is)
00332 {
00333   short ver;
00334   vsl_b_read(is, ver);
00335   switch (ver)
00336   {
00337    case 1:
00338     vsol_spatial_object_3d::b_read(is);
00339 
00340     delete storage_;
00341     storage_ = new vcl_vector<vsol_point_3d_sptr>();
00342     bool valid_ptr;
00343     vsl_b_read(is, valid_ptr);
00344     if (!valid_ptr)
00345       return;
00346     vsl_b_read(is, *storage_);
00347     this->compute_plane();
00348     break;
00349    default:
00350     vcl_cerr << "vsol_polygon_3d: unknown I/O version " << ver << '\n';
00351   }
00352 }
00353 
00354 //: Return IO version number;
00355 short vsol_polygon_3d::version() const
00356 {
00357   return 1;
00358 }
00359 
00360 //: Print an ascii summary to the stream
00361 void vsol_polygon_3d::print_summary(vcl_ostream &os) const
00362 {
00363   os << *this;
00364 }
00365 
00366 //: Binary save vsol_polygon_3d to stream.
00367 void
00368 vsl_b_write(vsl_b_ostream &os, vsol_polygon_3d const* p)
00369 {
00370   if (p==0) {
00371     vsl_b_write(os, false); // Indicate null pointer stored
00372   }
00373   else{
00374     vsl_b_write(os,true); // Indicate non-null pointer stored
00375     p->b_write(os);
00376   }
00377 }
00378 
00379 //: Binary load vsol_polygon_3d from stream.
00380 void
00381 vsl_b_read(vsl_b_istream &is, vsol_polygon_3d* &p)
00382 {
00383   delete p;
00384   bool not_null_ptr;
00385   vsl_b_read(is, not_null_ptr);
00386   if (not_null_ptr) {
00387    // p = new vsol_polygon_3d(vcl_vector<vsol_point_3d_sptr>());
00388     p = new vsol_polygon_3d();
00389     p->b_read(is);
00390   }
00391   else
00392     p = 0;
00393 }