OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimEpsgProjectionDatabase.cpp
Go to the documentation of this file.
1 //*************************************************************************************************
2 // OSSIM -- Open Source Software Image Map
3 //
4 // LICENSE: See top level LICENSE.txt file.
5 //
6 // AUTHOR: Oscar Kramer
7 //
8 // DESCRIPTION: Projection database for EPSG coded projections provided in database files
9 //
10 //*************************************************************************************************
11 // $Id: ossimEpsgProjectionDatabase.cpp 23177 2015-03-04 15:05:25Z gpotts $
15 #include <ossim/base/ossimCommon.h>
33 #include <cmath>
34 
35 //ossimEpsgProjectionDatabase* ossimEpsgProjectionDatabase::m_instance = 0;
36 
37 // Indexes into the DB file fields using "SPADAC EPSG" format (format "A").
38 // IF THE LINE FIELDS CHANGE ORDER, THIS LIST WILL NEED TO BE CHANGED TO REFLECT THE NEW ORDER!
39 enum
40 {
41  A_CODE = 0, // This is the EPSG code
78  A_NUM_FIELDS // Not an index, but a count
79 };
80 static const ossimString EPSG_DB_FORMAT_A ("EPSG_DB_FORMAT_A");
81 
82 // State Plane database CSV file field format (format "B")
83 // NOTE: Eventually, all EPSG-coded projections, including State Plane/HARN should be specified
84 // in the EPSG database format. Presently there is a disconnect between Geotrans params and EPSG-Db
85 // params, particularly regarding datums, that makes a purely EPSG-Db solution too awkward to
86 // implement, so provision is made here to continue reading the state plane CSV files.
87 enum
88 {
89  B_NAME = 0,
90  B_CODE, // This is the EPSG code
100  B_NUM_FIELDS // Not an index, but a count
101 };
102 static const ossimString STATE_PLANE_FORMAT_B ("STATE_PLANE");
103 
104 // "Ming Special" database CSV file format (format "C")
105 // State Plane Coordinate System (SPCS) coding is an alternate coding scheme that maps to EPSG.
106 // http://www.pcigeomatics.com/cgi-bin/pcihlp/PROJ%7CSPCS+ZONES
107 enum
108 {
109  C_NAME = 0,
111  C_NUM_FIELDS // Not an index, but a count
112 };
113 static const ossimString SPCS_EPSG_MAP_FORMAT_C ("SPCS_EPSG_MAP");
114 
115 //*************************************************************************************************
117 //*************************************************************************************************
118 double decodeSexagesimalDms(const ossimString& sex_str)
119 {
120  if (!sex_str.contains("."))
121  return sex_str.toDouble();
122 
123  double sign = 1.0;
124  if (sex_str.chars()[0] == '-')
125  sign = -1.0;
126 
127  double dsex, msex, ssex;
128  std::vector<ossimString> splitstr = sex_str.split(".");
129  dsex = splitstr[0].toDouble();
130 
131  if (splitstr.size() < 2)
132  return dsex;
133 
134  const char* MMSSssstr = splitstr[1].chars();
135  unsigned int str_size = (unsigned int) splitstr[1].size();
136  char minstr[] = "00";
137  ossimString secstr ("00.");
138  minstr[0] = MMSSssstr[0];
139  if (str_size > 1)
140  {
141  minstr[1] = MMSSssstr[1];
142  if (str_size > 2)
143  {
144  secstr = &(MMSSssstr[2]);
145  if (str_size == 3)
146  secstr += ossimString("0.");
147  else if (str_size > 4)
148  secstr.insert(2, ".");
149  }
150  }
151  msex = ossimString(minstr).toDouble();
152  ssex = secstr.toDouble();
153  dsex += sign*(msex + ssex/60.0)/60.0;
154  return dsex;
155 }
156 
157 //*************************************************************************************************
159 //*************************************************************************************************
161 {
162  static ossimEpsgProjectionDatabase inst;
163 
164  return &inst;
165  //if(!m_instance)
166  // m_instance = new ossimEpsgProjectionDatabase;
167  //return m_instance;
168 }
169 
170 //*************************************************************************************************
172 //*************************************************************************************************
174 {
175 }
176 
177 //*************************************************************************************************
179 //*************************************************************************************************
181  :
182  m_projDatabase(),
183  m_mutex()
184 {
185 }
186 
187 //*************************************************************************************************
189 //*************************************************************************************************
191 {
192  // Fetch filenames of all projection DB files from the share directory specified in
193  // ossim_preferences:
194 
195  // Optional ossim share dir:
197  preferencesKWL().findKey( std::string( "ossim_share_directory" ) );
198 
199  ossimString regEx = ossimString("^epsg_database_file[0-9]+");
200  vector<ossimString> keys =
202  vector<ossimString>::const_iterator i = keys.begin();
203 
204  // Create only once outside the loop:
205  ossimFilename epsg_path;
206  ossimFilename db_name;
207  ossimString group_id;
208  ossimString format_id;
209  ossimString line;
210 
211  // Loop over each file and read contents into memory:
212  while ( i != keys.end() )
213  {
214  db_name.clear();
215  epsg_path = ossimPreferences::instance()->preferencesKWL().findKey( (*i).string() );
216  if ( epsg_path.size() )
217  {
218  if ( !epsg_path.isRelative() )
219  {
220  //---
221  // example:
222  // epsg_database_file0:/usr/share/ossim/projection/ossim_epsg_projections-v7_4.csv
223  //---
224  db_name = epsg_path;
225  }
226  else if ( share_dir.size() )
227  {
228  //---
229  // example:
230  // ossim_share_dir: /usr/share/ossim
231  // epsg_database_file0: projection/ossim_epsg_projections-v7_4.csv
232  //---
233  db_name = share_dir.dirCat( epsg_path );
234 
235  //---
236  // This block is for backwards compatibility.
237  // Try tacking "projection" onto share dir.
238  //---
239  if ( !db_name.isReadable() )
240  {
241  db_name = share_dir.dirCat( ossimFilename("projection") );
242  db_name = db_name.dirCat( epsg_path);
243 
244  // Lastly: Try tacking "ossim/projection" onto share dir.
245  if ( !db_name.isReadable() )
246  {
247  db_name = share_dir.dirCat( ossimFilename("ossim/projection") );
248  db_name = db_name.dirCat( epsg_path);
249  }
250  }
251  }
252  }
253  ++i;
254 
255  if (!db_name.isReadable())
256  {
257  continue;
258  }
259 
260  // Open the DB file:
261  std::ifstream db_stream (db_name.chars());
262  bool good_file = false;
263  if (db_stream.good())
264  {
265  // Format specification implied in file's magic number:
266  std::getline(db_stream, format_id.string());
267  format_id.trim();
268  if ((format_id == EPSG_DB_FORMAT_A) ||
269  (format_id == STATE_PLANE_FORMAT_B) ||
270  (format_id == SPCS_EPSG_MAP_FORMAT_C))
271  good_file = true;
272  }
273  if (!good_file)
274  {
275  ossimNotify(ossimNotifyLevel_WARN)<<"ossimEpsgProjectionDatabase::initialize() -- "
276  "Encountered bad database file <"<<db_name<<">. Skipping this file."<<endl;
277  db_stream.close();
278  continue;
279  }
280 
281  // The file is good. Skip over the column descriptor line:
282  std::getline(db_stream, line.string());
283 
284  // Loop to read all data records:
285  while (!db_stream.eof())
286  {
287  ossimRefPtr<ProjDbRecord> db_record = new ProjDbRecord;
288  std::getline(db_stream, line.string());
289  db_record->csvRecord = line.explode(","); // ONLY CSV FILES CONSIDERED HERE
290  if (db_record->csvRecord.size())
291  {
292  // Check if primary EPSG database format A:
293  if (format_id == EPSG_DB_FORMAT_A)
294  {
295  db_record->code = db_record->csvRecord[A_CODE].toUInt32();
296  db_record->name = db_record->csvRecord[A_NAME];
297  db_record->csvFormat = FORMAT_A;
298  }
299 
300  // Check if State Plane (subset of EPSG but handled differently until projection
301  // geotrans-EPSG disconnect is resolved.
302  else if (format_id == STATE_PLANE_FORMAT_B)
303  {
304  db_record->code = db_record->csvRecord[B_CODE].toUInt32();
305  db_record->name = db_record->csvRecord[B_NAME];
306  db_record->csvFormat = FORMAT_B;
307  }
308 
309  // This format is for Ming-special State Plane Coordinate System coded format.
310  // This format is simply a mapping from SPCS spec name (OSSIM-specific) to EPSG code.
311  // Note that no proj is instantiated and no KWL is populated. Only name and EPSG mapped
312  // code is saved.
313  else if (format_id == SPCS_EPSG_MAP_FORMAT_C)
314  {
315  db_record->code = db_record->csvRecord[C_CODE].toUInt32();
316  db_record->name = db_record->csvRecord[C_NAME];
317  db_record->csvFormat = FORMAT_C;
318  }
319 
320  m_projDatabase.insert(make_pair(db_record->code, db_record));
321  }
322  }
323 
324  db_stream.close();
325  } // end of while loop over all DB files
326 }
327 
328 //*************************************************************************************************
331 //*************************************************************************************************
333 {
334  ossimMapProjection* proj = 0;
335 
336  // Quick check for bogus EPSG:
337  if ((epsg_code == 0) || (epsg_code == 32767))
338  return 0;
339 
340  // Check for Google projection:
341  else if (( epsg_code==3857) || (epsg_code == 900913))
342  {
343  proj = new ossimGoogleProjection();
344 
345  // Set this for saveState:
346  proj->setPcsCode( 3857 );
347  /*
348  const ossimDatum* datum = ossimDatumFactory::instance()->create(ossimString("6055"));
349  ossimMercatorProjection* merc_proj = new ossimMercatorProjection();
350  ossimGpt origin(0.0,0.0,0.0, datum);
351  merc_proj->setFalseEasting(0.0);
352  merc_proj->setFalseNorthing(0.0);
353  merc_proj->setOrigin(origin); // Also sets the projections datum to the origin's datum
354  merc_proj->update();
355  merc_proj->setPcsCode(900913);
356  proj = merc_proj;
357  */
358  }
359 
360  else
361  {
362  // Search database for entry:
363  m_mutex.lock();
364  if (m_projDatabase.empty())
365  {
366  initialize();
367  }
368  m_mutex.unlock();
369 
370  std::multimap<ossim_uint32, ossimRefPtr<ProjDbRecord> >::iterator db_iter =
371  m_projDatabase.find(epsg_code);
372  if (db_iter != m_projDatabase.end())
373  {
374  // See if a projection has already been created for this entry:
375  m_mutex.lock();
376  ossimRefPtr<ProjDbRecord> db_record = db_iter->second;
377  if ( db_record.valid() )
378  {
379  if (db_record->proj.valid())
380  proj = (ossimMapProjection*) db_record->proj->dup();
381  else
382  {
383  // Try decoding the EPSG code before accessing DB:
384  proj = createProjFromUtmCode(epsg_code);
385  if (proj)
386  {
387  db_record->proj = proj;
388  db_record->datumValid = true;
389  }
390  else if (db_iter->second->csvFormat == FORMAT_A)
391  {
392  proj = createProjFromFormatARecord( db_record.get() );
393  }
394  else if (db_iter->second->csvFormat == FORMAT_B)
395  {
396  proj = createProjFromFormatBRecord( db_record.get() );
397  }
398 
399  if (proj)
400  {
401  // To save allocated memory, get rid of the original CSV entry since a real
402  // projection is now represented in the database:
403  db_record->csvRecord.clear();
404  db_record->csvFormat = NOT_ASSIGNED;
405  }
406  }
407 
408  } // Matches: if ( db_record.valid() )
409  m_mutex.unlock();
410  }
411  }
412 
413  return proj;
414 }
415 
416 //*************************************************************************************************
419 //*************************************************************************************************
421 {
422  //std::cout << "ossimEpsgProjectionDatabase::findProjection: entered with spec " << spec << "\n";
423  ossimProjection* proj = 0;
424 
425  // Use the CRS code to access the database. The spec should be <group>:<code> where <group> is
426  // "EPSG" (the only group handled here):
427  ossim_uint32 spec_code;
428  ossimString spec_group ("epsg"); // default if only integer code provided
429  if (spec.contains(":"))
430  {
431  spec_group = spec.before(":");
432  spec_code = spec.after(":").toUInt32();
433  spec_group = spec_group.downcase();
434  }
435  else
436  {
437  spec_code = spec.toUInt32();
438  }
439 
440  // Presently only EPSG database is handled:
441  if ((spec_code != 0) && (spec_group == "epsg"))
442  return findProjection(spec_code);
443 
444  // The spec is probably a projection name. Need to search Db by the projection name.
445  // Search database for entry. The spec may use different delimiters than
446  // the DB so need to split the strings and compare the words:
447  ossimString separators ("_ /()");
448  vector<ossimString> split_spec = spec.split(separators, true);
449  vector<ossimString> split_db_name;
450  ossimRefPtr<ossimMapProjection> map_proj = 0;
451  if (m_projDatabase.empty())
452  initialize();
453  std::multimap<ossim_uint32, ossimRefPtr<ProjDbRecord> >::iterator db_iter = m_projDatabase.begin();
454  while ((db_iter != m_projDatabase.end()) && !proj)
455  {
456  ossimRefPtr<ProjDbRecord> db_record = db_iter->second;
457  if ( db_record.valid() )
458  {
459  split_db_name.clear();
460  db_record->name.split(split_db_name, separators, true);
461  if (split_spec == split_db_name)
462  {
463  // We may already have instantiated this projection, in which case just return its copy.
464  // Otherwise, create the projection from the EPSG code that corresponds to the name:
465  if (db_record->proj.valid())
466  proj = (ossimMapProjection*) db_record->proj->dup();
467  else
468  proj = findProjection(db_record->code);
469  return proj;
470  }
471  }
472  ++db_iter;
473  }
474 
475  // No hit? Could be that just a datum was identified, in which case we need a simple
476  // Platte Carree:
477  const ossimDatum* datum = ossimDatumFactoryRegistry::instance()->create(spec);
478  if (datum)
479  {
481  proj->setDatum(datum);
482  proj->setPcsCode(spec_code);
483  return proj;
484  }
485 
486  return 0;
487 }
488 
489 
490 //*************************************************************************************************
493 //*************************************************************************************************
495 {
496  if (m_projDatabase.empty())
497  initialize();
498  std::multimap<ossim_uint32, ossimRefPtr<ProjDbRecord> >::iterator db_iter = m_projDatabase.begin();
499  while (db_iter != m_projDatabase.end())
500  {
501  ossimRefPtr<ProjDbRecord> db_record = db_iter->second.get();
502  if ( db_record.valid() )
503  {
504  if (db_record->name == proj_name)
505  return (db_record->code);
506  }
507  ++db_iter;
508  }
509 
510  return 0;
511 }
512 
513 //*************************************************************************************************
518 //*************************************************************************************************
521 {
522  ossimString lost_type (lost_proj.getClassName());
523 
524  // Shortcut for EPSG:4326 (WGS-85 geographic rectangular -- very common):
525  if ((lost_type == "ossimEquDistCylProjection") && (lost_proj.getDatum()->epsgCode() == 6326))
526  return 4326;
527 
528  ossim_uint32 found_code = 0;
529  if (lost_type == "ossimUtmProjection")
530  {
531  found_code = getCodeFromUtmProj(dynamic_cast<const ossimUtmProjection*>(&lost_proj));
532  if (found_code)
533  return found_code;
534  }
535 
536  if (m_projDatabase.empty())
537  initialize();
538  ossimString lookup;
539  std::multimap<ossim_uint32, ossimRefPtr<ProjDbRecord> >::iterator db_iter =
540  m_projDatabase.begin();
541  while ((db_iter != m_projDatabase.end()) && (found_code == 0))
542  {
543  ossimRefPtr<ProjDbRecord> db_record = db_iter->second;
544  if ( db_record.valid() )
545  {
546  // Has a projection already been created for this db iter?
547  if (!db_record->proj.valid())
548  {
549  // No projection has been created yet for this DB entry.
550  // NOTE: THIS IS VERY SLOW BECAUSE WE ARE INSTANTIATING EVERY PROJECTION IN THE DB!!!
551  db_record->proj = dynamic_cast<ossimMapProjection*>(findProjection(db_record->code));
552  }
553  if (db_record->proj.valid() && (*(db_record->proj.get()) == lost_proj))
554  {
555  found_code = db_record->code;
556 
557  // Hack to remap projection code 4087 to 4326 (which is not really a projection
558  // code but other packages like to see 4326 for geographic projections.
559  // Hacked under protest (OLK, 08/2010)
560  if (found_code == 4087)
561  found_code = 4326;
562  }
563  }
564  ++db_iter;
565  }
566  return found_code;
567 }
568 
569 //*************************************************************************************************
572 //*************************************************************************************************
574 {
575  if (m_projDatabase.empty())
576  initialize();
577 
578  ossimString name ("");
579  std::multimap<ossim_uint32, ossimRefPtr<ProjDbRecord> >::iterator db_iter =
580  m_projDatabase.find(epsg_code);
581 
582  if (db_iter != m_projDatabase.end())
583  name = db_iter->second->name;
584 
585  return name;
586 }
587 
588 //*************************************************************************************************
593 //*************************************************************************************************
594 void ossimEpsgProjectionDatabase::getProjectionsList(std::vector<ossimString>& list) const
595 {
596  if (m_projDatabase.empty())
597  initialize();
598 
599  std::multimap<ossim_uint32, ossimRefPtr<ProjDbRecord> >::iterator db_iter = m_projDatabase.begin();
600  while (db_iter != m_projDatabase.end())
601  {
602  ossimRefPtr<ProjDbRecord> db_record = db_iter->second;
603  if ( db_record.valid() )
604  {
605  ossimString record ("EPSG:");
606  record += ossimString::toString(db_record->code);
607  record += " \"";
608  record += db_record->name;
609  record += "\"";
610  list.push_back(record);
611  }
612  ++db_iter;
613  }
614  return;
615 }
616 
617 //*************************************************************************************************
619 //
620 // LIMITATION: Currently not parsing the datum info from the EPSG database file due to disconnect
621 // with current ossimDatumFactory. Setting to default WGS84 with warning message.
622 //*************************************************************************************************
625 {
626  // Establish EPSG code and test for UTM (full projection is implied in the code itself -- no
627  // accessing the database). Until the database is solidified, it is probably better to do
628  // it this way:
629  record->datumValid = true;
630  record->proj = 0;
631 
632  // Establish the units in which the easting/northing is provided:
633  ossimUnitType mapProjUnits = OSSIM_METERS;
634  double mtrs_per_unit = 1.0;
635  if (record->csvRecord[A_UNITS] == "US survey foot")
636  {
637  mapProjUnits = OSSIM_US_SURVEY_FEET;
638  mtrs_per_unit = US_METERS_PER_FT;
639  }
640  else if (record->csvRecord[A_UNITS].contains("foot")) // THIS IS INTERNATIONAL FOOT, NOT EXACT FOR MANY INTERNATIONAL VARIETIES
641  {
642  mapProjUnits = OSSIM_FEET;
643  mtrs_per_unit = MTRS_PER_FT;
644  }
645  else if (record->csvRecord[A_UNITS].contains("kilometre"))
646  {
647  mapProjUnits = OSSIM_KILOMETERS;
648  mtrs_per_unit = 1000.0;
649  }
650  else if (!record->csvRecord[A_UNITS].contains("metre"))
651  {
652  // ### SKIP THIS MESSAGE BUT BE AWARE THAT THIS PROJECTION WON'T BE REPRESENTED IN DB ###
653  //ossimNotify(ossimNotifyLevel_WARN)<<MODULE<<"EPSG:"<<pcs_code<<" units of <"
654  // <<record->csvRecord[A_UNITS]<<"> not presently supported."<<endl;
655  return 0;
656  }
657 
658  // First create a datum given the datum code in the record:
659  ossim_uint32 gcs_code = record->csvRecord[A_DATUM_CODE].toUInt32();
660  const ossimDatum* datum = ossimEpsgDatumFactory::instance()->create(gcs_code);
661  if (!datum)
662  {
663  // Default to WGS 84 -- this may throw an exception:
665  record->datumValid = false;
666  }
667  const ossimEllipsoid* ellipsoid = datum->ellipsoid();
668 
669  ossimGpt origin(0,0,0,datum);
670  ossimString proj_type = record->csvRecord[A_PROJ_TYPE];
671  if (proj_type.contains("Transverse Mercator"))
672  {
673  origin.lat = decodeSexagesimalDms(record->csvRecord[A_NAT_ORG_LAT]);
674  origin.lon = decodeSexagesimalDms(record->csvRecord[A_NAT_ORG_LON]);
675  double fe = mtrs_per_unit*record->csvRecord[A_FALSE_EASTING].toDouble();
676  double fn = mtrs_per_unit*record->csvRecord[A_FALSE_NORTHING].toDouble();
677  double sf = record->csvRecord[A_NAT_ORG_SCALE].toDouble();
678  record->proj = new ossimTransMercatorProjection(*ellipsoid, origin, fe, fn, sf);
679  }
680  else if (proj_type.contains("Lambert Conic Conformal (1SP)"))
681  {
682  origin.lat = decodeSexagesimalDms(record->csvRecord[A_NAT_ORG_LAT]);
683  origin.lon = decodeSexagesimalDms(record->csvRecord[A_NAT_ORG_LON]);
684  double fe = mtrs_per_unit*record->csvRecord[A_FALSE_EASTING].toDouble();
685  double fn = mtrs_per_unit*record->csvRecord[A_FALSE_NORTHING].toDouble();
686  record->proj = new ossimLambertConformalConicProjection(*ellipsoid, origin, origin.lat,
687  origin.lat, fe, fn);
688  }
689  else if (proj_type.contains("Lambert Conic Conformal (2SP)"))
690  {
693  double p1 = decodeSexagesimalDms(record->csvRecord[A_STD_PARL_1_LAT]);
694  double p2 = decodeSexagesimalDms(record->csvRecord[A_STD_PARL_2_LAT]);
695  double fe = mtrs_per_unit*record->csvRecord[A_FALSE_ORG_EASTING].toDouble();
696  double fn = mtrs_per_unit*record->csvRecord[A_FALSE_ORG_NORTHING].toDouble();
697  record->proj = new ossimLambertConformalConicProjection(*ellipsoid, origin, p1, p2, fe, fn);
698  }
699  else if (proj_type.contains("Cassini"))
700  {
701  origin.lat = decodeSexagesimalDms(record->csvRecord[A_NAT_ORG_LAT]);
702  origin.lon = decodeSexagesimalDms(record->csvRecord[A_NAT_ORG_LON]);
703  double fe = mtrs_per_unit*record->csvRecord[A_FALSE_EASTING].toDouble();
704  double fn = mtrs_per_unit*record->csvRecord[A_FALSE_NORTHING].toDouble();
705  record->proj = new ossimCassiniProjection(*ellipsoid, origin, fe, fn);
706  }
707  else if (proj_type.contains("Mercator (1SP)"))
708  {
709  origin.lat = decodeSexagesimalDms(record->csvRecord[A_NAT_ORG_LAT]);
710  origin.lon = decodeSexagesimalDms(record->csvRecord[A_NAT_ORG_LON]);
711  double fe = mtrs_per_unit*record->csvRecord[A_FALSE_EASTING].toDouble();
712  double fn = mtrs_per_unit*record->csvRecord[A_FALSE_NORTHING].toDouble();
713  double sf = record->csvRecord[A_NAT_ORG_SCALE].toDouble();
714  record->proj = new ossimMercatorProjection(*ellipsoid, origin, fe, fn, sf);
715  }
716  else if(proj_type.contains("Popular Visualisation Sphere"))
717  {
718  origin.lat = decodeSexagesimalDms(record->csvRecord[A_NAT_ORG_LAT]);
719  origin.lon = decodeSexagesimalDms(record->csvRecord[A_NAT_ORG_LON]);
720  double fe = mtrs_per_unit*record->csvRecord[A_FALSE_EASTING].toDouble();
721  double fn = mtrs_per_unit*record->csvRecord[A_FALSE_NORTHING].toDouble();
722  double sf = record->csvRecord[A_NAT_ORG_SCALE].toDouble();
723  record->proj = new ossimMercatorProjection(*ellipsoid, origin, fe, fn, sf);
724 
725  // Set this for saveState:
726  record->proj->setPcsCode( 3785 );
727 
728  }
729  else if(proj_type.contains("Pseudo Mercator"))
730  {
731  record->proj = new ossimGoogleProjection();
732 
733  // Set this for saveState:
734  record->proj->setPcsCode( 3857 );
735 
736  }
737  else if (proj_type.contains("Albers"))
738  {
741  double p1 = decodeSexagesimalDms(record->csvRecord[A_STD_PARL_1_LAT]);
742  double p2 = decodeSexagesimalDms(record->csvRecord[A_STD_PARL_2_LAT]);
743  double fe = mtrs_per_unit*record->csvRecord[A_FALSE_ORG_EASTING].toDouble();
744  double fn = mtrs_per_unit*record->csvRecord[A_FALSE_ORG_NORTHING].toDouble();
745  record->proj = new ossimAlbersProjection(*ellipsoid, origin, p1, p2, fe, fn);
746  }
747  else if (proj_type.contains("Equidistant Cylindrical"))
748  {
750  origin.lon = decodeSexagesimalDms(record->csvRecord[A_NAT_ORG_LON]);
751  double fe = mtrs_per_unit*record->csvRecord[A_FALSE_EASTING].toDouble();
752  double fn = mtrs_per_unit*record->csvRecord[A_FALSE_NORTHING].toDouble();
753  record->proj = new ossimEquDistCylProjection(*ellipsoid, origin, fe, fn);
754  }
755  else if (proj_type.contains("New Zealand Map Grid"))
756  {
757  origin.lat = decodeSexagesimalDms(record->csvRecord[A_NAT_ORG_LAT]);
758  origin.lon = decodeSexagesimalDms(record->csvRecord[A_NAT_ORG_LON]);
759  double fe = mtrs_per_unit*record->csvRecord[A_FALSE_EASTING].toDouble();
760  double fn = mtrs_per_unit*record->csvRecord[A_FALSE_NORTHING].toDouble();
762  nz_proj->setOrigin(origin);
763  nz_proj->setFalseEastingNorthing(fe, fn);
764  record->proj = nz_proj;
765  }
766  else if (proj_type.contains("Polar Stereographic"))
767  {
768  origin.lat = decodeSexagesimalDms(record->csvRecord[A_NAT_ORG_LAT]);
769  origin.lon = decodeSexagesimalDms(record->csvRecord[A_NAT_ORG_LON]);
770  // double fe = mtrs_per_unit*record->csvRecord[A_FALSE_EASTING].toDouble();
771  // double fn = mtrs_per_unit*record->csvRecord[A_FALSE_NORTHING].toDouble();
772  ossimUpsProjection* ups_proj = new ossimUpsProjection(ossimEllipsoid(), origin);
773  record->proj = ups_proj;
774  }
775  else
776  {
777  // Can't handle it now.
778  //ossimNotify(ossimNotifyLevel_FATAL)<<MODULE<<"EPSG:"<<record->csvRecord[A_CODE]<<" \""<<proj_type<<"\" "
779  // "not presently supported. Returning NULL projection..."<<endl;
780  return 0;
781  }
782 
783  record->proj->setDatum(datum);
784  record->proj->setPcsCode(record->code);
785  record->proj->setProjectionUnits(mapProjUnits);
786 
787  return record->proj.get();
788 }
789 
790 //*************************************************************************************************
791 // ### HACK ###
795 //*************************************************************************************************
798 {
799  // Unfortunately, as of this writing, there is a disconnect between the Geotrans projection
800  // parameters and those provided by EPSG database. In the meantime, to maintain functionality,
801  // we intercept the EPSG code and programmatically arrive at the projection versus pulling
802  // all the parameters out of the Db record->
803  ossimStatePlaneProjectionInfo info(db_record->name,
804  db_record->code,
805  db_record->csvRecord[B_PROJ_TYPE],
806  db_record->csvRecord[B_PARAM1],
807  db_record->csvRecord[B_PARAM2],
808  db_record->csvRecord[B_PARAM3],
809  db_record->csvRecord[B_PARAM4],
810  db_record->csvRecord[B_FALSE_EASTING].toDouble(),
811  db_record->csvRecord[B_FALSE_NORTHING].toDouble(),
812  db_record->csvRecord[B_UNITS],
813  db_record->csvRecord[B_DATUM_CODE]);
814 
815  // NOTE: In order to avoid infinite recursion with this object, we initialized the PCS code in
816  // info to NULL to insure that the projection is instantiated directly (not via this class):
817  ossimKeywordlist kwl;
818  info.populateProjectionKeywords(kwl);
820  db_record->proj =
822  if (db_record->proj.valid())
823  {
824  db_record->proj->setPcsCode(db_record->csvRecord[B_CODE].toUInt32());
825  db_record->datumValid = true;
826  }
827 
828  return db_record->proj.get();
829 }
830 
831 //*************************************************************************************************
832 // ### HACK ###
836 //*************************************************************************************************
838 {
839  // This code originally found in deprecated ossimPcsCodeProjectionFactory authored by
840  // David Burken.
841  int type = code/100;
842  int zone = code%100;
843  ossimUtmProjection* proj = NULL;
844  switch (type)
845  {
846  case 322:
847  // utm, WGS72 (WGD), northern hemisphere
848  if ( (zone > 0 ) && (zone < 61) )
849  {
850  proj = new ossimUtmProjection(*(ossimDatumFactory::instance()->wgs72()->ellipsoid()));
851  proj->setDatum(ossimDatumFactory::instance()->wgs72());
852  proj->setZone(zone);
853  proj->setHemisphere('N');
854  }
855  break;
856 
857  case 323:
858  // utm, WGS72 (WGD), southern hemisphere
859  if ( (zone > 0) && (zone < 61) )
860  {
861  proj = new ossimUtmProjection(*(ossimDatumFactory::instance()->wgs72()->ellipsoid()));
862  proj->setDatum(ossimDatumFactory::instance()->wgs72());
863  proj->setZone(zone);
864  proj->setHemisphere('S');
865  }
866  break;
867 
868  case 326:
869  // utm, WGS84 (WGE), northern hemisphere
870  if ( (zone > 0) && (zone < 61) )
871  {
872  proj = new ossimUtmProjection(*(ossimDatumFactory::instance()->wgs84()->ellipsoid()));
873  proj->setDatum(ossimDatumFactory::instance()->wgs84());
874  proj->setZone(zone);
875  proj->setHemisphere('N');
876  }
877  break;
878 
879  case 327:
880  // utm, WGS84 (WGE), southern hemisphere
881  if ( (zone > 0) && (zone < 61) )
882  {
883  proj = new ossimUtmProjection(*(ossimDatumFactory::instance()->wgs84()->ellipsoid()));
884  proj->setDatum(ossimDatumFactory::instance()->wgs84());
885  proj->setZone(zone);
886  proj->setHemisphere('S');
887  }
888  break;
889 
890  case 267:
891  // utm, "NAS-C", northern hemisphere
892  // Only UTM NAD27 North zones 3 to 22 are in the 267xx range...
893  // 26729 through 26803 handled by state plane factory.
894  //---
895  if ( (code > 26702) && (code < 26723) )
896  {
898  create(ossimString("NAS-C"))->ellipsoid()));
899  proj->setDatum(ossimDatumFactory::instance()->create(ossimString("NAS-C")));
900  proj->setZone(zone);
901  proj->setHemisphere('N');
902  }
903  break;
904 
905  case 269:
906  // utm, "NAR-C", northern hemisphere
907  // Only UTM NAD83 North zones 3 to 23 are in the 269xx range...
908  // 26929 through 26998 handled by state plane factory.
909  if ( (code > 26902) && (code < 26924) )
910  {
912  create(ossimString("NAR-C"))->ellipsoid()));
913  proj->setDatum(ossimDatumFactory::instance()->create(ossimString("NAR-C")));
914  proj->setZone(zone);
915  proj->setHemisphere('N');
916  }
917  break;
918 
919  case 248:
920  // Provisional S. American 1956, 24818 through 24880
921  if ( (code > 24817) && (code < 24881) )
922  {
924  create(ossimString("PRP-M"))->ellipsoid()));
925  proj->setDatum(ossimDatumFactory::instance()->create(ossimString("PRP-M")));
926  if (zone > 60)
927  {
928  proj->setZone(zone - 60);
929  proj->setHemisphere('S');
930  }
931  else
932  {
933  proj->setZone(zone);
934  proj->setHemisphere('N');
935  }
936  }
937  break;
938 
939  } // End of switch on code.
940 
941  if (proj)
942  proj->setPcsCode(code);
943 
944  return proj;
945 }
946 
947 //*************************************************************************************************
949 //*************************************************************************************************
951 {
952  if (proj == NULL)
953  return 0;
954 
955  char hemisphere = proj->getHemisphere();
956  ossim_uint32 zone = proj->getZone();
957  ossimString datum_code = proj->getDatum()->code();
958 
959  if ((zone < 1 ) || (zone > 60))
960  return 0;
961 
962  ossim_uint32 epsg_code = zone;
963  if ((hemisphere == 'N') && (datum_code == "WGD"))
964  epsg_code += 32200;
965 
966  else if ((hemisphere == 'S') && (datum_code == "WGD"))
967  epsg_code += 32300;
968 
969  else if ((hemisphere == 'N') && (datum_code == "WGE"))
970  epsg_code += 32600;
971 
972  else if ((hemisphere == 'S') && (datum_code == "WGE"))
973  epsg_code += 32700;
974 
975  else if ((hemisphere == 'N') && (datum_code == "NAS-C") && (zone > 2) && (zone < 23))
976  epsg_code += 26700;
977 
978  else if ((hemisphere == 'N') && (datum_code == "NAR-C") && (zone > 2) && (zone < 24))
979  epsg_code += 26900;
980 
981  else if ((hemisphere == 'N') && (datum_code == "PRP-M"))
982  epsg_code += 24800;
983 
984  else if ((hemisphere == 'S') && (datum_code == "PRP-M"))
985  epsg_code += 24800 + 60;
986 
987  else
988  {
989  //---
990  // Use a projection code that does not imply a datum.
991  // See section "6.3.3.2 Projection Codes" for definition.
992  //---
993  if ( hemisphere == 'N' ) // Northern hemisphere.
994  {
995  epsg_code += 16000;
996  }
997  else // Southern hemisphere.
998  {
999  epsg_code += 16100;
1000  }
1001  }
1002 
1003  return epsg_code;
1004 }
1005 
virtual const ossimDatum * create(const ossimString &code) const
create method
ossim_uint32 getCodeFromUtmProj(const ossimUtmProjection *proj) const
Given UTM projection, derives the associated EPSG code. This is faster than a Db lookup.
void clear()
Erases the entire container.
Definition: ossimString.h:432
const ossimKeywordlist & preferencesKWL() const
virtual ossimObject * dup() const =0
ossimString before(const ossimString &str, std::string::size_type pos=0) const
METHOD: before(str, pos) Returns string beginning at pos and ending one before the token str If strin...
Real sign(Real x, Real y)
Definition: newmatrm.h:108
bool datumValid
FALSE if the datum code was not parsed and WGS84 defaulted.
Type for database record consists of EPSG code and serialized form of corresponding OSSIM projection ...
ossimUnitType
Represents serializable keyword/value map.
const std::string & findKey(const std::string &key) const
Find methods that take std::string(s).
void initialize() const
Populates the database with contents of DB files as specified in ossim_preferences.
std::string & insert(std::string::size_type pos, const char *s)
If pos > size(), throws out_of_range.
Definition: ossimString.h:898
static ossimDatumFactoryRegistry * instance()
instance method
std::basic_ifstream< char > ifstream
Class for char input file streams.
Definition: ossimIosFwd.h:44
bool valid() const
Definition: ossimRefPtr.h:75
virtual ossim_uint32 epsgCode() const
Definition: ossimDatum.h:59
static ossimMapProjectionFactory * instance()
virtual void setOrigin(const ossimGpt &origin)
Sets theOrigin to origin.
bool contains(char aChar) const
Definition: ossimString.h:58
void setFalseEastingNorthing(double falseEasting, double falseNorthing)
virtual const ossimString & code() const
Definition: ossimDatum.h:57
static ossimString toString(bool aValue)
Numeric to string methods.
void split(std::vector< ossimString > &result, const ossimString &separatorList, bool skipBlankFields=false) const
Splits this string into a vector of strings (fields) using the delimiter list specified.
Projection Database for coded projections defined in database files and specified via some coordinate...
virtual ossimString getClassName() const
Definition: ossimObject.cpp:64
ossim_uint32 toUInt32() const
std::istream & getline(std::istream &is, ossimString &str, char delim)
Definition: ossimString.h:916
ossim_uint32 findProjectionCode(const ossimString &projection_name) const
Given a projection name, assigns the group (e.g., "EPSG") and code of the projection.
void getProjectionsList(std::vector< ossimString > &typeList) const
Populates caller&#39;s list with all projections currently represented in the database.
ossimMapProjection * createProjFromUtmCode(ossim_uint32 code) const
HACKUTM projections as specified in the EPSG are indistinguishable from regular TM.
void push_back(char c)
Equivalent to insert(end(), c).
Definition: ossimString.h:905
#define US_METERS_PER_FT
Albers Equal Area Conic Projection.
yy_size_t size
virtual const ossimDatum * getDatum() const
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 void setPcsCode(ossim_uint32 pcsCode)
std::string::size_type size() const
Definition: ossimString.h:405
static ossimEpsgProjectionDatabase * instance()
Instantiates singleton instance of this class:
ossimMapProjection * createProjFromFormatBRecord(ProjDbRecord *record) const
Parses the State Plane Db record format and produce a projection (or NULL if invalid) ...
unsigned int ossim_uint32
virtual const ossimDatum * create(const ossimString &code) const
create method
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.
virtual const ossimEllipsoid * ellipsoid() const
Definition: ossimDatum.h:60
double toDouble() const
#define PTR_CAST(T, p)
Definition: ossimRtti.h:321
static ossimDatumFactory * instance()
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
void setZone(const ossimGpt &ground)
std::vector< ossimString > getSubstringKeyList(const ossimString &regularExpression) const
#define MTRS_PER_FT
std::multimap< ossim_uint32, ossimRefPtr< ProjDbRecord > > m_projDatabase
static const char * PCS_CODE_KW
virtual ~ossimEpsgProjectionDatabase()
Destructor.
bool isRelative() const
Checks whether file name is relative or absolute.
ossimFilename dirCat(const ossimFilename &file) const
ossimMapProjection * createProjFromFormatARecord(ProjDbRecord *record) const
Parses the "Spadac EPSG" Db record format and produces a projection (or NULL if invalid) ...
ossim_int32 getZone() const
double decodeSexagesimalDms(const ossimString &sex_str)
Converts sexagesimal DMS to decimal degrees.
ossim_float64 lat
Definition: ossimGpt.h:265
void setProjectionUnits(ossimUnitType units)
virtual void setDatum(const ossimDatum *datum)
Sets theDatum to datum.
ossimString after(const ossimString &str, std::string::size_type pos=0) const
METHOD: after(str, pos) Returns string immediately after the token str.
ossimString findProjectionName(ossim_uint32 epsg_code) const
NECESSARY HACK ### (originally implemented by ESH)ArcMap (9.2 and less) doesn&#39;t understand the non-me...
void setHemisphere(const ossimGpt &ground)
void remove(const char *key)
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...
ossimEpsgProjectionDatabase()
Constructor loads all Db files specified in the ossim prefs.
const std::string & string() const
Definition: ossimString.h:414