SpatialReferenceSystemManager.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2008 National Institute For Space Research (INPE) - Brazil.
2 
3  This file is part of the TerraLib - a Framework for building GIS enabled applications.
4 
5  TerraLib is free software: you can redistribute it and/or modify
6  it under the terms of the GNU Lesser General Public License as published by
7  the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  TerraLib is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public License
16  along with TerraLib. See COPYING. If not, write to
17  TerraLib Team at <terralib-team@terralib.org>.
18  */
19 
20 /*!
21  \file terralib/srs/SpatialReferenceSystemManager.cpp
22 
23  \brief A singleton to manage Coordinate Systems representations.
24 */
25 
26 // TerraLib
27 #include "../core/translator/Translator.h"
28 #include "../core/utils/Platform.h"
29 #include "../common/UnitsOfMeasureManager.h"
30 #include "../common/StringUtils.h"
31 #include "Exception.h"
33 #include "WKTReader.h"
34 
35 // Boost
36 #include <boost/property_tree/ptree.hpp>
37 #include <boost/property_tree/json_parser.hpp>
38 
39 // STL
40 #include <algorithm>
41 #include <cassert>
42 #include <limits>
43 #include <string>
44 #include <utility>
45 
46 
47 
49 {
50  std::ifstream f;
51 
52  f.open(fileName.c_str());
53 
54  if (!f.is_open())
55  return;
56 
57  boost::property_tree::ptree pt;
58  boost::property_tree::json_parser::read_json(f,pt);
59  for(boost::property_tree::ptree::value_type &v: pt.get_child("SRSs"))
60  {
61  if (v.second.get<unsigned int>("srid") > 100000)
62  mger->add(v.second.get<std::string>("name"), v.second.get<std::string>("pj4txt"),
63  v.second.get<std::string>("wkt"), v.second.get<unsigned int>("srid"), "USER");
64  else
65  mger->add(v.second.get<std::string>("name"), v.second.get<std::string>("pj4txt"),
66  v.second.get<std::string>("wkt"), v.second.get<unsigned int>("srid"));
67  }
68  f.close();
69 
70  return;
71 }
72 
73 te::srs::SpatialReferenceSystemManager::srs_desc::srs_desc(const std::string& name, unsigned int auth_id, const std::string& auth_name, const std::string& p4txt, const std::string& wkt):
74  m_name(name),
75  m_auth_id(auth_id),
76  m_auth_name(auth_name),
77  m_p4txt(p4txt),
78  m_wkt(wkt)
79 {}
80 
81 std::string
83 {
84  std::string ssrid = m_auth_name;
85  ssrid += ":";
86  ssrid += boost::lexical_cast<std::string>(m_auth_id);
87  return ssrid;
88 }
89 
91  default;
92 
94 {
95  clear();
96 }
97 
99 {
100  if(!m_set.empty())
101  throw Exception(TE_TR("The spatial reference system manager is already initialized!"));
102 
103 #ifdef NDEBUG
104  std::string jsonf = te::core::FindInTerraLibPath("share/terralib/json/srs.json");
105 #else
106  std::string jsonf = te::core::FindInTerraLibPath("share/terralib/json/srs_incomplete.json");
107 #endif
108  if(jsonf.empty())
109  throw Exception(TE_TR("Could not find srs.json!"));
110 
111  init(jsonf);
112 }
113 
114 void te::srs::SpatialReferenceSystemManager::init(const std::string& fileName)
115 {
116  try
117  {
118  clear();
119  LoadSpatialReferenceSystemManager(fileName, this);
120  }
121  catch(boost::property_tree::json_parser::json_parser_error &je)
122  {
123  std::string errmsg = "Error parsing: " + je.filename() + ": " + je.message();
124  te::srs::Exception ex(TE_TR(errmsg));
125  throw(ex);
126  }
127  catch (std::exception const& e)
128  {
129  std::cerr << e.what() << std::endl;
130  }
131  return;
132 }
133 
134 void te::srs::SpatialReferenceSystemManager::add(const std::string& name, const std::string& p4Txt, const std::string& wkt, unsigned int id, const std::string& authName)
135 {
136  std::string key = authName;
137  key += ":";
138  key += boost::lexical_cast<std::string>(id);
139 
140  boost::multi_index::nth_index<srs_set,0>::type::iterator it = boost::multi_index::get<0>(m_set).find(key);
141  if (it != boost::multi_index::get<0>(m_set).end())
142  throw te::srs::Exception(TE_TR("The CS identification already exists in the manager."));
143 
144  srs_desc record(name, id, authName, p4Txt, wkt);
145  m_set.insert(record);
146 }
147 
148 bool te::srs::SpatialReferenceSystemManager::recognizes(unsigned int id, const std::string& authName) const
149 {
150  std::string key = authName;
151  key += ":";
152  key += boost::lexical_cast<std::string>(id);
153 
154  boost::multi_index::nth_index<srs_set,0>::type::iterator it = boost::multi_index::get<0>(m_set).find(key);
155  if (it == boost::multi_index::get<0>(m_set).end())
156  {
157  key = "USER";
158  key += ":";
159  key += boost::lexical_cast<std::string>(id);
160  it = boost::multi_index::get<0>(m_set).find(key);
161  return (it != boost::multi_index::get<0>(m_set).end());
162  }
163  else
164  return true;
165 }
166 
167 std::unique_ptr<te::srs::SpatialReferenceSystem> te::srs::SpatialReferenceSystemManager::getSpatialReferenceSystem(unsigned int id, const std::string& authName) const
168 {
169  std::string wkt = getWkt(id,authName);
170  if (wkt.empty())
171  return std::unique_ptr<te::srs::SpatialReferenceSystem>();
172 
173  try
174  {
175  return std::unique_ptr<te::srs::SpatialReferenceSystem>(te::srs::WKTReader::read(wkt.c_str()));
176  }
177  catch(...)
178  {
179  throw te::srs::Exception(TE_TR("Error parsing the registered CS WKT."));
180  }
181  return std::unique_ptr<te::srs::SpatialReferenceSystem>();
182 }
183 
184 
185 std::string te::srs::SpatialReferenceSystemManager::getName(unsigned int id, const std::string& authName) const
186 {
187  std::string key = authName;
188  key += ":";
189  key += boost::lexical_cast<std::string>(id);
190 
191  boost::multi_index::nth_index<srs_set,0>::type::iterator it = boost::multi_index::get<0>(m_set).find(key);
192  if (it == boost::multi_index::get<0>(m_set).end())
193  {
194  key = "USER";
195  key += ":";
196  key += boost::lexical_cast<std::string>(id);
197  it = boost::multi_index::get<0>(m_set).find(key);
198  if (it!=boost::multi_index::get<0>(m_set).end())
199  return it->m_name;
200  }
201  else
202  return it->m_name;
203 
204  return "";
205 }
206 
207 std::string te::srs::SpatialReferenceSystemManager::getWkt(unsigned int id, const std::string& authName) const
208 {
209  std::string key = authName;
210  key += ":";
211  key += boost::lexical_cast<std::string>(id);
212 
213  boost::multi_index::nth_index<srs_set,0>::type::iterator it = boost::multi_index::get<0>(m_set).find(key);
214  if (it==boost::multi_index::get<0>(m_set).end())
215  {
216  key = "USER";
217  key += ":";
218  key += boost::lexical_cast<std::string>(id);
219  it = boost::multi_index::get<0>(m_set).find(key);
220  if (it!=boost::multi_index::get<0>(m_set).end())
221  return it->m_wkt;
222  }
223  else
224  return it->m_wkt;
225 
226  return "";
227 }
228 
229 std::string te::srs::SpatialReferenceSystemManager::getP4Txt(unsigned int id, const std::string& authName) const
230 {
231  std::string key = authName;
232  key += ":";
233  key += boost::lexical_cast<std::string>(id);
234 
235  boost::multi_index::nth_index<srs_set,0>::type::iterator it = boost::multi_index::get<0>(m_set).find(key);
236  if (it==boost::multi_index::get<0>(m_set).end())
237  {
238  key = "USER";
239  key += ":";
240  key += boost::lexical_cast<std::string>(id);
241  it = boost::multi_index::get<0>(m_set).find(key);
242  if (it!=boost::multi_index::get<0>(m_set).end())
243  return it->m_p4txt;
244  }
245  else
246  return it->m_p4txt;
247 
248  return "";
249 }
250 
251 std::pair<std::string,unsigned int> te::srs::SpatialReferenceSystemManager::getIdFromName(const std::string& name) const
252 {
253  std::pair< srs_set::nth_index< 1 >::type::const_iterator,
254  srs_set::nth_index< 1 >::type::const_iterator > iterators =
255  m_set.get< 1 >().equal_range(name);
256 
257  bool resultDeprecated = true;
258  bool currentDeprecated = false;
259  std::string upperCaseName;
260 
261  std::pair<std::string,unsigned int> result;
262  result.second = (std::numeric_limits<unsigned int>::max)();
263 
264  while( iterators.first != iterators.second )
265  {
266  assert( name == iterators.first->m_name );
267 
268  upperCaseName = te::common::Convert2UCase( iterators.first->m_name );
269  currentDeprecated = ( upperCaseName.find( "DEPRECATED" ) != std::string::npos );
270 
271  upperCaseName = te::common::Convert2UCase( iterators.first->m_wkt );
272  currentDeprecated = currentDeprecated ||
273  ( upperCaseName.find( "DEPRECATED" ) != std::string::npos );
274 
275  if(
276  (
277  resultDeprecated
278  &&
279  currentDeprecated
280  &&
281  ( iterators.first->m_auth_id < result.second )
282  )
283  ||
284  (
285  ( !resultDeprecated )
286  &&
287  ( !currentDeprecated )
288  &&
289  ( iterators.first->m_auth_id < result.second )
290  )
291  ||
292  (
293  resultDeprecated
294  &&
295  ( !currentDeprecated )
296  )
297  )
298  {
299  result.first = iterators.first->m_auth_name;
300  result.second = iterators.first->m_auth_id;
301  resultDeprecated = currentDeprecated;
302  }
303 
304  ++iterators.first;
305  }
306 
307  if( result.first.empty() )
308  {
309  throw te::srs::Exception(TE_TR("CS name not recognized."));
310  }
311 
312  return result;
313 }
314 
315 
316 std::pair<std::string,unsigned int> te::srs::SpatialReferenceSystemManager::getIdFromP4Txt(const std::string& p4Txt) const
317 {
318  std::pair< srs_set::nth_index< 2 >::type::const_iterator,
319  srs_set::nth_index< 2 >::type::const_iterator > iterators =
320  m_set.get< 2 >().equal_range(p4Txt);
321 
322  bool resultDeprecated = true;
323  bool currentDeprecated = false;
324  std::string upperCaseName;
325 
326  std::pair<std::string,unsigned int> result;
327  result.second = (std::numeric_limits<unsigned int>::max)();
328 
329  while( iterators.first != iterators.second )
330  {
331  assert( p4Txt == iterators.first->m_p4txt );
332 
333  upperCaseName = te::common::Convert2UCase( iterators.first->m_name );
334  currentDeprecated = ( upperCaseName.find( "DEPRECATED" ) != std::string::npos );
335 
336  upperCaseName = te::common::Convert2UCase( iterators.first->m_wkt );
337  currentDeprecated = currentDeprecated ||
338  ( upperCaseName.find( "DEPRECATED" ) != std::string::npos );
339 
340  if(
341  (
342  resultDeprecated
343  &&
344  currentDeprecated
345  &&
346  ( iterators.first->m_auth_id < result.second )
347  )
348  ||
349  (
350  ( !resultDeprecated )
351  &&
352  ( !currentDeprecated )
353  &&
354  ( iterators.first->m_auth_id < result.second )
355  )
356  ||
357  (
358  resultDeprecated
359  &&
360  ( !currentDeprecated )
361  )
362  )
363  {
364  result.first = iterators.first->m_auth_name;
365  result.second = iterators.first->m_auth_id;
366  resultDeprecated = currentDeprecated;
367  }
368 
369  ++iterators.first;
370  }
371 
372  if( result.first.empty() )
373  {
374  throw te::srs::Exception(TE_TR("CS name not recognized."));
375  }
376 
377  return result;
378 }
379 
380 std::pair<std::string,unsigned int> te::srs::SpatialReferenceSystemManager::getIdFromWkt(const std::string& wkt) const
381 {
382  std::pair< srs_set::nth_index< 3 >::type::const_iterator,
383  srs_set::nth_index< 3 >::type::const_iterator > iterators =
384  m_set.get< 3 >().equal_range(wkt);
385 
386  bool resultDeprecated = true;
387  bool currentDeprecated = false;
388  std::string upperCaseName;
389 
390  std::pair<std::string,unsigned int> result;
391  result.second = (std::numeric_limits<unsigned int>::max)();
392 
393  while( iterators.first != iterators.second )
394  {
395  assert( wkt == iterators.first->m_wkt );
396 
397  upperCaseName = te::common::Convert2UCase( iterators.first->m_name );
398  currentDeprecated = ( upperCaseName.find( "DEPRECATED" ) != std::string::npos );
399 
400  upperCaseName = te::common::Convert2UCase( iterators.first->m_wkt );
401  currentDeprecated = currentDeprecated ||
402  ( upperCaseName.find( "DEPRECATED" ) != std::string::npos );
403 
404  if(
405  (
406  resultDeprecated
407  &&
408  currentDeprecated
409  &&
410  ( iterators.first->m_auth_id < result.second )
411  )
412  ||
413  (
414  ( !resultDeprecated )
415  &&
416  ( !currentDeprecated )
417  &&
418  ( iterators.first->m_auth_id < result.second )
419  )
420  ||
421  (
422  resultDeprecated
423  &&
424  ( !currentDeprecated )
425  )
426  )
427  {
428  result.first = iterators.first->m_auth_name;
429  result.second = iterators.first->m_auth_id;
430  resultDeprecated = currentDeprecated;
431  }
432 
433  ++iterators.first;
434  }
435 
436  if( result.first.empty() )
437  {
438  throw te::srs::Exception(TE_TR("CS name not recognized."));
439  }
440 
441  return result;
442 }
443 
444 void te::srs::SpatialReferenceSystemManager::remove(unsigned int id, const std::string& authName)
445 {
446  std::string key = authName;
447  key += ":";
448  key += boost::lexical_cast<std::string>(id);
449 
450  boost::multi_index::nth_index<srs_set,0>::type::iterator it = boost::multi_index::get<0>(m_set).find(key);
451  if (it==boost::multi_index::get<0>(m_set).end())
452  {
453  key = "USER";
454  key += ":";
455  key += boost::lexical_cast<std::string>(id);
456  it = boost::multi_index::get<0>(m_set).find(key);
457  if (it!=boost::multi_index::get<0>(m_set).end())
458  m_set.erase(it);
459  }
460  else
461  m_set.erase(it);
462 }
463 
465 {
466  m_set.clear();
467 }
468 
469 std::pair<te::srs::SpatialReferenceSystemManager::iterator,te::srs::SpatialReferenceSystemManager::iterator>
471 {
473  te::srs::SpatialReferenceSystemManager::iterator>(boost::multi_index::get<0>(m_set).begin(), boost::multi_index::get<0>(m_set).end());
474 }
475 
477 {
478  return m_set.size();
479 }
480 
482 {
483  std::string unitName= "metre";
484  if (isGeographic(id,authName))
485  unitName = "degree";
486 
487  std::string pjstr = getP4Txt(id,authName);
488  if (pjstr.empty())
490 
491  std::size_t found = pjstr.find("+units=");
492  if (found!=std::string::npos)
493  {
494  std::size_t aux = pjstr.find(" ", found);
495  std::string unitsymbol = pjstr.substr(found+7,aux-(found+7));
497  }
498 
500 }
501 
502 
503 bool te::srs::SpatialReferenceSystemManager::isGeographic(unsigned int id, const std::string& authName)
504 {
505  std::string pjstr = getP4Txt(id,authName);
506  return (pjstr.find("+proj=longlat")!=std::string::npos);
507 }
508 
510 {
511  bool initialized = !m_set.empty();
512 
513  return initialized;
514 }
515 
517 {
518  boost::multi_index::nth_index<srs_set,4>::type::iterator it = boost::multi_index::get<4>(m_set).find("USER");
519  if (it==boost::multi_index::get<4>(m_set).end())
520  return boost::lexical_cast<std::string>(TE_SRS_USER_DEFINED_START_ID);
521 
522  unsigned int val = it->m_auth_id;
523  ++it;
524  while (it != boost::multi_index::get<4>(m_set).end())
525  {
526  if (it->m_auth_id > val)
527  val = it->m_auth_id;
528  ++it;
529  }
530  return boost::lexical_cast<std::string>(val+1);
531 }
std::pair< std::string, unsigned int > getIdFromWkt(const std::string &wkt) const
Returns a coordinate system identification given a WKT description.
A class to manage Coordinate Systems representations.
Base exception class for plugin module.
std::pair< te::srs::SpatialReferenceSystemManager::iterator, te::srs::SpatialReferenceSystemManager::iterator > getIterators() const
Returns an iterator mechanism over the coordinate system descriptions in the manager.
size_t size() const
Returns the number of objects in the manager.
UnitOfMeasurePtr findBySymbol(const std::string &symbol) const
Returns a unit of measure identified by its symbol.
An exception class for the SRS module.
bool isInitialized()
Checks if the System Manager is already initialized.
void add(const std::string &name, const std::string &p4Txt, const std::string &wkt, unsigned int id, const std::string &authName="EPSG")
Adds a <id, authority> to the manager.
void clear()
Removes all coordinate system representations from the manager.
std::string Convert2UCase(const std::string &value)
It converts a string to upper case.
Definition: StringUtils.h:168
boost::multi_index::nth_index< srs_set, 0 >::type::iterator iterator
An iterator by SRS <id,authority>
std::string getP4Txt(unsigned int id, const std::string &authName="EPSG") const
Returns a coordinate system PROJ4 description given an identification.
#define TE_TR(message)
It marks a string in order to get translated.
Definition: Translator.h:242
static SpatialReferenceSystem * read(const char *wkt)
It returns a valid SRS from a given WKT.
std::string getNewUserDefinedSRID()
Returns a SRID, not yet used, to identify an SRS created by an user.
SpatialReferenceSystemPtr getSpatialReferenceSystem(unsigned int id, const std::string &authName="EPSG") const
Returns a pointer to a coordinate system given an identification.
static UnitsOfMeasureManager & getInstance()
It returns a reference to the singleton instance.
std::pair< std::string, unsigned int > getIdFromName(const std::string &name) const
Returns a coordinate system identification given a name.
te::common::UnitOfMeasurePtr getUnit(unsigned int id, const std::string &authName="EPSG")
Returns the unit of measure for a SRS with a given id.
srs_desc(const std::string &name, unsigned int auth_id, const std::string &auth_name, const std::string &p4txt, const std::string &wkt)
A class to manage Coordinate Systems representations within TerraLib environment. ...
void remove(unsigned int id, const std::string &authName="EPSG")
Removes a coordinate system representation from the manager, given its identification.
bool recognizes(unsigned int id, const std::string &authName="EPSG") const
Returns true is a pair <id, authority> is recognized by the manager.
void init()
Inializes the manager from a JSON file containing instances of SRSs.
bool isGeographic(unsigned int id, const std::string &authName="EPSG")
Checks if a SRS with a given id refers to a geographic spatial reference system.
std::string getName(unsigned int id, const std::string &authName="EPSG") const
Returns a coordinate system name given an identification.
boost::shared_ptr< UnitOfMeasure > UnitOfMeasurePtr
#define TE_SRS_USER_DEFINED_START_ID
std::string getWkt(unsigned int id, const std::string &authName="EPSG") const
Returns a coordinate system WKT description given an id.
TECOREEXPORT std::string FindInTerraLibPath(const std::string &path)
Returns the path relative to a directory or file in the context of TerraLib.
void LoadSpatialReferenceSystemManager(const std::string fileName, te::srs::SpatialReferenceSystemManager *mger)
UnitOfMeasurePtr find(unsigned int id) const
Returns a unit of measure identified by its identificaton.
std::pair< std::string, unsigned int > getIdFromP4Txt(const std::string &p4Txt) const
Returns a coordinate system identification given a PROJ4 description.