Statistics
| Revision:

svn-gvsig-desktop / tags / v1_9_Build_1222 / libraries / libjni-proj4 / src / pj_init.c @ 41849

History | View | Annotate | Download (12.8 KB)

1
/******************************************************************************
2
 * $Id: pj_init.c,v 1.16 2004/09/08 15:23:37 warmerda Exp $
3
 *
4
 * Project:  PROJ.4
5
 * Purpose:  Initialize projection object from string definition.  Includes
6
 *           pj_init(), pj_init_plus() and pj_free() function.
7
 * Author:   Gerald Evenden, Frank Warmerdam <warmerdam@pobox.com>
8
 *
9
 ******************************************************************************
10
 * Copyright (c) 1995, Gerald Evenden
11
 * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
12
 *
13
 * Permission is hereby granted, free of charge, to any person obtaining a
14
 * copy of this software and associated documentation files (the "Software"),
15
 * to deal in the Software without restriction, including without limitation
16
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17
 * and/or sell copies of the Software, and to permit persons to whom the
18
 * Software is furnished to do so, subject to the following conditions:
19
 *
20
 * The above copyright notice and this permission notice shall be included
21
 * in all copies or substantial portions of the Software.
22
 *
23
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29
 * DEALINGS IN THE SOFTWARE.
30
 ******************************************************************************
31
 *
32
 * $Log: pj_init.c,v $
33
 * Revision 1.16  2004/09/08 15:23:37  warmerda
34
 * added new error for unknown prime meridians
35
 *
36
 * Revision 1.15  2004/05/05 01:45:41  warmerda
37
 * Made sword even longer.
38
 *
39
 * Revision 1.14  2004/05/05 01:45:00  warmerda
40
 * Make sword buffer larger so long +towgs84 parameters don't get split.
41
 *
42
 * Revision 1.13  2003/09/16 03:46:21  warmerda
43
 * dont use default ellps if any earth model info is set: bug 386
44
 *
45
 * Revision 1.12  2003/08/21 02:15:59  warmerda
46
 * improve MAX_ARG checking
47
 *
48
 * Revision 1.11  2003/06/09 21:23:16  warmerda
49
 * ensure start is initialized at very beginning of pj_init()
50
 *
51
 * Revision 1.10  2003/03/16 16:38:24  warmerda
52
 * Modified get_opt() to terminate reading the definition when a new
53
 * definition (a word starting with '<') is encountered, in addition to when
54
 * the definition terminator '<>' is encountered, so that unterminated
55
 * definitions like those in the distributed esri file will work properly.
56
 * http://bugzilla.remotesensing.org/show_bug.cgi?id=302
57
 *
58
 * Revision 1.9  2002/12/14 20:15:02  warmerda
59
 * added geocentric support, updated headers
60
 *
61
 */
62

    
63
#define PJ_LIB__
64
#include <projects.h>
65
#include <stdio.h>
66
#include <string.h>
67
#include <errno.h>
68

    
69
PJ_CVSID("$Id: pj_init.c,v 1.16 2004/09/08 15:23:37 warmerda Exp $");
70

    
71
static paralist *start;
72
extern FILE *pj_open_lib(char *, char *);
73

    
74
/************************************************************************/
75
/*                              get_opt()                               */
76
/************************************************************************/
77
static paralist *
78
get_opt(FILE *fid, char *name, paralist *next) {
79
    char sword[302], *word = sword+1;
80
    int first = 1, len, c;
81

    
82
    len = strlen(name);
83
    *sword = 't';
84
    while (fscanf(fid, "%300s", word) == 1) {
85
        if (*word == '#') /* skip comments */
86
            while((c = fgetc(fid)) != EOF && c != '\n') ;
87
        else if (*word == '<') { /* control name */
88
            if (first && !strncmp(name, word + 1, len)
89
                && word[len + 1] == '>')
90
                first = 0;
91
            else if (!first && *word == '<') {
92
                while((c = fgetc(fid)) != EOF && c != '\n') ;
93
                break;
94
            }
95
        } else if (!first && !pj_param(start, sword).i) {
96
            /* don't default ellipse if datum, ellps or any earth model
97
               information is set. */
98
            if( strncmp(word,"ellps=",6) != 0 
99
                || (!pj_param(start, "tdatum").i 
100
                    && !pj_param(start, "tellps").i 
101
                    && !pj_param(start, "ta").i 
102
                    && !pj_param(start, "tb").i 
103
                    && !pj_param(start, "trf").i 
104
                    && !pj_param(start, "tf").i) )
105
            {
106
                next = next->next = pj_mkparam(word);
107
            }
108
        }
109
    }
110

    
111
    if (errno == 25)
112
        errno = 0;
113
    return next;
114
}
115

    
116
/************************************************************************/
117
/*                            get_defaults()                            */
118
/************************************************************************/
119
static paralist *
120
get_defaults(paralist *next, char *name) {
121
        FILE *fid;
122

    
123
        if (fid = pj_open_lib("proj_def.dat", "rt")) {
124
                next = get_opt(fid, "general", next);
125
                rewind(fid);
126
                next = get_opt(fid, name, next);
127
                (void)fclose(fid);
128
        }
129
        if (errno)
130
                errno = 0; /* don't care if can't open file */
131
        return next;
132
}
133

    
134
/************************************************************************/
135
/*                              get_init()                              */
136
/************************************************************************/
137
static paralist *
138
get_init(paralist *next, char *name) {
139
        char fname[MAX_PATH_FILENAME+ID_TAG_MAX+3], *opt;
140
        FILE *fid;
141

    
142
        (void)strncpy(fname, name, MAX_PATH_FILENAME + ID_TAG_MAX + 1);
143
        if (opt = strrchr(fname, ':'))
144
                *opt++ = '\0';
145
        else { pj_errno = -3; return(0); }
146
        if (fid = pj_open_lib(fname, "rt"))
147
                next = get_opt(fid, opt, next);
148
        else
149
                return(0);
150
        (void)fclose(fid);
151
        if (errno == 25)
152
                errno = 0; /* unknown problem with some sys errno<-25 */
153
        return next;
154
}
155

    
156
/************************************************************************/
157
/*                            pj_init_plus()                            */
158
/*                                                                      */
159
/*      Same as pj_init() except it takes one argument string with      */
160
/*      individual arguments preceeded by '+', such as "+proj=utm       */
161
/*      +zone=11 +ellps=WGS84".                                         */
162
/************************************************************************/
163

    
164
PJ *
165
pj_init_plus( const char *definition )
166

    
167
{
168
#define MAX_ARG 200
169
    char        *argv[MAX_ARG];
170
    char        *defn_copy;
171
    int                argc = 0, i;
172
    PJ                *result;
173
    
174
    /* make a copy that we can manipulate */
175
    defn_copy = (char *) pj_malloc( strlen(definition)+1 );
176
    strcpy( defn_copy, definition );
177

    
178
    /* split into arguments based on '+' and trim white space */
179

    
180
    for( i = 0; defn_copy[i] != '\0'; i++ )
181
    {
182
        switch( defn_copy[i] )
183
        {
184
          case '+':
185
            if( i == 0 || defn_copy[i-1] == '\0' )
186
            {
187
                if( argc+1 == MAX_ARG )
188
                {
189
                    pj_errno = -44;
190
                    return NULL;
191
                }
192
                
193
                argv[argc++] = defn_copy + i + 1;
194
            }
195
            break;
196

    
197
          case ' ':
198
          case '\t':
199
          case '\n':
200
            defn_copy[i] = '\0';
201
            break;
202

    
203
          default:
204
            /* do nothing */;
205
        }
206
    }
207

    
208
    /* perform actual initialization */
209
    result = pj_init( argc, argv );
210

    
211
    pj_dalloc( defn_copy );
212

    
213
    return result;
214
}
215

    
216
/************************************************************************/
217
/*                              pj_init()                               */
218
/*                                                                      */
219
/*      Main entry point for initialing a PJ projections                */
220
/*      definition.  Note that the projection specific function is      */
221
/*      called to do the initial allocation so it can be created        */
222
/*      large enough to hold projection specific parameters.            */
223
/************************************************************************/
224

    
225
PJ *
226
pj_init(int argc, char **argv) {
227
        char *s, *name;
228
        PJ *(*proj)(PJ *);
229
        paralist *curr;
230
        int i;
231
        PJ *PIN = 0;
232

    
233
        errno = pj_errno = 0;
234
        start = NULL;
235

    
236
        /* put arguments into internal linked list */
237
        if (argc <= 0) { pj_errno = -1; goto bum_call; }
238
        for (i = 0; i < argc; ++i)
239
                if (i)
240
                        curr = curr->next = pj_mkparam(argv[i]);
241
                else
242
                        start = curr = pj_mkparam(argv[i]);
243
        if (pj_errno) goto bum_call;
244

    
245
        /* check if +init present */
246
        if (pj_param(start, "tinit").i) {
247
                paralist *last = curr;
248

    
249
                if (!(curr = get_init(curr, pj_param(start, "sinit").s)))
250
                        goto bum_call;
251
                if (curr == last) { pj_errno = -2; goto bum_call; }
252
        }
253

    
254
        /* find projection selection */
255
        if (!(name = pj_param(start, "sproj").s))
256
                { pj_errno = -4; goto bum_call; }
257
        for (i = 0; (s = pj_list[i].id) && strcmp(name, s) ; ++i) ;
258
        if (!s) { pj_errno = -5; goto bum_call; }
259

    
260
        /* set defaults, unless inhibited */
261
        if (!pj_param(start, "bno_defs").i)
262
                curr = get_defaults(curr, name);
263
        proj = (PJ *(*)(PJ *)) pj_list[i].proj;
264

    
265
        /* allocate projection structure */
266
        if (!(PIN = (*proj)(0))) goto bum_call;
267
        PIN->params = start;
268
        PIN->is_latlong = 0;
269
        PIN->is_geocent = 0;
270

    
271
        /* set datum parameters */
272
        if (pj_datum_set(start, PIN)) goto bum_call;
273

    
274
        /* set ellipsoid/sphere parameters */
275
        if (pj_ell_set(start, &PIN->a, &PIN->es)) goto bum_call;
276

    
277
        PIN->e = sqrt(PIN->es);
278
        PIN->ra = 1. / PIN->a;
279
        PIN->one_es = 1. - PIN->es;
280
        if (PIN->one_es == 0.) { pj_errno = -6; goto bum_call; }
281
        PIN->rone_es = 1./PIN->one_es;
282

    
283
        /* Now that we have ellipse information check for WGS84 datum */
284
        if( PIN->datum_type == PJD_3PARAM 
285
            && PIN->datum_params[0] == 0.0
286
            && PIN->datum_params[1] == 0.0
287
            && PIN->datum_params[2] == 0.0
288
            && PIN->a == 6378137.0
289
            && ABS(PIN->es - 0.006694379990) < 0.000000000050 )/*WGS84/GRS80*/
290
        {
291
            PIN->datum_type = PJD_WGS84;
292
        }
293
        
294
        /* set PIN->geoc coordinate system */
295
        PIN->geoc = (PIN->es && pj_param(start, "bgeoc").i);
296

    
297
        /* over-ranging flag */
298
        PIN->over = pj_param(start, "bover").i;
299

    
300
        /* central meridian */
301
        PIN->lam0=pj_param(start, "rlon_0").f;
302

    
303
        /* central latitude */
304
        PIN->phi0 = pj_param(start, "rlat_0").f;
305

    
306
        /* false easting and northing */
307
        PIN->x0 = pj_param(start, "dx_0").f;
308
        PIN->y0 = pj_param(start, "dy_0").f;
309

    
310
        /* general scaling factor */
311
        if (pj_param(start, "tk_0").i)
312
                PIN->k0 = pj_param(start, "dk_0").f;
313
        else if (pj_param(start, "tk").i)
314
                PIN->k0 = pj_param(start, "dk").f;
315
        else
316
                PIN->k0 = 1.;
317
        if (PIN->k0 <= 0.) {
318
                pj_errno = -31;
319
                goto bum_call;
320
        }
321

    
322
        /* set units */
323
        s = 0;
324
        if (name = pj_param(start, "sunits").s) { 
325
                for (i = 0; (s = pj_units[i].id) && strcmp(name, s) ; ++i) ;
326
                if (!s) { pj_errno = -7; goto bum_call; }
327
                s = pj_units[i].to_meter;
328
        }
329
        if (s || (s = pj_param(start, "sto_meter").s)) {
330
                PIN->to_meter = strtod(s, &s);
331
                if (*s == '/') /* ratio number */
332
                        PIN->to_meter /= strtod(++s, 0);
333
                PIN->fr_meter = 1. / PIN->to_meter;
334
        } else
335
                PIN->to_meter = PIN->fr_meter = 1.;
336

    
337
        /* prime meridian */
338
        s = 0;
339
        if (name = pj_param(start, "spm").s) { 
340
            const char *value = NULL;
341
            char *next_str = NULL;
342

    
343
            for (i = 0; pj_prime_meridians[i].id != NULL; ++i )
344
            {
345
                if( strcmp(name,pj_prime_meridians[i].id) == 0 )
346
                {
347
                    value = pj_prime_meridians[i].defn;
348
                    break;
349
                }
350
            }
351
            
352
            if( value == NULL 
353
                && (dmstor(name,&next_str) != 0.0  || *name == '0')
354
                && *next_str == '\0' )
355
                value = name;
356

    
357
            if (!value) { pj_errno = -46; goto bum_call; }
358
            PIN->from_greenwich = dmstor(value,NULL);
359
        }
360
        else
361
            PIN->from_greenwich = 0.0;
362

    
363
        /* projection specific initialization */
364
        if (!(PIN = (*proj)(PIN)) || errno || pj_errno) {
365
bum_call: /* cleanup error return */
366
                if (!pj_errno)
367
                        pj_errno = errno;
368
                if (PIN)
369
                        pj_free(PIN);
370
                else
371
                        for ( ; start; start = curr) {
372
                                curr = start->next;
373
                                pj_dalloc(start);
374
                        }
375
                PIN = 0;
376
        }
377
        return PIN;
378
}
379

    
380
/************************************************************************/
381
/*                              pj_free()                               */
382
/*                                                                      */
383
/*      This is the application callable entry point for destroying     */
384
/*      a projection definition.  It does work generic to all           */
385
/*      projection types, and then calls the projection specific        */
386
/*      free function (P->pfree()) to do local work.  This maps to      */
387
/*      the FREEUP code in the individual projection source files.      */
388
/************************************************************************/
389

    
390
void
391
pj_free(PJ *P) {
392
        if (P) {
393
                paralist *t = P->params, *n;
394

    
395
                /* free parameter list elements */
396
                for (t = P->params; t; t = n) {
397
                        n = t->next;
398
                        pj_dalloc(t);
399
                }
400

    
401
                /* free projection parameters */
402
                P->pfree(P);
403
        }
404
}
405

    
406