diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2019-11-18 21:04:59 +0100 |
|---|---|---|
| committer | Even Rouault <even.rouault@spatialys.com> | 2019-11-18 21:04:59 +0100 |
| commit | 2b9b65d0ffbe685fc33857df0f48a387d4611483 (patch) | |
| tree | 84961ed372c3d06ad9a04a0af14c3a1e5560039f /src | |
| parent | ee71b3412868a08c91d46066ddc39d30b08442d6 (diff) | |
| download | PROJ-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.cpp | 68 | ||||
| -rw-r--r-- | src/iso19111/c_api.cpp | 2 | ||||
| -rw-r--r-- | src/proj_internal.h | 20 |
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; |
