44int get_pj_area(
const struct pj_info *iproj,
double *xmin,
double *xmax,
45 double *ymin,
double *ymax)
47 struct Cell_head window;
57 if (window.proj != PROJECTION_LL) {
62 const char *projstr =
NULL;
64 struct pj_info oproj, tproj;
70 if (proj_get_type(iproj->pj) == PJ_TYPE_BOUND_CRS) {
73 source_crs = proj_get_source_crs(
NULL, iproj->pj);
76 proj_as_proj_string(
NULL, source_crs, PJ_PROJ_5,
NULL);
80 proj_destroy(source_crs);
84 projstr = proj_as_proj_string(
NULL, iproj->pj, PJ_PROJ_5,
NULL);
96 G_asprintf(&tproj.def,
"+proj=pipeline +step +inv %s +over", indef);
97 G_debug(1,
"get_pj_area() tproj.def: %s", tproj.def);
98 tproj.pj = proj_create(PJ_DEFAULT_CTX, tproj.def);
100 if (tproj.pj ==
NULL) {
101 G_warning(_(
"proj_create() failed for '%s'"), tproj.def);
104 proj_destroy(tproj.pj);
108 projstr = proj_as_proj_string(
NULL, tproj.pj, PJ_PROJ_5,
NULL);
109 if (projstr ==
NULL) {
110 G_warning(_(
"proj_create() failed for '%s'"), tproj.def);
113 proj_destroy(tproj.pj);
118 G_debug(1,
"proj_create() projstr '%s'", projstr);
124 estep = (window.east - window.west) / 21.;
125 nstep = (window.north - window.south) / 21.;
126 for (i = 0; i < 20; i++) {
127 x[i] = window.west + estep * (i + 1);
130 x[i + 20] = window.west + estep * (i + 1);
131 y[i + 20] = window.south;
133 x[i + 40] = window.west;
134 y[i + 40] = window.south + nstep * (i + 1);
136 x[i + 60] = window.east;
137 y[i + 60] = window.south + nstep * (i + 1);
140 y[80] = window.north;
142 y[81] = window.south;
144 y[82] = window.north;
146 y[83] = window.south;
147 x[84] = (window.west + window.east) / 2.;
148 y[84] = (window.north + window.south) / 2.;
152 proj_destroy(tproj.pj);
155 *xmin = *xmax =
x[84];
156 *ymin = *ymax = y[84];
157 for (i = 0; i < 84; i++) {
172 if (*xmin < -180 && *xmax < 180 && *xmin + 360 > *xmax) {
176 else if (*xmax > 180 && *xmin > -180 && *xmax - 360 < *xmin) {
181 G_debug(1,
"input window north: %.8f", window.north);
182 G_debug(1,
"input window south: %.8f", window.south);
183 G_debug(1,
"input window east: %.8f", window.east);
184 G_debug(1,
"input window west: %.8f", window.west);
186 G_debug(1,
"transformed xmin: %.8f", *xmin);
187 G_debug(1,
"transformed xmax: %.8f", *xmax);
188 G_debug(1,
"transformed ymin: %.8f", *ymin);
189 G_debug(1,
"transformed ymax: %.8f", *ymax);
195 if (fabs(*xmin) > 180) {
196 G_warning(_(
"Invalid west longitude %g"), *xmin);
199 if (fabs(*xmax) > 180) {
200 G_warning(_(
"Invalid east longitude %g"), *xmax);
203 if (fabs(*ymin) > 90) {
204 G_warning(_(
"Invalid south latitude %g"), *ymin);
207 if (fabs(*ymax) > 90) {
208 G_warning(_(
"Invalid north latitude %g"), *ymax);
212 G_warning(_(
"South %g is larger than north %g"), *ymin, *ymax);
216 G_debug(1,
"get_pj_area(): xmin %g, xmax %g, ymin %g, ymax %g", *xmin,
217 *xmax, *ymin, *ymax);
323 G_debug(1,
"Trying SRID '%s' ...", in_gpj->srid);
324 in_pj = proj_create(PJ_DEFAULT_CTX, in_gpj->srid);
326 G_warning(_(
"Unrecognized SRID '%s'"), in_gpj->srid);
329 *in_defstr =
G_store(in_gpj->srid);
333 ((
struct pj_info *)in_gpj)->meters = 1;
336 if (!in_pj && in_gpj->wkt) {
337 G_debug(1,
"Trying WKT '%s' ...", in_gpj->wkt);
338 in_pj = proj_create(PJ_DEFAULT_CTX, in_gpj->wkt);
340 G_warning(_(
"Unrecognized WKT '%s'"), in_gpj->wkt);
343 *in_defstr =
G_store(in_gpj->wkt);
347 ((
struct pj_info *)in_gpj)->meters = 1;
350 if (!in_pj && in_gpj->pj) {
351 in_pj = proj_clone(PJ_DEFAULT_CTX, in_gpj->pj);
353 if (*in_defstr && !**in_defstr)
358 G_warning(_(
"Unable to create PROJ object"));
374 if (proj_get_type(in_pj) == PJ_TYPE_BOUND_CRS) {
378 source_crs = proj_get_source_crs(
NULL, in_pj);
382 if (*in_defstr && !**in_defstr)
426 const struct pj_info *info_out,
427 struct pj_info *info_trans)
429 if (info_in->pj ==
NULL)
432 if (info_in->def ==
NULL)
433 G_fatal_error(_(
"Input coordinate system definition is NULL"));
438 info_trans->pj =
NULL;
439 info_trans->meters = 1.;
440 info_trans->zone = 0;
441 snprintf(info_trans->proj,
sizeof(info_trans->proj),
"pipeline");
444 if (info_trans->def) {
449 if (!info_in->pj || !info_in->proj[0] || !info_out->pj ||
450 !info_out->proj[0]) {
452 "A custom pipeline requires input and output projection info"));
458 info_trans->pj = proj_create(PJ_DEFAULT_CTX, info_trans->def);
459 if (info_trans->pj ==
NULL) {
460 G_warning(_(
"proj_create() failed for '%s'"), info_trans->def);
464 projstr = proj_as_proj_string(
NULL, info_trans->pj, PJ_PROJ_5,
NULL);
465 if (projstr ==
NULL) {
466 G_warning(_(
"proj_create() failed for '%s'"), info_trans->def);
476 info_trans->def =
G_store(projstr);
478 if (strstr(info_trans->def,
"axisswap")) {
480 _(
"The transformation pipeline contains an '%s' step. "
481 "Remove this step if easting and northing are swapped in "
486 G_debug(1,
"proj_create() pipeline: %s", info_trans->def);
491 ((
struct pj_info *)info_in)->meters = 1;
492 ((
struct pj_info *)info_out)->meters = 1;
497 else if (info_out->pj ==
NULL) {
498 const char *projstr =
NULL;
503 G_debug(1,
"ll equivalent definition: %s", indef);
508 G_asprintf(&(info_trans->def),
"+proj=pipeline +step +inv %s", indef);
509 info_trans->pj = proj_create(PJ_DEFAULT_CTX, info_trans->def);
510 if (info_trans->pj ==
NULL) {
511 G_warning(_(
"proj_create() failed for '%s'"), info_trans->def);
516 projstr = proj_as_proj_string(
NULL, info_trans->pj, PJ_PROJ_5,
NULL);
517 if (projstr ==
NULL) {
518 G_warning(_(
"proj_create() failed for '%s'"), info_trans->def);
526 else if (info_in->def && info_out->pj && info_out->def) {
528 char *insrid =
NULL, *outsrid =
NULL;
530 PJ_OBJ_LIST *op_list;
531 PJ_OPERATION_FACTORY_CONTEXT *operation_ctx;
532 PJ_AREA *pj_area =
NULL;
533 double xmin, xmax, ymin, ymax;
534 int op_count = 0, op_count_area = 0;
540 if (
get_pj_area(info_in, &xmin, &xmax, &ymin, &ymax)) {
541 pj_area = proj_area_create();
542 proj_area_set_bbox(pj_area, xmin, ymin, xmax, ymax);
545 G_warning(_(
"Unable to determine area of interest for '%s'"),
551 G_debug(1,
"source proj string: %s", info_in->def);
556 if (strncmp(info_in->srid,
"epsg", 4) == 0) {
559 ((
struct pj_info *)info_in)->srid = insrid;
565 if (in_pj ==
NULL || indef ==
NULL) {
566 G_warning(_(
"Input CRS not available for '%s'"), info_in->def);
570 G_debug(1,
"Input CRS definition: %s", indef);
572 G_debug(1,
"target proj string: %s", info_out->def);
576 if (info_out->srid) {
577 if (strncmp(info_out->srid,
"epsg", 4) == 0) {
580 ((
struct pj_info *)info_out)->srid = outsrid;
586 if (out_pj ==
NULL || outdef ==
NULL) {
587 G_warning(_(
"Output CRS not available for '%s'"), info_out->def);
591 G_debug(1,
"Output CRS definition: %s", outdef);
596 proj_create_operation_factory_context(PJ_DEFAULT_CTX,
NULL);
603 op_list = proj_create_operations(PJ_DEFAULT_CTX, in_pj, out_pj,
605 proj_operation_factory_context_destroy(operation_ctx);
609 op_count = proj_list_get_count(op_list);
615 for (i = 0; i < op_count; i++) {
616 const char *area_of_use, *projstr;
618 PJ_PROJ_INFO pj_info;
621 op = proj_list_get(PJ_DEFAULT_CTX, op_list, i);
622 op_norm = proj_normalize_for_visualization(PJ_DEFAULT_CTX, op);
625 G_warning(_(
"proj_normalize_for_visualization() failed for "
634 pj_info = proj_pj_info(op);
635 proj_get_area_of_use(
NULL, op, &w, &s, &e, &n, &area_of_use);
638 if (pj_info.description) {
640 pj_info.description);
646 if (pj_info.accuracy > 0) {
651 const char *str = proj_get_remarks(op);
657 str = proj_get_scope(op);
663 projstr = proj_as_proj_string(
NULL, op, PJ_PROJ_5,
NULL);
677 "with the %s option"),
683 proj_list_destroy(op_list);
707 proj_create_operation_factory_context(PJ_DEFAULT_CTX,
NULL);
708 proj_operation_factory_context_set_area_of_interest(
709 PJ_DEFAULT_CTX, operation_ctx, xmin, ymin, xmax, ymax);
710 proj_operation_factory_context_set_spatial_criterion(
711 PJ_DEFAULT_CTX, operation_ctx,
712 PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION);
714 proj_operation_factory_context_set_grid_availability_use(
715 PJ_DEFAULT_CTX, operation_ctx,
716 proj_context_is_network_enabled(PJ_DEFAULT_CTX)
717 ? PROJ_GRID_AVAILABILITY_KNOWN_AVAILABLE
718 : PROJ_GRID_AVAILABILITY_DISCARD_OPERATION_IF_MISSING_GRID);
728 op_list = proj_create_operations(PJ_DEFAULT_CTX, in_pj, out_pj,
730 proj_operation_factory_context_destroy(operation_ctx);
733 op_count_area = proj_list_get_count(op_list);
734 if (op_count_area == 0) {
736 info_trans->pj =
NULL;
738 else if (op_count_area == 1) {
739 info_trans->pj = proj_list_get(PJ_DEFAULT_CTX, op_list, 0);
745 info_trans->pj = proj_list_get(PJ_DEFAULT_CTX, op_list, 0);
748 proj_list_destroy(op_list);
774 proj_destroy(out_pj);
776 if (info_trans->pj) {
780 G_debug(1,
"proj_create_crs_to_crs() succeeded with PROJ%d",
784 proj_as_proj_string(
NULL, info_trans->pj, PJ_PROJ_5,
NULL);
786 info_trans->def =
G_store(projstr);
794 pj_norm = proj_normalize_for_visualization(PJ_DEFAULT_CTX,
799 _(
"proj_normalize_for_visualization() failed for '%s'"),
804 proj_as_proj_string(
NULL, pj_norm, PJ_PROJ_5,
NULL);
805 if (projstr && *projstr) {
806 proj_destroy(info_trans->pj);
807 info_trans->pj = pj_norm;
808 info_trans->def =
G_store(projstr);
811 proj_destroy(pj_norm);
812 G_warning(_(
"No PROJ definition for normalized version "
822 proj_destroy(info_trans->pj);
823 info_trans->pj =
NULL;
828 proj_area_destroy(pj_area);
837 if (info_trans->pj ==
NULL) {
838 G_warning(_(
"proj_create() failed for '%s'"), info_trans->def);
873int GPJ_transform(
const struct pj_info *info_in,
const struct pj_info *info_out,
874 const struct pj_info *info_trans,
int dir,
double *
x,
875 double *y,
double *z)
879 int in_is_ll, out_is_ll, in_deg2rad, out_rad2deg;
882 if (info_in->pj ==
NULL)
885 if (info_trans->pj ==
NULL)
888 in_deg2rad = out_rad2deg = 1;
891 METERS_in = info_in->meters;
892 in_is_ll = !strncmp(info_in->proj,
"ll", 2);
896 if (in_is_ll && proj_angular_input(info_trans->pj, dir) == 0) {
900 METERS_out = info_out->meters;
901 out_is_ll = !strncmp(info_out->proj,
"ll", 2);
905 if (out_is_ll && proj_angular_output(info_trans->pj, dir) == 0) {
916 METERS_out = info_in->meters;
917 out_is_ll = !strncmp(info_in->proj,
"ll", 2);
921 if (out_is_ll && proj_angular_output(info_trans->pj, dir) == 0) {
925 METERS_in = info_out->meters;
926 in_is_ll = !strncmp(info_out->proj,
"ll", 2);
930 if (in_is_ll && proj_angular_input(info_trans->pj, dir) == 0) {
944 c.lpzt.lam = (*x) / RAD_TO_DEG;
945 c.lpzt.phi = (*y) / RAD_TO_DEG;
958 c.xyzt.x = *
x * METERS_in;
959 c.xyzt.y = *y * METERS_in;
966 G_debug(1,
"c.xyzt.x: %g", c.xyzt.x);
967 G_debug(1,
"c.xyzt.y: %g", c.xyzt.y);
968 G_debug(1,
"c.xyzt.z: %g", c.xyzt.z);
971 c = proj_trans(info_trans->pj, dir, c);
972 ok = proj_errno(info_trans->pj);
975 G_warning(_(
"proj_trans() failed: %s"), proj_errno_string(ok));
984 *
x = c.lp.lam * RAD_TO_DEG;
985 *y = c.lp.phi * RAD_TO_DEG;
996 *
x = c.xyzt.x / METERS_out;
997 *y = c.xyzt.y / METERS_out;
1032 const struct pj_info *info_out,
1033 const struct pj_info *info_trans,
int dir,
double *
x,
1034 double *y,
double *z,
int n)
1041 int in_is_ll, out_is_ll, in_deg2rad, out_rad2deg;
1044 if (info_trans->pj ==
NULL)
1047 in_deg2rad = out_rad2deg = 1;
1048 if (dir == PJ_FWD) {
1050 METERS_in = info_in->meters;
1051 in_is_ll = !strncmp(info_in->proj,
"ll", 2);
1055 if (in_is_ll && proj_angular_input(info_trans->pj, dir) == 0) {
1059 METERS_out = info_out->meters;
1060 out_is_ll = !strncmp(info_out->proj,
"ll", 2);
1064 if (out_is_ll && proj_angular_output(info_trans->pj, dir) == 0) {
1075 METERS_out = info_in->meters;
1076 out_is_ll = !strncmp(info_in->proj,
"ll", 2);
1080 if (out_is_ll && proj_angular_output(info_trans->pj, dir) == 0) {
1084 METERS_in = info_out->meters;
1085 in_is_ll = !strncmp(info_out->proj,
"ll", 2);
1089 if (in_is_ll && proj_angular_input(info_trans->pj, dir) == 0) {
1100 z = G_malloc(
sizeof(
double) * n);
1102 for (i = 0; i < n; i++)
1117 for (i = 0; i < n; i++) {
1120 c.lpzt.lam = (*x) / RAD_TO_DEG;
1121 c.lpzt.phi = (*y) / RAD_TO_DEG;
1128 c = proj_trans(info_trans->pj, dir, c);
1129 if ((ok = proj_errno(info_trans->pj)) < 0)
1133 x[i] = c.lp.lam * RAD_TO_DEG;
1134 y[i] = c.lp.phi * RAD_TO_DEG;
1143 for (i = 0; i < n; i++) {
1146 c.lpzt.lam = (*x) / RAD_TO_DEG;
1147 c.lpzt.phi = (*y) / RAD_TO_DEG;
1154 c = proj_trans(info_trans->pj, dir, c);
1155 if ((ok = proj_errno(info_trans->pj)) < 0)
1159 x[i] = c.xy.x / METERS_out;
1160 y[i] = c.xy.y / METERS_out;
1167 for (i = 0; i < n; i++) {
1169 c.xyzt.x =
x[i] * METERS_in;
1170 c.xyzt.y = y[i] * METERS_in;
1172 c = proj_trans(info_trans->pj, dir, c);
1173 if ((ok = proj_errno(info_trans->pj)) < 0)
1177 x[i] = c.lp.lam * RAD_TO_DEG;
1178 y[i] = c.lp.phi * RAD_TO_DEG;
1187 for (i = 0; i < n; i++) {
1189 c.xyzt.x =
x[i] * METERS_in;
1190 c.xyzt.y = y[i] * METERS_in;
1192 c = proj_trans(info_trans->pj, dir, c);
1193 if ((ok = proj_errno(info_trans->pj)) < 0)
1196 x[i] = c.xy.x / METERS_out;
1197 y[i] = c.xy.y / METERS_out;
1205 G_warning(_(
"proj_trans() failed: %s"), proj_errno_string(ok));
1233 const struct pj_info *info_out)
1237 struct pj_info info_trans;
1244 METERS_in = info_in->meters;
1245 METERS_out = info_out->meters;
1247 if (strncmp(info_in->proj,
"ll", 2) == 0) {
1249 c.lpzt.lam = (*x) / RAD_TO_DEG;
1250 c.lpzt.phi = (*y) / RAD_TO_DEG;
1253 c = proj_trans(info_trans.pj, PJ_FWD, c);
1254 ok = proj_errno(info_trans.pj);
1256 if (strncmp(info_out->proj,
"ll", 2) == 0) {
1258 *
x = c.lp.lam * RAD_TO_DEG;
1259 *y = c.lp.phi * RAD_TO_DEG;
1263 *
x = c.xy.x / METERS_out;
1264 *y = c.xy.y / METERS_out;
1269 c.xyzt.x = *
x * METERS_in;
1270 c.xyzt.y = *y * METERS_in;
1273 c = proj_trans(info_trans.pj, PJ_FWD, c);
1274 ok = proj_errno(info_trans.pj);
1276 if (strncmp(info_out->proj,
"ll", 2) == 0) {
1278 *
x = c.lp.lam * RAD_TO_DEG;
1279 *y = c.lp.phi * RAD_TO_DEG;
1283 *
x = c.xy.x / METERS_out;
1284 *y = c.xy.y / METERS_out;
1287 proj_destroy(info_trans.pj);
1290 G_warning(_(
"proj_trans() failed: %d"), ok);
1319 const struct pj_info *info_in,
1320 const struct pj_info *info_out)
1326 struct pj_info info_trans;
1333 METERS_in = info_in->meters;
1334 METERS_out = info_out->meters;
1337 h = G_malloc(
sizeof *h *
count);
1339 for (i = 0; i <
count; ++i)
1344 if (strncmp(info_in->proj,
"ll", 2) == 0) {
1346 if (strncmp(info_out->proj,
"ll", 2) == 0) {
1347 for (i = 0; i <
count; i++) {
1349 c.lpzt.lam =
x[i] / RAD_TO_DEG;
1350 c.lpzt.phi = y[i] / RAD_TO_DEG;
1352 c = proj_trans(info_trans.pj, PJ_FWD, c);
1353 if ((ok = proj_errno(info_trans.pj)) < 0)
1356 x[i] = c.lp.lam * RAD_TO_DEG;
1357 y[i] = c.lp.phi * RAD_TO_DEG;
1361 for (i = 0; i <
count; i++) {
1363 c.lpzt.lam =
x[i] / RAD_TO_DEG;
1364 c.lpzt.phi = y[i] / RAD_TO_DEG;
1366 c = proj_trans(info_trans.pj, PJ_FWD, c);
1367 if ((ok = proj_errno(info_trans.pj)) < 0)
1370 x[i] = c.xy.x / METERS_out;
1371 y[i] = c.xy.y / METERS_out;
1377 if (strncmp(info_out->proj,
"ll", 2) == 0) {
1378 for (i = 0; i <
count; i++) {
1380 c.xyzt.x =
x[i] * METERS_in;
1381 c.xyzt.y = y[i] * METERS_in;
1383 c = proj_trans(info_trans.pj, PJ_FWD, c);
1384 if ((ok = proj_errno(info_trans.pj)) < 0)
1387 x[i] = c.lp.lam * RAD_TO_DEG;
1388 y[i] = c.lp.phi * RAD_TO_DEG;
1392 for (i = 0; i <
count; i++) {
1394 c.xyzt.x =
x[i] * METERS_in;
1395 c.xyzt.y = y[i] * METERS_in;
1397 c = proj_trans(info_trans.pj, PJ_FWD, c);
1398 if ((ok = proj_errno(info_trans.pj)) < 0)
1401 x[i] = c.xy.x / METERS_out;
1402 y[i] = c.xy.y / METERS_out;
1408 proj_destroy(info_trans.pj);
1411 G_warning(_(
"proj_trans() failed: %d"), ok);