core/vgl/vgl_area.txx
Go to the documentation of this file.
00001 // This is core/vgl/vgl_area.txx
00002 #ifndef vgl_area_txx_
00003 #define vgl_area_txx_
00004 
00005 #include "vgl_area.h"
00006 //:
00007 // \file
00008 #include <vgl/vgl_polygon.h>
00009 #include <vgl/vgl_point_2d.h>
00010 
00011 template <class T>
00012 T vgl_area_signed(vgl_polygon<T> const& poly)
00013 {
00014   // Compute the area using Green's theorem
00015   T area = T(0);
00016   for (unsigned int s = 0; s < poly.num_sheets(); ++s )
00017     for (unsigned int i = 0, j = (unsigned int)(poly[s].size()-1); i < poly[s].size(); j=i++ )
00018       area += poly[s][j].x() * poly[s][i].y() - poly[s][i].x() * poly[s][j].y();
00019 
00020   return area/2;
00021 }
00022 
00023 //: The area weighted center of a polygon
00024 //  In general this is different than the mean of the polygon's vertices
00025 template <class T>
00026 vgl_point_2d<T> vgl_centroid(vgl_polygon<T> const& poly)
00027 {
00028   T area = vgl_area_signed(poly);
00029   T x = T(0), y = T(0);
00030   for (unsigned int s = 0; s < poly.num_sheets(); ++s ){
00031     for (unsigned int i = 0, j = (unsigned int)(poly[s].size()-1); i < poly[s].size(); j=i++ ){
00032       T w = poly[s][j].x() * poly[s][i].y() - poly[s][i].x() * poly[s][j].y();
00033       x += (poly[s][j].x() + poly[s][i].x())*w;
00034       y += (poly[s][j].y() + poly[s][i].y())*w;
00035     }
00036   }
00037   x /= 6*area;
00038   y /= 6*area;
00039   return vgl_point_2d<T>(x,y);
00040 }
00041 
00042 // This function is not implemented inline because the cost of a
00043 // single function call is irrelevant compared to the cost of running
00044 // vgl_area_signed. It is therefore better to have fewer dependencies
00045 // in the header file and implement this function here.
00046 template <class T>
00047 T vgl_area( const vgl_polygon<T>& poly )
00048 {
00049   T area = vgl_area_signed(poly);
00050   return area<0 ? -area : area;
00051 }
00052 
00053 //: The orientation enforced area of a polygon.
00054 // \note This method assumes that the polygon is simple (i.e. no crossings)
00055 //  and the correct orientation is 'enforced' on the polygon (i.e. holes are
00056 //  given negative area) to ensure that the resultant area is correct
00057 // \sa vgl_area
00058 // \relatesalso vgl_polygon
00059 template <class T> T vgl_area_enforce_orientation(vgl_polygon<T> const& poly)
00060 {
00061   T area = T(0);
00062 
00063   // now check containment and enforce correct signs
00064   // if a sheet is inside an odd number of other sheets then it's a hole
00065   for (unsigned int t = 0; t < poly.num_sheets(); ++t)
00066   {
00067     const typename vgl_polygon<T>::sheet_t & test_pgon= poly[t];
00068     T t_area = T(0);
00069 
00070     // first calculate all test_pgon's area using Green's theorem
00071     for (unsigned int i = 0, j = (unsigned int)(test_pgon.size()-1); i < test_pgon.size(); j=i++ )
00072       t_area += test_pgon[j].x() * test_pgon[i].y() - test_pgon[i].x() * test_pgon[j].y();
00073 
00074     // test if one of t's points is inside the other sheets
00075     // assume sheets don't overlap!
00076     bool is_hole = false;
00077     T x = test_pgon[0].x();
00078     T y = test_pgon[0].y();
00079     for (unsigned int s = 0; s < poly.num_sheets(); ++s)
00080     {
00081       // don't check a sheet against itself
00082       if (s==t)
00083         continue;
00084 
00085       typename vgl_polygon<T>::sheet_t const& pgon = poly[s];
00086       unsigned int n = (unsigned int)(pgon.size());
00087       bool c = false;
00088       for (unsigned int i = 0, j = n-1; i < n; j = i++)
00089         // invert c for each edge crossing
00090         if ((((pgon[i].y() <= y) && (y < pgon[j].y())) || ((pgon[j].y() <= y) && (y < pgon[i].y()))) &&
00091             (x < (pgon[j].x() - pgon[i].x()) * (y - pgon[i].y()) / (pgon[j].y() - pgon[i].y()) + pgon[i].x()))
00092           c = !c;
00093 
00094       if (c)
00095         is_hole = !is_hole;
00096     }
00097 
00098     // if it's oriented in the wrong direction then reverse it
00099     if ( (!is_hole && t_area < 0) || (is_hole && t_area > 0))
00100       t_area = -t_area;
00101 
00102     area += t_area;
00103   }
00104 
00105   return area/2;
00106 }
00107 
00108 #undef VGL_AREA_INSTANTIATE
00109 #define VGL_AREA_INSTANTIATE(T) \
00110 template T vgl_area(vgl_polygon<T > const&); \
00111 template T vgl_area_signed(vgl_polygon<T > const&); \
00112 template T vgl_area_enforce_orientation(vgl_polygon<T > const&); \
00113 template vgl_point_2d<T > vgl_centroid(vgl_polygon<T > const&)
00114 
00115 #endif // vgl_area_txx_