@@ -104,6 +104,8 @@ Thomas Knudsen, thokn@sdfe.dk, 2017-10-01/2017-10-08
104104
105105***********************************************************************/
106106
107+ #define FROM_PROJ_CPP
108+
107109#include < ctype.h>
108110#include < errno.h>
109111#include < math.h>
@@ -116,9 +118,13 @@ Thomas Knudsen, thokn@sdfe.dk, 2017-10-01/2017-10-08
116118#include " proj.h"
117119#include " proj_internal.h"
118120#include " proj_strtod.h"
121+
122+ #include < algorithm>
119123#include < cmath> /* for isnan */
120124#include < math.h>
121125
126+ #include < proj/internal/internal.hpp>
127+
122128#include " optargpm.h"
123129
124130/* Package for flexible format I/O - ffio */
@@ -192,6 +198,7 @@ typedef struct {
192198 char crs_dst[MAX_OPERATION + 1 ];
193199 char crs_src[MAX_OPERATION + 1 ];
194200 PJ *P;
201+ bool crs_dst_is_lat_lon_or_y_x;
195202 PJ_COORD a, b, e;
196203 PJ_DIRECTION dir;
197204 int verbosity;
@@ -561,6 +568,21 @@ static int require_grid(const char *args) {
561568 const char *grid_filename = column (args, 1 );
562569 grid_info = proj_grid_info (grid_filename);
563570 if (strlen (grid_info.filename ) == 0 ) {
571+
572+ if (proj_context_is_network_enabled (nullptr )) {
573+ auto dbContext = NS_PROJ::io::DatabaseContext::create ();
574+ std::string fullFilename, packageName, url;
575+ bool directDownload, openLicense, gridAvailable = false ;
576+ if (dbContext->lookForGridInfo (
577+ grid_filename,
578+ /* considerKnownGridsAsAvailable = */ true , fullFilename,
579+ packageName, url, directDownload, openLicense,
580+ gridAvailable) &&
581+ gridAvailable) {
582+ return 0 ;
583+ }
584+ }
585+
564586 if (T.verbosity > 1 ) {
565587 fprintf (T.fout , " Test skipped because of missing grid %s\n " ,
566588 grid_filename);
@@ -644,6 +666,56 @@ static int operation(const char *args) {
644666 return 0 ;
645667}
646668
669+ static bool isLatOrNorthingFirst (const PJ *crs) {
670+ auto crsType = proj_get_type (crs);
671+
672+ if (crsType == PJ_TYPE_COMPOUND_CRS) {
673+ auto horiz_crs = proj_crs_get_sub_crs (nullptr , crs, 0 );
674+ assert (horiz_crs);
675+ bool ret = isLatOrNorthingFirst (horiz_crs);
676+ proj_destroy (horiz_crs);
677+ return ret;
678+ }
679+
680+ if (crsType != PJ_TYPE_GEOGRAPHIC_2D_CRS &&
681+ crsType != PJ_TYPE_GEOGRAPHIC_3D_CRS &&
682+ crsType != PJ_TYPE_GEOCENTRIC_CRS && crsType != PJ_TYPE_PROJECTED_CRS) {
683+ fprintf (stderr, " Bug in gie.cpp:%d: unsupported CRS type %d!\n " ,
684+ __LINE__, crsType);
685+ return false ;
686+ }
687+
688+ auto cs = proj_crs_get_coordinate_system (nullptr , crs);
689+ assert (cs);
690+
691+ const char *axisName = " " ;
692+ const char *unitName = " " ;
693+ proj_cs_get_axis_info (nullptr , cs, 0 ,
694+ &axisName, // name,
695+ nullptr , // abbrev
696+ nullptr , // direction
697+ nullptr , // unit conv factor
698+ &unitName, // unit name
699+ nullptr , // unit authority
700+ nullptr // unit code
701+ );
702+ const bool isLatOrNorthingFirst =
703+ NS_PROJ::internal::ci_find (std::string(axisName), "latitude") !=
704+ std::string::npos ||
705+ NS_PROJ::internal::ci_find(std::string(axisName), "northing") !=
706+ std::string::npos;
707+ proj_destroy (cs);
708+
709+ if (strcmp (unitName, " degree" ) != 0 && strcmp (unitName, " metre" ) != 0 ) {
710+ // We should add normalization to this unit in expect()
711+ fprintf (stderr, " Bug in gie.cpp:%d: unsupported unit %s!\n " , __LINE__,
712+ unitName);
713+ return false ;
714+ }
715+
716+ return isLatOrNorthingFirst;
717+ }
718+
647719static int crs_to_crs_operation () {
648720 T.op_id ++;
649721 T.operation_lineno = F->lineno ;
@@ -671,6 +743,14 @@ static int crs_to_crs_operation() {
671743 proj_errno_reset (nullptr );
672744 proj_context_use_proj4_init_rules (nullptr , T.use_proj4_init_rules );
673745
746+ T.crs_dst_is_lat_lon_or_y_x = false ;
747+ PJ *pj_dst = proj_create (nullptr , T.crs_dst );
748+ if (!pj_dst) {
749+ fprintf (stderr, " Cannot instantiate crs_dst = %s\n " , T.crs_dst );
750+ }
751+ T.crs_dst_is_lat_lon_or_y_x = isLatOrNorthingFirst (pj_dst);
752+ proj_destroy (pj_dst);
753+
674754 T.P = proj_create_crs_to_crs (nullptr , T.crs_src , T.crs_dst , nullptr );
675755
676756 strcpy (T.crs_src , " " );
@@ -925,18 +1005,6 @@ static int expect_failure_with_errno_message(int expected, int got) {
9251005 return 1 ;
9261006}
9271007
928- /* For test purposes, we want to call a transformation of the same */
929- /* dimensionality as the number of dimensions given in accept */
930- static PJ_COORD expect_trans_n_dim (const PJ_COORD &ci) {
931- if (4 == T.dimensions_given_at_last_accept )
932- return proj_trans (T.P , T.dir , ci);
933-
934- if (3 == T.dimensions_given_at_last_accept )
935- return pj_approx_3D_trans (T.P , T.dir , ci);
936-
937- return pj_approx_2D_trans (T.P , T.dir , ci);
938- }
939-
9401008/* ****************************************************************************/
9411009static int expect (const char *args) {
9421010 /* ****************************************************************************
@@ -989,7 +1057,7 @@ static int expect(const char *args) {
9891057 /* Try to carry out the operation - and expect failure */
9901058 ci =
9911059 proj_angular_input (T.P , T.dir ) ? torad_coord (T.P , T.dir , T.a ) : T.a ;
992- co = expect_trans_n_dim ( ci);
1060+ co = proj_trans (T. P , T. dir , ci);
9931061
9941062 if (expect_failure_with_errno) {
9951063 if (proj_errno (T.P ) == expect_failure_with_errno)
@@ -1043,7 +1111,7 @@ static int expect(const char *args) {
10431111
10441112 /* do the transformation, but mask off dimensions not given in expect-ation
10451113 */
1046- co = expect_trans_n_dim ( ci);
1114+ co = proj_trans (T. P , T. dir , ci);
10471115 if (T.dimensions_given < 4 )
10481116 co.v [3 ] = 0 ;
10491117 if (T.dimensions_given < 3 )
@@ -1056,23 +1124,68 @@ static int expect(const char *args) {
10561124 co.v [1 ], co.v [2 ], co.v [3 ]);
10571125
10581126#if 0
1059- /* We need to handle unusual axis orders - that'll be an item for version 5.1 */
1127+ /* We need to handle unusual axis orders when axisswap explicitly present.
1128+ * Otherwise when using dst_crs code below will take care of that.
1129+ */
10601130 if (T.P->axisswap) {
10611131 ce = proj_trans (T.P->axisswap, T.dir, ce);
10621132 co = proj_trans (T.P->axisswap, T.dir, co);
10631133 }
10641134#endif
1135+
10651136 if (std::isnan (co.v [0 ]) && std::isnan (ce.v [0 ])) {
10661137 d = 0.0 ;
1067- } else if (proj_angular_output (T.P , T.dir )) {
1138+ } else if (proj_angular_output (T.P , T.dir )) { // angular = radians...
1139+ d = proj_lpz_dist (T.P , ce, co);
1140+ } else if (proj_degree_output (T.P , T.dir )) {
1141+ co.v [0 ] = proj_torad (co.v [0 ]);
1142+ co.v [1 ] = proj_torad (co.v [1 ]);
1143+
1144+ ce.v [0 ] = proj_torad (ce.v [0 ]);
1145+ ce.v [1 ] = proj_torad (ce.v [1 ]);
1146+
1147+ if (T.crs_dst_is_lat_lon_or_y_x ) {
1148+ std::swap (co.v [0 ], co.v [1 ]);
1149+ std::swap (ce.v [0 ], ce.v [1 ]);
1150+ }
1151+
10681152 d = proj_lpz_dist (T.P , ce, co);
10691153 } else {
1070- d = proj_xyz_dist (co, ce);
1154+
1155+ if (T.crs_dst_is_lat_lon_or_y_x ) {
1156+ std::swap (co.v [0 ], co.v [1 ]);
1157+ std::swap (ce.v [0 ], ce.v [1 ]);
1158+ }
1159+
1160+ d = proj_xyz_dist (ce, co);
10711161 }
10721162
10731163 // Test written like that to handle NaN
10741164 if (!(d <= T.tolerance ))
10751165 return expect_message (d, args);
1166+
1167+ // Somewhat arbitrary temporal theshold but should be fine for all intended
1168+ // purposes.
1169+ constexpr double TEMPORAL_THESHOLD_IN_YEAR = 1e-4 ;
1170+ if (T.dimensions_given == 4 &&
1171+ std::fabs (ce.v [3 ] - co.v [3 ]) > TEMPORAL_THESHOLD_IN_YEAR) {
1172+ another_failure ();
1173+
1174+ if (T.verbosity < 0 )
1175+ return 1 ;
1176+ if (0 == T.op_ko && T.verbosity < 2 )
1177+ banner (T.operation );
1178+ fprintf (T.fout , " %s" , T.op_ko ? " -----\n " : delim);
1179+ fprintf (T.fout , " FAILURE in %s(%d):\n " ,
1180+ opt_strip_path (T.curr_file ), (int )F->lineno );
1181+ fprintf (T.fout , " expected: %s\n " , args);
1182+ fprintf (T.fout , " got: %.12f %.12f %.9f %.9f\n " ,
1183+ T.b .v [0 ], T.b .v [1 ], T.b .v [2 ], T.b .v [3 ]);
1184+ fprintf (T.fout , " deviation: %.4f year, %.4f maximum allowed\n " ,
1185+ std::fabs (ce.v [3 ] - co.v [3 ]), TEMPORAL_THESHOLD_IN_YEAR);
1186+ return 1 ;
1187+ }
1188+
10761189 succs++;
10771190
10781191 another_success ();
0 commit comments