35
35
#include "geocent.h"
37
PJ_CVSID("$Id: pj_transform.c 1504 2009-01-06 02:11:57Z warmerdam $");
37
PJ_CVSID("$Id: pj_transform.c 2000 2011-05-10 17:06:33Z warmerdam $");
39
static int pj_adjust_axis( projCtx ctx, const char *axis, int denormalize_flag,
40
long point_count, int point_offset,
41
double *x, double *y, double *z );
39
43
#ifndef SRS_WGS84_SEMIMAJOR
40
44
#define SRS_WGS84_SEMIMAJOR 6378137.0
63
67
** list or something, but while experimenting with it this should be fine.
66
static const int transient_error[45] = {
70
static const int transient_error[50] = {
67
71
/* 0 1 2 3 4 5 6 7 8 9 */
68
72
/* 0 to 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
69
73
/* 10 to 19 */ 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
70
74
/* 20 to 29 */ 1, 0, 0, 0, 0, 0, 0, 1, 0, 0,
71
/* 30 to 39 */ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
72
/* 40 to 44 */ 0, 0, 0, 0, 0 };
75
/* 30 to 39 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
76
/* 40 to 49 */ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
74
78
/************************************************************************/
75
79
/* pj_transform() */
94
srcdefn->ctx->last_errno = 0;
95
dstdefn->ctx->last_errno = 0;
92
97
if( point_offset == 0 )
95
100
/* -------------------------------------------------------------------- */
101
/* Transform unusual input coordinate axis orientation to */
102
/* standard form if needed. */
103
/* -------------------------------------------------------------------- */
104
if( strcmp(srcdefn->axis,"enu") != 0 )
108
err = pj_adjust_axis( srcdefn->ctx, srcdefn->axis,
109
0, point_count, point_offset, x, y, z );
114
/* -------------------------------------------------------------------- */
115
/* Transform Z to meters if it isn't already. */
116
/* -------------------------------------------------------------------- */
117
if( srcdefn->vto_meter != 1.0 && z != NULL )
119
for( i = 0; i < point_count; i++ )
120
z[point_offset*i] *= srcdefn->vto_meter;
123
/* -------------------------------------------------------------------- */
96
124
/* Transform geocentric source coordinates to lat/long. */
97
125
/* -------------------------------------------------------------------- */
98
126
if( srcdefn->is_geocent )
102
pj_errno = PJD_ERR_GEOCENTRIC;
130
pj_ctx_set_errno( pj_get_ctx(srcdefn), PJD_ERR_GEOCENTRIC);
103
131
return PJD_ERR_GEOCENTRIC;
118
if( pj_geocentric_to_geodetic( srcdefn->a_orig, srcdefn->es_orig,
119
point_count, point_offset,
146
err = pj_geocentric_to_geodetic( srcdefn->a_orig, srcdefn->es_orig,
147
point_count, point_offset,
124
153
/* -------------------------------------------------------------------- */
130
159
if( srcdefn->inv == NULL )
132
pj_errno = -17; /* this isn't correct, we need a no inverse err */
133
if( getenv( "PROJ_DEBUG" ) != NULL )
136
"pj_transform(): source projection not invertable\n" );
161
pj_ctx_set_errno( pj_get_ctx(srcdefn), -17 );
162
pj_log( pj_get_ctx(srcdefn), PJ_LOG_ERROR,
163
"pj_transform(): source projection not invertable" );
141
167
for( i = 0; i < point_count; i++ )
152
178
geodetic_loc = pj_inv( projected_loc, srcdefn );
179
if( srcdefn->ctx->last_errno != 0 )
155
if( (pj_errno != 33 /*EDOM*/ && pj_errno != 34 /*ERANGE*/ )
156
&& (pj_errno > 0 || pj_errno < -44 || point_count == 1
157
|| transient_error[-pj_errno] == 0 ) )
181
if( (srcdefn->ctx->last_errno != 33 /*EDOM*/
182
&& srcdefn->ctx->last_errno != 34 /*ERANGE*/ )
183
&& (srcdefn->ctx->last_errno > 0
184
|| srcdefn->ctx->last_errno < -44 || point_count == 1
185
|| transient_error[-srcdefn->ctx->last_errno] == 0 ) )
186
return srcdefn->ctx->last_errno;
161
189
geodetic_loc.u = HUGE_VAL;
183
211
/* -------------------------------------------------------------------- */
212
/* Do we need to translate from geoid to ellipsoidal vertical */
214
/* -------------------------------------------------------------------- */
215
if( srcdefn->has_geoid_vgrids )
217
if( pj_apply_vgridshift( srcdefn, "sgeoidgrids",
218
&(srcdefn->vgridlist_geoid),
219
&(srcdefn->vgridlist_geoid_count),
220
0, point_count, point_offset, x, y, z ) != 0 )
221
return pj_ctx_get_errno(srcdefn->ctx);
224
/* -------------------------------------------------------------------- */
184
225
/* Convert datums if needed, and possible. */
185
226
/* -------------------------------------------------------------------- */
186
227
if( pj_datum_transform( srcdefn, dstdefn, point_count, point_offset,
230
if( srcdefn->ctx->last_errno != 0 )
231
return srcdefn->ctx->last_errno;
233
return dstdefn->ctx->last_errno;
190
236
/* -------------------------------------------------------------------- */
237
/* Do we need to translate from geoid to ellipsoidal vertical */
239
/* -------------------------------------------------------------------- */
240
if( dstdefn->has_geoid_vgrids )
242
if( pj_apply_vgridshift( dstdefn, "sgeoidgrids",
243
&(dstdefn->vgridlist_geoid),
244
&(dstdefn->vgridlist_geoid_count),
245
1, point_count, point_offset, x, y, z ) != 0 )
246
return dstdefn->ctx->last_errno;
249
/* -------------------------------------------------------------------- */
191
250
/* But if they are staying lat long, adjust for the prime */
192
251
/* meridian if there is one in effect. */
193
252
/* -------------------------------------------------------------------- */
248
307
projected_loc = pj_fwd( geodetic_loc, dstdefn );
308
if( dstdefn->ctx->last_errno != 0 )
251
if( (pj_errno != 33 /*EDOM*/ && pj_errno != 34 /*ERANGE*/ )
252
&& (pj_errno > 0 || pj_errno < -44 || point_count == 1
253
|| transient_error[-pj_errno] == 0 ) )
310
if( (dstdefn->ctx->last_errno != 33 /*EDOM*/
311
&& dstdefn->ctx->last_errno != 34 /*ERANGE*/ )
312
&& (dstdefn->ctx->last_errno > 0
313
|| dstdefn->ctx->last_errno < -44 || point_count == 1
314
|| transient_error[-dstdefn->ctx->last_errno] == 0 ) )
315
return dstdefn->ctx->last_errno;
257
318
projected_loc.u = HUGE_VAL;
268
329
/* If a wrapping center other than 0 is provided, rewrap around */
269
330
/* the suggested center (for latlong coordinate systems only). */
270
331
/* -------------------------------------------------------------------- */
271
else if( dstdefn->is_latlong && dstdefn->long_wrap_center != 0 )
332
else if( dstdefn->is_latlong && dstdefn->is_long_wrap_set )
273
334
for( i = 0; i < point_count; i++ )
275
336
if( x[point_offset*i] == HUGE_VAL )
278
while( x[point_offset*i] < dstdefn->long_wrap_center - HALFPI )
279
x[point_offset*i] += PI;
280
while( x[point_offset*i] > dstdefn->long_wrap_center + HALFPI )
281
x[point_offset*i] -= PI;
339
while( x[point_offset*i] < dstdefn->long_wrap_center - PI )
340
x[point_offset*i] += TWOPI;
341
while( x[point_offset*i] > dstdefn->long_wrap_center + PI )
342
x[point_offset*i] -= TWOPI;
346
/* -------------------------------------------------------------------- */
347
/* Transform Z from meters if needed. */
348
/* -------------------------------------------------------------------- */
349
if( dstdefn->vto_meter != 1.0 && z != NULL )
351
for( i = 0; i < point_count; i++ )
352
z[point_offset*i] *= dstdefn->vfr_meter;
355
/* -------------------------------------------------------------------- */
356
/* Transform normalized axes into unusual output coordinate axis */
357
/* orientation if needed. */
358
/* -------------------------------------------------------------------- */
359
if( strcmp(dstdefn->axis,"enu") != 0 )
363
err = pj_adjust_axis( dstdefn->ctx, dstdefn->axis,
364
1, point_count, point_offset, x, y, z );
308
391
if( pj_Set_Geocentric_Parameters( &gi, a, b ) != 0 )
310
pj_errno = PJD_ERR_GEOCENTRIC;
393
return PJD_ERR_GEOCENTRIC;
314
396
for( i = 0; i < point_count; i++ )
321
403
if( pj_Convert_Geodetic_To_Geocentric( &gi, y[io], x[io], z[io],
322
404
x+io, y+io, z+io ) != 0 )
325
407
x[io] = y[io] = HUGE_VAL;
326
408
/* but keep processing points! */
333
415
/************************************************************************/
351
433
if( pj_Set_Geocentric_Parameters( &gi, a, b ) != 0 )
353
pj_errno = PJD_ERR_GEOCENTRIC;
435
return PJD_ERR_GEOCENTRIC;
357
438
for( i = 0; i < point_count; i++ )
408
489
else if( srcdefn->datum_type == PJD_GRIDSHIFT )
410
return strcmp( pj_param(srcdefn->params,"snadgrids").s,
411
pj_param(dstdefn->params,"snadgrids").s ) == 0;
491
return strcmp( pj_param(srcdefn->ctx, srcdefn->params,"snadgrids").s,
492
pj_param(dstdefn->ctx, dstdefn->params,"snadgrids").s ) == 0;
530
607
double src_a, src_es, dst_a, dst_es;
531
608
int z_is_temp = FALSE;
535
610
/* -------------------------------------------------------------------- */
536
611
/* We cannot do any meaningful datum transformation if either */
537
612
/* the source or destination are of an unknown datum type */
565
640
z_is_temp = TRUE;
568
#define CHECK_RETURN {if( pj_errno != 0 && (pj_errno > 0 || transient_error[-pj_errno] == 0) ) { if( z_is_temp ) pj_dalloc(z); return pj_errno; }}
643
#define CHECK_RETURN(defn) {if( defn->ctx->last_errno != 0 && (defn->ctx->last_errno > 0 || transient_error[-defn->ctx->last_errno] == 0) ) { if( z_is_temp ) pj_dalloc(z); return defn->ctx->last_errno; }}
570
645
/* -------------------------------------------------------------------- */
571
646
/* If this datum requires grid shifts, then apply it to geodetic */
573
648
/* -------------------------------------------------------------------- */
574
649
if( srcdefn->datum_type == PJD_GRIDSHIFT )
576
pj_apply_gridshift( pj_param(srcdefn->params,"snadgrids").s, 0,
577
point_count, point_offset, x, y, z );
651
pj_apply_gridshift_2( srcdefn, 0, point_count, point_offset, x, y, z );
652
CHECK_RETURN(srcdefn);
580
654
src_a = SRS_WGS84_SEMIMAJOR;
581
655
src_es = SRS_WGS84_ESQUARED;
586
660
dst_a = SRS_WGS84_SEMIMAJOR;
587
661
dst_es = SRS_WGS84_ESQUARED;
590
664
/* ==================================================================== */
591
665
/* Do we need to go through geocentric coordinates? */
592
666
/* ==================================================================== */
599
673
/* -------------------------------------------------------------------- */
600
674
/* Convert to geocentric coordinates. */
601
675
/* -------------------------------------------------------------------- */
602
pj_geodetic_to_geocentric( src_a, src_es,
603
point_count, point_offset, x, y, z );
676
srcdefn->ctx->last_errno =
677
pj_geodetic_to_geocentric( src_a, src_es,
678
point_count, point_offset, x, y, z );
679
CHECK_RETURN(srcdefn);
606
681
/* -------------------------------------------------------------------- */
607
682
/* Convert between datums. */
610
685
|| srcdefn->datum_type == PJD_7PARAM )
612
687
pj_geocentric_to_wgs84( srcdefn, point_count, point_offset,x,y,z);
688
CHECK_RETURN(srcdefn);
616
691
if( dstdefn->datum_type == PJD_3PARAM
617
692
|| dstdefn->datum_type == PJD_7PARAM )
619
694
pj_geocentric_from_wgs84( dstdefn, point_count,point_offset,x,y,z);
695
CHECK_RETURN(dstdefn);
623
698
/* -------------------------------------------------------------------- */
624
699
/* Convert back to geodetic coordinates. */
625
700
/* -------------------------------------------------------------------- */
626
pj_geocentric_to_geodetic( dst_a, dst_es,
627
point_count, point_offset, x, y, z );
701
dstdefn->ctx->last_errno =
702
pj_geocentric_to_geodetic( dst_a, dst_es,
703
point_count, point_offset, x, y, z );
704
CHECK_RETURN(dstdefn);
631
707
/* -------------------------------------------------------------------- */
633
709
/* -------------------------------------------------------------------- */
634
710
if( dstdefn->datum_type == PJD_GRIDSHIFT )
636
pj_apply_gridshift( pj_param(dstdefn->params,"snadgrids").s, 1,
637
point_count, point_offset, x, y, z );
712
pj_apply_gridshift_2( dstdefn, 1, point_count, point_offset, x, y, z );
713
CHECK_RETURN(dstdefn);
722
/************************************************************************/
723
/* pj_adjust_axis() */
725
/* Normalize or de-normalized the x/y/z axes. The normal form */
726
/* is "enu" (easting, northing, up). */
727
/************************************************************************/
728
static int pj_adjust_axis( projCtx ctx,
729
const char *axis, int denormalize_flag,
730
long point_count, int point_offset,
731
double *x, double *y, double *z )
734
double x_in, y_in, z_in = 0.0;
737
if( !denormalize_flag )
739
for( i = 0; i < point_count; i++ )
741
x_in = x[point_offset*i];
742
y_in = y[point_offset*i];
744
z_in = z[point_offset*i];
746
for( i_axis = 0; i_axis < 3; i_axis++ )
752
else if( i_axis == 1 )
757
switch( axis[i_axis] )
760
x[point_offset*i] = value; break;
762
x[point_offset*i] = -value; break;
764
y[point_offset*i] = value; break;
766
y[point_offset*i] = -value; break;
768
if( z ) z[point_offset*i] = value; break;
770
if( z ) z[point_offset*i] = -value; break;
772
pj_ctx_set_errno( ctx, PJD_ERR_AXIS );
779
else /* denormalize */
781
for( i = 0; i < point_count; i++ )
783
x_in = x[point_offset*i];
784
y_in = y[point_offset*i];
786
z_in = z[point_offset*i];
788
for( i_axis = 0; i_axis < 3; i_axis++ )
792
if( i_axis == 2 && z == NULL )
797
else if( i_axis == 1 )
802
switch( axis[i_axis] )
805
target[point_offset*i] = x_in; break;
807
target[point_offset*i] = -x_in; break;
809
target[point_offset*i] = y_in; break;
811
target[point_offset*i] = -y_in; break;
813
target[point_offset*i] = z_in; break;
815
target[point_offset*i] = -z_in; break;
817
pj_ctx_set_errno( ctx, PJD_ERR_AXIS );