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
00016
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
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;
00040
00041 private:
00042 boost::array<Point, topological> basis_;
00043 Point centroid_;
00044
00045
00046
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
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
00072 moment.template eigenvectors<topological>(basis_);
00073
00074 #ifndef NDEBUG
00075
00076 bool broken = false;
00077 for(unsigned i = 0; i < topological; ++i) {
00078 broken |= (fabs(basis_[i].norm2() - 1.0) > 1e-6);
00079 for(unsigned j = i + 1; j < topological; ++j) {
00080 broken |= (fabs(basis_[i].dot(basis_[j])) > 1e-6);
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
00098
00099 PPoint project(const Point& p) const {
00100 PPoint pp;
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
00110 PPoint project1(Point p) const {
00111 return project(p);
00112 }
00113
00114
00115
00116
00117 Point unproject(const PPoint& pp) const {
00118
00119
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
00146
00147 };
00148
00149 }
00150
00151 #endif