All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
PinController.h
1 // Copyright eeGeo Ltd (2012-2014), All Rights Reserved
2 
3 #pragma once
4 
5 #include "Types.h"
6 #include "IPinObserver.h"
7 #include "PinRepository.h"
8 #include "TerrainHeightProvider.h"
9 #include "IPinViewFactory.h"
10 #include "PinViewRenderer.h"
11 #include "Pin.h"
12 #include "PinView.h"
13 #include "Pins.h"
14 #include <map>
15 #include <algorithm>
16 
17 namespace Eegeo
18 {
19  namespace Pins
20  {
28  class PinController : protected Eegeo::NonCopyable, public IPinObserver
29  {
30  public:
38  PinController(PinRepository& pinRepository, Resources::Terrain::Heights::TerrainHeightProvider& terrainHeightProvider, IPinViewFactory& viewFactory, PinViewRenderer& viewRenderer)
39  : m_pinRepository(pinRepository)
40  , m_terrainHeightProvider(terrainHeightProvider)
41  , m_viewFactory(viewFactory)
42  , m_viewRenderer(viewRenderer)
43  {
44  m_pinRepository.AddPinObserver(*this);
45  }
46 
47  ~PinController()
48  {
49  m_pinRepository.RemovePinObserver(*this);
50 
51  for(TViewsByModel::iterator it = m_viewsByModel.begin(); it != m_viewsByModel.end(); ++it)
52  {
53  PinView* pView = it->second;
54  m_viewRenderer.RemoveView(*pView);
55  Eegeo_DELETE pView;
56  }
57  m_viewsByModel.clear();
58  }
59 
64  void Update(float deltaTime, const Camera::RenderCamera& renderCamera)
65  {
66  UpdateTerrainHeights();
67  UpdateViews();
68  m_viewRenderer.Update(renderCamera);
69  }
70 
74  virtual void OnPinAdded(Pin& pin)
75  {
76  Eegeo_ASSERT(!HasViewForModel(pin), "Attempt to add duplicate model to PinController.");
77 
78  PinView* pView = m_viewFactory.CreateViewForPin(pin);
79 
80  m_pinsNeedingHeightLookup.push_back(&pin);
81  m_viewsByModel[&pin] = pView;
82  m_viewRenderer.AddView(*pView);
83  }
84 
88  virtual void OnPinRemoved(Pin& pin)
89  {
90  Eegeo_ASSERT(HasViewForModel(pin), "Attempt to remove unknown model from PinController.");
91  PinView* pView = GetViewForModel(pin);
92 
93  m_pinsNeedingHeightLookup.erase(std::remove(m_pinsNeedingHeightLookup.begin(), m_pinsNeedingHeightLookup.end(), &pin), m_pinsNeedingHeightLookup.end());
94  m_viewsByModel.erase(&pin);
95  m_viewRenderer.RemoveView(*pView);
96 
97  Eegeo_DELETE(pView);
98  }
99 
104  void GetScreenBoundsForPin(const Pin& pin, Geometry::Bounds2D& outScreenBounds) const
105  {
106  const PinView* pView = GetViewForModel(pin);
107  Eegeo_ASSERT(pView != NULL, "Can't find screen bounds for a pin model that doesn't have a corresponding view.");
108 
109  outScreenBounds = pView->GetScreenSpaceBounds();
110  }
111 
117  bool TryGetPinsIntersectingScreenPoint(const v2& screenPoint, std::vector<Pin*>& outIntersectingPins) const
118  {
119  outIntersectingPins.clear();
120 
121  std::vector<PinView*> intersectingViews;
122  if(m_viewRenderer.TryGetViewsIntersectingScreenPoint(screenPoint, intersectingViews))
123  {
124  for(std::vector<PinView*>::const_iterator it = intersectingViews.begin(); it != intersectingViews.end(); ++it)
125  {
126  PinView* pView = *it;
127  outIntersectingPins.push_back(&(pView->GetPin()));
128  }
129  }
130 
131  return (outIntersectingPins.size() > 0);
132  }
133 
134 
139  float GetScaleForPin(const Pin& pin) const
140  {
141  const PinView* pView = GetViewForModel(pin);
142  Eegeo_ASSERT(pView != NULL, "Can't get scale for a pin model that doesn't have a corresponding view.");
143  return pView->GetScale();
144  }
145 
150  void SetScaleForPin(const Pin& pin, float pinScale)
151  {
152  PinView* pView = GetViewForModel(pin);
153  Eegeo_ASSERT(pView != NULL, "Can't set scale for a pin model that doesn't have a corresponding view.");
154  pView->SetScale(pinScale);
155  }
156 
157  protected:
158  virtual void UpdateViews()
159  {
160  for(TViewsByModel::iterator it = m_viewsByModel.begin(); it != m_viewsByModel.end(); ++it)
161  {
162  const Pin* pPin = it->first;
163  PinView* pView = it->second;
164 
165  const dv3& origin = pPin->GetEcefPosition();
166  pView->SetEcefOrigin(origin);
167  pView->SetTransform(pPin->GetTransform());
168  pView->SetTransformOrigin(pPin->GetTransformOrigin());
169  pView->SetColor(pPin->GetColor());
170  }
171  }
172 
173  private:
174  PinRepository& m_pinRepository;
175  Resources::Terrain::Heights::TerrainHeightProvider& m_terrainHeightProvider;
176  IPinViewFactory& m_viewFactory;
177  PinViewRenderer& m_viewRenderer;
178 
179  typedef std::map<Pin*, PinView*> TViewsByModel;
180 
181  std::vector<Pin*> m_pinsNeedingHeightLookup;
182 
183  TViewsByModel m_viewsByModel;
184 
185  PinView* GetViewForModel(const Pin& pin) const
186  {
187  TViewsByModel::const_iterator foundPin = m_viewsByModel.find(const_cast<Pin*>(&pin));
188 
189  if(foundPin != m_viewsByModel.end())
190  {
191  return foundPin->second;
192  }
193 
194  return NULL;
195  }
196 
197  bool HasViewForModel(const Pin& pin) const
198  {
199  return (GetViewForModel(pin) != NULL);
200  }
201 
202  void UpdateTerrainHeights()
203  {
204  const int maxPinsToUpdatePerFrame = 30;
205  const int numberOfPinsNeedingLookup = static_cast<int>(m_pinsNeedingHeightLookup.size());
206  int pinsToUpdateThisFrame = std::min(numberOfPinsNeedingLookup, maxPinsToUpdatePerFrame);
207 
208  while (pinsToUpdateThisFrame--)
209  {
210  Pin* pPin = m_pinsNeedingHeightLookup.back();
211 
212  float terrainHeight;
213  int queryTerminationLevel;
214 
215  if(m_terrainHeightProvider.TryGetHeight(pPin->GetEcefGeoidLocation(),
216  0,
217  pPin->TerrainHeightLevel(),
218  pPin->TerrainHeight(),
219  queryTerminationLevel,
220  terrainHeight))
221  {
222  pPin->SetTerrainHeight(terrainHeight, queryTerminationLevel);
223  }
224 
225  m_pinsNeedingHeightLookup.pop_back();
226  }
227 
228  int numOfPinsInRepo = m_pinRepository.GetNumOfPins();
229  if (m_pinsNeedingHeightLookup.empty() && numOfPinsInRepo > 0)
230  {
231  RepopulatePinLookupVector();
232  }
233  }
234 
235  void RepopulatePinLookupVector()
236  {
237  for (int pinIndex = 0; pinIndex < m_pinRepository.GetNumOfPins(); ++pinIndex)
238  {
239  Pin *pPin = m_pinRepository.GetPinAtIndex(pinIndex);
240  m_pinsNeedingHeightLookup.push_back(pPin);
241  }
242  }
243  };
244  }
245 }