Coverage Report

Created: 2025-07-11 06:33

/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
18.9k
PJCoordOperation::~PJCoordOperation() {
42
    /**************************************************************************************/
43
18.9k
    proj_destroy(pj);
44
18.9k
    proj_destroy(pjSrcGeocentricToLonLat);
45
18.9k
    proj_destroy(pjDstGeocentricToLonLat);
46
18.9k
}
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
8.77k
static bool isSpecialCaseForNAD83_to_NAD83HARN(const std::string &opName) {
59
8.77k
    return opName.find("NAD83 to NAD83(HARN) (47)") != std::string::npos ||
60
8.77k
           opName.find("NAD83 to NAD83(HARN) (48)") != std::string::npos ||
61
8.77k
           opName.find("NAD83 to NAD83(HARN) (49)") != std::string::npos ||
62
8.77k
           opName.find("NAD83 to NAD83(HARN) (50)") != std::string::npos;
63
8.77k
}
64
65
// Returns true if the passed operation uses "GDA94 to WGS 84 (1)", which
66
// is the null transformation
67
8.75k
static bool isSpecialCaseForGDA94_to_WGS84(const std::string &opName) {
68
8.75k
    return opName.find("GDA94 to WGS 84 (1)") != std::string::npos;
69
8.75k
}
70
71
// Returns true if the passed operation uses "GDA2020 to WGS 84 (2)", which
72
// is the null transformation
73
8.71k
static bool isSpecialCaseForWGS84_to_GDA2020(const std::string &opName) {
74
8.71k
    return opName.find("GDA2020 to WGS 84 (2)") != std::string::npos;
75
8.71k
}
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
8.77k
    : idxInOriginalList(idxInOriginalListIn), minxSrc(minxSrcIn),
84
8.77k
      minySrc(minySrcIn), maxxSrc(maxxSrcIn), maxySrc(maxySrcIn),
85
8.77k
      minxDst(minxDstIn), minyDst(minyDstIn), maxxDst(maxxDstIn),
86
8.77k
      maxyDst(maxyDstIn), pj(pjIn), name(nameIn), accuracy(accuracyIn),
87
8.77k
      pseudoArea(pseudoAreaIn), areaName(areaNameIn ? areaNameIn : ""),
88
8.77k
      isOffshore(areaName.find("- offshore") != std::string::npos),
89
8.77k
      isUnknownAreaName(areaName.empty() || areaName == "unknown"),
90
8.77k
      isPriorityOp(isSpecialCaseForNAD83_to_NAD83HARN(name) ||
91
8.77k
                   isSpecialCaseForGDA94_to_WGS84(name) ||
92
8.77k
                   isSpecialCaseForWGS84_to_GDA2020(name)),
93
8.77k
      pjSrcGeocentricToLonLat(pjSrcGeocentricToLonLatIn
94
8.77k
                                  ? proj_clone(pjSrcGeocentricToLonLatIn->ctx,
95
1.49k
                                               pjSrcGeocentricToLonLatIn)
96
8.77k
                                  : nullptr),
97
8.77k
      pjDstGeocentricToLonLat(pjDstGeocentricToLonLatIn
98
8.77k
                                  ? proj_clone(pjDstGeocentricToLonLatIn->ctx,
99
144
                                               pjDstGeocentricToLonLatIn)
100
8.77k
                                  : nullptr) {
101
8.77k
    const auto IsLonLatOrLatLon = [](const PJ *crs, bool &isLonLatDegreeOut,
102
17.5k
                                     bool &isLatLonDegreeOut) {
103
17.5k
        const auto eType = proj_get_type(crs);
104
17.5k
        if (eType == PJ_TYPE_GEOGRAPHIC_2D_CRS ||
105
17.5k
            eType == PJ_TYPE_GEOGRAPHIC_3D_CRS) {
106
2.41k
            const auto cs = proj_crs_get_coordinate_system(crs->ctx, crs);
107
2.41k
            const char *direction = "";
108
2.41k
            double conv_factor = 0;
109
2.41k
            constexpr double EPS = 1e-14;
110
2.41k
            if (proj_cs_get_axis_info(crs->ctx, cs, 0, nullptr, nullptr,
111
2.41k
                                      &direction, &conv_factor, nullptr,
112
2.41k
                                      nullptr, nullptr) &&
113
2.41k
                ci_equal(direction, "East")) {
114
1.77k
                isLonLatDegreeOut = fabs(conv_factor - M_PI / 180) < EPS;
115
1.77k
            } else if (proj_cs_get_axis_info(crs->ctx, cs, 1, nullptr, nullptr,
116
643
                                             &direction, &conv_factor, nullptr,
117
643
                                             nullptr, nullptr) &&
118
643
                       ci_equal(direction, "East")) {
119
513
                isLatLonDegreeOut = fabs(conv_factor - M_PI / 180) < EPS;
120
513
            }
121
2.41k
            proj_destroy(cs);
122
2.41k
        }
123
17.5k
    };
124
125
8.77k
    const auto source = proj_get_source_crs(pj->ctx, pj);
126
8.77k
    if (source) {
127
8.77k
        IsLonLatOrLatLon(source, srcIsLonLatDegree, srcIsLatLonDegree);
128
8.77k
        proj_destroy(source);
129
8.77k
    }
130
131
8.77k
    const auto target = proj_get_target_crs(pj->ctx, pj);
132
8.77k
    if (target) {
133
8.77k
        IsLonLatOrLatLon(target, dstIsLonLatDegree, dstIsLatLonDegree);
134
8.77k
        proj_destroy(target);
135
8.77k
    }
136
8.77k
}
137
138
//! @endcond