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