ProjectionPlane.h

Go to the documentation of this file.
00001 #ifndef ProjectionPlane_HEADER
00002 #define ProjectionPlane_HEADER
00003 
00004 #include <math.h>
00005 #include <boost/array.hpp>
00006 #include "Point.h"
00007 #include "Matrix.h"
00008 
00009 namespace Geometry {
00010 
00011 template <unsigned ambient, unsigned topological, bool b = (ambient==topological)>
00012 class ProjectionPlane;
00013 
00014 /***************************************************************************
00015  * Easy case: if the two dimensions are the same, there is no projection
00016  * to do.
00017  ***************************************************************************/
00018 template <unsigned d> class ProjectionPlane<d, d, true> {
00019 private:
00020 typedef Geometry::Point<d> Point;
00021 public:
00022 template <class iterator> ProjectionPlane(iterator, iterator) { }
00023 template <class iterator> ProjectionPlane(iterator, iterator, int) { }
00024 const Point& project(const Point& p) const { return p; }
00025 Point project1(Point p) const { return p; }
00026 const Point& unproject(const Point& p) const { return p; }
00027 std::string toString() const { return "identity-plane"; }
00028 };
00029 
00030 
00031 
00032 /***************************************************************************
00033  * The interesting case.
00034  ***************************************************************************/
00035 template <unsigned ambient, unsigned topological>
00036 class ProjectionPlane<ambient, topological, false> {
00037 public:
00038 typedef Geometry::Point<ambient> Point;
00039 typedef Geometry::Point<topological> PPoint; // projected point
00040 
00041 private:
00042 boost::array<Point, topological> basis_; 
00043 Point centroid_;
00044 
00045 /***************************************************************************
00046  * Compute the best projection plane of a set of points.
00047  ***************************************************************************/
00048 private:
00049 template <class point_iterator>
00050 void init(const point_iterator& begin, const point_iterator& end) {
00051   assert(ambient > topological);
00052 
00053   unsigned num_pts = 0;
00054 
00055   // Compute the centroid and the moment matrix.
00056   centroid_.assign(0.0);
00057   BOUNDED_FOREACH(Point p, begin, end) {
00058     centroid_ += p;
00059     num_pts++;
00060   }
00061 
00062   assert(num_pts >= topological + 1);
00063   centroid_ /= (double)num_pts; 
00064 
00065   Matrix<ambient, ambient> moment(0.0);
00066   BOUNDED_FOREACH(Point p, begin, end) {
00067     p -= centroid_;
00068     moment += Matrix<ambient, ambient>(p, p);
00069   }
00070 
00071   // Copy the largest eigenvectors into the basis.
00072   moment.template eigenvectors<topological>(basis_);
00073 
00074 #ifndef NDEBUG
00075   // Check the basis is actually (almost) orthonormal.
00076   bool broken = false;
00077   for(unsigned i = 0; i < topological; ++i) {
00078     broken |= (fabs(basis_[i].norm2() - 1.0) > 1e-6); // normal?
00079     for(unsigned j = i + 1; j < topological; ++j) {
00080       broken |= (fabs(basis_[i].dot(basis_[j])) > 1e-6); // ortho
00081     }
00082   }
00083   if (broken) {
00084     fprintf(stderr, "Broken projection plane: %s\n", toString().c_str());
00085     assert(!broken);
00086   }
00087 #endif
00088 }
00089 
00090 public:
00091 template <class point_iterator>
00092 ProjectionPlane(const point_iterator& begin, const point_iterator& end) {
00093   init(begin, end);
00094 }
00095 
00096 /***************************************************************************
00097  * Project down to the coordinate plane.
00098  ***************************************************************************/
00099 PPoint project(const Point& p) const {
00100   PPoint pp;  // uninitialized
00101   Point p2 = p - centroid_ ;
00102 
00103   for(unsigned i = 0; i < topological; ++i) {
00104     pp[i] = p2.dot(basis_[i]);
00105   }
00106   return pp;
00107 }
00108 
00109 // necessary for STL functional stuff
00110 PPoint project1(Point p) const {
00111   return project(p);
00112 }
00113 
00114 /***************************************************************************
00115  * Project up from the coordinate plane to the real plane.
00116  ***************************************************************************/
00117 Point unproject(const PPoint& pp) const {
00118   /*
00119     pp = centroid + \sum_{i\in topo} ( pp[i] * basis_[i] )
00120    */
00121 
00122   Point unprojected = centroid_;
00123 
00124   for(unsigned i = 0; i < topological; ++i) {
00125     unprojected += (basis_[i]) * (pp[i]);
00126   }
00127 
00128   return unprojected;
00129 }
00130 
00131 std::string toString() const {
00132   char buffer[4096];
00133   snprintf(buffer, sizeof(buffer), "dim %u, centroid %s, basis << ",
00134       unsigned(topological), centroid_.toString().c_str());
00135   std::string s = buffer;
00136   BOOST_FOREACH(const Point& p, basis_) {
00137     s += p.toString().c_str();
00138     s += ' ';
00139   }
00140   s += ">>";
00141   return s;
00142 }
00143 
00144 /***************************************************************************
00145  * FIN
00146  ***************************************************************************/
00147 };
00148 
00149 }
00150 
00151 #endif

Generated on Thu Mar 27 19:04:14 2008 by  doxygen 1.4.6