31
31
#include "cpl_port.h"
32
32
#include "cpl_string.h"
34
#include "geo_normalize.h"
35
34
#include "geovalues.h"
36
#include "ogr_spatialref.h"
39
#define nCitationNameTypes 9
44
CitProjectionName = 2,
53
char* ImagineCitationTranslation(const char* psCitation, geokey_t keyID);
54
char** CitationStringParse(const char* psCitation);
55
void SetLinearUnitCitation(GTIF* psGTIF, char* pszLinearUOMName);
56
void SetGeogCSCitation(GTIF * psGTIF, OGRSpatialReference *poSRS, char* angUnitName, int nDatum, short nSpheroid);
57
OGRBoolean SetCitationToSRS(GTIF* hGTIF, char* szCTString, int nCTStringLen,
58
geokey_t geoKey, OGRSpatialReference* poSRS, OGRBoolean* linearUnitIsSet);
59
void GetGeogCSFromCitation(char* szGCSName, int nGCSName,
64
char **ppszSpheroidName,
65
char **ppszAngularUnits);
35
#include "gt_citation.h"
37
CPL_CVSID("$Id: gt_citation.cpp 21848 2011-02-25 16:41:38Z warmerdam $")
39
static const char *apszUnitMap[] = {
43
"centimeters", "0.01",
46
"millimeters", "0.001",
47
"millimeter", "0.001",
49
"kilometers", "1000.0",
50
"kilometer", "1000.0",
52
"us_survey_feet", "0.3048006096012192",
53
"us_survey_foot", "0.3048006096012192",
54
"feet", "0.3048006096012192",
55
"foot", "0.3048006096012192",
56
"ft", "0.3048006096012192",
57
"international_feet", "0.3048",
58
"international_foot", "0.3048",
59
"inches", "0.0254000508001",
60
"inch", "0.0254000508001",
61
"in", "0.0254000508001",
68
"modified_american_feet", "0.3048122530",
69
"modified_american_foot", "0.3048122530",
70
"clarke_feet", "0.3047972651",
71
"clarke_foot", "0.3047972651",
72
"indian_feet", "0.3047995142",
73
"indian_foot", "0.3047995142",
74
"Yard_Indian", "0.9143985307444408",
75
"Foot_Clarke", "0.304797265",
76
"Foot_Gold_Coast", "0.3047997101815088",
77
"Link_Clarke", "0.2011661949",
78
"Yard_Sears", "0.9143984146160287",
79
"50_Kilometers", "50000.0",
80
"150_Kilometers", "150000.0",
67
84
/************************************************************************/
68
85
/* ImagineCitationTranslation() */
70
87
/* Translate ERDAS Imagine GeoTif citation */
71
88
/************************************************************************/
72
char* ImagineCitationTranslation(const char* psCitation, geokey_t keyID)
89
char* ImagineCitationTranslation(char* psCitation, geokey_t keyID)
77
if(EQUALN(psCitation, "IMAGINE GeoTIFF Support", strlen("IMAGINE GeoTIFF Support")))
91
static const char *keyNames[] = {
92
"NAD = ", "Datum = ", "Ellipsoid = ", "Units = ", NULL
81
// this is a handle IMAGING style citation
83
p = strchr(psCitation, '$');
88
const char* p1 = NULL;
95
case PCSCitationGeoKey:
96
osName = "PCS Name = ";
98
case GTCitationGeoKey:
99
osName = "CS Name = ";
101
case GeogCitationGeoKey:
102
if(!strstr(p, "Unable to"))
103
osName = "GCS Name = ";
110
osName.append(p, p1-p);
114
p = strstr(psCitation, "Projection Name = ");
117
p += strlen("Projection Name = ");
118
p1 = strchr(p, '\n');
120
p1 = strchr(p, '\0');
124
osName.append(p, p1-p);
127
p = strstr(psCitation, "Datum = ");
130
p += strlen("Datum = ");
131
p1 = strchr(p, '\n');
133
p1 = strchr(p, '\0');
137
osName += "Datum = ";
138
osName.append(p, p1-p);
141
p = strstr(psCitation, "Ellipsoid = ");
144
p += strlen("Ellipsoid = ");
145
p1 = strchr(p, '\n');
147
p1 = strchr(p, '\0');
151
osName += "Ellipsoid = ";
152
osName.append(p, p1-p);
155
p = strstr(psCitation, "Units = ");
158
p += strlen("Units = ");
159
p1 = strchr(p, '\n');
161
p1 = strchr(p, '\0');
165
osName += "LUnits = ";
166
osName.append(p, p1-p);
169
if(strlen(osName) > 0)
171
ret = CPLStrdup(osName);
99
if(EQUALN(psCitation, "IMAGINE GeoTIFF Support", strlen("IMAGINE GeoTIFF Support")))
101
// this is a handle IMAGING style citation
107
p = strchr(psCitation, '$');
108
if( p && strchr(p, '\n') )
109
p = strchr(p, '\n') + 1;
113
char *p2 = strchr(p, '\n');
116
p2 = strchr(p, '\0');
119
for(i=0; keyNames[i]!=NULL; i++)
121
p2 = strstr(p, keyNames[i]);
127
// PCS name, GCS name and PRJ name
132
case PCSCitationGeoKey:
133
if(strstr(psCitation, "Projection = "))
134
strcpy(name, "PRJ Name = ");
136
strcpy(name, "PCS Name = ");
138
case GTCitationGeoKey:
139
strcpy(name, "PCS Name = ");
141
case GeogCitationGeoKey:
142
if(!strstr(p, "Unable to"))
143
strcpy(name, "GCS Name = ");
151
if((p2 = strstr(psCitation, "Projection Name = ")) != 0)
152
p = p2 + strlen("Projection Name = ");
153
if((p2 = strstr(psCitation, "Projection = ")) != 0)
154
p = p2 + strlen("Projection = ");
155
if(p1[0] == '\0' || p1[0] == '\n' || p1[0] == ' ')
158
while( p2>0 && (p2[0] == ' ' || p2[0] == '\0' || p2[0] == '\n') )
164
strncat(name, p, p1-p+1);
166
name[strlen(name)] = '\0';
171
// All other parameters
172
for(i=0; keyNames[i]!=NULL; i++)
174
p = strstr(psCitation, keyNames[i]);
177
p += strlen(keyNames[i]);
179
char *p2 = strchr(p, '\n');
182
p2 = strchr(p, '\0');
185
for(int j=0; keyNames[j]!=NULL; j++)
187
p2 = strstr(p, keyNames[j]);
194
if(EQUAL(keyNames[i], "Units = "))
195
strcat(name, "LUnits = ");
197
strcat(name, keyNames[i]);
198
if(p1[0] == '\0' || p1[0] == '\n' || p1[0] == ' ')
201
while( p2>0 && (p2[0] == ' ' || p2[0] == '\0' || p2[0] == '\n') )
207
strncat(name, p, p1-p+1);
209
name[strlen(name)] = '\0';
214
ret = CPLStrdup(name);
177
220
/************************************************************************/
180
223
/* Parse a Citation string */
181
224
/************************************************************************/
182
char** CitationStringParse(const char* psCitation)
226
char** CitationStringParse(char* psCitation, geokey_t keyID)
188
ret = (char **) CPLCalloc(sizeof(char*), nCitationNameTypes);
189
const char* pDelimit = NULL;
190
const char* pStr = psCitation;
192
int nCitationLen = strlen(psCitation);
193
OGRBoolean nameFound = FALSE;
194
while((pStr-psCitation+1)< nCitationLen)
196
if( (pDelimit = strstr(pStr, "|")) )
199
osName.append(pStr, pDelimit-pStr);
205
pStr += strlen(pStr);
207
const char* name = osName.c_str();
208
if( strstr(name, "PCS Name = ") )
210
if (!ret[CitPcsName])
211
ret[CitPcsName] = CPLStrdup(name+strlen("PCS Name = "));
214
if(strstr(name, "Projection Name = "))
216
if (!ret[CitProjectionName])
217
ret[CitProjectionName] = CPLStrdup(name+strlen("Projection Name = "));
220
if(strstr(name, "LUnits = "))
222
if (!ret[CitLUnitsName])
223
ret[CitLUnitsName] = CPLStrdup(name+strlen("LUnits = "));
226
if(strstr(name, "GCS Name = "))
228
if (!ret[CitGcsName])
229
ret[CitGcsName] = CPLStrdup(name+strlen("GCS Name = "));
232
if(strstr(name, "Datum = "))
234
if (!ret[CitDatumName])
235
ret[CitDatumName] = CPLStrdup(name+strlen("Datum = "));
238
if(strstr(name, "Ellipsoid = "))
240
if (!ret[CitEllipsoidName])
241
ret[CitEllipsoidName] = CPLStrdup(name+strlen("Ellipsoid = "));
244
if(strstr(name, "Primem = "))
246
if (!ret[CitPrimemName])
247
ret[CitPrimemName] = CPLStrdup(name+strlen("Primem = "));
250
if(strstr(name, "AUnits = "))
252
if (!ret[CitAUnitsName])
253
ret[CitAUnitsName] = CPLStrdup(name+strlen("AUnits = "));
232
ret = (char **) CPLCalloc(sizeof(char*), nCitationNameTypes);
233
char* pDelimit = NULL;
234
char* pStr = psCitation;
236
int nameLen = strlen(psCitation);
237
OGRBoolean nameFound = FALSE;
238
while((pStr-psCitation+1)< nameLen)
240
if( (pDelimit = strstr(pStr, "|")) != NULL )
242
strncpy( name, pStr, pDelimit-pStr );
243
name[pDelimit-pStr] = '\0';
249
pStr += strlen(pStr);
251
if( strstr(name, "PCS Name = ") )
253
ret[CitPcsName] = CPLStrdup(name+strlen("PCS Name = "));
256
if(strstr(name, "PRJ Name = "))
258
ret[CitProjectionName] = CPLStrdup(name+strlen("PRJ Name = "));
261
if(strstr(name, "LUnits = "))
263
ret[CitLUnitsName] = CPLStrdup(name+strlen("LUnits = "));
266
if(strstr(name, "GCS Name = "))
268
ret[CitGcsName] = CPLStrdup(name+strlen("GCS Name = "));
271
if(strstr(name, "Datum = "))
273
ret[CitDatumName] = CPLStrdup(name+strlen("Datum = "));
276
if(strstr(name, "Ellipsoid = "))
278
ret[CitEllipsoidName] = CPLStrdup(name+strlen("Ellipsoid = "));
281
if(strstr(name, "Primem = "))
283
ret[CitPrimemName] = CPLStrdup(name+strlen("Primem = "));
286
if(strstr(name, "AUnits = "))
288
ret[CitAUnitsName] = CPLStrdup(name+strlen("AUnits = "));
292
if( !nameFound && keyID == GeogCitationGeoKey )
294
ret[CitGcsName] = CPLStrdup(name);
265
306
/************************************************************************/
266
307
/* SetLinearUnitCitation() */
379
420
OGRBoolean SetCitationToSRS(GTIF* hGTIF, char* szCTString, int nCTStringLen,
380
421
geokey_t geoKey, OGRSpatialReference* poSRS, OGRBoolean* linearUnitIsSet)
382
OGRBoolean ret = FALSE;
423
OGRBoolean ret = FALSE;
424
char* lUnitName = NULL;
425
if(!lUnitName || strlen(lUnitName) == 0 || EQUAL(lUnitName, "unknown"))
383
426
*linearUnitIsSet = FALSE;
384
char* imgCTName = ImagineCitationTranslation(szCTString, geoKey);
387
strncpy(szCTString, imgCTName, nCTStringLen);
388
szCTString[nCTStringLen-1] = '\0';
389
CPLFree( imgCTName );
391
char** ctNames = CitationStringParse(szCTString);
394
if( poSRS->GetRoot() == NULL)
395
poSRS->SetNode( "PROJCS", "unnamed" );
396
if(ctNames[CitPcsName])
398
poSRS->SetNode( "PROJCS", ctNames[CitPcsName] );
401
else if(geoKey != GTCitationGeoKey)
404
if( GTIFKeyGet( hGTIF, GTCitationGeoKey, szPCSName, 0, sizeof(szPCSName) ) )
406
poSRS->SetNode( "PROJCS", szPCSName );
411
if(ctNames[CitProjectionName])
412
poSRS->SetProjection( ctNames[CitProjectionName] );
414
if(ctNames[CitLUnitsName])
417
if (GTIFKeyGet(hGTIF, ProjLinearUnitSizeGeoKey, &unitSize, 0,
420
poSRS->SetLinearUnits( ctNames[CitLUnitsName], unitSize);
421
*linearUnitIsSet = TRUE;
424
for(int i= 0; i<nCitationNameTypes; i++)
425
CPLFree( ctNames[i] );
428
*linearUnitIsSet = TRUE;
430
char* imgCTName = ImagineCitationTranslation(szCTString, geoKey);
433
strncpy(szCTString, imgCTName, nCTStringLen);
434
szCTString[nCTStringLen-1] = '\0';
435
CPLFree( imgCTName );
437
char** ctNames = CitationStringParse(szCTString, geoKey);
440
if( poSRS->GetRoot() == NULL)
441
poSRS->SetNode( "PROJCS", "unnamed" );
442
if(ctNames[CitPcsName])
444
poSRS->SetNode( "PROJCS", ctNames[CitPcsName] );
447
if(ctNames[CitProjectionName])
448
poSRS->SetProjection( ctNames[CitProjectionName] );
450
if(ctNames[CitLUnitsName])
452
double unitSize = 0.0;
453
int size = strlen(ctNames[CitLUnitsName]);
454
if(strchr(ctNames[CitLUnitsName], '\0'))
456
for( int i = 0; apszUnitMap[i] != NULL; i += 2 )
458
if( EQUALN(apszUnitMap[i], ctNames[CitLUnitsName], size) )
460
unitSize = atof(apszUnitMap[i+1]);
464
if( unitSize == 0.0 )
465
GTIFKeyGet(hGTIF, ProjLinearUnitSizeGeoKey, &unitSize, 0,
467
poSRS->SetLinearUnits( ctNames[CitLUnitsName], unitSize);
468
*linearUnitIsSet = TRUE;
470
for(int i= 0; i<nCitationNameTypes; i++)
471
CPLFree( ctNames[i] );
475
/* if no "PCS Name = " (from Erdas) in GTCitationGeoKey */
476
if(geoKey == GTCitationGeoKey)
478
if(strlen(szCTString) > 0 && !strstr(szCTString, "PCS Name = "))
480
const char* pszProjCS = poSRS->GetAttrValue( "PROJCS" );
481
if((!(pszProjCS && strlen(pszProjCS) > 0) && !strstr(szCTString, "Projected Coordinates"))
482
|| strstr(pszProjCS, "unnamed"))
483
poSRS->SetNode( "PROJCS", szCTString );
431
492
/************************************************************************/
541
/************************************************************************/
542
/* CheckCitationKeyForStatePlaneUTM() */
544
/* Handle state plane and UTM in citation key */
545
/************************************************************************/
546
OGRBoolean CheckCitationKeyForStatePlaneUTM(GTIF* hGTIF, GTIFDefn* psDefn, OGRSpatialReference* poSRS, OGRBoolean* pLinearUnitIsSet)
548
if( !hGTIF || !psDefn || !poSRS )
550
char szCTString[512];
551
szCTString[0] = '\0';
557
OGRBoolean hasUnits = FALSE;
558
if( GTIFKeyGet( hGTIF, GTCitationGeoKey, szCTString, 0, sizeof(szCTString) ) )
560
if( strstr(szCTString, "us") && strstr(szCTString, "survey")
561
&& (strstr(szCTString, "feet") || strstr(szCTString, "foot")))
562
strcpy(units, "us_survey_feet");
563
else if(strstr(szCTString, "feet") || strstr(szCTString, "foot"))
564
strcpy(units, "international_feet");
565
else if(strstr(szCTString, "meter"))
566
strcpy(units, "meters");
568
if (strlen(units) > 0)
571
if( strstr( szCTString, "Projection Name = ") && strstr( szCTString, "_StatePlane_"))
573
const char *pStr = strstr( szCTString, "Projection Name = ") + strlen("Projection Name = ");
574
const char* pReturn = strchr( pStr, '\n');
576
strncpy(CSName, pStr, pReturn-pStr);
577
CSName[pReturn-pStr] = '\0';
578
#if GDAL_VERSION_NUM >=1900
579
if( poSRS->ImportFromESRIStatePlaneWKT(0, NULL, NULL, 32767, CSName) == OGRERR_NONE )
581
// for some erdas citation keys, the state plane CS name is incomplete, the unit check is necessary.
582
OGRBoolean done = FALSE;
585
OGR_SRSNode *poUnit = poSRS->GetAttrNode( "PROJCS|UNIT" );
587
if( poUnit != NULL && poUnit->GetChildCount() >= 2 )
589
const char* unitName = poUnit->GetChild(0)->GetValue();
590
if (strstr(units, "us_survey_feet"))
592
if (strstr(unitName, "us_survey_feet") || strstr(unitName, "Foot_US") || strstr(unitName, "foot_US"))
595
else if (strstr(units, "international_feet"))
597
if (strstr(unitName, "international_feet") || strstr(unitName, "Foot") || strstr(unitName, "foot"))
600
else if (strstr(units, "meters"))
602
if (strstr(unitName, "meter") || strstr(unitName, "Meter"))
615
char *pszUnitsName = NULL;
616
GTIFGetUOMLengthInfo( psDefn->UOMLength, &pszUnitsName, NULL );
617
if( pszUnitsName && strlen(pszUnitsName) > 0 )
619
strcpy( szCTString, pszUnitsName );
620
GTIFFreeMemory( pszUnitsName );
621
if( strstr(szCTString, "us") && strstr(szCTString, "survey")
622
&& (strstr(szCTString, "feet") || strstr(szCTString, "foot")))
623
strcpy(units, "us_survey_feet");
624
else if(strstr(szCTString, "feet") || strstr(szCTString, "foot"))
625
strcpy(units, "international_feet");
626
else if(strstr(szCTString, "meter"))
627
strcpy(units, "meters");
632
if (strlen(units) == 0)
633
strcpy(units, "meters");
635
/* check PCSCitationGeoKey if it exists */
636
szCTString[0] = '\0';
637
if( hGTIF && GTIFKeyGet( hGTIF, PCSCitationGeoKey, szCTString, 0, sizeof(szCTString)) )
639
/* For tif created by LEICA(ERDAS), ESRI state plane pe string was used and */
640
/* the state plane zone is given in PCSCitation. Therefore try Esri pe string first. */
641
SetCitationToSRS(hGTIF, szCTString, strlen(szCTString), PCSCitationGeoKey, poSRS, pLinearUnitIsSet);
642
const char *pcsName = poSRS->GetAttrValue("PROJCS");
643
const char *pStr = NULL;
644
if( (pcsName && (pStr = strstr(pcsName, "State Plane Zone ")) != NULL)
645
|| (pStr = strstr(szCTString, "State Plane Zone ")) != NULL )
647
pStr += strlen("State Plane Zone ");
648
int statePlaneZone = abs(atoi(pStr));
651
if( strstr(szCTString, "NAD83") || strstr(szCTString, "NAD = 83") )
652
strcpy(nad, "NAD83");
653
else if( strstr(szCTString, "NAD27") || strstr(szCTString, "NAD = 27") )
654
strcpy(nad, "NAD27");
655
#if GDAL_VERSION_NUM >=1900
656
if( poSRS->ImportFromESRIStatePlaneWKT(statePlaneZone, (const char*)nad, (const char*)units, psDefn->PCS) == OGRERR_NONE )
660
else if( pcsName && (pStr = strstr(pcsName, "UTM Zone ")) != NULL )
661
CheckUTM( psDefn, szCTString );
664
/* check state plane again to see if a pe string is available */
665
if( psDefn->PCS != KvUserDefined )
667
#if GDAL_VERSION_NUM >=1900
668
if( poSRS->ImportFromESRIStatePlaneWKT(0, NULL, (const char*)units, psDefn->PCS) == OGRERR_NONE )
675
/************************************************************************/
678
/* Check utm proj code by its name. */
679
/************************************************************************/
680
void CheckUTM( GTIFDefn * psDefn, char * pszCtString )
682
if(!psDefn || !pszCtString)
685
static const char *apszUtmProjCode[] = {
686
"PSAD56", "17N", "16017",
687
"PSAD56", "18N", "16018",
688
"PSAD56", "19N", "16019",
689
"PSAD56", "20N", "16020",
690
"PSAD56", "21N", "16021",
691
"PSAD56", "17S", "16117",
692
"PSAD56", "18S", "16118",
693
"PSAD56", "19S", "16119",
694
"PSAD56", "20S", "16120",
695
"PSAD56", "21S", "16121",
696
"PSAD56", "22S", "16122",
699
char* p = strstr(pszCtString, "Datum = ");
703
p += strlen("Datum = ");
704
char* p1 = strchr(p, '|');
707
strncpy(datumName, p, (p1-p));
708
datumName[p1-p] = '\0';
711
strcpy(datumName, p);
715
p = strstr(pszCtString, "UTM Zone ");
718
p += strlen("UTM Zone ");
719
char* p1 = strchr(p, '|');
722
strncpy(utmName, p, (p1-p));
723
utmName[p1-p] = '\0';
729
for(int i=0; apszUtmProjCode[i]!=NULL; i += 3)
731
if(EQUALN(utmName, apszUtmProjCode[i+1], strlen(apszUtmProjCode[i+1])) &&
732
EQUAL(datumName, apszUtmProjCode[i]) )
734
if(psDefn->ProjCode != atoi(apszUtmProjCode[i+2]))
736
psDefn->ProjCode = (short) atoi(apszUtmProjCode[i+2]);
737
GTIFGetProjTRFInfo( psDefn->ProjCode, NULL, &(psDefn->Projection),