1 
2 ///////////////////////////////////////////////////////////
3 //                                                       //
4 //                         SAGA                          //
5 //                                                       //
6 //      System for Automated Geoscientific Analyses      //
7 //                                                       //
8 //           Application Programming Interface           //
9 //                                                       //
10 //                  Library: SAGA_API                    //
11 //                                                       //
12 //-------------------------------------------------------//
13 //                                                       //
14 //                    projections.cpp                    //
15 //                                                       //
16 //          Copyright (C) 2009 by Olaf Conrad            //
17 //                                                       //
18 //-------------------------------------------------------//
19 //                                                       //
20 // This file is part of 'SAGA - System for Automated     //
21 // Geoscientific Analyses'.                              //
22 //                                                       //
23 // This library is free software; you can redistribute   //
24 // it and/or modify it under the terms of the GNU Lesser //
25 // General Public License as published by the Free       //
26 // Software Foundation, either version 2.1 of the        //
27 // License, or (at your option) any later version.       //
28 //                                                       //
29 // This library is distributed in the hope that it will  //
30 // be useful, but WITHOUT ANY WARRANTY; without even the //
31 // implied warranty of MERCHANTABILITY or FITNESS FOR A  //
32 // PARTICULAR PURPOSE. See the GNU Lesser General Public //
33 // License for more details.                             //
34 //                                                       //
35 // You should have received a copy of the GNU Lesser     //
36 // General Public License along with this program; if    //
37 // not, see <http://www.gnu.org/licenses/>.              //
38 //                                                       //
39 //-------------------------------------------------------//
40 //                                                       //
41 //    contact:    Olaf Conrad                            //
42 //                Institute of Geography                 //
43 //                University of Hamburg                  //
44 //                Germany                                //
45 //                                                       //
46 //    e-mail:     oconrad@saga-gis.org                   //
47 //                                                       //
48 ///////////////////////////////////////////////////////////
49 
50 //---------------------------------------------------------
51 #include "geo_tools.h"
52 
53 #include "table.h"
54 
55 
56 ///////////////////////////////////////////////////////////
57 //														 //
58 //														 //
59 //														 //
60 ///////////////////////////////////////////////////////////
61 
62 //---------------------------------------------------------
63 CSG_Projections		gSG_Projections;
64 
65 //---------------------------------------------------------
SG_Get_Projections(void)66 CSG_Projections &	SG_Get_Projections(void)
67 {
68 	return( gSG_Projections );
69 }
70 
71 
72 ///////////////////////////////////////////////////////////
73 //														 //
74 ///////////////////////////////////////////////////////////
75 
76 //---------------------------------------------------------
SG_Get_Projection_Type(const CSG_String & Identifier)77 TSG_Projection_Type	SG_Get_Projection_Type				(const CSG_String &Identifier)
78 {
79 	if( !Identifier.CmpNoCase("PROJCS") )	return( SG_PROJ_TYPE_CS_Projected  );
80 	if( !Identifier.CmpNoCase("GEOGCS") )	return( SG_PROJ_TYPE_CS_Geographic );
81 	if( !Identifier.CmpNoCase("GEOCCS") )	return( SG_PROJ_TYPE_CS_Geocentric );
82 
83 	return( SG_PROJ_TYPE_CS_Undefined );
84 }
85 
86 //---------------------------------------------------------
SG_Get_Projection_Type_Identifier(TSG_Projection_Type Type)87 CSG_String			SG_Get_Projection_Type_Identifier	(TSG_Projection_Type Type)
88 {
89 	switch( Type )
90 	{
91 	case SG_PROJ_TYPE_CS_Projected :	return( "PROJCS"    );
92 	case SG_PROJ_TYPE_CS_Geographic:	return( "GEOGCS"    );
93 	case SG_PROJ_TYPE_CS_Geocentric:	return( "GEOCCS"    );
94 	default                        :	return( "UNDEFINED" );
95 	}
96 }
97 
98 //---------------------------------------------------------
SG_Get_Projection_Type_Name(TSG_Projection_Type Type)99 CSG_String			SG_Get_Projection_Type_Name			(TSG_Projection_Type Type)
100 {
101 	switch( Type )
102 	{
103 	case SG_PROJ_TYPE_CS_Projected :	return( _TL("Projected Coordinate System" ) );
104 	case SG_PROJ_TYPE_CS_Geographic:	return( _TL("Geographic Coordinate System") );
105 	case SG_PROJ_TYPE_CS_Geocentric:	return( _TL("Geocentric Coordinate System") );
106 	default                        :	return( _TL("Undefined Coordinate System" ) );
107 	}
108 }
109 
110 
111 ///////////////////////////////////////////////////////////
112 //														 //
113 ///////////////////////////////////////////////////////////
114 
115 //---------------------------------------------------------
116 const char	SG_Projection_Units[SG_PROJ_UNIT_Undefined + 1][3][32]	=
117 {
118 	{	"km"    , "Kilometers" , "Kilometer"					},
119 	{	"m"    	, "Meters"	   , "Meter"						},
120 	{	"dm"    , "Decimeters" , "Decimeter"					},
121 	{	"cm"    , "Centimeters", "Centimeter"					},
122 	{	"mm"    , "Millimeters", "Millimeter"					},
123 	{	"kmi"   , "Miles"      , "International Nautical Mile"	},
124 	{	"in"    , "Inches"     , "International Inch"			},
125 	{	"ft"    , "Feet"       , "International Foot"			},
126 	{	"yd"    , "Yards"      , "International Yard"			},
127 	{	"mi"    , "Miles"      , "International Statute Mile"	},
128 	{	"fath"  , "Fathoms"    , "International Fathom"			},
129 	{	"ch"    , "Chains"     , "International Chain"			},
130 	{	"link"  , "Links"      , "International Link"			},
131 	{	"us-in" , "Inches"     , "U.S. Surveyor's Inch"			},
132 	{	"us-ft" , "Feet"       , "U.S. Surveyor's Foot"			},
133 	{	"us-yd" , "Yards"      , "U.S. Surveyor's Yard"			},
134 	{	"us-ch" , "Chains"     , "U.S. Surveyor's Chain"		},
135 	{	"us-mi" , "Miles"      , "U.S. Surveyor's Statute Mile"	},
136 	{	"ind-yd", "Yards"      , "Indian Yard"					},
137 	{	"ind-ft", "Feet"       , "Indian Foot"					},
138 	{	"ind-ch", "Chains"     , "Indian Chain"					},
139 	{	""      , ""           , ""								}
140 };
141 
142 //---------------------------------------------------------
143 // same as proj4.
SG_Get_Projection_Unit(const CSG_String & Identifier)144 TSG_Projection_Unit	SG_Get_Projection_Unit				(const CSG_String &Identifier)
145 {
146 	for(int i=0; i<SG_PROJ_UNIT_Undefined; i++)
147 	{
148 		if( !Identifier.CmpNoCase(SG_Projection_Units[i][0])
149 		||  !Identifier.CmpNoCase(SG_Projection_Units[i][2]) )
150 		{
151 			return( (TSG_Projection_Unit)i );
152 		}
153 	}
154 
155 	return( !Identifier.CmpNoCase("metre") ? SG_PROJ_UNIT_Meter : SG_PROJ_UNIT_Undefined );
156 }
157 
158 //---------------------------------------------------------
159 // same as proj4.
SG_Get_Projection_Unit_Identifier(TSG_Projection_Unit Unit)160 CSG_String			SG_Get_Projection_Unit_Identifier	(TSG_Projection_Unit Unit)
161 {
162 	if(	Unit < 0 || Unit > SG_PROJ_UNIT_Undefined )
163 		Unit	= SG_PROJ_UNIT_Undefined;
164 
165 	return( SG_Projection_Units[Unit][0] );
166 }
167 
168 //---------------------------------------------------------
SG_Get_Projection_Unit_Name(TSG_Projection_Unit Unit,bool bSimple)169 CSG_String			SG_Get_Projection_Unit_Name			(TSG_Projection_Unit Unit, bool bSimple)
170 {
171 	if(	Unit < 0 || Unit > SG_PROJ_UNIT_Undefined )
172 		Unit	= SG_PROJ_UNIT_Undefined;
173 
174 	return( SG_Projection_Units[Unit][bSimple ? 1 : 2] );
175 }
176 
177 //---------------------------------------------------------
SG_Get_Projection_Unit_To_Meter(TSG_Projection_Unit Unit)178 double				SG_Get_Projection_Unit_To_Meter		(TSG_Projection_Unit Unit)
179 {
180 	switch( Unit )
181 	{
182 	case SG_PROJ_UNIT_Kilometer        :	return( 1000. );
183 	case SG_PROJ_UNIT_Meter            :	return( 1. );
184 	case SG_PROJ_UNIT_Decimeter        :	return( 0.1 );
185 	case SG_PROJ_UNIT_Centimeter       :	return( 0.01 );
186 	case SG_PROJ_UNIT_Millimeter       :	return( 0.001 );
187 	case SG_PROJ_UNIT_Int_Nautical_Mile:	return( 1852. );
188 	case SG_PROJ_UNIT_Int_Inch         :	return( 0.0254 );
189 	case SG_PROJ_UNIT_Int_Foot         :	return( 0.3048 );
190 	case SG_PROJ_UNIT_Int_Yard         :	return( 0.9144 );
191 	case SG_PROJ_UNIT_Int_Statute_Mile :	return( 1609.344 );
192 	case SG_PROJ_UNIT_Int_Fathom       :	return( 1.8288 );
193 	case SG_PROJ_UNIT_Int_Chain        :	return( 20.1168 );
194 	case SG_PROJ_UNIT_Int_Link         :	return( 0.201168 );
195 	case SG_PROJ_UNIT_US_Inch          :	return( 1. / 39.37 );
196 	case SG_PROJ_UNIT_US_Foot          :	return( 0.304800609601219 );
197 	case SG_PROJ_UNIT_US_Yard          :	return( 0.914401828803658 );
198 	case SG_PROJ_UNIT_US_Chain         :	return( 20.11684023368047 );
199 	case SG_PROJ_UNIT_US_Statute_Mile  :	return( 1609.347218694437 );
200 	case SG_PROJ_UNIT_Indian_Yard      :	return( 0.91439523 );
201 	case SG_PROJ_UNIT_Indian_Foot      :	return( 0.30479841 );
202 	case SG_PROJ_UNIT_Indian_Chain     :	return( 20.11669506 );
203 	default                            :	return( 1. );
204 	}
205 }
206 
207 //---------------------------------------------------------
SG_Set_Projection_Unit(const CSG_MetaData & m,TSG_Projection_Unit & Unit,CSG_String & Name,double & To_Meter)208 bool				SG_Set_Projection_Unit		(const CSG_MetaData &m, TSG_Projection_Unit &Unit, CSG_String &Name, double &To_Meter)
209 {
210 	if( m("UNIT") )
211 	{
212 		if( m["UNIT"].Get_Property("name", Name) && (Unit = SG_Get_Projection_Unit(Name)) != SG_PROJ_UNIT_Undefined )
213 		{
214 			Name		= SG_Get_Projection_Unit_Name    (Unit);
215 			To_Meter	= SG_Get_Projection_Unit_To_Meter(Unit);
216 		}
217 		else if( !m["UNIT"].Get_Content().asDouble(To_Meter) || To_Meter <= 0. )
218 		{
219 			To_Meter	=  1.;
220 		}
221 
222 		return( true );
223 	}
224 
225 	return( false );
226 }
227 
228 
229 ///////////////////////////////////////////////////////////
230 //														 //
231 //														 //
232 //														 //
233 ///////////////////////////////////////////////////////////
234 
235 //---------------------------------------------------------
CSG_Projection(void)236 CSG_Projection::CSG_Projection(void)
237 {
238 	Destroy();
239 }
240 
~CSG_Projection(void)241 CSG_Projection::~CSG_Projection(void)
242 {}
243 
244 //---------------------------------------------------------
CSG_Projection(const CSG_Projection & Projection)245 CSG_Projection::CSG_Projection(const CSG_Projection &Projection)
246 {
247 	Destroy();
248 
249 	Create(Projection);
250 }
251 
Create(const CSG_Projection & Projection)252 bool CSG_Projection::Create(const CSG_Projection &Projection)
253 {
254 	return( Assign(Projection) );
255 }
256 
Assign(const CSG_Projection & Projection)257 bool CSG_Projection::Assign(const CSG_Projection &Projection)
258 {
259 	m_Name			= Projection.m_Name;
260 	m_Type			= Projection.m_Type;
261 	m_Unit			= Projection.m_Unit;
262 	m_Unit_To_Meter	= Projection.m_Unit_To_Meter;
263 	m_Unit_Name		= Projection.m_Unit_Name;
264 	m_WKT			= Projection.m_WKT;
265 	m_Proj4			= Projection.m_Proj4;
266 	m_Authority		= Projection.m_Authority;
267 	m_Authority_ID	= Projection.m_Authority_ID;
268 
269 	return( true );
270 }
271 
272 //---------------------------------------------------------
CSG_Projection(int Authority_ID,const SG_Char * Authority)273 CSG_Projection::CSG_Projection(int Authority_ID, const SG_Char *Authority)
274 {
275 	Destroy();
276 
277 	Create(Authority_ID, Authority);
278 }
279 
Create(int Authority_ID,const SG_Char * Authority)280 bool CSG_Projection::Create(int Authority_ID, const SG_Char *Authority)
281 {
282 	return( Assign(Authority_ID, Authority) );
283 }
284 
Assign(int Authority_ID,const SG_Char * Authority)285 bool CSG_Projection::Assign(int Authority_ID, const SG_Char *Authority)
286 {
287 	return( Authority && *Authority
288 		? gSG_Projections.Get_Projection(*this, Authority, Authority_ID)
289 		: gSG_Projections.Get_Projection(*this,            Authority_ID)
290 	);
291 }
292 
293 //---------------------------------------------------------
CSG_Projection(const CSG_String & Projection,TSG_Projection_Format Format)294 CSG_Projection::CSG_Projection(const CSG_String &Projection, TSG_Projection_Format Format)
295 {
296 	Create(Projection, Format);
297 }
298 
Create(const CSG_String & Projection,TSG_Projection_Format Format)299 bool CSG_Projection::Create(const CSG_String &Projection, TSG_Projection_Format Format)
300 {
301 	return( Assign(Projection, Format) );
302 }
303 
Assign(const CSG_String & Projection,TSG_Projection_Format Format)304 bool CSG_Projection::Assign(const CSG_String &Projection, TSG_Projection_Format Format)
305 {
306 	Destroy();
307 
308 	if( Projection.is_Empty() )
309 	{
310 		return( false );
311 	}
312 
313 	//-----------------------------------------------------
314 	int				i;
315 	CSG_String		s;
316 	CSG_MetaData	m;
317 
318 	switch( Format )
319 	{
320 	default:
321 		return( false );
322 
323 	//-----------------------------------------------------
324 	case SG_PROJ_FMT_EPSG:
325 		return( Projection.asInt(i) && Assign(i, SG_T("EPSG")) );
326 
327 	//-----------------------------------------------------
328 	case SG_PROJ_FMT_Proj4:
329 		if( !gSG_Projections.WKT_from_Proj4(s, Projection) )
330 		{
331 			return( false );
332 		}
333 
334 		m_WKT	= s;
335 		m_Proj4	= Projection;
336 
337 		m		= gSG_Projections.WKT_to_MetaData(m_WKT);
338 
339 		break;
340 
341 	//-----------------------------------------------------
342 	case SG_PROJ_FMT_WKT:
343 		m		= gSG_Projections.WKT_to_MetaData(Projection);
344 
345 		if(	m.Get_Property("authority_name", s) && s.CmpNoCase("EPSG") == 0
346 		&&	m.Get_Property("authority_code", i) && gSG_Projections.Get_Projection(*this, i) )
347 		{
348 			return( true );
349 		}
350 
351 		if( gSG_Projections.WKT_to_Proj4(s, Projection) )
352 		{
353 			m_Proj4	= s;
354 		}
355 
356 		m_WKT	= Projection;
357 
358 		break;
359 	}
360 
361 	//-----------------------------------------------------
362 	m_Name	= m.Get_Property("name");
363 	m_Type	= SG_Get_Projection_Type(m.Get_Name());
364 
365 	SG_Set_Projection_Unit(m, m_Unit, m_Unit_Name, m_Unit_To_Meter);
366 
367 	return( true );
368 }
369 
370 //---------------------------------------------------------
CSG_Projection(const CSG_String & WKT,const CSG_String & Proj4)371 CSG_Projection::CSG_Projection(const CSG_String &WKT, const CSG_String &Proj4)
372 {
373 	Create(WKT, Proj4);
374 }
375 
Create(const CSG_String & WKT,const CSG_String & Proj4)376 bool CSG_Projection::Create(const CSG_String &WKT, const CSG_String &Proj4)
377 {
378 	return( Assign(WKT, Proj4) );
379 }
380 
Assign(const CSG_String & WKT,const CSG_String & Proj4)381 bool CSG_Projection::Assign(const CSG_String &WKT, const CSG_String &Proj4)
382 {
383 	if( Assign(WKT) )
384 	{
385 		m_Proj4	= Proj4;
386 
387 		return( true );
388 	}
389 
390 	return( false );
391 }
392 
393 //---------------------------------------------------------
Destroy(void)394 void CSG_Projection::Destroy(void)
395 {
396 	m_Name			= _TL("undefined");
397 	m_Type			= SG_PROJ_TYPE_CS_Undefined;
398 	m_Unit			= SG_PROJ_UNIT_Undefined;
399 	m_Unit_To_Meter	= 1.;
400 	m_Unit_Name		.Clear();
401 	m_WKT			.Clear();
402 	m_Proj4			.Clear();
403 	m_Authority		.Clear();
404 	m_Authority_ID	= -1;
405 }
406 
407 
408 ///////////////////////////////////////////////////////////
409 //														 //
410 ///////////////////////////////////////////////////////////
411 
412 //---------------------------------------------------------
Load(const CSG_String & FileName,TSG_Projection_Format Format)413 bool CSG_Projection::Load(const CSG_String &FileName, TSG_Projection_Format Format)
414 {
415 	CSG_File	Stream(FileName, SG_FILE_R, false);
416 
417 	return( Load(Stream, Format) );
418 }
419 
420 //---------------------------------------------------------
Save(const CSG_String & FileName,TSG_Projection_Format Format) const421 bool CSG_Projection::Save(const CSG_String &FileName, TSG_Projection_Format Format) const
422 {
423 	CSG_File	Stream(FileName, SG_FILE_W, false);
424 
425 	return( is_Okay() && Save(Stream, Format) );
426 }
427 
428 //---------------------------------------------------------
Load(CSG_File & Stream,TSG_Projection_Format Format)429 bool CSG_Projection::Load(CSG_File &Stream, TSG_Projection_Format Format)
430 {
431 	if( Stream.is_Reading() )
432 	{
433 		CSG_String	s;
434 
435 		Stream.Read(s, (size_t)Stream.Length());
436 
437 		return( Assign(s, Format) );
438 	}
439 
440 	return( false );
441 }
442 
443 //---------------------------------------------------------
Save(CSG_File & Stream,TSG_Projection_Format Format) const444 bool CSG_Projection::Save(CSG_File &Stream, TSG_Projection_Format Format)	const
445 {
446 	if( is_Okay() && Stream.is_Writing() )
447 	{
448 		switch( Format )
449 		{
450 		case SG_PROJ_FMT_WKT: default:
451 			return( Stream.Write(m_WKT  ) == m_WKT  .Length() );
452 
453 		case SG_PROJ_FMT_Proj4:
454 			return( Stream.Write(m_Proj4) == m_Proj4.Length() );
455 		}
456 	}
457 
458 	return( false );
459 }
460 
461 //---------------------------------------------------------
Load(const CSG_MetaData & Projection)462 bool CSG_Projection::Load(const CSG_MetaData &Projection)
463 {
464 	CSG_MetaData	*pEntry;
465 
466 	if( (pEntry = Projection.Get_Child("OGC_WKT")) != NULL )
467 	{
468 		Assign(pEntry->Get_Content(), SG_PROJ_FMT_WKT);
469 
470 		if( (pEntry = Projection.Get_Child("PROJ4")) != NULL )
471 		{
472 			m_Proj4	= pEntry->Get_Content();
473 		}
474 
475 		return( true );
476 	}
477 
478 	return( false );
479 }
480 
481 //---------------------------------------------------------
Save(CSG_MetaData & Projection) const482 bool CSG_Projection::Save(CSG_MetaData &Projection) const
483 {
484 	Projection.Del_Children();
485 
486 	Projection.Add_Child("OGC_WKT", m_WKT      );
487 	Projection.Add_Child("PROJ4"  , m_Proj4    );
488 	Projection.Add_Child("EPSG"   , Get_EPSG() );
489 
490 	return( true );
491 }
492 
493 
494 ///////////////////////////////////////////////////////////
495 //														 //
496 ///////////////////////////////////////////////////////////
497 
498 //---------------------------------------------------------
499 #define WKT_GCS_WGS84	"GEOGCS[\"WGS 84\",AUTHORITY[\"EPSG\",\"4326\"]],"\
500 	"DATUM[\"WGS_1984\",AUTHORITY[\"EPSG\",\"6326\"]],"\
501 		"SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],"\
502 	"PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],"\
503 	"UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]]"
504 
505 //---------------------------------------------------------
506 #define PROJ4_GCS_WGS84	"+proj=longlat +datum=WGS84 +no_defs"
507 
508 //---------------------------------------------------------
Set_GCS_WGS84(void)509 bool CSG_Projection::Set_GCS_WGS84(void)
510 {
511 	return( Create(WKT_GCS_WGS84, PROJ4_GCS_WGS84) );
512 }
513 
514 //---------------------------------------------------------
Set_UTM_WGS84(int Zone,bool bSouth)515 bool CSG_Projection::Set_UTM_WGS84(int Zone, bool bSouth)
516 {
517 	if( Zone < 1 || Zone > 60 )
518 	{
519 		return( false );
520 	}
521 
522 	//-----------------------------------------------------
523 	int	EPSG_ID	= (bSouth ? 32700 : 32600) + Zone;
524 
525 	if( Create(EPSG_ID) )
526 	{
527 		return( true );
528 	}
529 
530 	//-----------------------------------------------------
531 	CSG_String	WKT, Proj4;
532 
533 	WKT.Printf("PROJCS[\"WGS 84 / UTM zone %d%c\",%s"						// Zone, N/S, Datum
534 		"PROJECTION[\"Transverse_Mercator\"],AUTHORITY[\"EPSG\",\"%d\"]]"	// EPSG ID
535 			"PARAMETER[\"latitude_of_origin\",0],"
536 			"PARAMETER[\"central_meridian\",%d],"							// Central Meridian
537 			"PARAMETER[\"scale_factor\",0.9996],"
538 			"PARAMETER[\"false_easting\",500000],"
539 			"PARAMETER[\"false_northing\",%d],"								// False Northing
540 			"AXIS[\"Easting\",EAST],"
541 			"AXIS[\"Northing\",NORTH],"
542 			"UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]]",
543 		Zone, bSouth ? 'S' : 'N', CSG_String(WKT_GCS_WGS84).c_str(), EPSG_ID, 6 * (Zone - 1) - 177, bSouth ? 10000000 : 0
544 	);
545 
546 	Proj4.Printf("+proj=utm +zone=%d%s +datum=WGS84 +units=m +no_defs", Zone, bSouth ? SG_T(" +south") : SG_T(""));
547 
548 	return( Create(WKT, Proj4) );
549 }
550 
551 
552 ///////////////////////////////////////////////////////////
553 //														 //
554 ///////////////////////////////////////////////////////////
555 
556 //---------------------------------------------------------
is_Equal(const CSG_Projection & Projection) const557 bool CSG_Projection::is_Equal(const CSG_Projection &Projection)	const
558 {
559 	if( is_Okay() != Projection.is_Okay() )
560 	{
561 		return( false );
562 	}
563 
564 	if( !is_Okay() )	// both are not valid
565 	{
566 		return( true );
567 	}
568 
569 	if( !m_Authority.is_Empty() && !Projection.m_Authority.is_Empty() )
570 	{
571 		return(	m_Authority.CmpNoCase(Projection.m_Authority) == 0 && m_Authority_ID == Projection.m_Authority_ID );
572 	}
573 
574 	if( m_Proj4.CmpNoCase(Projection.m_Proj4) == 0 )	// the simple case...
575 	{
576 		return( true );
577 	}
578 
579 	//-----------------------------------------------------
580 	CSG_Table	parms[2];	// okay, let's perform a more detailed check...
581 
582 	for(int i=0; i<2; i++)
583 	{
584 		parms[i].Add_Field("key", SG_DATATYPE_String);
585 		parms[i].Add_Field("val", SG_DATATYPE_String);
586 
587 		CSG_Strings	s	= SG_String_Tokenize(i == 0 ? m_Proj4 : Projection.m_Proj4, "+");
588 
589 		for(int j=0, k=0; j<s.Get_Count(); j++)
590 		{
591 			CSG_String	key	= s[j].BeforeFirst('='); key.Trim(false); key.Trim(true); key.Make_Lower();
592 			CSG_String	val	= s[j].AfterFirst ('='); val.Trim(false); val.Trim(true); val.Make_Lower();
593 
594 			if( !key.is_Empty() && key.Cmp("no_defs") && parms[i].Add_Record() )
595 			{
596 				parms[i][k][0]	= key;
597 				parms[i][k][1]	= val;
598 
599 				k++;
600 			}
601 		}
602 	}
603 
604 	if( parms[0].Get_Count() != parms[1].Get_Count() )	// should be the same...
605 	{
606 		return( false );
607 	}
608 
609 	parms[0].Set_Index(0, TABLE_INDEX_Ascending);	// sort by key...
610 	parms[1].Set_Index(0, TABLE_INDEX_Ascending);
611 
612 	for(int j=0; j<parms[0].Get_Count(); j++)
613 	{
614 		if( SG_STR_CMP(parms[0][j].asString(0), parms[1][j].asString(0)) )	// does the key match ?
615 		{
616 			return( false );
617 		}
618 
619 		if( SG_STR_CMP(parms[0][j].asString(1), parms[1][j].asString(1)) )	// doe the value string match ?
620 		{
621 			double	d[2];
622 
623 			if( !CSG_String(parms[0][j].asString(1)).asDouble(d[0])	// does the numerical value representation match ?
624 			||  !CSG_String(parms[1][j].asString(1)).asDouble(d[1]) || d[0] != d[1] )
625 			{
626 				return( false );
627 			}
628 		}
629 	}
630 
631 	return( true );
632 }
633 
634 
635 ///////////////////////////////////////////////////////////
636 //														 //
637 ///////////////////////////////////////////////////////////
638 
639 //---------------------------------------------------------
Get_Description(void) const640 CSG_String CSG_Projection::Get_Description(void)	const
641 {
642 	CSG_String	s;
643 
644 	s	= SG_Get_Projection_Type_Name(m_Type);
645 
646 	if( is_Okay() )
647 	{
648 		if( m_Authority.Length() > 0 && m_Authority_ID > 0 )
649 		{
650 			s	+= CSG_String::Format(" [%s %d]", m_Authority.c_str(), m_Authority_ID);
651 		}
652 
653 		s	+= ":\n" + m_Name;
654 
655 		if( m_Proj4.Length() > 0 )
656 		{
657 			s	+= "\n[" + m_Proj4 + "]";
658 		}
659 	}
660 
661 	return( s );
662 }
663 
664 
665 ///////////////////////////////////////////////////////////
666 //														 //
667 //														 //
668 //														 //
669 ///////////////////////////////////////////////////////////
670 
671 //---------------------------------------------------------
672 enum ESG_PROJ_FIELD_ID
673 {
674 	PRJ_FIELD_SRID		= 0,
675 	PRJ_FIELD_AUTH_NAME,
676 	PRJ_FIELD_AUTH_SRID,
677 	PRJ_FIELD_SRTEXT,
678 	PRJ_FIELD_PROJ4TEXT
679 };
680 
681 
682 ///////////////////////////////////////////////////////////
683 //														 //
684 ///////////////////////////////////////////////////////////
685 
686 //---------------------------------------------------------
CSG_Projections(void)687 CSG_Projections::CSG_Projections(void)
688 {
689 	_On_Construction();
690 }
691 
692 //---------------------------------------------------------
CSG_Projections(bool bLoadDefaults)693 CSG_Projections::CSG_Projections(bool bLoadDefaults)
694 {
695 	_On_Construction();
696 
697 	Create(bLoadDefaults);
698 }
699 
Create(bool bLoadDefaults)700 bool CSG_Projections::Create(bool bLoadDefaults)
701 {
702 	Destroy();
703 
704 	if( bLoadDefaults )	// load spatial reference system database and dictionary
705 	{
706 		#if defined(_SAGA_LINUX)
707 			CSG_String	Path_Shared	= SHARE_PATH;
708 		#else
709 			CSG_String	Path_Shared	= SG_UI_Get_Application_Path(true);
710 		#endif
711 
712 		SG_UI_Msg_Lock(true);
713 
714 		Load_Dictionary(SG_File_Make_Path(Path_Shared, "saga_prj", "dic"));
715 		Load_DB        (SG_File_Make_Path(Path_Shared, "saga_prj", "srs"));
716 
717 		SG_UI_Msg_Lock(false);
718 	}
719 
720 	return( true );
721 }
722 
723 //---------------------------------------------------------
CSG_Projections(const CSG_String & File_DB)724 CSG_Projections::CSG_Projections(const CSG_String &File_DB)
725 {
726 	_On_Construction();
727 
728 	Create(File_DB);
729 }
730 
Create(const CSG_String & File_DB)731 bool CSG_Projections::Create(const CSG_String &File_DB)
732 {
733 	SG_UI_Msg_Lock(true);
734 
735 	bool	bResult	= Load_DB(File_DB);
736 
737 	SG_UI_Msg_Lock(false);
738 
739 	return( bResult );
740 }
741 
742 //---------------------------------------------------------
_On_Construction(void)743 void CSG_Projections::_On_Construction(void)
744 {
745 	m_pProjections	= new CSG_Table;
746 
747 	m_pProjections->Add_Field("srid"     , SG_DATATYPE_Int   );	// PRJ_FIELD_SRID
748 	m_pProjections->Add_Field("auth_name", SG_DATATYPE_String);	// PRJ_FIELD_AUTH_NAME
749 	m_pProjections->Add_Field("auth_srid", SG_DATATYPE_Int   );	// PRJ_FIELD_AUTH_SRID
750 	m_pProjections->Add_Field("srtext"   , SG_DATATYPE_String);	// PRJ_FIELD_SRTEXT
751 	m_pProjections->Add_Field("proj4text", SG_DATATYPE_String);	// PRJ_FIELD_PROJ4TEXT
752 
753 	Reset_Dictionary();
754 }
755 
756 //---------------------------------------------------------
~CSG_Projections(void)757 CSG_Projections::~CSG_Projections(void)
758 {
759 	Destroy();
760 
761 	delete(m_pProjections);
762 }
763 
764 //---------------------------------------------------------
Destroy(void)765 void CSG_Projections::Destroy(void)
766 {
767 	if( m_pProjections )
768 	{
769 		m_pProjections->Del_Records();
770 	}
771 
772 	Reset_Dictionary();
773 }
774 
775 
776 ///////////////////////////////////////////////////////////
777 //														 //
778 ///////////////////////////////////////////////////////////
779 
780 //---------------------------------------------------------
Reset_Dictionary(void)781 bool CSG_Projections::Reset_Dictionary(void)
782 {
783 	_Set_Dictionary(m_Proj4_to_WKT,  1);
784 	_Set_Dictionary(m_WKT_to_Proj4, -1);
785 
786 	return( true );
787 }
788 
789 //---------------------------------------------------------
Load_Dictionary(const CSG_String & FileName)790 bool CSG_Projections::Load_Dictionary(const CSG_String &FileName)
791 {
792 	CSG_Table	Table;
793 
794 	if( SG_File_Exists(FileName) && Table.Create(FileName) && Table.Get_Field_Count() >= 3 )
795 	{
796 		CSG_Table	Proj4_to_WKT(&Table), WKT_to_Proj4(&Table);
797 
798 		for(int i=0; i<Table.Get_Count(); i++)
799 		{
800 			switch( Table[i].asString(1)[0] )
801 			{
802 			case SG_T('<'):	// ignore proj4 to wkt translation
803 				WKT_to_Proj4.Add_Record(Table.Get_Record(i));
804 				break;
805 
806 			case SG_T('>'):	// ignore wkt to proj4 translation
807 				Proj4_to_WKT.Add_Record(Table.Get_Record(i));
808 				break;
809 
810 			default:
811 				Proj4_to_WKT.Add_Record(Table.Get_Record(i));
812 				WKT_to_Proj4.Add_Record(Table.Get_Record(i));
813 			}
814 		}
815 
816 		m_Proj4_to_WKT.Create(&Proj4_to_WKT, 0, 2, true);
817 		m_WKT_to_Proj4.Create(&WKT_to_Proj4, 2, 0, true);
818 
819 		return( true );
820 	}
821 
822 	return( false );
823 }
824 
825 //---------------------------------------------------------
Save_Dictionary(const CSG_String & File)826 bool CSG_Projections::Save_Dictionary(const CSG_String &File)
827 {
828 	CSG_Table	Table;
829 
830 	return( _Set_Dictionary(Table, 0) && Table.Save(File) );
831 }
832 
833 
834 ///////////////////////////////////////////////////////////
835 //														 //
836 ///////////////////////////////////////////////////////////
837 
838 //---------------------------------------------------------
Load_DB(const CSG_String & FileName,bool bAppend)839 bool CSG_Projections::Load_DB(const CSG_String &FileName, bool bAppend)
840 {
841 	CSG_Table	Table;
842 
843 	if( SG_File_Exists(FileName) && Table.Create(FileName) )
844 	{
845 		if( !bAppend )
846 		{
847 			Destroy();
848 		}
849 
850 		Table.Set_Index(PRJ_FIELD_SRTEXT, TABLE_INDEX_Ascending);
851 
852 		for(int i=0; i<Table.Get_Count() && SG_UI_Process_Set_Progress(i, Table.Get_Count()); i++)
853 		{
854 			m_pProjections->Add_Record(Table.Get_Record_byIndex(i));
855 		}
856 
857 		return( true );
858 	}
859 
860 	return( false );
861 }
862 
863 //---------------------------------------------------------
Save_DB(const CSG_String & File)864 bool CSG_Projections::Save_DB(const CSG_String &File)
865 {
866 	return( m_pProjections->Save(File) );
867 }
868 
869 
870 ///////////////////////////////////////////////////////////
871 //														 //
872 ///////////////////////////////////////////////////////////
873 
874 //---------------------------------------------------------
Get_GCS_WGS84(void)875 const CSG_Projection & CSG_Projections::Get_GCS_WGS84(void)
876 {
877 	static CSG_Projection Projection(WKT_GCS_WGS84, PROJ4_GCS_WGS84);
878 
879 	return( Projection );
880 }
881 
882 
883 ///////////////////////////////////////////////////////////
884 //														 //
885 ///////////////////////////////////////////////////////////
886 
887 //---------------------------------------------------------
Get_Count(void) const888 int CSG_Projections::Get_Count(void) const
889 {
890 	return( m_pProjections->Get_Count() );
891 }
892 
893 //---------------------------------------------------------
Add(const CSG_Projection & Projection)894 bool CSG_Projections::Add(const CSG_Projection &Projection)
895 {
896 	return( false );
897 }
898 
899 //---------------------------------------------------------
Add(const SG_Char * WKT,const SG_Char * Proj4,const SG_Char * Authority,int Authority_ID)900 bool CSG_Projections::Add(const SG_Char *WKT, const SG_Char *Proj4, const SG_Char *Authority, int Authority_ID)
901 {
902 	CSG_Table_Record	*pProjection	= m_pProjections->Add_Record();
903 
904 	pProjection->Set_Value(PRJ_FIELD_SRID     , m_pProjections->Get_Count());
905 	pProjection->Set_Value(PRJ_FIELD_AUTH_NAME, Authority);
906 	pProjection->Set_Value(PRJ_FIELD_AUTH_SRID, Authority_ID);
907 	pProjection->Set_Value(PRJ_FIELD_SRTEXT   , WKT);
908 	pProjection->Set_Value(PRJ_FIELD_PROJ4TEXT, Proj4);
909 
910 	return( true );
911 }
912 
913 //---------------------------------------------------------
Get_Projection(int Index) const914 CSG_Projection CSG_Projections::Get_Projection(int Index)	const
915 {
916 	CSG_Projection	Projection;
917 
918 	if( Index >= 0 && Index < m_pProjections->Get_Count() )
919 	{
920 		CSG_Table_Record	*pRecord	= m_pProjections->Get_Record(Index);
921 
922 		Projection.m_Authority		= pRecord->asString(PRJ_FIELD_AUTH_NAME);
923 		Projection.m_Authority_ID	= pRecord->asInt   (PRJ_FIELD_AUTH_SRID);
924 		Projection.m_WKT			= pRecord->asString(PRJ_FIELD_SRTEXT   );
925 		Projection.m_Proj4			= pRecord->asString(PRJ_FIELD_PROJ4TEXT);
926 
927 		CSG_MetaData	m	= WKT_to_MetaData(Projection.m_WKT);
928 
929 		Projection.m_Name	= m.Get_Property("name");
930 		Projection.m_Type	= !m.Get_Name().Cmp("GEOCCS") ? SG_PROJ_TYPE_CS_Geocentric
931 							: !m.Get_Name().Cmp("GEOGCS") ? SG_PROJ_TYPE_CS_Geographic
932 							: !m.Get_Name().Cmp("PROJCS") ? SG_PROJ_TYPE_CS_Projected
933 							: SG_PROJ_TYPE_CS_Undefined;
934 
935 		SG_Set_Projection_Unit(m, Projection.m_Unit, Projection.m_Unit_Name, Projection.m_Unit_To_Meter);
936 	}
937 
938 	return( Projection );
939 }
940 
941 //---------------------------------------------------------
Get_Projection(CSG_Projection & Projection,int EPSG_ID) const942 bool CSG_Projections::Get_Projection(CSG_Projection &Projection, int EPSG_ID)	const
943 {
944 	return( Get_Projection(Projection, "", EPSG_ID) );
945 }
946 
Get_Projection(CSG_Projection & Projection,const CSG_String & Authority,int Authority_ID) const947 bool CSG_Projections::Get_Projection(CSG_Projection &Projection, const CSG_String &Authority, int Authority_ID)	const
948 {
949 	for(int i=0; i<m_pProjections->Get_Count(); i++)
950 	{
951 		CSG_Table_Record	*pProjection	= m_pProjections->Get_Record(i);
952 
953 		if( Authority_ID == pProjection->asInt(PRJ_FIELD_AUTH_SRID)
954 		&& (Authority.is_Empty() || Authority.CmpNoCase(pProjection->asString(PRJ_FIELD_AUTH_NAME)) == 0) )
955 		{
956 			Projection	= Get_Projection(i);
957 
958 			return( true );
959 		}
960 	}
961 
962 	return( false );
963 }
964 
965 
966 ///////////////////////////////////////////////////////////
967 //														 //
968 ///////////////////////////////////////////////////////////
969 
970 //---------------------------------------------------------
EPSG_to_Proj4(CSG_String & Proj4,int EPSG_Code) const971 bool CSG_Projections::EPSG_to_Proj4(CSG_String &Proj4, int EPSG_Code) const
972 {
973 	for(int i=0; i<m_pProjections->Get_Count(); i++)
974 	{
975 		if( m_pProjections->Get_Record(i)->asInt(PRJ_FIELD_AUTH_SRID) == EPSG_Code )
976 		{
977 			Proj4	= m_pProjections->Get_Record(i)->asString(PRJ_FIELD_PROJ4TEXT);
978 
979 			return( true );
980 		}
981 	}
982 
983 	Proj4.Printf("+init=epsg:%d ", EPSG_Code);
984 
985 	return( false );
986 }
987 
988 //---------------------------------------------------------
EPSG_to_WKT(CSG_String & WKT,int EPSG_Code) const989 bool CSG_Projections::EPSG_to_WKT(CSG_String &WKT, int EPSG_Code) const
990 {
991 	for(int i=0; i<m_pProjections->Get_Count(); i++)
992 	{
993 		if( m_pProjections->Get_Record(i)->asInt(PRJ_FIELD_AUTH_SRID) == EPSG_Code )
994 		{
995 			WKT		= m_pProjections->Get_Record(i)->asString(PRJ_FIELD_SRTEXT);
996 
997 			return( true );
998 		}
999 	}
1000 
1001 	return( false );
1002 }
1003 
1004 
1005 ///////////////////////////////////////////////////////////
1006 //														 //
1007 ///////////////////////////////////////////////////////////
1008 
1009 //---------------------------------------------------------
Get_Names_List(TSG_Projection_Type Type) const1010 CSG_String CSG_Projections::Get_Names_List(TSG_Projection_Type Type) const
1011 {
1012 	CSG_String	Names;
1013 
1014 	for(int i=0; i<Get_Count(); i++)
1015 	{
1016 		CSG_Table_Record	*pProjection	= m_pProjections->Get_Record(i);
1017 
1018 		CSG_String	WKT		= pProjection->asString(PRJ_FIELD_SRTEXT);
1019 		int			SRID	= pProjection->asInt   (PRJ_FIELD_SRID);
1020 
1021 		TSG_Projection_Type	iType;
1022 
1023 		iType	= !WKT.BeforeFirst('[').Cmp("PROJCS") ? SG_PROJ_TYPE_CS_Projected
1024 				: !WKT.BeforeFirst('[').Cmp("GEOGCS") ? SG_PROJ_TYPE_CS_Geographic
1025 				: !WKT.BeforeFirst('[').Cmp("GEOCCS") ? SG_PROJ_TYPE_CS_Geocentric
1026 				: SG_PROJ_TYPE_CS_Undefined;
1027 
1028 		if( Type == SG_PROJ_TYPE_CS_Undefined )
1029 		{
1030 			Names	+= CSG_String::Format("{%d}%s: %s|", SRID,
1031 				SG_Get_Projection_Type_Name(iType).c_str(),
1032 				WKT.AfterFirst('\"').BeforeFirst('\"').c_str()
1033 			);
1034 		}
1035 		else if( Type == iType )
1036 		{
1037 			Names	+= CSG_String::Format("{%d}%s|", SRID,
1038 				WKT.AfterFirst('\"').BeforeFirst('\"').c_str()
1039 			);
1040 		}
1041 	}
1042 
1043 	return( Names );
1044 }
1045 
1046 
1047 ///////////////////////////////////////////////////////////
1048 //														 //
1049 ///////////////////////////////////////////////////////////
1050 
1051 //---------------------------------------------------------
_WKT_to_MetaData(CSG_MetaData & MetaData,const CSG_String & WKT)1052 bool CSG_Projections::_WKT_to_MetaData(CSG_MetaData &MetaData, const CSG_String &WKT)
1053 {
1054 	int			i, l;
1055 	CSG_String	Key;
1056 	CSG_Strings	Content;
1057 
1058 	//-----------------------------------------------------
1059 	Content.Add("");
1060 
1061 	for(i=0, l=-1; l!=0 && i<(int)WKT.Length(); i++)
1062 	{
1063 		if( l < 0 )	// read key
1064 		{
1065 			switch( WKT[i] )
1066 			{
1067 			default :           Key += WKT[i]; break;
1068 			case ' ':	                       break;
1069 			case '[': case '(':	l    = 1;      break;
1070 			case ')': case ']':	               return( false );
1071 			}
1072 		}
1073 		else		// read content
1074 		{
1075 			bool	bAdd;
1076 
1077 			switch( WKT[i] )
1078 			{
1079 			default:				bAdd	= true;		break;
1080 			case '\"': case ' ':	bAdd	= false;	break;
1081 			case '[' : case '(':	bAdd	= ++l > 1;	break;
1082 			case ']' : case ')':	bAdd	= l-- > 1;	break;
1083 			case ',' : if( !(bAdd = l > 1) )	Content.Add("");	break;
1084 			}
1085 
1086 			if( bAdd )
1087 			{
1088 				Content[Content.Get_Count() - 1]	+= WKT[i];
1089 			}
1090 		}
1091 	}
1092 
1093 	if( Key.Length() == 0 || Content[0].Length() == 0 )
1094 	{
1095 		return( false );
1096 	}
1097 
1098 	//-----------------------------------------------------
1099 	if( !Key.Cmp("AUTHORITY" ) && Content.Get_Count() == 2 )	// AUTHORITY  ["<name>", "<code>"]
1100 	{
1101 		MetaData.Add_Property("authority_name", Content[0]);
1102 		MetaData.Add_Property("authority_code", Content[1]);
1103 
1104 		return( true );
1105 	}
1106 
1107 	CSG_MetaData	*pKey	= MetaData.Add_Child(Key);
1108 
1109 	if(	(!Key.Cmp("GEOCCS"    ) && Content.Get_Count() >= 4)  	// GEOCCS     ["<name>", <datum>, <prime meridian>, <linear unit> {,<axis>, <axis>, <axis>} {,<authority>}]
1110 	||	(!Key.Cmp("GEOGCS"    ) && Content.Get_Count() >= 4)  	// GEOGCS     ["<name>", <datum>, <prime meridian>, <angular unit> {,<twin axes>} {,<authority>}]
1111 	||	(!Key.Cmp("PROJCS"    ) && Content.Get_Count() >= 3)  	// PROJCS     ["<name>", <geographic cs>, <projection>, {<parameter>,}* <linear unit> {,<twin axes>}{,<authority>}]
1112 	||	(!Key.Cmp("DATUM"     ) && Content.Get_Count() >= 2) )	// DATUM      ["<name>", <spheroid> {,<to wgs84>} {,<authority>}]
1113 	{
1114 		pKey->Add_Property("name", Content[0]);
1115 	}
1116 
1117 	if(	(!Key.Cmp("PRIMEM"    ) && Content.Get_Count() >= 2)  	// PRIMEM     ["<name>", <longitude> {,<authority>}]
1118 	||	(!Key.Cmp("UNIT"      ) && Content.Get_Count() >= 2)  	// UNIT       ["<name>", <conversion factor> {,<authority>}]
1119 	||	(!Key.Cmp("AXIS"      ) && Content.Get_Count() >= 2)  	// AXIS       ["<name>", NORTH|SOUTH|EAST|WEST|UP|DOWN|OTHER]
1120 	||	(!Key.Cmp("PARAMETER" ) && Content.Get_Count() >= 2) )	// PARAMETER  ["<name>", <value>]
1121 	{
1122 		pKey->Add_Property("name", Content[0]);
1123 
1124 		pKey->Set_Content(Content[1]);
1125 	}
1126 
1127 	if( (!Key.Cmp("SPHEROID"  ) && Content.Get_Count() >= 3) )	// SPHEROID   ["<name>", <semi-major axis>, <inverse flattening> {,<authority>}]
1128 	{
1129 		pKey->Add_Property("name", Content[0]);
1130 		pKey->Add_Child   ("a"   , Content[1]);
1131 		pKey->Add_Child   ("rf"  , Content[2]);
1132 	}
1133 
1134 	if( (!Key.Cmp("TOWGS84"   ) && Content.Get_Count() >= 7) )	// TOWGS84    [<dx>, <dy>, <dz>, <ex>, <ey>, <ez>, <ppm>]
1135 	{
1136 		pKey->Add_Child("dx"     , Content[0]);
1137 		pKey->Add_Child("dy"     , Content[1]);
1138 		pKey->Add_Child("dz"     , Content[2]);
1139 		pKey->Add_Child("ex"     , Content[3]);
1140 		pKey->Add_Child("ey"     , Content[4]);
1141 		pKey->Add_Child("ez"     , Content[5]);
1142 		pKey->Add_Child("ppm"    , Content[6]);
1143 	}
1144 
1145 	if( (!Key.Cmp("PROJECTION") && Content.Get_Count() >= 1) )	// PROJECTION ["<name>" {,<authority>}]
1146 	{
1147 		pKey->Set_Content(Content[0]);
1148 	}
1149 
1150 	//-----------------------------------------------------
1151 	for(i=0; i<Content.Get_Count(); i++)
1152 	{
1153 		_WKT_to_MetaData(*pKey, Content[i]);
1154 	}
1155 
1156 	return( true );
1157 }
1158 
1159 //---------------------------------------------------------
WKT_to_MetaData(const CSG_String & WKT)1160 CSG_MetaData CSG_Projections::WKT_to_MetaData(const CSG_String &WKT)
1161 {
1162 	CSG_MetaData	MetaData;
1163 
1164 	_WKT_to_MetaData(MetaData, WKT);
1165 
1166 	if( MetaData.Get_Children_Count() == 1 )
1167 	{
1168 		return( *MetaData.Get_Child(0) );
1169 	}
1170 
1171 	MetaData.Destroy();
1172 
1173 	return( MetaData );
1174 }
1175 
1176 
1177 ///////////////////////////////////////////////////////////
1178 //														 //
1179 ///////////////////////////////////////////////////////////
1180 
1181 //---------------------------------------------------------
1182 // DATUM  ["<name>",
1183 //     SPHEROID["<name>", <semi-major axis>, <inverse flattening>]
1184 //    *TOWGS84 [<dx>, <dy>, <dz>, <ex>, <ey>, <ez>, <ppm>]
1185 // ]
1186 //---------------------------------------------------------
_WKT_to_Proj4_Set_Datum(CSG_String & Proj4,const CSG_MetaData & WKT) const1187 bool CSG_Projections::_WKT_to_Proj4_Set_Datum(CSG_String &Proj4, const CSG_MetaData &WKT) const
1188 {
1189 	if( WKT.Cmp_Property("name", "WGS84") )
1190 	{
1191 		Proj4	+= " +datum=WGS84";
1192 
1193 		return( true );
1194 	}
1195 
1196 	double	a, b;
1197 
1198 	if(	!WKT("SPHEROID") ||	WKT["SPHEROID"].Get_Children_Count() != 2
1199 	||	!WKT["SPHEROID"][0].Get_Content().asDouble(a) || a <= 0.
1200 	||	!WKT["SPHEROID"][1].Get_Content().asDouble(b) || b <  0. )
1201 	{
1202 		return( false );
1203 	}
1204 
1205 	b	= b > 0. ? a - a / b : a;
1206 
1207 	Proj4	+= CSG_String::Format(" +a=%f", a);	// Semimajor radius of the ellipsoid axis
1208 	Proj4	+= CSG_String::Format(" +b=%f", b);	// Semiminor radius of the ellipsoid axis
1209 
1210 	if(	WKT("TOWGS84") && WKT["TOWGS84"].Get_Children_Count() == 7 )
1211 	{
1212 		Proj4	+= " +towgs84=";
1213 
1214 		for(int i=0; i<7; i++)
1215 		{
1216 			if( i > 0 )
1217 			{
1218 				Proj4	+= ",";
1219 			}
1220 
1221 			Proj4	+= WKT["TOWGS84"][i].Get_Content();
1222 		}
1223 	}
1224 
1225 	return( true );
1226 }
1227 
1228 //---------------------------------------------------------
WKT_to_Proj4(CSG_String & Proj4,const CSG_String & WKT) const1229 bool CSG_Projections::WKT_to_Proj4(CSG_String &Proj4, const CSG_String &WKT) const
1230 {
1231 	Proj4.Clear();
1232 
1233 	CSG_MetaData	m	= WKT_to_MetaData(WKT);
1234 
1235 	if( m.Get_Children_Count() == 0 )
1236 	{
1237 		return( false );
1238 	}
1239 
1240 	//-----------------------------------------------------
1241 	int			Authority_Code;
1242 	CSG_String	Authority_Name;
1243 
1244 	if(	m.Get_Property("authority_name", Authority_Name) && Authority_Name.CmpNoCase("EPSG") == 0
1245 	&&	m.Get_Property("authority_code", Authority_Code) && EPSG_to_Proj4(Proj4, Authority_Code) )
1246 	{	//	Proj4.Printf("+init=epsg:%d", Authority_Code);
1247 		return( true );
1248 	}
1249 
1250 	//-----------------------------------------------------
1251 	double	d;
1252 
1253 	//-----------------------------------------------------
1254 	// GEOCCS["<name>",
1255 	//    DATUM  ["<name>", ...],
1256 	//    PRIMEM ["<name>", <longitude>],
1257 	//    UNIT   ["<name>", <conversion factor>],
1258 	//   *AXIS   ["<name>", NORTH|SOUTH|EAST|WEST|UP|DOWN|OTHER], AXIS...
1259 	// ]
1260 	if( m.Cmp_Name("GEOCCS") )
1261 	{
1262 		Proj4	= CSG_String::Format("+proj=geocent");
1263 
1264 		if( !m("DATUM") || !_WKT_to_Proj4_Set_Datum(Proj4, m["DATUM"]) )
1265 		{
1266 			return( false );
1267 		}
1268 
1269 		if( m("PRIMEM") && m["PRIMEM"].Get_Content().asDouble(d) && d != 0. )
1270 		{
1271 			Proj4	+= CSG_String::Format(" +pm=%f", d);
1272 		}
1273 
1274 		Proj4	+= CSG_String::Format(" +no_defs");	// Don't use the /usr/share/proj/proj_def.dat defaults file
1275 
1276 		return( true );
1277 	}
1278 
1279 	//-----------------------------------------------------
1280 	// GEOGCS["<name>,
1281 	//    DATUM  ["<name>", ...],
1282 	//    PRIMEM ["<name>", <longitude>],
1283 	//    UNIT   ["<name>", <conversion factor>],
1284 	//   *AXIS   ["<name>", NORTH|SOUTH|EAST|WEST|UP|DOWN|OTHER], AXIS...
1285 	// ]
1286 	if( m.Cmp_Name("GEOGCS") )
1287 	{
1288 		Proj4	= "+proj=longlat";
1289 
1290 		if( !m("DATUM") || !_WKT_to_Proj4_Set_Datum(Proj4, m["DATUM"]) )
1291 		{
1292 			return( false );
1293 		}
1294 
1295 		if( m("PRIMEM") && m["PRIMEM"].Get_Content().asDouble(d) && d != 0. )
1296 		{
1297 			Proj4	+= CSG_String::Format(" +pm=%f", d);
1298 		}
1299 
1300 		Proj4	+= CSG_String::Format(" +no_defs");	// Don't use the /usr/share/proj/proj_def.dat defaults file
1301 
1302 		return( true );
1303 	}
1304 
1305 	//-----------------------------------------------------
1306 	// PROJCS["<name>,
1307 	//     GEOGCS    ["<name>, ...],
1308 	//     PROJECTION["<name>"],
1309 	//    *PARAMETER ["<name>", <value>], PARAMETER...
1310 	//     UNIT      ["<name>", <conversion factor>],
1311 	//    *AXIS      ["<name>", NORTH|SOUTH|EAST|WEST|UP|DOWN|OTHER], AXIS...
1312 	// ]
1313 	if( m.Cmp_Name("PROJCS") && m("GEOGCS") && m("PROJECTION") && m_WKT_to_Proj4.Get_Translation(m["PROJECTION"].Get_Content(), Proj4) )
1314 	{
1315 		if( m["PROJECTION"].Cmp_Content("Transverse_Mercator") ) // UTM ???
1316 		{
1317 			double	Scale = -1., Easting = -1., Northing = -1., Meridian = -1., Latitude = -1.;
1318 
1319 			for(int i=0; i<m.Get_Children_Count(); i++)
1320 			{
1321 				if( m[i].Cmp_Name("PARAMETER") )
1322 				{
1323 					double	v;
1324 
1325 					if( m[i].Cmp_Property("name", "central_meridian"  , true) && m[i].Get_Content().asDouble(v) ) Meridian = v;
1326 					if( m[i].Cmp_Property("name", "latitude_of_origin", true) && m[i].Get_Content().asDouble(v) ) Latitude = v;
1327 					if( m[i].Cmp_Property("name", "scale_factor"      , true) && m[i].Get_Content().asDouble(v) ) Scale    = v;
1328 					if( m[i].Cmp_Property("name", "false_easting"     , true) && m[i].Get_Content().asDouble(v) ) Easting  = v;
1329 					if( m[i].Cmp_Property("name", "false_northing"    , true) && m[i].Get_Content().asDouble(v) ) Northing = v;
1330 				}
1331 			}
1332 
1333 			if( Latitude == 0. && Scale == 0.9996 && Easting  == 500000. && (Northing == 0. || Northing == 10000000.) )
1334 			{
1335 				Proj4	= "+proj=utm";
1336 
1337 				if(	!m["GEOGCS"]("DATUM") || !_WKT_to_Proj4_Set_Datum(Proj4, m["GEOGCS"]["DATUM"]) )
1338 				{
1339 					return( false );
1340 				}
1341 
1342 				Proj4	+= CSG_String::Format(" +zone=%d", (int)((183. + Meridian) / 6.));
1343 
1344 				if( Northing == 10000000. )
1345 				{
1346 					Proj4	+= " +south";
1347 				}
1348 
1349 				Proj4	+= CSG_String::Format(" +no_defs");	// Don't use the /usr/share/proj/proj_def.dat defaults file
1350 
1351 				return( true );
1352 			}
1353 		}
1354 
1355 		//-------------------------------------------------
1356 		Proj4	= "+proj=" + Proj4;
1357 
1358 		if(	!m["GEOGCS"]("DATUM") || !_WKT_to_Proj4_Set_Datum(Proj4, m["GEOGCS"]["DATUM"]) )
1359 		{
1360 			return( false );
1361 		}
1362 
1363 		if( m("PRIMEM") && m["PRIMEM"].Get_Content().asDouble(d) && d != 0. )
1364 		{
1365 			Proj4	+= CSG_String::Format(" +pm=%f", d);
1366 		}
1367 
1368 		for(int i=0; i<m.Get_Children_Count(); i++)
1369 		{
1370 			if( m[i].Cmp_Name("PARAMETER") )
1371 			{
1372 				CSG_String	Parameter;
1373 
1374 				if( m_WKT_to_Proj4.Get_Translation(m[i].Get_Property("name"), Parameter) )
1375 				{
1376 					Proj4	+= " +" + Parameter + "=" + m[i].Get_Content();
1377 				}
1378 				else
1379 				{
1380 					SG_UI_Msg_Add_Error(CSG_String::Format(">> WKT: %s [%s]", _TL("unknown parameter"), m[i].Get_Property("name")));
1381 				}
1382 			}
1383 		}
1384 
1385 		if( m("UNIT") && m["UNIT"].Get_Content().asDouble(d) && d != 0. && d != 1. )
1386 		{
1387 			Proj4	+= CSG_String::Format(" +to_meter=%f", d);
1388 		}
1389 
1390 		Proj4	+= CSG_String::Format(" +no_defs");	// Don't use the /usr/share/proj/proj_def.dat defaults file
1391 
1392 		return( true );
1393 	}
1394 
1395 	//-----------------------------------------------------
1396 	return( false );
1397 }
1398 
1399 
1400 ///////////////////////////////////////////////////////////
1401 //														 //
1402 ///////////////////////////////////////////////////////////
1403 
1404 //---------------------------------------------------------
_Proj4_Find_Parameter(const CSG_String & Proj4,const CSG_String & Key) const1405 bool CSG_Projections::_Proj4_Find_Parameter(const CSG_String &Proj4, const CSG_String &Key) const
1406 {
1407 	return(	Proj4.Find("+" + Key) >= 0 );
1408 }
1409 
1410 //---------------------------------------------------------
_Proj4_Read_Parameter(CSG_String & Value,const CSG_String & Proj4,const CSG_String & Key) const1411 bool CSG_Projections::_Proj4_Read_Parameter(CSG_String &Value, const CSG_String &Proj4, const CSG_String &Key) const
1412 {
1413 	Value.Clear();
1414 
1415 	int	l, i = Proj4.Find("+" + Key + "=");
1416 
1417 	if( i >= 0 )
1418 	{
1419 		for(++i, l=0; l<2 && i<(int)Proj4.Length(); i++)
1420 		{
1421 			switch( Proj4[i] )
1422 			{
1423 			case '=':	l++;	break;
1424 			case '+':	l=2;	break;
1425 			case ' ':	l=2;	break;
1426 			default:
1427 				if( l == 1 )
1428 				{
1429 					Value	+= Proj4[i];
1430 				}
1431 			}
1432 		}
1433 	}
1434 
1435 	return( Value.Length() > 0 );
1436 }
1437 
1438 //---------------------------------------------------------
1439 /* ellipsoids (a, b)
1440 	{	"MERIT"		, "6378137.0"	, "6356752.298"	},	// MERIT 1983
1441 	{	"SGS85"		, "6378136.0"	, "6356751.302"	},	// Soviet Geodetic System 85
1442 	{	"GRS80"		, "6378137.0"	, "6356752.314"	},	// GRS 1980 (IUGG, 1980)
1443 	{	"IAU76"		, "6378140.0"	, "6356755.288"	},	// IAU 1976
1444 	{	"airy"		, "6377563.396"	, "6356256.91"	},	// Airy 1830
1445 	{	"APL4.9"	, "6378137.0"	, "6356751.796"	},	// Appl. Physics. 1965
1446 	{	"NWL9D"		, "6378145.0"	, "6356759.769"	},	// Naval Weapons Lab., 1965
1447 	{	"mod_airy"	, "6377340.189"	, "6356034.446"	},	// Modified Airy
1448 	{	"andrae"	, "6377104.43"	, "6355847.415"	},	// Andrae 1876 (Den., Iclnd.)
1449 	{	"aust_SA"	, "6378160.0"	, "6356774.719"	},	// Australian Natl & S. Amer. 1969
1450 	{	"GRS67"		, "6378160.0"	, "6356774.516"	},	// GRS 67 (IUGG 1967)
1451 	{	"bessel"	, "6377397.155"	, "6356078.963"	},	// Bessel 1841
1452 	{	"bess_nam"	, "6377483.865"	, "6356165.383"	},	// Bessel 1841 (Namibia)
1453 	{	"clrk66"	, "6378206.4"	, "6356583.8"	},	// Clarke 1866
1454 	{	"clrk80"	, "6378249.145"	, "6356514.966"	},	// Clarke 1880 mod.
1455 	{	"CPM"		, "6375738.7"	, "6356666.222"	},	// Comm. des Poids et Mesures 1799
1456 	{	"delmbr"	, "6376428.0"	, "6355957.926"	},	// Delambre 1810 (Belgium)
1457 	{	"engelis"	, "6378136.05"	, "6356751.323"	},	// Engelis 1985
1458 	{	"evrst30"	, "6377276.345"	, "6356075.413"	},	// Everest 1830
1459 	{	"evrst48"	, "6377304.063"	, "6356103.039"	},	// Everest 1948
1460 	{	"evrst56"	, "6377301.243"	, "6356100.228"	},	// Everest 1956
1461 	{	"evrst69"	, "6377295.664"	, "6356094.668"	},	// Everest 1969
1462 	{	"evrstSS"	, "6377298.556"	, "6356097.55"	},	// Everest (Sabah & Sarawak)
1463 	{	"fschr60"	, "6378166.0"	, "6356784.284"	},	// Fischer (Mercury Datum) 1960
1464 	{	"fschr60m"	, "6378155.0"	, "6356773.32"	},	// Modified Fischer 1960
1465 	{	"fschr68"	, "6378150.0"	, "6356768.337"	},	// Fischer 1968
1466 	{	"helmert"	, "6378200.0"	, "6356818.17"	},	// Helmert 1906
1467 	{	"hough"		, "6378270.0"	, "6356794.343"	},	// Hough
1468 	{	"intl"		, "6378388.0"	, "6356911.946"	},	// International 1909 (Hayford)
1469 	{	"krass"		, "6378245.0"	, "6356863.019"	},	// Krassovsky, 1942
1470 	{	"kaula"		, "6378163.0"	, "6356776.992"	},	// Kaula 1961
1471 	{	"lerch"		, "6378139.0"	, "6356754.292"	},	// Lerch 1979
1472 	{	"mprts"		, "6397300.0"	, "6363806.283"	},	// Maupertius 1738
1473 	{	"new_intl"	, "6378157.5"	, "6356772.2"	},	// New International 1967
1474 	{	"plessis"	, "6376523.0"	, "6355863"		},	// Plessis 1817 (France)
1475 	{	"SEasia"	, "6378155.0"	, "6356773.321"	},	// Southeast Asia
1476 	{	"walbeck"	, "6376896.0"	, "6355834.847"	},	// Walbeck
1477 	{	"WGS60"		, "6378165.0"	, "6356783.287"	},	// WGS 60
1478 	{	"WGS66"		, "6378145.0"	, "6356759.769"	},	// WGS 66
1479 	{	"WGS72"		, "6378135.0"	, "6356750.52"	},	// WGS 72
1480 	{	"WGS84"		, "6378137.0"	, "6356752.314"	},	// WGS 84
1481 	{	"sphere"	, "6370997.0"	, "6370997.0"	}	// Normal Sphere (r=6370997)
1482 */
1483 
_Proj4_Get_Ellipsoid(CSG_String & Value,const CSG_String & Proj4) const1484 bool CSG_Projections::_Proj4_Get_Ellipsoid(CSG_String &Value, const CSG_String &Proj4) const
1485 {
1486 	const char	ellipsoid[42][2][32]	=
1487 	{	//  ellipsoid	      a				   b
1488 		{	"MERIT"		, "6378137.0,298.257"		},	// MERIT 1983
1489 		{	"SGS85"		, "6378136.0,298.257"		},	// Soviet Geodetic System 85
1490 		{	"GRS80"		, "6378137.0,298.2572221"	},	// GRS 1980 (IUGG, 1980)
1491 		{	"IAU76"		, "6378140.0,298.257"		},	// IAU 1976
1492 		{	"airy"		, "6377563.396,299.3249753"	},	// Airy 1830
1493 		{	"APL4.9"	, "6378137.0,298.25"		},	// Appl. Physics. 1965
1494 		{	"NWL9D"		, "6378145.0,298.25"		},	// Naval Weapons Lab., 1965
1495 		{	"mod_airy"	, "6377340.189,299.3249374"	},	// Modified Airy
1496 		{	"andrae"	, "6377104.43,300"			},	// Andrae 1876 (Den., Iclnd.)
1497 		{	"aust_SA"	, "6378160.0,298.25"		},	// Australian Natl & S. Amer. 1969
1498 		{	"GRS67"		, "6378160.0,298.2471674"	},	// GRS 67 (IUGG 1967)
1499 		{	"bessel"	, "6377397.155,299.1528128"	},	// Bessel 1841
1500 		{	"bess_nam"	, "6377483.865,299.1528128"	},	// Bessel 1841 (Namibia)
1501 		{	"clrk66"	, "6378206.4,294.9786982"	},	// Clarke 1866
1502 		{	"clrk80"	, "6378249.145,293.4663"	},	// Clarke 1880 mod.
1503 		{	"CPM"		, "6375738.7,334.29"		},	// Comm. des Poids et Mesures 1799
1504 		{	"delmbr"	, "6376428.0,311.5"			},	// Delambre 1810 (Belgium)
1505 		{	"engelis"	, "6378136.05,298.2566"		},	// Engelis 1985
1506 		{	"evrst30"	, "6377276.345,300.8017"	},	// Everest 1830
1507 		{	"evrst48"	, "6377304.063,300.8017"	},	// Everest 1948
1508 		{	"evrst56"	, "6377301.243,300.8017"	},	// Everest 1956
1509 		{	"evrst69"	, "6377295.664,300.8017"	},	// Everest 1969
1510 		{	"evrstSS"	, "6377298.556,300.8017"	},	// Everest (Sabah & Sarawak)
1511 		{	"fschr60"	, "6378166.0,298.3"			},	// Fischer (Mercury Datum) 1960
1512 		{	"fschr60m"	, "6378155.0,298.3"			},	// Modified Fischer 1960
1513 		{	"fschr68"	, "6378150.0,298.3"			},	// Fischer 1968
1514 		{	"helmert"	, "6378200.0,298.3"			},	// Helmert 1906
1515 		{	"hough"		, "6378270.0,297"			},	// Hough
1516 		{	"intl"		, "6378388.0,297"			},	// International 1909 (Hayford)
1517 		{	"krass"		, "6378245.0,298.3"			},	// Krassovsky, 1942
1518 		{	"kaula"		, "6378163.0,298.24"		},	// Kaula 1961
1519 		{	"lerch"		, "6378139.0,298.257"		},	// Lerch 1979
1520 		{	"mprts"		, "6397300.0,191"			},	// Maupertius 1738
1521 		{	"new_intl"	, "6378157.5,298.2496154"	},	// New International 1967
1522 		{	"plessis"	, "6376523.0,308.6409971"	},	// Plessis 1817 (France)
1523 		{	"SEasia"	, "6378155.0,298.3000002"	},	// Southeast Asia
1524 		{	"walbeck"	, "6376896.0,302.7800002"	},	// Walbeck
1525 		{	"WGS60"		, "6378165.0,298.3"			},	// WGS 60
1526 		{	"WGS66"		, "6378145.0,298.25"		},	// WGS 66
1527 		{	"WGS72"		, "6378135.0,298.26"		},	// WGS 72
1528 		{	"WGS84"		, "6378137.0,298.2572236"	},	// WGS 84
1529 		{	"sphere"	, "6370997.0,-1"			}	// Normal Sphere (r=6370997)
1530 	};
1531 
1532 	//-----------------------------------------------------
1533 	if( _Proj4_Read_Parameter(Value, Proj4, "ellps") )
1534 	{
1535 		for(int i=0; i<42; i++)
1536 		{
1537 			if( !Value.CmpNoCase(ellipsoid[i][0]) )
1538 			{
1539 				Value.Printf("SPHEROID[\"%s\",%s]", SG_STR_MBTOSG(ellipsoid[i][0]), SG_STR_MBTOSG(ellipsoid[i][1]));
1540 
1541 				return( true );
1542 			}
1543 		}
1544 	}
1545 
1546 	//-----------------------------------------------------
1547 	double	a, b;
1548 
1549 	a	= _Proj4_Read_Parameter(Value, Proj4, "a" ) && Value.asDouble(a) ? a : 6378137.;
1550 
1551 	b	= _Proj4_Read_Parameter(Value, Proj4, "b" ) && Value.asDouble(b) ? a / (a - b)
1552 		: _Proj4_Read_Parameter(Value, Proj4, "rf") && Value.asDouble(b) ? b
1553 		: _Proj4_Read_Parameter(Value, Proj4, "f" ) && Value.asDouble(b) ? 1. / b
1554 		: _Proj4_Read_Parameter(Value, Proj4, "e" ) && Value.asDouble(b) ? a / (a - sqrt(b*b - a*a))
1555 		: _Proj4_Read_Parameter(Value, Proj4, "es") && Value.asDouble(b) ? a / (a - sqrt( b  - a*a))
1556 		: 298.2572236;
1557 
1558 	Value	= CSG_String::Format("SPHEROID[\"Ellipsoid\",%f,%f]", a, b);
1559 
1560 	return( true );
1561 }
1562 
1563 //---------------------------------------------------------
_Proj4_Get_Datum(CSG_String & Value,const CSG_String & Proj4) const1564 bool CSG_Projections::_Proj4_Get_Datum(CSG_String &Value, const CSG_String &Proj4) const
1565 {
1566 	const char	datum[9][3][64]	=
1567 	{	//	datum_id		  ellipse		  definition
1568 		{	"WGS84"			, "WGS84"		, "0,0,0,0,0,0,0"											},
1569 		{	"GGRS87"		, "GRS80"		, "-199.87,74.79,246.62,0,0,0,0"							},	// Greek_Geodetic_Reference_System_1987
1570 		{	"NAD83"			, "GRS80"		, "0,0,0,0,0,0,0"											},	// North_American_Datum_1983
1571 	//	{	"NAD27"			, "clrk66"		, "nadgrids=@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat"		},	// North_American_Datum_1927
1572 		{	"potsdam"		, "bessel"		, "606.0,23.0,413.0,0,0,0,0"								},	// Potsdam Rauenberg 1950 DHDN
1573 		{	"carthage"		, "clark80"		, "-263.0,6.0,431.0,0,0,0,0"								},	// Carthage 1934 Tunisia
1574 		{	"hermannskogel"	, "bessel"		, "653.0,-212.0,449.0,0,0,0,0"								},	// Hermannskogel
1575 		{	"ire65"			, "mod_airy"	, "482.530,-130.596,564.557,-1.042,-0.214,-0.631,8.15"		},	// Ireland 1965
1576 		{	"nzgd49"		, "intl"		, "59.47,-5.04,187.44,0.47,-0.1,1.024,-4.5993"				},	// New Zealand Geodetic Datum 1949
1577 		{	"OSGB36"		, "airy"		, "446.448,-125.157,542.060,0.1502,0.2470,0.8421,-20.4894"	}	// Airy 1830
1578 	};
1579 
1580 	CSG_String	Spheroid, ToWGS84;
1581 
1582 	//-----------------------------------------------------
1583 	if( _Proj4_Read_Parameter(Value, Proj4, "datum") )
1584 	{
1585 		for(int i=0; i<9; i++)
1586 		{
1587 			if( !Value.CmpNoCase(datum[i][0]) && _Proj4_Get_Ellipsoid(Spheroid, CSG_String::Format("+ellps=%s", SG_STR_MBTOSG(datum[i][1]))) )
1588 			{
1589 				Value.Printf("DATUM[\"%s\",%s,TOWGS84[%s]]", SG_STR_MBTOSG(datum[i][0]), Spheroid.c_str(), SG_STR_MBTOSG(datum[i][2]));
1590 
1591 				return( true );
1592 			}
1593 		}
1594 	}
1595 
1596 	//-----------------------------------------------------
1597 	if( _Proj4_Get_Ellipsoid(Spheroid, Proj4) )
1598 	{
1599 		Value	 = "DATUM[\"Datum\","+ Spheroid;
1600 
1601 		if( _Proj4_Read_Parameter(ToWGS84, Proj4, "towgs84") )
1602 		{
1603 			Value	+= ",TOWGS84[" + ToWGS84 + "]";
1604 		}
1605 		else
1606 		{
1607 			Value	+= ",TOWGS84[0,0,0,0,0,0,0]";
1608 		}
1609 
1610 		Value	+= "]";
1611 
1612 		return( true );
1613 	}
1614 
1615 	//-----------------------------------------------------
1616 	Value	= "DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563],TOWGS84[0,0,0,0,0,0,0]]";
1617 
1618 	return( false );
1619 }
1620 
1621 //---------------------------------------------------------
_Proj4_Get_Prime_Meridian(CSG_String & Value,const CSG_String & Proj4) const1622 bool CSG_Projections::_Proj4_Get_Prime_Meridian(CSG_String &Value, const CSG_String &Proj4) const
1623 {
1624 	const char	meridian[12][2][16]	=
1625 	{
1626 		{	"lisbon"	, "-9.131906111"	},
1627 		{	"paris"		, "2.337229167"		},
1628 		{	"bogota"	, "74.08091667"		},
1629 		{	"madrid"	, "-3.687911111"	},
1630 		{	"rome"		, "12.45233333"		},
1631 		{	"bern"		, "7.439583333"		},
1632 		{	"jakarta"	, "106.8077194"		},
1633 		{	"ferro"		, "-17.66666667"	},
1634 		{	"brussels"	, "4.367975"		},
1635 		{	"stockholm"	, "18.05827778"		},
1636 		{	"athens"	, "23.7163375"		},
1637 		{	"oslo"		, "10.72291667"		}
1638 	};
1639 
1640 	//-----------------------------------------------------
1641 	if( _Proj4_Read_Parameter(Value, Proj4, "pm") )
1642 	{
1643 		for(int i=0; i<12; i++)
1644 		{
1645 			if( !Value.CmpNoCase(meridian[i][0]) )
1646 			{
1647 				Value.Printf("PRIMEM[\"%s\",%s]", SG_STR_MBTOSG(meridian[i][0]), SG_STR_MBTOSG(meridian[i][1]));
1648 
1649 				return( true );
1650 			}
1651 		}
1652 
1653 		double	d;
1654 
1655 		if( Value.asDouble(d) && d != 0. )
1656 		{
1657 			Value.Printf("PRIMEM[\"Prime_Meridian\",%f]", d);
1658 
1659 			return( true );
1660 		}
1661 	}
1662 
1663 	//-----------------------------------------------------
1664 	Value	= "PRIMEM[\"Greenwich\",0]";
1665 
1666 	return( false );
1667 }
1668 
1669 //---------------------------------------------------------
_Proj4_Get_Unit(CSG_String & Value,const CSG_String & Proj4) const1670 bool CSG_Projections::_Proj4_Get_Unit(CSG_String &Value, const CSG_String &Proj4) const
1671 {
1672 	//-----------------------------------------------------
1673 	TSG_Projection_Unit	Unit	= _Proj4_Read_Parameter(Value, Proj4, "units") ? SG_Get_Projection_Unit(Value) : SG_PROJ_UNIT_Undefined;
1674 
1675 	if( Unit != SG_PROJ_UNIT_Undefined )
1676 	{
1677 		Value	= "UNIT[\"" + SG_Get_Projection_Unit_Name(Unit) + "\"," + SG_Get_String(SG_Get_Projection_Unit_To_Meter(Unit), -16) + "]";
1678 
1679 		return( true );
1680 	}
1681 
1682 	//-----------------------------------------------------
1683 	double	 d;
1684 
1685 	if( _Proj4_Read_Parameter(Value, Proj4, "to_meter") && Value.asDouble(d) && d > 0. && d != 1. )
1686 	{
1687 		Value.Printf("UNIT[\"Unit\",%f]", d);
1688 
1689 		return( true );
1690 	}
1691 
1692 	//-----------------------------------------------------
1693 	Value	= "UNIT[\"metre\",1]";
1694 
1695 	return( false );
1696 }
1697 
1698 //---------------------------------------------------------
WKT_from_Proj4(CSG_String & WKT,const CSG_String & Proj4) const1699 bool CSG_Projections::WKT_from_Proj4(CSG_String &WKT, const CSG_String &Proj4) const
1700 {
1701 	CSG_String	Value, GeogCS, ProjCS;
1702 
1703 	//-----------------------------------------------------
1704 	if( !_Proj4_Read_Parameter(ProjCS, Proj4, "proj") )
1705 	{
1706 		SG_UI_Msg_Add_Error(CSG_String::Format("Proj4 >> WKT: %s", _TL("no projection type defined")));
1707 
1708 		return( false );
1709 	}
1710 
1711 	//-----------------------------------------------------
1712 	// GEOGCS["<name>
1713 	//    DATUM  ["<name>
1714 	//        SPHEROID["<name>", <semi-major axis>, <inverse flattening>],
1715 	//       *TOWGS84 [<dx>, <dy>, <dz>, <ex>, <ey>, <ez>, <ppm>]
1716 	//    ],
1717 	//    PRIMEM ["<name>", <longitude>],
1718 	//    UNIT   ["<name>", <conversion factor>],
1719 	//   *AXIS   ["<name>", NORTH|SOUTH|EAST|WEST|UP|DOWN|OTHER],
1720 	//   *AXIS   ["<name>", NORTH|SOUTH|EAST|WEST|UP|DOWN|OTHER]
1721 	// ]
1722 
1723 	GeogCS	 = "GEOGCS[\"GCS\",";
1724 
1725 	_Proj4_Get_Datum			(Value, Proj4);	GeogCS	+= Value;	GeogCS	+= ",";
1726 	_Proj4_Get_Prime_Meridian	(Value, Proj4);	GeogCS	+= Value;	GeogCS	+= ",";
1727 
1728 	GeogCS	+= "UNIT[\"degree\",0.01745329251994328]]";
1729 
1730 	//-----------------------------------------------------
1731 	if(	!ProjCS.CmpNoCase("lonlat") || !ProjCS.CmpNoCase("longlat")
1732 	||	!ProjCS.CmpNoCase("latlon") || !ProjCS.CmpNoCase("latlong") )
1733 	{
1734 		WKT	= GeogCS;
1735 
1736 		return( true );
1737 	}
1738 
1739 	//-----------------------------------------------------
1740 	// PROJCS["<name>
1741 	//     GEOGCS    [ ...... ],
1742 	//     PROJECTION["<name>"],
1743 	//    *PARAMETER ["<name>", <value>], ...
1744 	//     UNIT      ["<name>", <conversion factor>],
1745 	//    *AXIS      ["<name>", NORTH|SOUTH|EAST|WEST|UP|DOWN|OTHER],
1746 	//    *AXIS      ["<name>", NORTH|SOUTH|EAST|WEST|UP|DOWN|OTHER]
1747 	// ]
1748 
1749 	if( !m_Proj4_to_WKT.Get_Translation(ProjCS, Value) )
1750 	{
1751 		SG_UI_Msg_Add_Error(CSG_String::Format("Proj4 >> WKT: %s [%s]", _TL("no translation available"), ProjCS.c_str()));
1752 
1753 		return( false );
1754 	}
1755 
1756 	//-----------------------------------------------------
1757 	// UTM ...
1758 
1759 	if( !ProjCS.CmpNoCase("utm") )
1760 	{
1761 		double	Zone;
1762 
1763 		if( !_Proj4_Read_Parameter(Value, Proj4, "zone") || !Value.asDouble(Zone) )
1764 		{
1765 			SG_UI_Msg_Add_Error(CSG_String::Format("Proj4 >> WKT: %s", _TL("invalid utm zone")));
1766 
1767 			return( false );
1768 		}
1769 
1770 		bool South	= _Proj4_Find_Parameter(Proj4, "south");
1771 
1772 		WKT		 = CSG_String::Format("PROJCS[\"UTM zone %d%c\",%s,PROJECTION[Transverse_Mercator]", (int)Zone, South ? 'S' : 'N', GeogCS.c_str());
1773 
1774 		WKT		+= CSG_String::Format(",PARAMETER[\"%s\",%d]", SG_T("latitude_of_origin"), 0);
1775 		WKT		+= CSG_String::Format(",PARAMETER[\"%s\",%d]", SG_T("central_meridian"  ), (int)(Zone * 6 - 183));
1776 		WKT		+= CSG_String::Format(",PARAMETER[\"%s\",%f]", SG_T("scale_factor"      ), 0.9996);
1777 		WKT		+= CSG_String::Format(",PARAMETER[\"%s\",%d]", SG_T("false_easting"     ), 500000);
1778 		WKT		+= CSG_String::Format(",PARAMETER[\"%s\",%d]", SG_T("false_northing"    ), South ? 10000000 : 0);
1779 		WKT		+= ",UNIT[\"metre\",1]]";
1780 
1781 		return( true );
1782 	}
1783 
1784 	//-----------------------------------------------------
1785 	// Parameters ...
1786 
1787 	WKT		 = CSG_String::Format("PROJCS[\"%s\",%s,PROJECTION[%s]", Value.c_str(), GeogCS.c_str(), Value.c_str());
1788 
1789 	ProjCS	= Proj4;
1790 
1791 	while( ProjCS.Find('+') >= 0 )
1792 	{
1793 		CSG_String	Key;
1794 
1795 		ProjCS	= ProjCS.AfterFirst ('+');
1796 		Value	= ProjCS.BeforeFirst('=');
1797 
1798 		if( m_Proj4_to_WKT.Get_Translation(Value, Key) )
1799 		{
1800 			Value	= ProjCS.AfterFirst('=');
1801 
1802 			if( Value.Find('+') >= 0 )
1803 			{
1804 				Value	= Value.BeforeFirst('+');
1805 			}
1806 
1807 			WKT	+= ",PARAMETER[\"" + Key + "\"," + Value + "]";
1808 		}
1809 	}
1810 
1811 	//-----------------------------------------------------
1812 	// Unit ...
1813 
1814 	_Proj4_Get_Unit(Value, Proj4);
1815 
1816 	WKT	+= "," + Value + "]";
1817 
1818 	//-----------------------------------------------------
1819 	return( true );
1820 }
1821 
1822 
1823 ///////////////////////////////////////////////////////////
1824 //														 //
1825 //														 //
1826 //														 //
1827 ///////////////////////////////////////////////////////////
1828 
1829 //---------------------------------------------------------
_Set_Dictionary(CSG_Table & Dictionary,int Direction)1830 bool CSG_Projections::_Set_Dictionary(CSG_Table &Dictionary, int Direction)
1831 {
1832 	const int	n	= 209;
1833 	const char	Translation[n][4][128]	= {
1834 		//	 PROJ4		  DIR	WKT										   DESCRIPTION
1835 
1836 		// Projection Types, *) = not verified
1837 		{	"aea"		, " ", "Albers_Conic_Equal_Area"				, "Albers Equal Area"	},
1838 		{	"aea"		, "<", "Albers"									, "[ESRI] Albers Equal Area"	},
1839 		{	"aeqd"		, " ", "Azimuthal_Equidistant"					, "Azimuthal Equidistant"	},
1840 		{	"airy"		, " ", "Airy"									, "*) Airy"	},
1841 		{	"aitoff"	, " ", "Aitoff"									, "[ESRI] Aitoff"	},
1842 		{	"alsk"		, " ", "Mod_Stererographics_of_Alaska"			, "*) Mod. Stererographics of Alaska"	},
1843 		{	"apian"		, " ", "Apian_Globular_I"						, "*) Apian Globular I"	},
1844 		{	"august"	, " ", "August_Epicycloidal"					, "*) August Epicycloidal"	},
1845 		{	"bacon"		, " ", "Bacon_Globular"							, "*) Bacon Globular"	},
1846 		{	"bipc"		, " ", "Bipolar_conic_of_western_hemisphere"	, "*) Bipolar conic of western hemisphere"	},
1847 		{	"boggs"		, " ", "Boggs_Eumorphic"						, "*) Boggs Eumorphic"	},
1848 		{	"bonne"		, " ", "Bonne"									, "Bonne (Werner lat_1=90)"	},
1849 		{	"cass"		, " ", "Cassini_Soldner"						, "Cassini"	},
1850 		{	"cass"		, "<", "Cassini"								, "[ESRI] Cassini"	},
1851 		{	"cc"		, " ", "Central_Cylindrical"					, "*) Central Cylindrical"	},
1852 		{	"cea"		, " ", "Cylindrical_Equal_Area"					, "Equal Area Cylindrical, alias: Lambert Cyl.Eq.A., Normal Authalic Cyl. (FME), Behrmann (SP=30), Gall Orthogr. (SP=45)"	},
1853 		{	"cea"		, "<", "Behrmann"								, "[ESRI] Behrmann (standard parallel = 30)"	},
1854 		{	"chamb"		, " ", "Chamberlin_Trimetric"					, "*) Chamberlin Trimetric"	},
1855 		{	"collg"		, " ", "Collignon"								, "*) Collignon"	},
1856 		{	"crast"		, " ", "Craster_Parabolic"						, "[ESRI] Craster Parabolic (Putnins P4)"	},
1857 		{	"denoy"		, " ", "Denoyer_Semi_Elliptical"				, "*) Denoyer Semi-Elliptical"	},
1858 		{	"eck1"		, " ", "Eckert_I"								, "*) Eckert I"	},
1859 		{	"eck2"		, " ", "Eckert_II"								, "*) Eckert II"	},
1860 		{	"eck3"		, " ", "Eckert_III"								, "*) Eckert III"	},
1861 		{	"eck4"		, " ", "Eckert_IV"								, "Eckert IV"	},
1862 		{	"eck5"		, " ", "Eckert_V"								, "*) Eckert V"	},
1863 		{	"eck6"		, " ", "Eckert_VI"								, "Eckert VI"	},
1864 		{	"eqc"		, " ", "Equirectangular"						, "Equidistant Cylindrical (Plate Caree)"	},
1865 		{	"eqc"		, "<", "Equidistant_Cylindrical"				, "[ESRI] Equidistant Cylindrical (Plate Caree)"	},
1866 		{	"eqc"		, "<", "Plate_Carree"							, "[ESRI] Equidistant Cylindrical (Plate Caree)"	},
1867 		{	"eqdc"		, " ", "Equidistant_Conic"						, "*) Equidistant Conic"	},
1868 		{	"euler"		, " ", "Euler"									, "*) Euler"	},
1869 		{	"etmerc"	, " ", "Extended_Transverse_Mercator"			, "*) Extended Transverse Mercator"	},
1870 		{	"fahey"		, " ", "Fahey"									, "*) Fahey"	},
1871 		{	"fouc"		, " ", "Foucault"								, "*) Foucaut"	},
1872 		{	"fouc_s"	, " ", "Foucault_Sinusoidal"					, "*) Foucaut Sinusoidal"	},
1873 		{	"gall"		, " ", "Gall_Stereographic"						, "Gall (Gall Stereographic)"	},
1874 		{	"geocent"	, " ", "Geocentric"								, "*) Geocentric"	},
1875 		{	"geos"		, " ", "GEOS"									, "Geostationary Satellite View"	},
1876 		{	"gins8"		, " ", "Ginsburg_VIII"							, "*) Ginsburg VIII (TsNIIGAiK)"	},
1877 		{	"gn_sinu"	, " ", "General_Sinusoidal_Series"				, "*) General Sinusoidal Series"	},
1878 		{	"gnom"		, " ", "Gnomonic"								, "Gnomonic"	},
1879 		{	"goode"		, " ", "Goode_Homolosine"						, "*) Goode Homolosine"	},
1880 		{	"gs48"		, " ", "Mod_Stererographics_48"					, "*) Mod. Stererographics of 48 U.S."	},
1881 		{	"gs50"		, " ", "Mod_Stererographics_50"					, "*) Mod. Stererographics of 50 U.S."	},
1882 		{	"hammer"	, " ", "Hammer_Eckert_Greifendorff"				, "*) Hammer & Eckert-Greifendorff"	},
1883 		{	"hatano"	, " ", "Hatano_Asymmetrical_Equal_Area"			, "*) Hatano Asymmetrical Equal Area"	},
1884 		{	"igh"		, " ", "World_Goode_Homolosine_Land"			, "*) Interrupted Goode Homolosine"	},
1885 		{	"imw_p"		, " ", "International_Map_of_the_World_Polyconic", "*) International Map of the World Polyconic"	},
1886 		{	"kav5"		, " ", "Kavraisky_V"							, "*) Kavraisky V"	},
1887 		{	"kav7"		, " ", "Kavraisky_VII"							, "*) Kavraisky VII"	},
1888 		{	"krovak"	, " ", "Krovak"									, "Krovak"	},
1889 		{	"labrd"		, " ", "Laborde_Oblique_Mercator"				, "*) Laborde"	},
1890 		{	"laea"		, " ", "Lambert_Azimuthal_Equal_Area"			, "Lambert Azimuthal Equal Area"	},
1891 		{	"lagrng"	, " ", "Lagrange"								, "*) Lagrange"	},
1892 		{	"larr"		, " ", "Larrivee"								, "*) Larrivee"	},
1893 		{	"lask"		, " ", "Laskowski"								, "*) Laskowski"	},
1894 		{	"lcc"		, "<", "Lambert_Conformal_Conic_1SP"			, "Lambert Conformal Conic (1 standard parallel)"	},
1895 		{	"lcc"		, "<", "Lambert_Conformal_Conic_2SP"			, "Lambert Conformal Conic (2 standard parallels)"	},
1896 		{	"lcc"		, " ", "Lambert_Conformal_Conic"				, "Lambert Conformal Conic"	},
1897 		{	"lcca"		, " ", "Lambert_Conformal_Conic_Alternative"	, "*) Lambert Conformal Conic Alternative"	},
1898 		{	"leac"		, " ", "Lambert_Equal_Area_Conic"				, "*) Lambert Equal Area Conic"	},
1899 		{	"lee_os"	, " ", "Lee_Oblated_Stereographic"				, "*) Lee Oblated Stereographic"	},
1900 		{	"loxim"		, " ", "Loximuthal"								, "[ESRI] Loximuthal"	},
1901 		{	"lsat"		, " ", "Space_oblique_for_LANDSAT"				, "*) Space oblique for LANDSAT"	},
1902 		{	"mbt_s"		, " ", "McBryde_Thomas_Flat_Polar_Sine"			, "*) McBryde-Thomas Flat-Polar Sine"	},
1903 		{	"mbt_fps"	, " ", "McBryde_Thomas_Flat_Polar_Sine_2"		, "*) McBryde-Thomas Flat-Pole Sine (No. 2)"	},
1904 		{	"mbtfpp"	, " ", "McBryde_Thomas_Flat_Polar_Parabolic"	, "*) McBride-Thomas Flat-Polar Parabolic"	},
1905 		{	"mbtfpq"	, " ", "Flat_Polar_Quartic"						, "[ESRI] McBryde-Thomas Flat-Polar Quartic"	},
1906 		{	"mbtfps"	, " ", "McBryde_Thomas_Flat_Polar_Sinusoidal"	, "*) McBryde-Thomas Flat-Polar Sinusoidal"	},
1907 		{	"merc"		, " ", "Mercator"								, "[ESRI] Mercator"	},
1908 		{	"merc"		, "<", "Mercator_1SP"							, "Mercator (1 standard parallel)"	},
1909 		{	"merc"		, "<", "Mercator_2SP"							, "Mercator (2 standard parallels)"	},
1910 		{	"mil_os"	, " ", "Miller_Oblated_Stereographic"			, "*) Miller Oblated Stereographic"	},
1911 		{	"mill"		, " ", "Miller_Cylindrical"						, "Miller Cylindrical"	},
1912 		{	"moll"		, " ", "Mollweide"								, "Mollweide"	},
1913 		{	"murd1"		, " ", "Murdoch_I"								, "*) Murdoch I"	},
1914 		{	"murd2"		, " ", "Murdoch_II"								, "*) Murdoch II"	},
1915 		{	"murd3"		, " ", "Murdoch_III"							, "*) Murdoch III"	},
1916 		{	"nell"		, " ", "Nell"									, "*) Nell"	},
1917 		{	"nell_h"	, " ", "Nell_Hammer"							, "*) Nell-Hammer"	},
1918 		{	"nicol"		, " ", "Nicolosi_Globular"						, "*) Nicolosi Globular"	},
1919 		{	"nsper"		, " ", "Near_sided_perspective"					, "*) Near-sided perspective"	},
1920 		{	"nzmg"		, " ", "New_Zealand_Map_Grid"					, "New Zealand Map Grid"	},
1921 		{	"ob_tran"	, " ", "General_Oblique_Transformation"			, "*) General Oblique Transformation"	},
1922 		{	"ocea"		, " ", "Oblique_Cylindrical_Equal_Area"			, "*) Oblique Cylindrical Equal Area"	},
1923 		{	"oea"		, " ", "Oblated_Equal_Area"						, "*) Oblated Equal Area"	},
1924 		{	"omerc"		, " ", "Hotine_Oblique_Mercator"				, "Oblique Mercator"	},
1925 		{	"omerc"		, "<", "Oblique_Mercator"						, "Oblique Mercator"	},
1926 		{	"ortel"		, " ", "Ortelius_Oval"							, "*) Ortelius Oval"	},
1927 		{	"ortho"		, " ", "Orthographic"							, "Orthographic (ESRI: World from Space)"	},
1928 		{	"pconic"	, " ", "Perspective_Conic"						, "*) Perspective Conic"	},
1929 		{	"poly"		, " ", "Polyconic"								, "*) Polyconic (American)"	},
1930 		{	"putp1"		, " ", "Putnins_P1"								, "*) Putnins P1"	},
1931 		{	"putp2"		, " ", "Putnins_P2"								, "*) Putnins P2"	},
1932 		{	"putp3"		, " ", "Putnins_P3"								, "*) Putnins P3"	},
1933 		{	"putp3p"	, " ", "Putnins_P3'"							, "*) Putnins P3'"	},
1934 		{	"putp4p"	, " ", "Putnins_P4'"							, "*) Putnins P4'"	},
1935 		{	"putp5"		, " ", "Putnins_P5"								, "*) Putnins P5"	},
1936 		{	"putp5p"	, " ", "Putnins_P5'"							, "*) Putnins P5'"	},
1937 		{	"putp6"		, " ", "Putnins_P6"								, "*) Putnins P6"	},
1938 		{	"putp6p"	, " ", "Putnins_P6'"							, "*) Putnins P6'"	},
1939 		{	"qua_aut"	, " ", "Quartic_Authalic"						, "[ESRI] Quartic Authalic"	},
1940 		{	"robin"		, " ", "Robinson"								, "Robinson"	},
1941 		{	"rouss"		, " ", "Roussilhe_Stereographic"				, "*) Roussilhe Stereographic"	},
1942 		{	"rpoly"		, " ", "Rectangular_Polyconic"					, "*) Rectangular Polyconic"	},
1943 		{	"sinu"		, " ", "Sinusoidal"								, "Sinusoidal (Sanson-Flamsteed)"	},
1944 		{	"somerc"	, " ", "Hotine_Oblique_Mercator"				, "Swiss Oblique Mercator"	},
1945 		{	"somerc"	, "<", "Swiss_Oblique_Cylindrical"				, "Swiss Oblique Cylindrical"	},
1946 		{	"somerc"	, "<", "Hotine_Oblique_Mercator_Azimuth_Center"	, "[ESRI] Swiss Oblique Mercator/Cylindrical"	},
1947 		{	"stere"		, "<", "Polar_Stereographic"					, "Stereographic"	},
1948 		{	"stere"		, " ", "Stereographic"							, "[ESRI] Stereographic"	},
1949 		{	"sterea"	, " ", "Oblique_Stereographic"					, "Oblique Stereographic Alternative"	},
1950 		{	"gstmerc"	, " ", "Gauss_Schreiber_Transverse_Mercator"	, "*) Gauss-Schreiber Transverse Mercator (aka Gauss-Laborde Reunion)"	},
1951 		{	"tcc"		, " ", "Transverse_Central_Cylindrical"			, "*) Transverse Central Cylindrical"	},
1952 		{	"tcea"		, " ", "Transverse_Cylindrical_Equal_Area"		, "*) Transverse Cylindrical Equal Area"	},
1953 		{	"tissot"	, " ", "Tissot_Conic"							, "*) Tissot Conic"	},
1954 		{	"tmerc"		, " ", "Transverse_Mercator"					, "*) Transverse Mercator"	},
1955 		{	"tmerc"		, "<", "Gauss_Kruger"							, "[ESRI] DHDN"	},
1956 		{	"tpeqd"		, " ", "Two_Point_Equidistant"					, "*) Two Point Equidistant"	},
1957 		{	"tpers"		, " ", "Tilted_perspective"						, "*) Tilted perspective"	},
1958 		{	"ups"		, " ", "Universal_Polar_Stereographic"			, "*) Universal Polar Stereographic"	},
1959 		{	"urm5"		, " ", "Urmaev_V"								, "*) Urmaev V"	},
1960 		{	"urmfps"	, " ", "Urmaev_Flat_Polar_Sinusoidal"			, "*) Urmaev Flat-Polar Sinusoidal"	},
1961 		{	"utm"		, ">", "Transverse_Mercator"					, "*) Universal Transverse Mercator (UTM)"	},
1962 		{	"vandg"		, "<", "Van_Der_Grinten_I"						, "[ESRI] van der Grinten (I)"	},
1963 		{	"vandg"		, " ", "VanDerGrinten"							, "van der Grinten (I)"	},
1964 		{	"vandg2"	, " ", "VanDerGrinten_II"						, "*) van der Grinten II"	},
1965 		{	"vandg3"	, " ", "VanDerGrinten_III"						, "*) van der Grinten III"	},
1966 		{	"vandg4"	, " ", "VanDerGrinten_IV"						, "*) van der Grinten IV"	},
1967 		{	"vitk1"		, " ", "Vitkovsky_I"							, "*) Vitkovsky I"	},
1968 		{	"wag1"		, " ", "Wagner_I"								, "*) Wagner I (Kavraisky VI)"	},
1969 		{	"wag2"		, " ", "Wagner_II"								, "*) Wagner II"	},
1970 		{	"wag3"		, " ", "Wagner_III"								, "*) Wagner III"	},
1971 		{	"wag4"		, " ", "Wagner_IV"								, "*) Wagner IV"	},
1972 		{	"wag5"		, " ", "Wagner_V"								, "*) Wagner V"	},
1973 		{	"wag6"		, " ", "Wagner_VI"								, "*) Wagner VI"	},
1974 		{	"wag7"		, " ", "Wagner_VII"								, "*) Wagner VII"	},
1975 		{	"weren"		, " ", "Werenskiold_I"							, "*) Werenskiold I"	},
1976 		{	"wink1"		, " ", "Winkel_I"								, "[ESRI] Winkel I"	},
1977 		{	"wink2"		, " ", "Winkel_II"								, "[ESRI] Winkel II"	},
1978 		{	"wintri"	, " ", "Winkel_Tripel"							, "[ESRI] Winkel Tripel"	},
1979 
1980 		// Core Projection Types and Parameters that don't require explicit translation"	},
1981 	//	{	"lonlat"	, " ", "GEOGCS"									, "Lat/long (Geodetic)"	},
1982 	//	{	"latlon"	, ">", "GEOGCS"									, "Lat/long (Geodetic alias)"	},
1983 	//	{	"latlong"	, ">", "GEOGCS"									, "Lat/long (Geodetic alias)"	},
1984 	//	{	"longlat"	, ">", "GEOGCS"									, "Lat/long (Geodetic alias)"	},
1985 
1986 	//	{	"a"			, " ", ""										, "Semimajor radius of the ellipsoid axis"	},
1987 	//	{	"axis"		, " ", ""										, "Axis orientation (new in 4.8.0)"	},
1988 	//	{	"b			, " ", ""										, "Semiminor radius of the ellipsoid axis"	},
1989 	//	{	"datum		, " ", ""										, "Datum name (see `proj -ld`)"	},
1990 	//	{	"ellps		, " ", ""										, "Ellipsoid name (see `proj -le`)"	},
1991 	//	{	"nadgrids	, " ", ""										, "Filename of NTv2 grid file to use for datum transforms (see below)"	},
1992 	//	{	"no_defs	, " ", ""										, "Don't use the /usr/share/proj/proj_def.dat defaults file"	},
1993 	//	{	"pm			, " ", ""										, "Alternate prime meridian (typically a city name, see below)"	},
1994 	//	{	"proj		, " ", ""										, "Projection name (see `proj -l`)"	},
1995 	//	{	"to_meter	, " ", ""										, "Multiplier to convert map units to 1.0m"	},
1996 	//	{	"towgs84	, " ", ""										, "3 or 7 term datum transform parameters (see below)"	},
1997 	//	{	"units		, " ", ""										, "meters, US survey feet, etc."	},
1998 
1999 	//	{	"south		, " ", ""										, "Denotes southern hemisphere UTM zone"	},
2000 	//	{	"zone		, " ", ""										, "UTM zone"	},
2001 
2002 	//	{	"lon_wrap"	, " ", ""										, "Center longitude to use for wrapping (see below)"	},
2003 	//	{	"over"		, " ", ""										, "Allow longitude output outside -180 to 180 range, disables wrapping (see below)"	},
2004 
2005 		// General Projection Parameters"	},
2006 		{	"alpha"		, " ", "azimuth"								, "? Used with Oblique Mercator and possibly a few others"	},
2007 		{	"k"			, ">", "scale_factor"							, "Scaling factor (old name)"	},
2008 		{	"K"			, ">", "scale_factor"							, "? Scaling factor (old name)"	},
2009 		{	"k_0"		, " ", "scale_factor"							, "Scaling factor (new name)"	},
2010 		{	"lat_0"		, " ", "latitude_of_origin"						, "Latitude of origin"	},
2011 		{	"lat_0"		, "<", "latitude_of_center"						, "Latitude of center"	},
2012 		{	"lat_0"		, "<", "central_parallel"						, "[ESRI] Latitude of center"	},
2013 		{	"lat_1"		, " ", "standard_parallel_1"					, "Latitude of first standard parallel"	},
2014 		{	"lat_2"		, " ", "standard_parallel_2"					, "Latitude of second standard parallel"	},
2015 		{	"lat_ts"	, ">", "latitude_of_origin"						, "Latitude of true scale"	},
2016 		{	"lon_0"		, " ", "central_meridian"						, "Central meridian"	},
2017 		{	"lon_0"		, "<", "longitude_of_center"					, "Longitude of center"	},
2018 		{	"lonc"		, " ", "longitude_of_center"					, "? Longitude used with Oblique Mercator and possibly a few others"	},
2019 		{	"x_0"		, " ", "false_easting"							, "False easting"	},
2020 		{	"y_0"		, " ", "false_northing"							, "False northing"	},
2021 
2022 		// Additional Projection Parameters"	},
2023 		{	"azi"		, " ", ""										, ""	},
2024 		{	"belgium"	, " ", ""										, ""	},
2025 		{	"beta"		, " ", ""										, ""	},
2026 		{	"czech"		, " ", ""										, ""	},
2027 		{	"gamma"		, " ", ""										, ""	},
2028 		{	"geoc"		, " ", ""										, ""	},
2029 		{	"guam"		, " ", ""										, ""	},
2030 		{	"h"			, " ", "satellite_height"						, "Satellite height (geos - Geostationary Satellite View)"	},
2031 		{	"lat_b"		, " ", ""										, ""	},
2032 		{	"lat_t"		, " ", ""										, ""	},
2033 		{	"lon_1"		, " ", ""										, ""	},
2034 		{	"lon_2"		, " ", ""										, ""	},
2035 		{	"lsat"		, " ", ""										, ""	},
2036 		{	"m"			, " ", ""										, ""	},
2037 		{	"M"			, " ", ""										, ""	},
2038 		{	"n"			, " ", ""										, ""	},
2039 		{	"no_cut"	, " ", ""										, ""	},
2040 		{	"no_off"	, " ", ""										, ""	},
2041 		{	"no_rot"	, " ", ""										, ""	},
2042 		{	"ns"		, " ", ""										, ""	},
2043 		{	"o_alpha"	, " ", ""										, ""	},
2044 		{	"o_lat_1"	, " ", ""										, ""	},
2045 		{	"o_lat_2"	, " ", ""										, ""	},
2046 		{	"o_lat_c"	, " ", ""										, ""	},
2047 		{	"o_lat_p"	, " ", ""										, ""	},
2048 		{	"o_lon_1"	, " ", ""										, ""	},
2049 		{	"o_lon_2"	, " ", ""										, ""	},
2050 		{	"o_lon_c"	, " ", ""										, ""	},
2051 		{	"o_lon_p"	, " ", ""										, ""	},
2052 		{	"o_proj"	, " ", ""										, ""	},
2053 		{	"over"		, " ", ""										, ""	},
2054 		{	"p"			, " ", ""										, ""	},
2055 		{	"path"		, " ", ""										, ""	},
2056 		{	"q"			, " ", ""										, ""	},
2057 		{	"R"			, " ", ""										, ""	},
2058 		{	"R_a"		, " ", ""										, ""	},
2059 		{	"R_A"		, " ", ""										, ""	},
2060 		{	"R_g"		, " ", ""										, ""	},
2061 		{	"R_h"		, " ", ""										, ""	},
2062 		{	"R_lat_a"	, " ", ""										, ""	},
2063 		{	"R_lat_g"	, " ", ""										, ""	},
2064 		{	"rot"		, " ", ""										, ""	},
2065 		{	"R_V"		, " ", ""										, ""	},
2066 		{	"s"			, " ", ""										, ""	},
2067 		{	"sym"		, " ", ""										, ""	},
2068 		{	"t"			, " ", ""										, ""	},
2069 		{	"theta"		, " ", ""										, ""	},
2070 		{	"tilt"		, " ", ""										, ""	},
2071 		{	"vopt"		, " ", ""										, ""	},
2072 		{	"W"			, " ", ""										, ""	},
2073 		{	"westo"		, " ", ""										, ""	},
2074 
2075 		{	""			, " ", ""										, ""	}	// dummy
2076 	};
2077 
2078 	//-----------------------------------------------------
2079 	Dictionary.Destroy();
2080 	Dictionary.Set_Name("Proj.4-WKT Dictionary");
2081 
2082 	if( Direction == 0 )
2083 	{
2084 		Dictionary.Add_Field("PROJ4", SG_DATATYPE_String);
2085 		Dictionary.Add_Field("DIR"  , SG_DATATYPE_String);
2086 		Dictionary.Add_Field("WKT"  , SG_DATATYPE_String);
2087 		Dictionary.Add_Field("DESC" , SG_DATATYPE_String);
2088 
2089 		for(int i=0; i<n; i++)
2090 		{
2091 			CSG_Table_Record	*pRecord	= Dictionary.Add_Record();
2092 
2093 			pRecord->Set_Value(0, Translation[i][0]);
2094 			pRecord->Set_Value(1, Translation[i][1]);
2095 			pRecord->Set_Value(2, Translation[i][2]);
2096 			pRecord->Set_Value(3, Translation[i][3]);
2097 		}
2098 	}
2099 	else if( Direction > 0 )	// Proj4 to WKT
2100 	{
2101 		Dictionary.Add_Field("PROJ4", SG_DATATYPE_String);
2102 		Dictionary.Add_Field("WKT"  , SG_DATATYPE_String);
2103 
2104 		for(int i=0; i<n; i++)
2105 		{
2106 			if( Translation[i][1][0] != '<' )	// only WKT to Proj4
2107 			{
2108 				CSG_Table_Record	*pRecord	= Dictionary.Add_Record();
2109 
2110 				pRecord->Set_Value(0, Translation[i][0]);
2111 				pRecord->Set_Value(1, Translation[i][2]);
2112 			}
2113 		}
2114 	}
2115 	else if( Direction < 0 )	// WKT to Proj4
2116 	{
2117 		Dictionary.Add_Field("WKT"  , SG_DATATYPE_String);
2118 		Dictionary.Add_Field("PROJ4", SG_DATATYPE_String);
2119 
2120 		for(int i=0; i<n; i++)
2121 		{
2122 			if( Translation[i][1][0] != '>' )	// only Proj4 to WKT
2123 			{
2124 				CSG_Table_Record	*pRecord	= Dictionary.Add_Record();
2125 
2126 				pRecord->Set_Value(0, Translation[i][2]);
2127 				pRecord->Set_Value(1, Translation[i][0]);
2128 			}
2129 		}
2130 	}
2131 
2132 	return( Dictionary.Get_Count() > 0 );
2133 }
2134 
2135 //---------------------------------------------------------
_Set_Dictionary(CSG_Translator & Dictionary,int Direction)2136 bool CSG_Projections::_Set_Dictionary(CSG_Translator &Dictionary, int Direction)
2137 {
2138 	CSG_Table	Table;
2139 
2140 	return( _Set_Dictionary(Table, Direction) && Dictionary.Create(&Table, 0, 1, true) );
2141 }
2142 
2143 
2144 ///////////////////////////////////////////////////////////
2145 //														 //
2146 //														 //
2147 //														 //
2148 ///////////////////////////////////////////////////////////
2149 
2150 //---------------------------------------------------------
2151 #include "shapes.h"
2152 #include "tool_library.h"
2153 
2154 //---------------------------------------------------------
SG_Get_Projected(CSG_Shapes * pSource,CSG_Shapes * pTarget,const CSG_Projection & Target)2155 bool	SG_Get_Projected	(CSG_Shapes *pSource, CSG_Shapes *pTarget, const CSG_Projection &Target)
2156 {
2157 	if( !pSource || !pSource->is_Valid() )
2158 	{
2159 		return( false );
2160 	}
2161 
2162 	if( pSource->Get_Projection() == Target )
2163 	{
2164 		return( pTarget ? pTarget->Create(*pSource) : true );
2165 	}
2166 
2167 	if( !pSource->Get_Projection().is_Okay() || !Target.is_Okay() )
2168 	{
2169 		return( false );
2170 	}
2171 
2172 	CSG_Tool	*pTool	= SG_Get_Tool_Library_Manager().Create_Tool("pj_proj4", 2);	// Coordinate Transformation (Shapes)
2173 
2174 	SG_UI_ProgressAndMsg_Lock(true);
2175 
2176 	bool	bResult	= pTool && pTool->Set_Manager(NULL);
2177 
2178 	if( bResult )
2179 	{
2180 		pTool->Set_Parameter("CRS_PROJ4", Target.Get_Proj4());
2181 		pTool->Set_Parameter("SOURCE"   , pSource);
2182 		pTool->Set_Parameter("TARGET"   , pTarget);
2183 		pTool->Set_Parameter("COPY"     , pTarget ? true : false);
2184 		pTool->Set_Parameter("PARALLEL" , true);
2185 
2186 		bResult	= pTool->Execute();
2187 	}
2188 
2189 	SG_UI_ProgressAndMsg_Lock(false);
2190 
2191 	SG_Get_Tool_Library_Manager().Delete_Tool(pTool);
2192 
2193 	return( bResult );
2194 }
2195 
2196 //---------------------------------------------------------
SG_Get_Projected(const CSG_Projection & Source,const CSG_Projection & Target,TSG_Point & Point)2197 bool	SG_Get_Projected	(const CSG_Projection &Source, const CSG_Projection &Target, TSG_Point &Point)
2198 {
2199 	if( Source == Target )
2200 	{
2201 		return( true );
2202 	}
2203 
2204 	if( Source.is_Okay() && Target.is_Okay() )
2205 	{
2206 		CSG_Tool	*pTool	= SG_Get_Tool_Library_Manager().Create_Tool("pj_proj4", 29);	// Single Coordinate Transformation
2207 
2208 		SG_UI_ProgressAndMsg_Lock(true);
2209 
2210 		bool	bResult	= pTool && pTool->Set_Manager(NULL)
2211 		&&  pTool->Set_Parameter("TARGET_CRS", Target.Get_Proj4())
2212 		&&	pTool->Set_Parameter("SOURCE_CRS", Source.Get_Proj4())
2213 		&&  pTool->Set_Parameter("SOURCE_X"  , Point.x)
2214 		&&  pTool->Set_Parameter("SOURCE_Y"  , Point.y)
2215 		&&  pTool->Execute();
2216 
2217 		if( bResult )
2218 		{
2219 			Point.x	= pTool->Get_Parameter("TARGET_X")->asDouble();
2220 			Point.y	= pTool->Get_Parameter("TARGET_Y")->asDouble();
2221 		}
2222 
2223 		SG_UI_ProgressAndMsg_Lock(false);
2224 
2225 		SG_Get_Tool_Library_Manager().Delete_Tool(pTool);
2226 
2227 		return( bResult );
2228 	}
2229 
2230 	return( false );
2231 }
2232 
2233 //---------------------------------------------------------
SG_Get_Projected(const CSG_Projection & Source,const CSG_Projection & Target,TSG_Rect & Rectangle)2234 bool	SG_Get_Projected	(const CSG_Projection &Source, const CSG_Projection &Target, TSG_Rect &Rectangle)
2235 {
2236 	if( Source == Target )
2237 	{
2238 		return( true );
2239 	}
2240 
2241 	if( Source.is_Okay() && Target.is_Okay() )
2242 	{
2243 		CSG_Shapes	Points[2];
2244 
2245 		Points[0].Create(SHAPE_TYPE_Point);
2246 		Points[0].Get_Projection().Create(Source);
2247 		Points[0].Add_Shape()->Add_Point(Rectangle.xMin, Rectangle.yMin);
2248 		Points[0].Add_Shape()->Add_Point(Rectangle.xMin, Rectangle.yMax);
2249 		Points[0].Add_Shape()->Add_Point(Rectangle.xMax, Rectangle.yMax);
2250 		Points[0].Add_Shape()->Add_Point(Rectangle.xMax, Rectangle.yMin);
2251 
2252 		if( SG_Get_Projected(&Points[0], &Points[1], Target) )
2253 		{
2254 			Rectangle	= Points[1].Get_Extent();
2255 
2256 			return( true );
2257 		}
2258 	}
2259 
2260 	return( false );
2261 }
2262 
2263 
2264 ///////////////////////////////////////////////////////////
2265 //														 //
2266 //														 //
2267 //														 //
2268 ///////////////////////////////////////////////////////////
2269 
2270 //---------------------------------------------------------
SG_Grid_Get_Geographic_Coordinates(CSG_Grid * pGrid,CSG_Grid * pLon,CSG_Grid * pLat)2271 bool	SG_Grid_Get_Geographic_Coordinates	(CSG_Grid *pGrid, CSG_Grid *pLon, CSG_Grid *pLat)
2272 {
2273 	bool	bResult	= false;
2274 
2275 	if( pGrid && pGrid->is_Valid() && pGrid->Get_Projection().is_Okay() && (pLon || pLat) )
2276 	{
2277 		CSG_Grid Lon; if( !pLon ) { pLon = &Lon; } pLon->Create(pGrid->Get_System());
2278 		CSG_Grid Lat; if( !pLat ) { pLat = &Lat; } pLat->Create(pGrid->Get_System());
2279 
2280 		SG_RUN_TOOL(bResult, "pj_proj4", 17,	// geographic coordinate grids
2281 				SG_TOOL_PARAMETER_SET("GRID", pGrid)
2282 			&&	SG_TOOL_PARAMETER_SET("LON" , pLon )
2283 			&&	SG_TOOL_PARAMETER_SET("LAT" , pLat )
2284 		)
2285 	}
2286 
2287 	return( bResult );
2288 }
2289 
2290 
2291 ///////////////////////////////////////////////////////////
2292 //														 //
2293 //														 //
2294 //														 //
2295 ///////////////////////////////////////////////////////////
2296 
2297 //---------------------------------------------------------
2298