OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimWktProjectionFactory.cpp
Go to the documentation of this file.
1 //*************************************************************************************************
2 // License: See top level LICENSE.txt file.
3 //
4 // Author: Oscar Kramer
5 //
6 // DESCRIPTION:
7 // Projection Factory for EPSG coded projections. These are projections
8 // that are fully defined in database files and specified via a projection coordinate system (PCS)
9 // code.
10 //
11 //*************************************************************************************************
12 // $Id: ossimWktProjectionFactory.cpp 23379 2015-06-17 19:17:24Z okramer $
13 
27 #include <sstream>
28 
30 
31 static const ossimString WKT_MAGIC("WKT_PCS");
32 
33 /*************************************************************************************************
34  * Sample WKT string (for reference, line feeds and spaces added for human readability)
35  *
36  * PROJCS["NAD_1983_HARN_Lambert_Conformal_Conic",
37  * GEOGCS["GCS_North_American_1983_HARN",
38  * DATUM["NAD83_High_Accuracy_Regional_Network",
39  * SPHEROID["GRS_1980",6378137,298.257222101, AUTHORITY["EPSG","7019"]],
40  * AUTHORITY["EPSG","6152"]],
41  * PRIMEM["Greenwich",0],
42  * UNIT["degree",0.0174532925199433]],
43  * PROJECTION["Lambert_Conformal_Conic_2SP"],
44  * PARAMETER["standard_parallel_1",43],
45  * PARAMETER["standard_parallel_2",45.5],
46  * PARAMETER["latitude_of_origin",41.75],
47  * PARAMETER["central_meridian",-120.5],
48  * PARAMETER["false_easting",1312335.958005249],
49  * PARAMETER["false_northing",0],
50  * UNIT["foot",0.3048, AUTHORITY["EPSG","9002"]]]
51  *
52  * Another sample (with EPSG at the top for easy instantiation of full projection):
53  *
54  * PROJCS["WGS 84 / UTM zone 41N",
55  * AUTHORITY["EPSG","32641"],
56  * GEOGCS["WGS 84",
57  * DATUM["WGS_1984",
58  * SPHEROID["WGS 84",6378137,298.2572235630016, AUTHORITY["EPSG","7030"]],
59  * AUTHORITY["EPSG","6326"]],
60  * PRIMEM["Greenwich",0],
61  * UNIT["degree",0.0174532925199433]],
62  * PROJECTION["Transverse_Mercator"],
63  * PARAMETER["latitude_of_origin",0],
64  * PARAMETER["central_meridian",63],
65  * PARAMETER["scale_factor",0.9996],
66  * PARAMETER["false_easting",500000],
67  * PARAMETER["false_northing",0],
68  * UNIT["metre",1, AUTHORITY["EPSG","9001"]]]
69  *
70  **************************************************************************************************/
71 
72 //*************************************************************************************************
74 //*************************************************************************************************
76 {
77  if (!m_instance)
79  return m_instance;
80 }
81 
82 //*************************************************************************************************
84 //*************************************************************************************************
86 {
87  // Fetch filename of WKT projection DB file specified in ossim_preferences:
88 
89  // Optional ossim share dir:
91  preferencesKWL().findKey( std::string( "ossim_share_directory" ) );
92 
93  ossimFilename db_name;
94 
96  findKey( std::string( "wkt_database_file" ) );
97 
98  if ( wkt_path.size() )
99  {
100  if ( !wkt_path.isRelative() )
101  {
102  //---
103  // example:
104  // wkt_database_file:/usr/share/ossim/projection/ossim_wkt_pcs.csv
105  //---
106  db_name = wkt_path;
107  }
108  else if ( share_dir.size() )
109  {
110  //---
111  // example:
112  // ossim_share_dir: /usr/share/ossim
113  // wkt_database_file: projection/ossim_wkt_pcs.csv
114  //---
115  db_name = share_dir.dirCat( wkt_path );
116 
117  //---
118  // This block is for backwards compatibility.
119  // Try tacking "projection" onto share dir.
120  //---
121  if ( !db_name.isReadable() )
122  {
123  db_name = share_dir.dirCat( ossimFilename("projection") );
124  db_name = db_name.dirCat( wkt_path);
125 
126  // Lastly: Try tacking "ossim/projection" onto share dir.
127  if ( !db_name.isReadable() )
128  {
129  db_name = share_dir.dirCat( ossimFilename("ossim/projection") );
130  db_name = db_name.dirCat( wkt_path);
131  }
132  }
133  }
134  }
135 
136  if (!db_name.isReadable())
137  return;
138 
139  // Create only once outside the loop:
140  ossimString format_id;
141  ossimString line;
142 
143  // Open the DB file:
144  std::ifstream db_stream(db_name.chars());
145  bool good_file = false;
146  if (db_stream.good())
147  {
148  // Format specification implied in file's magic number:
149  std::getline(db_stream, format_id.string());
150  format_id.trim();
151  if (format_id == WKT_MAGIC)
152  good_file = true;
153  }
154  if (!good_file)
155  {
157  << "ossimWktProjectionDatabase::loadRecords() -- Encountered bad WKT database file <"
158  << db_name << ">. Skipping this file." << endl;
159  db_stream.close();
160  return;
161  }
162 
163  // The file is good. Skip over the column descriptor line:
164  std::getline(db_stream, line.string());
165 
166  // Loop to read all data records:
167  while (!db_stream.eof())
168  {
169  std::getline(db_stream, line.string());
170  std::vector<ossimString> csvRecord = line.explode(","); // ONLY CSV FILES CONSIDERED HERE
171  if (csvRecord.size())
172  {
173  std::pair<std::string, ossim_uint32> projRecord;
174  projRecord.first = csvRecord[1].string();
175  projRecord.second = csvRecord[0].toUInt32();
176  m_wktProjRecords.insert(projRecord);
177  }
178  }
179 
180 // for ( std::map<ossimString, ossim_uint32>::const_iterator it = m_wktProjRecords.begin();
181 // it != m_wktProjRecords.end(); it++)
182 // cout << "[" << it->first << ", " << it->second << "]"<<endl;
183 
184  db_stream.close();
185 }
186 
188 {
189  if (m_wktProjRecords.empty())
190  loadRecords();
191 
192  std::map<std::string, ossim_uint32>::const_iterator it = m_wktProjRecords.find(pcsName.string());
193 
194  if (it != m_wktProjRecords.end())
195  {
196  // Found an entry by this name, fetch the EPSG code:
197  return it->second;
198  }
199  return 0;
200 }
201 
202 
203 //*************************************************************************************************
205 //*************************************************************************************************
207  const char *prefix) const
208 {
209  // The WKT for the horizontal projection may be part of a compound coordinate system, as
210  // indicated by the "COMPD_CS" prefix. Need to remove that prefix first.
211  ossimString compd_cs ("COMPD_CS.");
212  ossimKeywordlist temp_kwl (keywordList);
213  temp_kwl.stripPrefixFromAll(compd_cs);
214 
215  ossimProjection* proj = 0;
216  ossimString pcs_name = temp_kwl.find(prefix, "PROJCS.name");
217  if (pcs_name.empty())
218  return 0;
219 
220  if (m_wktProjRecords.empty())
221  loadRecords();
222 
223  // Search the WKT DB for a mapping of projection name to EPSG code. This should take care of
224  // majority of cases, like UTM:
225  ossimString epsg_code;
226  std::map<std::string, ossim_uint32>::const_iterator it = m_wktProjRecords.find(pcs_name.string());
227  if (it != m_wktProjRecords.end())
228  {
229  // Found an entry by this name, fetch the EPSG code:
230  epsg_code = ossimString::toString(it->second);
231  }
232  else
233  {
234  // The name specified in the WKT could not be found in our WKT->EPSG map.
235  // Check for EPSG code in WKT itself:
236  ossimString auth_name = temp_kwl.find(prefix, "PROJCS.AUTHORITY.name");
237  if (auth_name == "EPSG")
238  epsg_code = temp_kwl.find(prefix, "PROJCS.AUTHORITY.param0");
239  }
240 
241  // Use EPSG if determined:
242  if (!epsg_code.empty())
243  {
244  // Strip quotes if any:
245  epsg_code.trim( ossimString("\"") );
246 
248  if (proj)
249  return proj;
250  }
251 
252  // Not EPSG, so check conventional proj spec in WKT:
253  ossimString proj_name = temp_kwl.find(prefix, "PROJCS.PROJECTION.name");
254  if (proj_name.empty())
255  return 0;
256  proj_name.downcase();
257  proj_name.gsub(" ", "_", true);
258 
259  // Note that prefix is ignored. This KWL is assumed to come from ossimWkt that doesn't prefix:
260  if (proj_name.contains("transverse_mercator"))
261  proj = doTransverseMercator(temp_kwl);
262  else if (proj_name.contains("mercator"))
263  proj = doMercator(temp_kwl);
264  else if (proj_name.contains("lambert"))
265  proj = doLambertConformalConic(temp_kwl);
266  else if (proj_name.contains("equirectangular"))
267  proj = doEquiDistCylindrical(temp_kwl);
268  else if (proj_name.contains("cylindrical_equal_area"))
269  proj = doEquiAreaCylindrical(temp_kwl);
270 
271  return proj;
272 }
273 
274 //*************************************************************************************************
275 // This is the principal factory method. It accepts a WKT string, e.g.
276 //
277 // "Anguilla_1957_British_West_Indies_Grid",
278 //
279 // or complete WKT, e.g.
280 //
281 // PROJCS["Anguilla_1957_British_West_Indies_Grid", GEOGCS[...
282 //
283 // IMPORTANT NOTE: Image tie-points cannot be conveyed by a WKT projection string. The projection
284 // created here will not be fully initialized for use in rendering imagery.
285 //*************************************************************************************************
287 {
288  ossimProjection* proj = 0;
289  ossimWkt wkt;
290  if (wkt.parse(spec))
291  {
292  proj = createProjection(wkt.getKwl());
293  }
294  return proj;
295 }
296 
297 //*************************************************************************************************
299 {
300  return createProjection(typeName);
301 }
302 
303 //*************************************************************************************************
305  const char* prefix) const
306 {
307  return createProjection(kwl, prefix);
308 }
309 
310 //*************************************************************************************************
312 //*************************************************************************************************
314  ossim_uint32 /* entryIdx */) const
315 {
316  return 0;
317 }
318 
319 //*************************************************************************************************
322 //*************************************************************************************************
323 void ossimWktProjectionFactory::getTypeNameList(std::vector<ossimString>& typeList) const
324 {
325  if (m_wktProjRecords.empty())
326  loadRecords();
327 
328  std::map<std::string, ossim_uint32>::iterator db_iter = m_wktProjRecords.begin();
329  while (db_iter != m_wktProjRecords.end())
330  {
331  typeList.push_back(ossimString(db_iter->first));
332  db_iter++;
333  }
334  return;
335 }
336 
338 {
340  doMapCommon<ossimTransMercatorProjection*>(kwl, proj);
341 
342  // Determine first the units:
343  ossimString name_read;
344  ossimString val_read;
345 
346  // Read projection parameters from WKT KWL:
347  int param_idx = 0;
348  do
349  {
350  ossimString param("PROJCS.PARAMETER");
351  param += ossimString::toString(param_idx++);
352  name_read = kwl.find(param + ".name");
353  val_read = kwl.find(param + ".param0");
354 
355  if (name_read.contains("scale_factor"))
356  {
357  proj->setScaleFactor(val_read.toDouble());
358  break;
359  }
360 
361  } while (!name_read.empty());
362 
363  return proj;
364 }
365 
367 {
369  doMapCommon<ossimMercatorProjection*>(kwl, proj);
370 
371  // Determine first the units:
372  ossimString name_read;
373  ossimString val_read;
374 
375  // Read projection parameters from WKT KWL:
376  int param_idx = 0;
377  do
378  {
379  ossimString param("PROJCS.PARAMETER");
380  param += ossimString::toString(param_idx++);
381  name_read = kwl.find(param + ".name");
382  val_read = kwl.find(param + ".param0");
383 
384  if (name_read.contains("scale_factor"))
385  {
386  proj->setScaleFactor(val_read.toDouble());
387  break;
388  }
389 
390  } while (!name_read.empty());
391 
392  return proj;
393 }
394 
396 {
398  doMapCommon<ossimLambertConformalConicProjection*>(kwl, proj);
399 
400  // Determine first the units:
401  ossimString name_read;
402  ossimString val_read;
403 
404  // Read projection parameters from WKT KWL:
405  int param_idx = 0;
406  do
407  {
408  ossimString param("PROJCS.PARAMETER");
409  param += ossimString::toString(param_idx++);
410  name_read = kwl.find(param + ".name");
411  val_read = kwl.find(param + ".param0");
412 
413  if (name_read.contains("standard_parallel_1"))
414  proj->setStandardParallel1(val_read.toDouble());
415 
416  else if (name_read.contains("standard_parallel_2"))
417  proj->setStandardParallel2(val_read.toDouble());
418 
419  } while (!name_read.empty());
420 
421  return proj;
422 }
423 
425 {
427  doMapCommon<ossimEquDistCylProjection*>(kwl, proj);
428 
429  return proj;
430 }
431 
433 {
435  doMapCommon<ossimCylEquAreaProjection*>(kwl, proj);
436 
437  return proj;
438 }
439 
440 template<class T>
442 {
443  ossimString name_read;
444  ossimString val_read;
445 
446  const ossimDatum* datum = 0;
447  name_read = kwl.find("PROJCS.GEOGCS.AUTHORITY.name");
448  val_read = kwl.find("PROJCS.GEOGCS.AUTHORITY.param0");
449  if ((name_read == "EPSG") && (!val_read.empty()))
450  {
451  datum = ossimEpsgDatumFactory::instance()->create(val_read.toUInt32());
452  if (datum)
453  proj->setDatum(datum);
454  // TODO: HARN Datum not being handled
455  }
456 
457  // Determine first the units:
458  name_read = kwl.find("PROJCS.UNIT.name");
459  double conv_factor = 1.0;
460  if (name_read.contains("f")) // feet|foot
461  {
462  conv_factor = MTRS_PER_FT;
463  proj->setProjectionUnits(OSSIM_FEET);
464  }
465 
466  // Read projection parameters from WKT KWL:
467  int param_idx = 0;
468  ossimGpt origin(0, 0, 0, datum);
469  do
470  {
471  ossimString param("PROJCS.PARAMETER");
472  param += ossimString::toString(param_idx++);
473  name_read = kwl.find(param + ".name");
474  val_read = kwl.find(param + ".param0");
475 
476  if (name_read.contains("central_meridian"))
477  origin.lon = val_read.toDouble();
478 
479  else if (name_read.contains("latitude_of_origin"))
480  origin.lat = val_read.toDouble();
481 
482  else if (name_read.contains("false_easting"))
483  proj->setFalseEasting(val_read.toDouble() * conv_factor);
484 
485  else if (name_read.contains("false_northing"))
486  proj->setFalseNorthing(val_read.toDouble() * conv_factor);
487 
488  } while (!name_read.empty());
489 
490  proj->setOrigin(origin);
491 }
492 
const ossimKeywordlist & preferencesKWL() const
ossimProjection * doEquiAreaCylindrical(const ossimKeywordlist &kwl) const
virtual void getTypeNameList(std::vector< ossimString > &typeList) const
This returns the type name of all objects in all factories.
void stripPrefixFromAll(const ossimString &regularExpression)
Represents serializable keyword/value map.
std::basic_ifstream< char > ifstream
Class for char input file streams.
Definition: ossimIosFwd.h:44
const char * find(const char *key) const
Projection Factory for coded projections defined in database.
void doMapCommon(const ossimKeywordlist &kwl, T proj) const
bool contains(char aChar) const
Definition: ossimString.h:58
std::map< std::string, ossim_uint32 > m_wktProjRecords
static ossimWktProjectionFactory * m_instance
Singleton implementation.
static ossimString toString(bool aValue)
Numeric to string methods.
ossim_uint32 toUInt32() const
std::istream & getline(std::istream &is, ossimString &str, char delim)
Definition: ossimString.h:916
virtual ossim_uint32 getCode(const ossimString &name)
ossim_float64 lon
Definition: ossimGpt.h:266
virtual const ossimDatum * create(const ossimString &epsg_spec) const
Creates a datum instance given an EPSG spec in the form "EPSG:<datum_code>".
virtual ossimProjection * createProjection(const ossimFilename &filename, ossim_uint32 entryIdx) const
STUB. Not implemented.
std::string::size_type size() const
Definition: ossimString.h:405
static ossimEpsgProjectionDatabase * instance()
Instantiates singleton instance of this class:
void setScaleFactor(double scaleFactor)
unsigned int ossim_uint32
const char * chars() const
For backward compatibility.
Definition: ossimString.h:77
ossimString trim(const ossimString &valueToTrim=ossimString(" \\)) const
this will strip lead and trailing character passed in.
double toDouble() const
virtual ossimObject * createObject(const ossimString &typeName) const
Utility/support data class to parse WKT text string to an ossimKeywordlist.
Definition: ossimWkt.h:68
void loadRecords() const
Loads all SRS CSV files specified in the ossim prefs.
static ossimEpsgDatumFactory * instance()
Singleton implementation.
static ossimString downcase(const ossimString &aString)
Definition: ossimString.cpp:48
std::vector< ossimString > explode(const ossimString &delimeter) const
static ossimPreferences * instance()
bool isReadable() const
ossimProjection * doLambertConformalConic(const ossimKeywordlist &kwl) const
#define MTRS_PER_FT
bool isRelative() const
Checks whether file name is relative or absolute.
ossimFilename dirCat(const ossimFilename &file) const
bool empty() const
Definition: ossimString.h:411
ossimProjection * doEquiDistCylindrical(const ossimKeywordlist &kwl) const
ossim_float64 lat
Definition: ossimGpt.h:265
ossimString & gsub(const ossimString &searchKey, const ossimString &replacementValue, bool replaceAll=false)
Substitutes searchKey string with replacementValue and returns a reference to *this.
bool parse(const std::string &wkt)
Parses string to keyword list.
Definition: ossimWkt.cpp:52
const ossimKeywordlist & getKwl() const
Definition: ossimWkt.cpp:63
ossimWktProjectionFactory()
Constructor loads the WKT CSV file specified in the ossim prefs with "wkt_database_file" keyword...
ossimProjection * doMercator(const ossimKeywordlist &kwl) const
ossimProjection * doTransverseMercator(const ossimKeywordlist &kwl) const
std::string::size_type find(const std::string &s, std::string::size_type pos=0) const
Searches for s as a substring of *this, beginning at character pos of *this.
Definition: ossimString.h:753
static ossimWktProjectionFactory * instance()
Implements singleton pattern.
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
ossimProjection * findProjection(const ossimString &proj_spec) const
Returns a projection corresponding to the projection specified, or NULL if no entry found...
const std::string & string() const
Definition: ossimString.h:414