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