Statistics
| Revision:

svn-gvsig-desktop / tags / v1_1_2_Build_1045 / libraries / libjni-proj4 / src / pj_transform.c @ 38629

History | View | Annotate | Download (22.5 KB)

1
/******************************************************************************
2
 * $Id: pj_transform.c,v 1.13 2004/10/25 15:34:36 fwarmerdam Exp $
3
 *
4
 * Project:  PROJ.4
5
 * Purpose:  Perform overall coordinate system to coordinate system 
6
 *           transformations (pj_transform() function) including reprojection
7
 *           and datum shifting.
8
 * Author:   Frank Warmerdam, warmerdam@pobox.com
9
 *
10
 ******************************************************************************
11
 * Copyright (c) 2000, Frank Warmerdam
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_transform.c,v $
33
 * Revision 1.13  2004/10/25 15:34:36  fwarmerdam
34
 * make names of geodetic funcs from geotrans unique
35
 *
36
 * Revision 1.12  2004/05/03 19:45:23  warmerda
37
 * Altered so that raw ellpses are treated as a essentially having a
38
 * +towgs84=0,0,0 specification so ellpisoid shifts are applied.
39
 * Fixed so that prime meridian shifts are applied if the coordinate system is
40
 * not lat/long (ie. if it is projected).  This fixes:
41
 * http://bugzilla.remotesensing.org/show_bug.cgi?id=510
42
 *
43
 * Revision 1.11  2004/01/24 09:37:19  warmerda
44
 * pj_transform() will no longer return an error code if any of the points are
45
 * transformable.  In this case the application is expected to check for
46
 * HUGE_VAL to identify failed points.
47
 * As part of the implementation, I added a list of pj_errno values that
48
 * are transient (ie per-point) rather than indicating global failure for the
49
 * coordinate system definition.  We use this in deciding which pj_fwd and
50
 * pj_inv error codes are really fatal and should be reported.
51
 *
52
 * Revision 1.10  2003/08/21 02:09:06  warmerda
53
 * added a bunch of HUGE_VAL checking
54
 *
55
 * Revision 1.9  2003/03/26 16:52:30  warmerda
56
 * added check that an inverse transformation func exists
57
 *
58
 * Revision 1.8  2002/12/14 20:35:43  warmerda
59
 * implement units support for geocentric coordinates
60
 *
61
 * Revision 1.7  2002/12/14 20:14:35  warmerda
62
 * added geocentric support
63
 *
64
 * Revision 1.6  2002/12/09 16:01:02  warmerda
65
 * added prime meridian support
66
 *
67
 * Revision 1.5  2002/12/01 19:25:26  warmerda
68
 * applied fix for 7 param shift in pj_geocentric_from_wgs84, see bug 194
69
 *
70
 * Revision 1.4  2002/02/15 14:30:36  warmerda
71
 * provide default Z array if none passed in in pj_datum_transform()
72
 *
73
 * Revision 1.3  2001/04/04 21:13:21  warmerda
74
 * do arcsecond/radian and ppm datum parm transformation in pj_set_datum()
75
 *
76
 * Revision 1.2  2001/04/04 16:08:08  warmerda
77
 * rewrote 7 param datum shift to match EPSG:9606, now works with example
78
 *
79
 * Revision 1.1  2000/07/06 23:32:27  warmerda
80
 * New
81
 *
82
 */
83

    
84
#include <projects.h>
85
#include <string.h>
86
#include <math.h>
87
#include "geocent.h"
88

    
89
PJ_CVSID("$Id: pj_transform.c,v 1.13 2004/10/25 15:34:36 fwarmerdam Exp $");
90

    
91
#ifndef SRS_WGS84_SEMIMAJOR
92
#define SRS_WGS84_SEMIMAJOR 6378137.0
93
#endif
94

    
95
#ifndef SRS_WGS84_ESQUARED
96
#define SRS_WGS84_ESQUARED 0.006694379990
97
#endif
98

    
99
#define Dx_BF (defn->datum_params[0])
100
#define Dy_BF (defn->datum_params[1])
101
#define Dz_BF (defn->datum_params[2])
102
#define Rx_BF (defn->datum_params[3])
103
#define Ry_BF (defn->datum_params[4])
104
#define Rz_BF (defn->datum_params[5])
105
#define M_BF  (defn->datum_params[6])
106

    
107
/* 
108
** This table is intended to indicate for any given error code in 
109
** the range 0 to -44, whether that error will occur for all locations (ie.
110
** it is a problem with the coordinate system as a whole) in which case the
111
** value would be 0, or if the problem is with the point being transformed
112
** in which case the value is 1. 
113
**
114
** At some point we might want to move this array in with the error message
115
** list or something, but while experimenting with it this should be fine. 
116
*/
117

    
118
static int transient_error[45] = {
119
    /*             0  1  2  3  4  5  6  7  8  9   */
120
    /* 0 to 9 */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
121
    /* 10 to 19 */ 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,  
122
    /* 20 to 29 */ 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 
123
    /* 30 to 39 */ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 
124
    /* 40 to 44 */ 0, 0, 0, 0, 0 };
125

    
126
/************************************************************************/
127
/*                            pj_transform()                            */
128
/*                                                                      */
129
/*      Currently this function doesn't recognise if two projections    */
130
/*      are identical (to short circuit reprojection) because it is     */
131
/*      difficult to compare PJ structures (since there are some        */
132
/*      projection specific components).                                */
133
/************************************************************************/
134

    
135
int pj_transform( PJ *srcdefn, PJ *dstdefn, long point_count, int point_offset,
136
                  double *x, double *y, double *z )
137

    
138
{
139
    long      i;
140
    int       need_datum_shift;
141

    
142
    pj_errno = 0;
143

    
144
    if( point_offset == 0 )
145
        point_offset = 1;
146

    
147
/* -------------------------------------------------------------------- */
148
/*      Transform geocentric source coordinates to lat/long.            */
149
/* -------------------------------------------------------------------- */
150
    if( srcdefn->is_geocent )
151
    {
152
        if( z == NULL )
153
        {
154
            pj_errno = PJD_ERR_GEOCENTRIC;
155
            return PJD_ERR_GEOCENTRIC;
156
        }
157

    
158
        if( srcdefn->to_meter != 1.0 )
159
        {
160
            for( i = 0; i < point_count; i++ )
161
            {
162
                x[point_offset*i] *= srcdefn->to_meter;
163
                y[point_offset*i] *= srcdefn->to_meter;
164
            }
165
        }
166

    
167
        if( pj_geocentric_to_geodetic( srcdefn->a, srcdefn->es,
168
                                       point_count, point_offset, 
169
                                       x, y, z ) != 0) 
170
            return pj_errno;
171
    }
172

    
173
/* -------------------------------------------------------------------- */
174
/*      Transform source points to lat/long, if they aren't             */
175
/*      already.                                                        */
176
/* -------------------------------------------------------------------- */
177
    else if( !srcdefn->is_latlong )
178
    {
179
        if( srcdefn->inv == NULL )
180
        {
181
            pj_errno = -17; /* this isn't correct, we need a no inverse err */
182
            if( getenv( "PROJ_DEBUG" ) != NULL )
183
            {
184
                fprintf( stderr, 
185
                       "pj_transform(): source projection not invertable\n" );
186
            }
187
            return pj_errno;
188
        }
189

    
190
        for( i = 0; i < point_count; i++ )
191
        {
192
            XY         projected_loc;
193
            LP               geodetic_loc;
194

    
195
            projected_loc.u = x[point_offset*i];
196
            projected_loc.v = y[point_offset*i];
197

    
198
            if( projected_loc.u == HUGE_VAL )
199
                continue;
200

    
201
            geodetic_loc = pj_inv( projected_loc, srcdefn );
202
            if( pj_errno != 0 )
203
            {
204
                if( pj_errno > 0 || pj_errno < -44 || point_count == 1
205
                    || transient_error[-pj_errno] == 0 )
206
                    return pj_errno;
207
                else
208
                {
209
                    geodetic_loc.u = HUGE_VAL;
210
                    geodetic_loc.v = HUGE_VAL;
211
                }
212
            }
213

    
214
            x[point_offset*i] = geodetic_loc.u;
215
            y[point_offset*i] = geodetic_loc.v;
216
        }
217
    }
218
/* -------------------------------------------------------------------- */
219
/*      But if they are already lat long, adjust for the prime          */
220
/*      meridian if there is one in effect.                             */
221
/* -------------------------------------------------------------------- */
222
    if( srcdefn->from_greenwich != 0.0 )
223
    {
224
        for( i = 0; i < point_count; i++ )
225
        {
226
            if( x[point_offset*i] != HUGE_VAL )
227
                x[point_offset*i] += srcdefn->from_greenwich;
228
        }
229
    }
230

    
231
/* -------------------------------------------------------------------- */
232
/*      Convert datums if needed, and possible.                         */
233
/* -------------------------------------------------------------------- */
234
    if( pj_datum_transform( srcdefn, dstdefn, point_count, point_offset, 
235
                            x, y, z ) != 0 )
236
        return pj_errno;
237

    
238
/* -------------------------------------------------------------------- */
239
/*      But if they are staying lat long, adjust for the prime          */
240
/*      meridian if there is one in effect.                             */
241
/* -------------------------------------------------------------------- */
242
    if( dstdefn->from_greenwich != 0.0 )
243
    {
244
        for( i = 0; i < point_count; i++ )
245
        {
246
            if( x[point_offset*i] != HUGE_VAL )
247
                x[point_offset*i] -= dstdefn->from_greenwich;
248
        }
249
    }
250

    
251

    
252
/* -------------------------------------------------------------------- */
253
/*      Transform destination latlong to geocentric if required.        */
254
/* -------------------------------------------------------------------- */
255
    if( dstdefn->is_geocent )
256
    {
257
        if( z == NULL )
258
        {
259
            pj_errno = PJD_ERR_GEOCENTRIC;
260
            return PJD_ERR_GEOCENTRIC;
261
        }
262

    
263
        pj_geodetic_to_geocentric( dstdefn->a, dstdefn->es,
264
                                   point_count, point_offset, x, y, z );
265

    
266
        if( dstdefn->fr_meter != 1.0 )
267
        {
268
            for( i = 0; i < point_count; i++ )
269
            {
270
                if( x[point_offset*i] != HUGE_VAL )
271
                {
272
                    x[point_offset*i] *= dstdefn->fr_meter;
273
                    y[point_offset*i] *= dstdefn->fr_meter;
274
                }
275
            }
276
        }
277
    }
278

    
279
/* -------------------------------------------------------------------- */
280
/*      Transform destination points to projection coordinates, if      */
281
/*      desired.                                                        */
282
/* -------------------------------------------------------------------- */
283
    else if( !dstdefn->is_latlong )
284
    {
285
        for( i = 0; i < point_count; i++ )
286
        {
287
            XY         projected_loc;
288
            LP               geodetic_loc;
289

    
290
            geodetic_loc.u = x[point_offset*i];
291
            geodetic_loc.v = y[point_offset*i];
292

    
293
            if( geodetic_loc.u == HUGE_VAL )
294
                continue;
295

    
296
            projected_loc = pj_fwd( geodetic_loc, dstdefn );
297
            if( pj_errno != 0 )
298
            {
299
                if( pj_errno > 0 || pj_errno < -44 || point_count == 1
300
                    || transient_error[-pj_errno] == 0 )
301
                    return pj_errno;
302
                else
303
                {
304
                    projected_loc.u = HUGE_VAL;
305
                    projected_loc.v = HUGE_VAL;
306
                }
307
            }
308

    
309
            x[point_offset*i] = projected_loc.u;
310
            y[point_offset*i] = projected_loc.v;
311
        }
312
    }
313

    
314
    return 0;
315
}
316

    
317
/************************************************************************/
318
/*                     pj_geodetic_to_geocentric()                      */
319
/************************************************************************/
320

    
321
int pj_geodetic_to_geocentric( double a, double es, 
322
                               long point_count, int point_offset,
323
                               double *x, double *y, double *z )
324

    
325
{
326
    double b;
327
    int    i;
328

    
329
    if( es == 0.0 )
330
        b = a;
331
    else
332
        b = a * sqrt(1-es);
333

    
334
    if( pj_Set_Geocentric_Parameters( a, b ) != 0 )
335
    {
336
        pj_errno = PJD_ERR_GEOCENTRIC;
337
        return pj_errno;
338
    }
339

    
340
    for( i = 0; i < point_count; i++ )
341
    {
342
        long io = i * point_offset;
343

    
344
        if( pj_Convert_Geodetic_To_Geocentric( y[io], x[io], z[io], 
345
                                            x+io, y+io, z+io ) != 0 )
346
        {
347
            pj_errno = PJD_ERR_GEOCENTRIC;
348
            return PJD_ERR_GEOCENTRIC;
349
        }
350
    }
351

    
352
    return 0;
353
}
354

    
355
/************************************************************************/
356
/*                     pj_geodetic_to_geocentric()                      */
357
/************************************************************************/
358

    
359
int pj_geocentric_to_geodetic( double a, double es, 
360
                               long point_count, int point_offset,
361
                               double *x, double *y, double *z )
362

    
363
{
364
    double b;
365
    int    i;
366

    
367
    if( es == 0.0 )
368
        b = a;
369
    else
370
        b = a * sqrt(1-es);
371

    
372
    if( pj_Set_Geocentric_Parameters( a, b ) != 0 )
373
    {
374
        pj_errno = PJD_ERR_GEOCENTRIC;
375
        return pj_errno;
376
    }
377

    
378
    for( i = 0; i < point_count; i++ )
379
    {
380
        long io = i * point_offset;
381

    
382
        if( x[io] == HUGE_VAL )
383
            continue;
384

    
385
        pj_Convert_Geocentric_To_Geodetic( x[io], y[io], z[io], 
386
                                        y+io, x+io, z+io );
387
    }
388

    
389
    return 0;
390
}
391

    
392
/************************************************************************/
393
/*                         pj_compare_datums()                          */
394
/*                                                                      */
395
/*      Returns TRUE if the two datums are identical, otherwise         */
396
/*      FALSE.                                                          */
397
/************************************************************************/
398

    
399
int pj_compare_datums( PJ *srcdefn, PJ *dstdefn )
400

    
401
{
402
    if( srcdefn->datum_type != dstdefn->datum_type )
403
    {
404
        return 0;
405
    }
406
    else if( srcdefn->a != dstdefn->a 
407
             || ABS(srcdefn->es - dstdefn->es) > 0.000000000050 )
408
    {
409
        /* the tolerence for es is to ensure that GRS80 and WGS84 are
410
           considered identical */
411
        return 0;
412
    }
413
    else if( srcdefn->datum_type == PJD_3PARAM )
414
    {
415
        return (srcdefn->datum_params[0] == dstdefn->datum_params[0]
416
                && srcdefn->datum_params[1] == dstdefn->datum_params[1]
417
                && srcdefn->datum_params[2] == dstdefn->datum_params[2]);
418
    }
419
    else if( srcdefn->datum_type == PJD_7PARAM )
420
    {
421
        return (srcdefn->datum_params[0] == dstdefn->datum_params[0]
422
                && srcdefn->datum_params[1] == dstdefn->datum_params[1]
423
                && srcdefn->datum_params[2] == dstdefn->datum_params[2]
424
                && srcdefn->datum_params[3] == dstdefn->datum_params[3]
425
                && srcdefn->datum_params[4] == dstdefn->datum_params[4]
426
                && srcdefn->datum_params[5] == dstdefn->datum_params[5]
427
                && srcdefn->datum_params[6] == dstdefn->datum_params[6]);
428
    }
429
    else if( srcdefn->datum_type == PJD_GRIDSHIFT )
430
    {
431
        return strcmp( pj_param(srcdefn->params,"snadgrids").s,
432
                       pj_param(dstdefn->params,"snadgrids").s ) == 0;
433
    }
434
    else
435
        return 1;
436
}
437

    
438
/************************************************************************/
439
/*                       pj_geocentic_to_wgs84()                        */
440
/************************************************************************/
441

    
442
int pj_geocentric_to_wgs84( PJ *defn, 
443
                            long point_count, int point_offset,
444
                            double *x, double *y, double *z )
445

    
446
{
447
    int       i;
448

    
449
    pj_errno = 0;
450

    
451
    if( defn->datum_type == PJD_3PARAM )
452
    {
453
        for( i = 0; i < point_count; i++ )
454
        {
455
            long io = i * point_offset;
456
            
457
            if( x[io] == HUGE_VAL )
458
                continue;
459

    
460
            x[io] = x[io] + defn->datum_params[0];
461
            y[io] = y[io] + defn->datum_params[1];
462
            z[io] = z[io] + defn->datum_params[2];
463
        }
464
    }
465
    else if( defn->datum_type == PJD_7PARAM )
466
    {
467
        for( i = 0; i < point_count; i++ )
468
        {
469
            long io = i * point_offset;
470
            double x_out, y_out, z_out;
471

    
472
            if( x[io] == HUGE_VAL )
473
                continue;
474

    
475
            x_out = M_BF*(       x[io] - Rz_BF*y[io] + Ry_BF*z[io]) + Dx_BF;
476
            y_out = M_BF*( Rz_BF*x[io] +       y[io] - Rx_BF*z[io]) + Dy_BF;
477
            z_out = M_BF*(-Ry_BF*x[io] + Rx_BF*y[io] +       z[io]) + Dz_BF;
478

    
479
            x[io] = x_out;
480
            y[io] = y_out;
481
            z[io] = z_out;
482
        }
483
    }
484

    
485
    return 0;
486
}
487

    
488
/************************************************************************/
489
/*                      pj_geocentic_from_wgs84()                       */
490
/************************************************************************/
491

    
492
int pj_geocentric_from_wgs84( PJ *defn, 
493
                              long point_count, int point_offset,
494
                              double *x, double *y, double *z )
495

    
496
{
497
    int       i;
498

    
499
    pj_errno = 0;
500

    
501
    if( defn->datum_type == PJD_3PARAM )
502
    {
503
        for( i = 0; i < point_count; i++ )
504
        {
505
            long io = i * point_offset;
506

    
507
            if( x[io] == HUGE_VAL )
508
                continue;
509
            
510
            x[io] = x[io] - defn->datum_params[0];
511
            y[io] = y[io] - defn->datum_params[1];
512
            z[io] = z[io] - defn->datum_params[2];
513
        }
514
    }
515
    else if( defn->datum_type == PJD_7PARAM )
516
    {
517
        for( i = 0; i < point_count; i++ )
518
        {
519
            long io = i * point_offset;
520
            double x_tmp, y_tmp, z_tmp;
521

    
522
            if( x[io] == HUGE_VAL )
523
                continue;
524

    
525
            x_tmp = (x[io] - Dx_BF) / M_BF;
526
            y_tmp = (y[io] - Dy_BF) / M_BF;
527
            z_tmp = (z[io] - Dz_BF) / M_BF;
528

    
529
            x[io] =        x_tmp + Rz_BF*y_tmp - Ry_BF*z_tmp;
530
            y[io] = -Rz_BF*x_tmp +       y_tmp + Rx_BF*z_tmp;
531
            z[io] =  Ry_BF*x_tmp - Rx_BF*y_tmp +       z_tmp;
532
        }
533
    }
534

    
535
    return 0;
536
}
537

    
538
/************************************************************************/
539
/*                         pj_datum_transform()                         */
540
/************************************************************************/
541

    
542
int pj_datum_transform( PJ *srcdefn, PJ *dstdefn, 
543
                        long point_count, int point_offset,
544
                        double *x, double *y, double *z )
545

    
546
{
547
    double      src_a, src_es, dst_a, dst_es;
548
    int         z_is_temp = FALSE;
549

    
550
    pj_errno = 0;
551

    
552
/* -------------------------------------------------------------------- */
553
/*      Short cut if the datums are identical.                          */
554
/* -------------------------------------------------------------------- */
555
    if( pj_compare_datums( srcdefn, dstdefn ) )
556
        return 0;
557

    
558
    src_a = srcdefn->a;
559
    src_es = srcdefn->es;
560

    
561
    dst_a = dstdefn->a;
562
    dst_es = dstdefn->es;
563

    
564
/* -------------------------------------------------------------------- */
565
/*      Create a temporary Z array if one is not provided.              */
566
/* -------------------------------------------------------------------- */
567
    if( z == NULL )
568
    {
569
        int        bytes = sizeof(double) * point_count * point_offset;
570
        z = (double *) pj_malloc(bytes);
571
        memset( z, 0, bytes );
572
        z_is_temp = TRUE;
573
    }
574

    
575
#define CHECK_RETURN {if( pj_errno != 0 ) { if( z_is_temp ) pj_dalloc(z); return pj_errno; }}
576

    
577
/* -------------------------------------------------------------------- */
578
/*        If this datum requires grid shifts, then apply it to geodetic   */
579
/*      coordinates.                                                    */
580
/* -------------------------------------------------------------------- */
581
    if( srcdefn->datum_type == PJD_GRIDSHIFT )
582
    {
583
        pj_apply_gridshift( pj_param(srcdefn->params,"snadgrids").s, 0, 
584
                            point_count, point_offset, x, y, z );
585
        CHECK_RETURN;
586

    
587
        src_a = SRS_WGS84_SEMIMAJOR;
588
        src_es = 0.006694379990;
589
    }
590

    
591
    if( dstdefn->datum_type == PJD_GRIDSHIFT )
592
    {
593
        dst_a = SRS_WGS84_SEMIMAJOR;
594
        dst_es = 0.006694379990;
595
    }
596
        
597
/* ==================================================================== */
598
/*      Do we need to go through geocentric coordinates?                */
599
/* ==================================================================== */
600
    if( src_es != dst_es || src_a != dst_a
601
        || srcdefn->datum_type == PJD_3PARAM 
602
        || srcdefn->datum_type == PJD_7PARAM
603
        || dstdefn->datum_type == PJD_3PARAM 
604
        || dstdefn->datum_type == PJD_7PARAM)
605
    {
606
/* -------------------------------------------------------------------- */
607
/*      Convert to geocentric coordinates.                              */
608
/* -------------------------------------------------------------------- */
609
        pj_geodetic_to_geocentric( src_a, src_es,
610
                                   point_count, point_offset, x, y, z );
611
        CHECK_RETURN;
612

    
613
/* -------------------------------------------------------------------- */
614
/*      Convert between datums.                                         */
615
/* -------------------------------------------------------------------- */
616
        if( srcdefn->datum_type == PJD_3PARAM 
617
            || srcdefn->datum_type == PJD_7PARAM )
618
        {
619
            pj_geocentric_to_wgs84( srcdefn, point_count, point_offset,x,y,z);
620
            CHECK_RETURN;
621
        }
622

    
623
        if( dstdefn->datum_type == PJD_3PARAM 
624
            || dstdefn->datum_type == PJD_7PARAM )
625
        {
626
            pj_geocentric_from_wgs84( dstdefn, point_count,point_offset,x,y,z);
627
            CHECK_RETURN;
628
        }
629

    
630
/* -------------------------------------------------------------------- */
631
/*      Convert back to geodetic coordinates.                           */
632
/* -------------------------------------------------------------------- */
633
        pj_geocentric_to_geodetic( dst_a, dst_es,
634
                                   point_count, point_offset, x, y, z );
635
        CHECK_RETURN;
636
    }
637

    
638
/* -------------------------------------------------------------------- */
639
/*      Apply grid shift to destination if required.                    */
640
/* -------------------------------------------------------------------- */
641
    if( dstdefn->datum_type == PJD_GRIDSHIFT )
642
    {
643
        pj_apply_gridshift( pj_param(dstdefn->params,"snadgrids").s, 1,
644
                            point_count, point_offset, x, y, z );
645
        CHECK_RETURN;
646
    }
647

    
648
    if( z_is_temp )
649
        pj_dalloc( z );
650

    
651
    return 0;
652
}
653