Number5
Visualisierung 2 Project - Florian Schober (0828151, f.schober@live.com), Andreas Walch (0926780, walch.andreas89@gmail.com)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
QuadTree.cpp
Go to the documentation of this file.
1 #include "Application.hpp"
2 
3 QuadTree::QuadTree(Application* app, uvec2 const & size, uint const maxDistance)
4  : m_maxDistance(maxDistance)
5  , m_app(app)
6 {
7  resize(size);
8 
10  cout << "Picker-Mode: multi-threaded" << endl;
11  else
12  cout << "Picker-Mode: single-threaded" << endl;
13 }
14 void QuadTree::resize(uvec2 const & size)
15 {
16  if (m_data.size() == size) return;
17 
18  m_data.resize(size);
19 
20  if (size == uvec2(0,0))
21  m_levels.clear();
22  else
23  m_levels.resize((uint)glm::max(glm::ceil(glm::log2((float)size.x)),
24  glm::ceil(glm::log2((float)size.y)) ));
25  m_levels.shrink_to_fit();
26 
27  uint level = 0;
28  for (uvec2 levelSize(1,1); levelSize.x < size.x || levelSize.y < size.y ; levelSize *= 2)
29  {
30  m_levels[level].resize(levelSize);
31 
32  level ++;
33  }
34 }
35 bool QuadTree::findNear(uvec2 const & pos_, OUT id_t & foundId, OUT uvec2 & foundPos, OUT float & foundDistance)
36 {
37  auto pos = pos_;
38 
39  if (m_data.size() == uvec2(0,0))
40  return false;
41 
42  if (false)
43  {
44  if (m_data.at(pos) == 0)
45  return false;
46 
47  foundId = m_data.at(pos);
48  foundPos = pos;
49  return true;
50  }
51 
52  if (!m_levels[0].at(0,0)) return false;
53 
54  list<uvec2> candidates;
55  candidates.push_back(uvec2(0,0));
56 
57 
58  for (auto levelIdx = 1U; levelIdx < m_levels.size() ; levelIdx ++)
59  {
60  auto& level = m_levels[levelIdx];
61  auto posOnLevel = pos / (2U << (m_levels.size() - levelIdx - 1));
62  auto maxDistanceOnLevel = m_maxDistance / (2U << (m_levels.size() - levelIdx - 1));
63  auto nCandidates = candidates.size();
64 
65  for (auto& candidate : candidates)
66  {
67  candidate *= 2U;
68  candidates.push_front(candidate + uvec2(1,0));
69  candidates.push_front(candidate + uvec2(0,1));
70  candidates.push_front(candidate + uvec2(1,1));
71  }
72 
73  // remove empty candidates
74  candidates.remove_if([&level]
75  (uvec2 const & candidate)
76  {
77  return !level.at(candidate);
78  });
79 
80  // declare distance-function
81  auto distances = [&posOnLevel]
82  (uvec2 const & candidate, float* deltas)
83  {
84  deltas[0] = glm::length(vec2(candidate) - vec2(posOnLevel) - vec2(-0.5f,-0.5f));
85  deltas[1] = glm::length(vec2(candidate) - vec2(posOnLevel) - vec2( 0.5f,-0.5f));
86  deltas[2] = glm::length(vec2(candidate) - vec2(posOnLevel) - vec2(-0.5f, 0.5f));
87  deltas[3] = glm::length(vec2(candidate) - vec2(posOnLevel) - vec2( 0.5f, 0.5f));
88  };
89  auto minDistance = [distances]
90  (uvec2 const & candidate)
91  {
92  float deltas[4];
93  distances(candidate, deltas);
94  return (float)(*min_element(deltas, deltas + 4));
95  };
96  auto maxDistance = [distances]
97  (uvec2 const & candidate)
98  {
99  float deltas[4];
100  distances(candidate, deltas);
101  return (float)(*max_element(deltas, deltas + 4));
102  };
103 
104 
105  // compute min-distance
106  float minimum_of_maxDistance = (float)(maxDistanceOnLevel+1);
107  for(auto& candidate : candidates)
108  minimum_of_maxDistance = glm::min(minimum_of_maxDistance,
109  maxDistance(candidate));
110 
111  // remove candidates further away than min-distance
112  candidates.remove_if([minDistance, minimum_of_maxDistance]
113  (uvec2 const & candidate)
114  {
115  return minDistance(candidate) > (minimum_of_maxDistance);
116  });
117  }
118 
119  auto nCandidates = candidates.size();
120  for (auto& candidate : candidates)
121  {
122  candidate *= 2U;
123  candidates.push_front(candidate + uvec2(1,0));
124  candidates.push_front(candidate + uvec2(0,1));
125  candidates.push_front(candidate + uvec2(1,1));
126  }
127 
128  // remove empty candidates
129  candidates.remove_if([this]
130  (uvec2 const & candidate)
131  {
132  return m_data.at(candidate) == 0;
133  });
134 
135  if (candidates.empty())
136  return false;
137 
138  // declare distance-function
139  auto distance = [pos]
140  (uvec2 const & candidate)
141  {
142  return glm::length(vec2(candidate)-vec2(pos));
143  };
144 
145  foundPos = *min_element(candidates.begin(), candidates.end(), [distance]
146  (uvec2 const & a, uvec2 const & b)
147  {
148  return distance(a) < distance(b);
149  });
150 
151  foundDistance = distance(foundPos);
152  if (foundDistance > m_maxDistance)
153  return false;
154 
155  foundId = m_data.at(foundPos);
156  return true;
157 }
158 
159 void QuadTree::maxDistance(uint const distance)
160 {
161  m_maxDistance = distance;
162 }
163 uint const QuadTree::maxDistance() const
164 {
165  return m_maxDistance;
166 }
167 
168 
169 void QuadTree::updateLayersBaseCell(uint const layer, uint const x, uint const y)
170 {
171  auto baseLevel = m_levels.rbegin();
172 
173  auto const layerDiff = m_levels.size() - layer;
174  auto layerExpansion = 2 << (layerDiff-1);
175 
176  updateLayerArea(&m_data, baseLevel, x * layerExpansion, y * layerExpansion, layerExpansion);
177 
178  // create other layers
179  for (auto level = m_levels.rbegin() + 1; level != m_levels.rend(); level ++)
180  {
181  auto lastLevel = level - 1;
182 
183  layerExpansion /= 2;
184 
185  updateLayerArea(lastLevel, level, x * layerExpansion, y * layerExpansion, layerExpansion);
186 
187  if (layerExpansion == 1)
188  break;
189  }
190 
191 }
192 
194 {
195  auto& tasks = m_app->getTasks();
196 
197  tasks.schedule([this](){ updateLayersBaseCell(1, 0, 0); }, &(m_updateLayersParallelMutex[0]));
198  tasks.schedule([this](){ updateLayersBaseCell(1, 1, 0); }, &(m_updateLayersParallelMutex[1]));
199  tasks.schedule([this](){ updateLayersBaseCell(1, 0, 1); }, &(m_updateLayersParallelMutex[2]));
200  tasks.schedule([this](){ updateLayersBaseCell(1, 1, 1); }, &(m_updateLayersParallelMutex[3]));
201 
202  for (auto& handle : m_updateLayersParallelMutex)
203  handle.wait();
204 
205  updateLayerCell(&(m_levels[1]), &(m_levels[0]), 0, 0);
206 }
208 {
209  updateLayersBaseCell(0, 0, 0);
210 }
uint16 id_t
The data-type used for the id-buffer.
Definition: Util.hpp:6
TaskManager & getTasks()
Configuration & getConfig()
Definition: Application.hpp:36
void updateLayerArea(TBaseLayer base, TCurrentLayer current, uint const offset_x, uint const offset_y, uint size)
Definition: QuadTree.hpp:204
vector< MidLevel > m_levels
Definition: QuadTree.hpp:113
uint const maxDistance() const
Definition: QuadTree.cpp:163
void resize(uvec2 const &size)
Definition: QuadTree.cpp:14
void updateLayersBaseCell(uint const layer, uint const x, uint const y)
Definition: QuadTree.cpp:169
array< auto_reset_event, 4 > m_updateLayersParallelMutex
Definition: QuadTree.hpp:115
uint m_maxDistance
Definition: QuadTree.hpp:114
void schedule(T fnc)
Definition: TaskManager.hpp:86
Application * m_app
Definition: QuadTree.hpp:111
void updateLayersParallel()
Definition: QuadTree.cpp:193
bool pickerMultiThreaded() const
void updateLayersSerial()
Definition: QuadTree.cpp:207
DataLevel m_data
Definition: QuadTree.hpp:112
T & at(uvec2 const &pos)
Definition: QuadTree.hpp:39
void updateLayerCell(TBaseLayer base, TCurrentLayer current, uint const x, uint const y)
Definition: QuadTree.hpp:219
uvec2 const & size() const
Definition: QuadTree.hpp:100
void resize(uvec2 const &size)
Definition: QuadTree.hpp:79
bool findNear(uvec2 const &pos, OUT id_t &foundId, OUT uvec2 &foundPos, OUT float &foundDistance)
Definition: QuadTree.cpp:35
QuadTree(Application *app, uvec2 const &size, uint const maxDistance)
Definition: QuadTree.cpp:3