root/FalconView/trunk/public/fvw_core/GeodataDataSources/LibkmlNetworkLink.cpp @ 2267

Revision 2267, 14.0 KB (checked in by JO94, 6 months ago)

tree now honors <open> tag in KML

Line 
1// Copyright (c) 1994-2010 Georgia Tech Research Corporation, Atlanta, GA
2// This file is part of FalconView(tm).
3
4// FalconView(tm) is free software: you can redistribute it and/or modify
5// it under the terms of the GNU Lesser General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// FalconView(tm) is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public License
15// along with FalconView(tm).  If not, see <http://www.gnu.org/licenses/>.
16
17// FalconView(tm) is a trademark of Georgia Tech Research Corporation.
18
19// LibkmlNetworkLink.cpp : Implementation of CLibkmlNetworkLink
20
21#include "stdafx.h"
22#include "LibkmlNetworkLink.h"
23#include "UtilityMethods.h"
24#include "LibkmlDataSource.h"
25#include "ComErrorObject.h"
26
27// CLibkmlNetworkLink
28
29STDMETHODIMP CLibkmlNetworkLink::get_DataSetCount(LONG* count)
30{
31   try
32   {
33      PopulateWrappedDataSourceAsNecessary();
34      if (m_wrappedDataSource)
35         return m_wrappedDataSource->get_DataSetCount(count);
36   }
37   catch (...)
38   {
39      // There is a lot of bad KML out there.  Google Earth ignores it silently.
40      // Returning zero here and just logging the problem keeps FalconView from halting
41      // the KML loading process.  PopulateWrappedDataSourceAsNecessary() will
42      // throw up failed assert messages in debug mode.
43      std::string msg("failed to get data set count (something is wrong with this KML?) - returning count of zero");
44      CUtilityMethods::WriteStringToFVErrorLog(msg);
45   }
46
47   *count = 0;
48   return S_OK;
49}
50
51STDMETHODIMP CLibkmlNetworkLink::raw_GetDataSet(LONG index, IFvDataSet** dataSet)
52{
53   TRY_BLOCK
54   {
55      PopulateWrappedDataSourceAsNecessary();
56      if (m_wrappedDataSource)
57         return m_wrappedDataSource->raw_GetDataSet(index, dataSet);
58      return E_FAIL;
59   }
60   CATCH_BLOCK_RET
61}
62
63STDMETHODIMP CLibkmlNetworkLink::get_Name(BSTR* name)
64{
65   TRY_BLOCK
66   {
67      if (m_networkLink->has_name())
68      {
69         *name = _bstr_t(m_networkLink->get_name().c_str()).Detach();
70      }
71      else
72      {
73         PopulateWrappedDataSourceAsNecessary();
74         if (m_wrappedDataSource)
75            return m_wrappedDataSource->get_Name(name);
76         *name = _bstr_t("<NetworkLink>").Detach();
77      }
78
79      return S_OK;
80   }
81   CATCH_BLOCK_RET
82}
83
84STDMETHODIMP CLibkmlNetworkLink::raw_GetDataSetByName(BSTR name, IFvDataSet** dataSet)
85{
86   TRY_BLOCK
87   {
88      PopulateWrappedDataSourceAsNecessary();
89      if (m_wrappedDataSource)
90         return m_wrappedDataSource->raw_GetDataSetByName(name, dataSet);
91      return E_FAIL;
92   }
93   CATCH_BLOCK_RET
94}
95
96STDMETHODIMP CLibkmlNetworkLink::get_DataSourceCount(LONG* count)
97{
98   try
99   {
100      PopulateWrappedDataSourceAsNecessary();
101      if (m_wrappedDataSource)
102         return m_wrappedDataSource->get_DataSourceCount(count);
103   }
104   catch (...)
105   {
106      // There is a lot of bad KML out there.  Google Earth ignores it silently.
107      // Returning zero here and just logging the problem keeps FalconView from halting
108      // the KML loading process.  PopulateWrappedDataSourceAsNecessary() will
109      // throw up failed assert messages in debug mode.
110      std::string msg("failed to get data source count (something is wrong with this KML?) - returning count of zero");
111      CUtilityMethods::WriteStringToFVErrorLog(msg);
112   }
113
114   *count = 0;
115   return S_OK;
116}
117
118STDMETHODIMP CLibkmlNetworkLink::raw_GetDataSource(LONG index, IFvDataSource** dataSource)
119{
120   TRY_BLOCK
121   {
122      PopulateWrappedDataSourceAsNecessary();
123      if (m_wrappedDataSource)
124         return m_wrappedDataSource->raw_GetDataSource(index, dataSource);
125      return E_FAIL;
126   }
127   CATCH_BLOCK_RET
128}
129
130STDMETHODIMP CLibkmlNetworkLink::raw_GetDataSourceByName(BSTR name, IFvDataSource** dataSource)
131{
132   TRY_BLOCK
133   {
134      PopulateWrappedDataSourceAsNecessary();
135      if (m_wrappedDataSource)
136         return m_wrappedDataSource->raw_GetDataSourceByName(name, dataSource);
137      return E_FAIL;
138   }
139   CATCH_BLOCK_RET
140}
141
142STDMETHODIMP CLibkmlNetworkLink::get_Handle(LONG* handle)
143{
144   *handle = m_handle;
145   return S_OK;
146}
147
148STDMETHODIMP CLibkmlNetworkLink::raw_GetImageByIdentifier(BSTR identifier, VARIANT* imageData)
149{
150   TRY_BLOCK
151   {
152      PopulateWrappedDataSourceAsNecessary();
153
154      if (m_wrappedDataSource)
155      {
156         ISymbolFactoryPtr symbolFactory = m_wrappedDataSource;
157         if (symbolFactory)
158            return symbolFactory->raw_GetImageByIdentifier(identifier, imageData);
159      }
160
161      ISymbolFactoryPtr symbol_factory = m_rootDS;
162      return symbol_factory->raw_GetImageByIdentifier(identifier, imageData);
163   }
164   CATCH_BLOCK_RET
165}
166
167void CLibkmlNetworkLink::AssociateWithLibkmlNetworkLink(kmldom::NetworkLinkPtr networkLink, ILibkmlDataSource* rootDS)
168{
169   rootDS->InternalRefAdding(); // see comments in InternalRefAdding implementation
170   m_rootDS = rootDS;
171   m_networkLink = networkLink;
172}
173
174void CLibkmlNetworkLink::PopulateWrappedDataSourceAsNecessary()
175{
176   // call from within a TRY_BLOCK
177
178   // This object lightly wraps a data source that is opened from the network link.  If there is no data source opened from the network link,
179   // this object just returns whatever may be on the <NetworkLink> element that it represents.
180
181   try
182   {
183      if (!m_wrappedDataSource && m_networkLink->has_link())
184      {
185         // If the regionation parameters have been set and the feature is active,
186         // then we'll skip it.  Note that, if the regionation parameters have not been set
187         // then an element is not considered active in this case.  (If the network link does not
188         // have a <Region> tag, it is loaded regardless.)
189
190         // if the given feature does not have a region, then find the youngest ancestor that does
191         kmldom::FeaturePtr feature = kmldom::AsFeature(m_networkLink);
192         while (feature != NULL && feature->has_region() == false)
193            feature = kmldom::AsFeature(CUtilityMethods::GetAncestorOfType(feature, kmldom::Type_Feature));
194
195         if ( feature == NULL // feature is null if not regionated
196              || (m_degreesPerPixelX >= 0 && m_degreesPerPixelY >= 0
197                  && CUtilityMethods::KMLFeatureInRegion(m_networkLink, m_leftLon,
198                                                         m_bottomLat, m_rightLon, m_topLat,
199                                                         m_degreesPerPixelX, m_degreesPerPixelY)))
200         {
201            // get the base URL
202            IFvDataSourcePtr dataSource(CLSID_LibkmlDataSource);
203            ILibkmlDataSourcePtr libkmlDataSource = dataSource;
204            kmldom::LinkPtr link = m_networkLink->get_link();
205            std::string url = CUtilityMethods::ResolveURI((char*)m_rootDS->URL, (char*)link->get_href().c_str());
206
207            // if the link has a <viewFormat> tag, honor it
208            if (CUtilityMethods::LooksLikeHttp(url.c_str()) && link->has_viewformat())
209            {
210               // JVO TODO: test across antemeridian, on rotated map
211
212               std::string viewformat = link->get_viewformat();
213
214               const size_t SIZE = 30;
215               char buf[SIZE];
216
217               sprintf_s(buf, SIZE, "%f", (m_rightLon - m_leftLon) / 2);
218               CUtilityMethods::ReplaceAllInString(viewformat, "[lookatLon]", buf);
219               CUtilityMethods::ReplaceAllInString(viewformat, "[lookatTerrainLon]", buf);
220               CUtilityMethods::ReplaceAllInString(viewformat, "[cameraLon]", buf);
221
222               sprintf_s(buf, SIZE, "%f", (m_topLat - m_bottomLat) / 2);
223               CUtilityMethods::ReplaceAllInString(viewformat, "[lookatLat]", buf);
224               CUtilityMethods::ReplaceAllInString(viewformat, "[lookatTerrainLat]", buf);
225               CUtilityMethods::ReplaceAllInString(viewformat, "[cameraLat]", buf);
226
227               sprintf_s(buf, SIZE, "%f", m_leftLon);
228               CUtilityMethods::ReplaceAllInString(viewformat, "[bboxWest]", buf);
229
230               sprintf_s(buf, SIZE, "%f", m_bottomLat);
231               CUtilityMethods::ReplaceAllInString(viewformat, "[bboxSouth]", buf);
232
233               sprintf_s(buf, SIZE, "%f", m_rightLon);
234               CUtilityMethods::ReplaceAllInString(viewformat, "[bboxEast]", buf);
235
236               sprintf_s(buf, SIZE, "%f", m_topLat);
237               CUtilityMethods::ReplaceAllInString(viewformat, "[bboxNorth]", buf);
238
239               // elements below set to "0" (zero)
240               buf[0] = '0';
241               buf[1] = 0;
242               CUtilityMethods::ReplaceAllInString(viewformat, "[lookatRange]", buf);
243               CUtilityMethods::ReplaceAllInString(viewformat, "[lookatTilt]", buf);
244               CUtilityMethods::ReplaceAllInString(viewformat, "[lookatHeading]", buf);
245               CUtilityMethods::ReplaceAllInString(viewformat, "[lookatTerrainAlt]", buf);
246               CUtilityMethods::ReplaceAllInString(viewformat, "[cameraAlt]", buf);
247               CUtilityMethods::ReplaceAllInString(viewformat, "[horizFov]", buf);
248               CUtilityMethods::ReplaceAllInString(viewformat, "[vertFov]", buf);
249               CUtilityMethods::ReplaceAllInString(viewformat, "[horizPixels]", buf);
250               CUtilityMethods::ReplaceAllInString(viewformat, "[vertPixels]", buf);
251               CUtilityMethods::ReplaceAllInString(viewformat, "[terrainEnabled]", buf);
252
253               // append the view format string
254               if (url.at(url.length() - 1) != '&')
255                  url.append("&");
256               url.append(viewformat);
257            }
258
259            // populate the data source from the URL
260            long handle = libkmlDataSource->GetHandle();
261            CLibkmlDataSource* ds = (CLibkmlDataSource*)CInternalObjectRegistry::GetObject(handle);
262            std::string kml_data;
263            ds->FetchDataRelativeToDataSource(url.c_str(), kml_data);
264            ds->LoadKML(kml_data, url.c_str());
265
266            m_wrappedDataSource = dataSource.Detach();
267
268            // register for callbacks on the wrapped data source so that changes notices get fired to anything registered
269            // for callbacks on the root data source
270            dataSource = libkmlDataSource; // reassociate the smart pointer after Detach()
271            dataSource->RegisterForCallbacks(this);
272
273            // indicate to the root data source that something has changed
274            if (!m_bFirstAttemptToLoad)
275               CLibkmlDataSource::FireDataSourceChanged(m_rootDS->Handle);
276         }
277      }
278   }
279   catch (...)
280   {
281      m_wrappedDataSource = NULL;
282      THROW_ERROR_MSG2(E_FAIL, "exception in CLibkmlNetworkLink::PopulateWrappedDataSourceAsNecessary()");
283   }
284
285   m_bFirstAttemptToLoad = FALSE;
286}
287
288STDMETHODIMP CLibkmlNetworkLink::raw_Extent2D(double* minX, double* minY, double* maxX, double* maxY)
289{
290   TRY_BLOCK
291   {
292      PopulateWrappedDataSourceAsNecessary();
293      if (m_wrappedDataSource)
294         return m_wrappedDataSource->raw_Extent2D(minX, minY, maxX, maxY);
295      return E_FAIL;
296   }
297   CATCH_BLOCK_RET
298}
299
300STDMETHODIMP CLibkmlNetworkLink::get_Description(BSTR* description)
301{
302   TRY_BLOCK
303   {
304      if (m_networkLink->has_description())
305      {
306         *description = _bstr_t(m_networkLink->get_description().c_str()).Detach();
307      }
308      else
309      {
310         PopulateWrappedDataSourceAsNecessary();
311         if (m_wrappedDataSource)
312            return m_wrappedDataSource->get_Description(description);
313         *description = _bstr_t("A KML <NetworkLink>.").Detach();
314      }
315
316      return S_OK;
317   }
318   CATCH_BLOCK_RET
319}
320
321STDMETHODIMP CLibkmlNetworkLink::raw_RegisterForCallbacks(IFvDataSourceCallback* fvDataSourceCallback)
322{
323   TRY_BLOCK
324   {
325      IFvDataSourcePtr rootDS = m_rootDS;
326      return rootDS->RegisterForCallbacks(fvDataSourceCallback);;
327   }
328   CATCH_BLOCK_RET
329}
330
331STDMETHODIMP CLibkmlNetworkLink::raw_UnregisterForCallbacks(IFvDataSourceCallback* fvDataSourceCallback)
332{
333   TRY_BLOCK
334   {
335      IFvDataSourcePtr rootDS = m_rootDS;
336      return rootDS->UnregisterForCallbacks(fvDataSourceCallback);;
337   }
338   CATCH_BLOCK_RET
339}
340
341STDMETHODIMP CLibkmlNetworkLink::raw_SetRegionationParameters(
342   DOUBLE leftLon, DOUBLE bottomLat, DOUBLE rightLon, DOUBLE topLat,
343   DOUBLE degreesPerPixelX, DOUBLE degreesPerPixelY)
344{
345   TRY_BLOCK
346   {
347      // save the parameters
348      m_leftLon = leftLon;
349      m_bottomLat = bottomLat;
350      m_rightLon = rightLon;
351      m_topLat = topLat;
352      m_degreesPerPixelX = degreesPerPixelX;
353      m_degreesPerPixelY = degreesPerPixelY;
354
355      // repopulate the wrapped data source (this may fire a data source changed notification)
356      PopulateWrappedDataSourceAsNecessary();
357
358      // pass the parameters on to any wrapped data source
359      IRegionatedKMLContainerPtr regionatedKMLContainer = m_wrappedDataSource;
360      if (regionatedKMLContainer)
361         regionatedKMLContainer->SetRegionationParameters(leftLon, bottomLat, rightLon, topLat, degreesPerPixelX, degreesPerPixelY);
362
363      return S_OK;
364   }
365   CATCH_BLOCK_RET
366}
367
368STDMETHODIMP CLibkmlNetworkLink::raw_DataSourceChanged()
369{
370   CLibkmlDataSource::FireDataSourceChanged(m_rootDS->Handle);
371   return S_OK;
372}
373
374STDMETHODIMP CLibkmlNetworkLink::raw_CheckConnectString(BSTR connectString, VARIANT_BOOL* valid)
375{
376   return E_NOTIMPL;
377}
378
379STDMETHODIMP CLibkmlNetworkLink::get_Visible(VARIANT_BOOL *visible)
380{
381   *visible = m_visible;
382   return S_OK;
383}
384
385STDMETHODIMP CLibkmlNetworkLink::put_Visible(VARIANT_BOOL visible)
386{
387   m_visible = visible;
388   return S_OK;
389}
390
391STDMETHODIMP CLibkmlNetworkLink::get_Expanded(VARIANT_BOOL *expanded)
392{
393   *expanded = m_expanded;
394   return S_OK;
395}
396
397STDMETHODIMP CLibkmlNetworkLink::put_Expanded(VARIANT_BOOL expanded)
398{
399   m_expanded = expanded;
400   return S_OK;
401}
Note: See TracBrowser for help on using the browser.