/src/proj/src/coord_operation.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * Project: PROJ |
3 | | * Purpose: PJCoordOperation methods |
4 | | * |
5 | | * Author: Even Rouault, <even.rouault at spatialys.com> |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2018-2024, Even Rouault, <even.rouault at spatialys.com> |
9 | | * |
10 | | * Permission is hereby granted, free of charge, to any person obtaining a |
11 | | * copy of this software and associated documentation files (the "Software"), |
12 | | * to deal in the Software without restriction, including without limitation |
13 | | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
14 | | * and/or sell copies of the Software, and to permit persons to whom the |
15 | | * Software is furnished to do so, subject to the following conditions: |
16 | | * |
17 | | * The above copyright notice and this permission notice shall be included |
18 | | * in all copies or substantial portions of the Software. |
19 | | * |
20 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
21 | | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
22 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
23 | | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
24 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
25 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
26 | | * DEALINGS IN THE SOFTWARE. |
27 | | *****************************************************************************/ |
28 | | |
29 | | #define FROM_PROJ_CPP |
30 | | |
31 | | #include "proj.h" |
32 | | #include "proj_internal.h" |
33 | | #include <math.h> |
34 | | |
35 | | #include "proj/internal/internal.hpp" |
36 | | |
37 | | using namespace NS_PROJ::internal; |
38 | | |
39 | | //! @cond Doxygen_Suppress |
40 | | /**************************************************************************************/ |
41 | 0 | PJCoordOperation::~PJCoordOperation() { |
42 | | /**************************************************************************************/ |
43 | 0 | proj_destroy(pj); |
44 | 0 | proj_destroy(pjSrcGeocentricToLonLat); |
45 | 0 | proj_destroy(pjDstGeocentricToLonLat); |
46 | 0 | } |
47 | | |
48 | | /**************************************************************************************/ |
49 | 0 | bool PJCoordOperation::isInstantiable() const { |
50 | | /**************************************************************************************/ |
51 | 0 | if (isInstantiableCached == INSTANTIABLE_STATUS_UNKNOWN) |
52 | 0 | isInstantiableCached = proj_coordoperation_is_instantiable(pj->ctx, pj); |
53 | 0 | return (isInstantiableCached == 1); |
54 | 0 | } |
55 | | |
56 | | // Returns true if the passed operation uses NADCON5 grids for NAD83 to |
57 | | // NAD83(HARN) |
58 | 0 | static bool isSpecialCaseForNAD83_to_NAD83HARN(const std::string &opName) { |
59 | 0 | return opName.find("NAD83 to NAD83(HARN) (47)") != std::string::npos || |
60 | 0 | opName.find("NAD83 to NAD83(HARN) (48)") != std::string::npos || |
61 | 0 | opName.find("NAD83 to NAD83(HARN) (49)") != std::string::npos || |
62 | 0 | opName.find("NAD83 to NAD83(HARN) (50)") != std::string::npos; |
63 | 0 | } |
64 | | |
65 | | // Returns true if the passed operation uses "GDA94 to WGS 84 (1)", which |
66 | | // is the null transformation |
67 | 0 | static bool isSpecialCaseForGDA94_to_WGS84(const std::string &opName) { |
68 | 0 | return opName.find("GDA94 to WGS 84 (1)") != std::string::npos; |
69 | 0 | } |
70 | | |
71 | | // Returns true if the passed operation uses "GDA2020 to WGS 84 (2)", which |
72 | | // is the null transformation |
73 | 0 | static bool isSpecialCaseForWGS84_to_GDA2020(const std::string &opName) { |
74 | 0 | return opName.find("GDA2020 to WGS 84 (2)") != std::string::npos; |
75 | 0 | } |
76 | | |
77 | | PJCoordOperation::PJCoordOperation( |
78 | | int idxInOriginalListIn, double minxSrcIn, double minySrcIn, |
79 | | double maxxSrcIn, double maxySrcIn, double minxDstIn, double minyDstIn, |
80 | | double maxxDstIn, double maxyDstIn, PJ *pjIn, const std::string &nameIn, |
81 | | double accuracyIn, double pseudoAreaIn, const char *areaNameIn, |
82 | | const PJ *pjSrcGeocentricToLonLatIn, const PJ *pjDstGeocentricToLonLatIn) |
83 | 0 | : idxInOriginalList(idxInOriginalListIn), minxSrc(minxSrcIn), |
84 | 0 | minySrc(minySrcIn), maxxSrc(maxxSrcIn), maxySrc(maxySrcIn), |
85 | 0 | minxDst(minxDstIn), minyDst(minyDstIn), maxxDst(maxxDstIn), |
86 | 0 | maxyDst(maxyDstIn), pj(pjIn), name(nameIn), accuracy(accuracyIn), |
87 | 0 | pseudoArea(pseudoAreaIn), areaName(areaNameIn ? areaNameIn : ""), |
88 | 0 | isOffshore(areaName.find("- offshore") != std::string::npos), |
89 | 0 | isUnknownAreaName(areaName.empty() || areaName == "unknown"), |
90 | 0 | isPriorityOp(isSpecialCaseForNAD83_to_NAD83HARN(name) || |
91 | 0 | isSpecialCaseForGDA94_to_WGS84(name) || |
92 | 0 | isSpecialCaseForWGS84_to_GDA2020(name)), |
93 | 0 | pjSrcGeocentricToLonLat(pjSrcGeocentricToLonLatIn |
94 | 0 | ? proj_clone(pjSrcGeocentricToLonLatIn->ctx, |
95 | 0 | pjSrcGeocentricToLonLatIn) |
96 | 0 | : nullptr), |
97 | 0 | pjDstGeocentricToLonLat(pjDstGeocentricToLonLatIn |
98 | 0 | ? proj_clone(pjDstGeocentricToLonLatIn->ctx, |
99 | 0 | pjDstGeocentricToLonLatIn) |
100 | 0 | : nullptr) { |
101 | 0 | const auto IsLonLatOrLatLon = [](const PJ *crs, bool &isLonLatDegreeOut, |
102 | 0 | bool &isLatLonDegreeOut) { |
103 | 0 | const auto eType = proj_get_type(crs); |
104 | 0 | if (eType == PJ_TYPE_GEOGRAPHIC_2D_CRS || |
105 | 0 | eType == PJ_TYPE_GEOGRAPHIC_3D_CRS) { |
106 | 0 | const auto cs = proj_crs_get_coordinate_system(crs->ctx, crs); |
107 | 0 | const char *direction = ""; |
108 | 0 | double conv_factor = 0; |
109 | 0 | constexpr double EPS = 1e-14; |
110 | 0 | if (proj_cs_get_axis_info(crs->ctx, cs, 0, nullptr, nullptr, |
111 | 0 | &direction, &conv_factor, nullptr, |
112 | 0 | nullptr, nullptr) && |
113 | 0 | ci_equal(direction, "East")) { |
114 | 0 | isLonLatDegreeOut = fabs(conv_factor - M_PI / 180) < EPS; |
115 | 0 | } else if (proj_cs_get_axis_info(crs->ctx, cs, 1, nullptr, nullptr, |
116 | 0 | &direction, &conv_factor, nullptr, |
117 | 0 | nullptr, nullptr) && |
118 | 0 | ci_equal(direction, "East")) { |
119 | 0 | isLatLonDegreeOut = fabs(conv_factor - M_PI / 180) < EPS; |
120 | 0 | } |
121 | 0 | proj_destroy(cs); |
122 | 0 | } |
123 | 0 | }; |
124 | |
|
125 | 0 | const auto source = proj_get_source_crs(pj->ctx, pj); |
126 | 0 | if (source) { |
127 | 0 | IsLonLatOrLatLon(source, srcIsLonLatDegree, srcIsLatLonDegree); |
128 | 0 | proj_destroy(source); |
129 | 0 | } |
130 | |
|
131 | 0 | const auto target = proj_get_target_crs(pj->ctx, pj); |
132 | 0 | if (target) { |
133 | 0 | IsLonLatOrLatLon(target, dstIsLonLatDegree, dstIsLatLonDegree); |
134 | 0 | proj_destroy(target); |
135 | 0 | } |
136 | 0 | } |
137 | | |
138 | | //! @endcond |