00001
00002
00003
00004
00005
00006
00007
00008 #ifndef MESHOCTREE_HPP_
00009 #define MESHOCTREE_HPP_
00010
00011 #include"MathHelper.h"
00012 #include"fv_float.h"
00013 #include<list>
00014 #include<vector>
00015
00016 namespace FemViewer
00017 {
00018 using namespace fvmath;
00019
00020
00021 template<typename T>
00022 class Octree
00023 {
00024 typedef typename::CVec3<CoordType> WorldPoint;
00025 public:
00026
00027 template<typename Iter>
00028 Octree(const Iter& begin, const Iter& end, unsigned int min) :
00029 m_minObjects(min)
00030 {
00031 WorldPoint p0, p1;
00032 CalculateExtents(begin, end, p0, p1);
00033 m_p0 = p0;
00034 m_p1 = p1;
00035
00036 for(Iter iter = begin; iter != end; ++iter)
00037 {
00038 m_objects.push_back(*iter);
00039 }
00040
00041 PopulateSubTrees();
00042 }
00043
00044
00045
00046
00047 template<typename Iter>
00048 Octree(const Iter& begin, const Iter& end, unsigned int min,
00049 const WorldPoint& p0, const WorldPoint& p1, bool keepAll = false) :
00050 m_p0(p0),
00051 m_p1(p1),
00052 m_minObjects(min)
00053 {
00054 PopulateOctree(p0, p1, begin, end, keepAll);
00055 }
00056
00057 T* GetObject(const WorldPoint& p)
00058 {
00059 if( !InBox(p, m_p0, m_p1) )
00060 {
00061 return 0;
00062 }
00063
00064 if( m_children.empty() )
00065 {
00066 for(typename std::vector<T*>::iterator iter = m_objects.begin(); iter != m_objects.end(); ++iter)
00067 {
00068 if( (*iter)->ContainsPoint(p) )
00069 {
00070 return *iter;
00071 }
00072 }
00073
00074 return 0;
00075 }
00076 else
00077 {
00078 for(typename std::list<Octree<T>* >::iterator iter = m_children.begin(); iter != m_children.end(); ++iter)
00079 {
00080 T* childResult = (*iter)->GetObject(p);
00081 if( childResult ) return childResult;
00082 }
00083 }
00084 return 0;
00085 }
00086
00087 const WorldPoint& GetMin() const { return m_p0; }
00088 const WorldPoint& GetMax() const { return m_p1; }
00089
00090 unsigned int GetNumObjects() const { return m_objects.size(); }
00091
00092 private:
00093 Octree(const Octree<T>& rhs);
00094 Octree<T>& operator=(const Octree<T>& rhs);
00095
00096 template<typename Iter>
00097 void CalculateExtents(const Iter& begin, const Iter& end, WorldPoint& p0, WorldPoint& p1)
00098 {
00099 p0 = WorldPoint(std::numeric_limits<CoordType>::max(), std::numeric_limits<CoordType>::max(), std::numeric_limits<CoordType>::max());
00100 p1 = WorldPoint(-std::numeric_limits<CoordType>::max(), -std::numeric_limits<CoordType>::max(), -std::numeric_limits<CoordType>::max());
00101
00102 for(Iter iter = begin; iter != end; ++iter)
00103 {
00104 p0 = Min(p0, (*iter)->GetMinExtent());
00105 p1 = Max(p1, (*iter)->GetMaxExtent());
00106 }
00107 }
00108
00109 template<typename Iter>
00110 void PopulateOctree(const WorldPoint& p0, const WorldPoint& p1, const Iter& begin, const Iter& end, bool canKeepAll = false)
00111 {
00112 m_p0 = p0;
00113 m_p1 = p1;
00114
00115
00116 for(Iter iter = begin; iter != end; ++iter)
00117 {
00118 WorldPoint min = (*iter)->GetMinExtent();
00119 WorldPoint max = (*iter)->GetMaxExtent();
00120
00121
00122 if( BoxesIntersect(min, max, m_p0, m_p1) )
00123 {
00124 m_objects.push_back(*iter);
00125 }
00126 }
00127
00128
00129
00130 if( !canKeepAll && this->GetNumObjects() == std::distance(begin, end) )
00131 {
00132 return;
00133 }
00134
00135 if( m_objects.size() > m_minObjects )
00136 {
00137 PopulateSubTrees();
00138 }
00139 }
00140
00141 bool HasElement(unsigned int id)
00142 {
00143 for(unsigned int i = 0; i < m_objects.size(); ++i)
00144 {
00145 if( m_objects[i]->GetId() == id ) return true;
00146 }
00147 return false;
00148 }
00149 T* GetElement(unsigned int id)
00150 {
00151 for(unsigned int i = 0; i < m_objects.size(); ++i)
00152 {
00153 if( m_objects[i]->GetId() == id ) return m_objects[i];
00154 }
00155 return 0;
00156 }
00157
00158
00159
00160 void PopulateSubTrees()
00161 {
00162
00163 WorldPoint mid = m_p0 + (m_p1-m_p0)/2.0;
00164
00165 Octree<T>* boxes[8];
00166 boxes[0] = new Octree<T>(m_objects.begin(), m_objects.end(), m_minObjects,
00167 WorldPoint(m_p0.x()-.001, m_p0.y()-.001, m_p0.z()-.001), WorldPoint(mid.x()+.001, mid.y()+.001, mid.z()+.001));
00168 boxes[1] = new Octree<T>(m_objects.begin(), m_objects.end(), m_minObjects,
00169 WorldPoint(mid.x()-.001, m_p0.y()-.001, m_p0.z()-.001), WorldPoint(m_p1.x()+.001, mid.y()+.001, mid.z()+.001));
00170 boxes[2] = new Octree<T>(m_objects.begin(), m_objects.end(), m_minObjects,
00171 WorldPoint(m_p0.x()-.001, mid.y()-.001, m_p0.z()-.001), WorldPoint(mid.x()+.001, m_p1.y()+.001, mid.z()+.001));
00172 boxes[3] = new Octree<T>(m_objects.begin(), m_objects.end(), m_minObjects,
00173 WorldPoint(mid.x()-.001, mid.y()-.001, m_p0.z()-.001), WorldPoint(m_p1.x()+.001, m_p1.y()+.001, mid.z()+.001));
00174
00175 boxes[4] = new Octree<T>(m_objects.begin(), m_objects.end(), m_minObjects,
00176 WorldPoint(m_p0.x()-.001, m_p0.y()-.001, mid.z()-.001), WorldPoint(mid.x()+.001, mid.y()+.001, m_p1.z()+.001));
00177 boxes[5] = new Octree<T>(m_objects.begin(), m_objects.end(), m_minObjects,
00178 WorldPoint(mid.x()-.001, m_p0.y()-.001, mid.z()-.001), WorldPoint(m_p1.x()+.001, mid.y()+.001, m_p1.z()+.001));
00179 boxes[6] = new Octree<T>(m_objects.begin(), m_objects.end(), m_minObjects,
00180 WorldPoint(m_p0.x()-.001, mid.y()-.001, mid.z()-.001), WorldPoint(mid.x()+.001, m_p1.y()+.001, m_p1.z()+.001));
00181 boxes[7] = new Octree<T>(m_objects.begin(), m_objects.end(), m_minObjects,
00182 WorldPoint(mid.x()-.001, mid.y()-.001, mid.z()-.001), WorldPoint(m_p1.x()+.001, m_p1.y()+.001, m_p1.z()+.001));
00183
00184
00185 for(unsigned int i = 0; i < 8; ++i)
00186 {
00187 if( boxes[i]->GetNumObjects() > 0 )
00188 {
00189 m_children.push_back(boxes[i]);
00190 }
00191 else
00192 {
00193 delete boxes[i];
00194 }
00195 }
00196 }
00197 bool InBox(const WorldPoint& testPoint, const WorldPoint& p0, const WorldPoint& p1)
00198 {
00199 return testPoint.x >= p0.x &&
00200 testPoint.y >= p0.y &&
00201 testPoint.z >= p0.z &&
00202 testPoint.x <= p1.x &&
00203 testPoint.y <= p1.y &&
00204 testPoint.z <= p1.z;
00205 }
00206
00207 bool LineSegmentsOverlap(double x0, double x1, double y0, double y1)
00208 {
00209 return x1 >= y0 && x0 <= y1;
00210 }
00211
00212 bool BoxesIntersect(const WorldPoint& box0Min, const WorldPoint& box0Max,
00213 const WorldPoint& box1Min, const WorldPoint& box1Max)
00214 {
00215 return LineSegmentsOverlap(box0Min.x, box0Max.x, box1Min.x, box1Max.x) &&
00216 LineSegmentsOverlap(box0Min.y, box0Max.y, box1Min.y, box1Max.y) &&
00217 LineSegmentsOverlap(box0Min.z, box0Max.z, box1Min.z, box1Max.z);
00218 }
00219
00220
00221 WorldPoint m_p0;
00222 WorldPoint m_p1;
00223
00224
00225 std::vector<T*> m_objects;
00226
00227
00228 std::list<Octree<T>* > m_children;
00229
00230 unsigned int m_minObjects;
00231 };
00232 }
00233
00234
00235
00236 #endif