aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2019-11-18 21:04:59 +0100
committerEven Rouault <even.rouault@spatialys.com>2019-11-18 21:04:59 +0100
commit2b9b65d0ffbe685fc33857df0f48a387d4611483 (patch)
tree84961ed372c3d06ad9a04a0af14c3a1e5560039f /src
parentee71b3412868a08c91d46066ddc39d30b08442d6 (diff)
downloadPROJ-2b9b65d0ffbe685fc33857df0f48a387d4611483.tar.gz
PROJ-2b9b65d0ffbe685fc33857df0f48a387d4611483.zip
proj_trans(): tune selection of operation when there are several alternatives, to select the operation with best accuracy
Diffstat (limited to 'src')
-rw-r--r--src/4D_api.cpp68
-rw-r--r--src/iso19111/c_api.cpp2
-rw-r--r--src/proj_internal.h20
3 files changed, 61 insertions, 29 deletions
diff --git a/src/4D_api.cpp b/src/4D_api.cpp
index 039788be..26e9456e 100644
--- a/src/4D_api.cpp
+++ b/src/4D_api.cpp
@@ -193,40 +193,58 @@ similarly, but prefers the 2D resp. 3D interfaces if available.
direction = opposite_direction(direction);
if( !P->alternativeCoordinateOperations.empty() ) {
- // Do a first pass and select the first coordinate operation whose area
- // of use is compatible with the input coordinate
+ // Do a first pass and select the operations that match the area of use
+ // and has the best accuracy.
+ int iBest = -1;
+ double bestAccuracy = std::numeric_limits<double>::max();
int i = 0;
for( const auto &alt: P->alternativeCoordinateOperations ) {
+ bool spatialCriterionOK = false;
if( direction == PJ_FWD ) {
if( coord.xyzt.x >= alt.minxSrc &&
coord.xyzt.y >= alt.minySrc &&
coord.xyzt.x <= alt.maxxSrc &&
- coord.xyzt.y <= alt.maxySrc ) {
- if( P->iCurCoordOp != i ) {
- std::string msg("Using coordinate operation ");
- msg += alt.name;
- pj_log(P->ctx, PJ_LOG_TRACE, msg.c_str());
- P->iCurCoordOp = i;
- }
- return pj_fwd4d( coord, alt.pj );
+ coord.xyzt.y <= alt.maxySrc) {
+ spatialCriterionOK = true;
}
} else {
if( coord.xyzt.x >= alt.minxDst &&
coord.xyzt.y >= alt.minyDst &&
coord.xyzt.x <= alt.maxxDst &&
coord.xyzt.y <= alt.maxyDst ) {
- if( P->iCurCoordOp != i ) {
- std::string msg("Using coordinate operation ");
- msg += alt.name;
- pj_log(P->ctx, PJ_LOG_TRACE, msg.c_str());
- P->iCurCoordOp = i;
- }
- return pj_inv4d( coord, alt.pj );
+ spatialCriterionOK = true;
+ }
+ }
+
+ if( spatialCriterionOK ) {
+ // The offshore test is for the "Test bug 245 (use +datum=carthage)"
+ // of testvarious. The long=10 lat=34 point belongs both to the
+ // onshore and offshore Tunisia area of uses, but is slightly
+ // onshore. So in a general way, prefer a onshore area to a
+ // offshore one.
+ if( iBest < 0 ||
+ (alt.accuracy >= 0 && alt.accuracy < bestAccuracy &&
+ !alt.isOffshore) ) {
+ iBest = i;
+ bestAccuracy = alt.accuracy;
}
}
+
i ++;
}
+ if( iBest >= 0 ) {
+ const auto& alt = P->alternativeCoordinateOperations[iBest];
+ if( P->iCurCoordOp != iBest ) {
+ std::string msg("Using coordinate operation ");
+ msg += alt.name;
+ pj_log(P->ctx, PJ_LOG_TRACE, msg.c_str());
+ P->iCurCoordOp = iBest;
+ }
+ return direction == PJ_FWD ?
+ pj_fwd4d( coord, alt.pj ) : pj_inv4d( coord, alt.pj );
+ }
+
// In case we did not find an operation whose area of use is compatible
// with the input coordinate, then goes through again the list, and
// use the first operation that does not require grids.
@@ -919,6 +937,7 @@ static PJ* add_coord_op_to_list(PJ* op,
double east_lon, double north_lat,
PJ* pjGeogToSrc,
PJ* pjGeogToDst,
+ bool isOffshore,
std::vector<PJconsts::CoordOperation>& altCoordOps) {
/*****************************************************************************/
@@ -940,9 +959,11 @@ static PJ* add_coord_op_to_list(PJ* op,
{
const char* c_name = proj_get_name(op);
std::string name(c_name ? c_name : "");
+
+ const double accuracy = proj_coordoperation_get_accuracy(op->ctx, op);
altCoordOps.emplace_back(minxSrc, minySrc, maxxSrc, maxySrc,
minxDst, minyDst, maxxDst, maxyDst,
- op, name);
+ op, name, accuracy, isOffshore);
op = nullptr;
}
return op;
@@ -1160,14 +1181,17 @@ PJ *proj_create_crs_to_crs_from_pj (PJ_CONTEXT *ctx, const PJ *source_crs, cons
double east_lon = 0.0;
double north_lat = 0.0;
+ const char* areaName = nullptr;
if( proj_get_area_of_use(ctx, op,
- &west_lon, &south_lat, &east_lon, &north_lat, nullptr) )
+ &west_lon, &south_lat, &east_lon, &north_lat, &areaName) )
{
+ const bool isOffshore =
+ areaName && strstr(areaName, "offshore");
if( west_lon <= east_lon )
{
op = add_coord_op_to_list(op,
west_lon, south_lat, east_lon, north_lat,
- pjGeogToSrc, pjGeogToDst,
+ pjGeogToSrc, pjGeogToDst, isOffshore,
P->alternativeCoordinateOperations);
}
else
@@ -1176,11 +1200,11 @@ PJ *proj_create_crs_to_crs_from_pj (PJ_CONTEXT *ctx, const PJ *source_crs, cons
op = add_coord_op_to_list(op,
west_lon, south_lat, 180, north_lat,
- pjGeogToSrc, pjGeogToDst,
+ pjGeogToSrc, pjGeogToDst, isOffshore,
P->alternativeCoordinateOperations);
op_clone = add_coord_op_to_list(op_clone,
-180, south_lat, east_lon, north_lat,
- pjGeogToSrc, pjGeogToDst,
+ pjGeogToSrc, pjGeogToDst, isOffshore,
P->alternativeCoordinateOperations);
proj_destroy(op_clone);
}
diff --git a/src/iso19111/c_api.cpp b/src/iso19111/c_api.cpp
index cac09656..18794f9d 100644
--- a/src/iso19111/c_api.cpp
+++ b/src/iso19111/c_api.cpp
@@ -7642,7 +7642,7 @@ PJ *proj_normalize_for_visualization(PJ_CONTEXT *ctx, const PJ *obj) {
minxSrc, minySrc, maxxSrc, maxySrc, minxDst, minyDst,
maxxDst, maxyDst,
pj_obj_create(ctx, co->normalizeForVisualization()),
- co->nameStr());
+ co->nameStr(), alt.accuracy, alt.isOffshore);
}
}
return pjNew.release();
diff --git a/src/proj_internal.h b/src/proj_internal.h
index 5289e1c9..3ca927a3 100644
--- a/src/proj_internal.h
+++ b/src/proj_internal.h
@@ -533,23 +533,31 @@ struct PJconsts {
double maxyDst = 0.0;
PJ* pj = nullptr;
std::string name{};
+ double accuracy = -1.0;
+ bool isOffshore = false;
CoordOperation(double minxSrcIn, double minySrcIn, double maxxSrcIn, double maxySrcIn,
double minxDstIn, double minyDstIn, double maxxDstIn, double maxyDstIn,
- PJ* pjIn, const std::string& nameIn):
+ PJ* pjIn, const std::string& nameIn, double accuracyIn, bool isOffshoreIn):
minxSrc(minxSrcIn), minySrc(minySrcIn), maxxSrc(maxxSrcIn), maxySrc(maxySrcIn),
minxDst(minxDstIn), minyDst(minyDstIn), maxxDst(maxxDstIn), maxyDst(maxyDstIn),
- pj(pjIn), name(nameIn) {}
+ pj(pjIn), name(nameIn),
+ accuracy(accuracyIn),
+ isOffshore(isOffshoreIn)
+ {
+ }
CoordOperation(const CoordOperation&) = delete;
CoordOperation(CoordOperation&& other):
minxSrc(other.minxSrc), minySrc(other.minySrc), maxxSrc(other.maxxSrc), maxySrc(other.maxySrc),
minxDst(other.minxDst), minyDst(other.minyDst), maxxDst(other.maxxDst), maxyDst(other.maxyDst),
- name(std::move(other.name)) {
- pj = other.pj;
- other.pj = nullptr;
- }
+ name(std::move(other.name)),
+ accuracy(other.accuracy),
+ isOffshore(other.isOffshore) {
+ pj = other.pj;
+ other.pj = nullptr;
+ }
CoordOperation& operator=(const CoordOperation&) = delete;