Coverage Report

Created: 2026-07-16 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PROJ/src/transformations/tinshift_json.hpp
Line
Count
Source
1
/******************************************************************************
2
 * Project:  PROJ
3
 * Purpose:  Functionality related to TIN based transformations
4
 * Author:   Even Rouault, <even.rouault at spatialys.com>
5
 *
6
 ******************************************************************************
7
 * Copyright (c) 2020, Even Rouault, <even.rouault at spatialys.com>
8
 *
9
 * Permission is hereby granted, free of charge, to any person obtaining a
10
 * copy of this software and associated documentation files (the "Software"),
11
 * to deal in the Software without restriction, including without limitation
12
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13
 * and/or sell copies of the Software, and to permit persons to whom the
14
 * Software is furnished to do so, subject to the following conditions:
15
 *
16
 * The above copyright notice and this permission notice shall be included
17
 * in all copies or substantial portions of the Software.
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25
 * DEALINGS IN THE SOFTWARE.
26
 *****************************************************************************/
27
28
#ifndef TINSHIFT_JSON_HPP
29
#define TINSHIFT_JSON_HPP
30
31
#ifdef PROJ_COMPILATION
32
#include "proj/internal/include_nlohmann_json.hpp"
33
#else
34
#include "nlohmann/json.hpp"
35
#endif
36
37
#include <algorithm>
38
#include <cmath>
39
#include <exception>
40
#include <functional>
41
#include <limits>
42
#include <memory>
43
#include <string>
44
#include <vector>
45
46
#include "quadtree.hpp"
47
#include "tinshift_iface.hpp"
48
49
#ifndef TINSHIFT_JSON_NAMESPACE
50
#define TINSHIFT_JSON_NAMESPACE TINShiftJSON
51
#endif
52
53
#include "tinshift_json_exceptions.hpp"
54
55
namespace TINSHIFT_JSON_NAMESPACE {
56
57
enum FallbackStrategy {
58
    FALLBACK_NONE,
59
    FALLBACK_NEAREST_SIDE,
60
    FALLBACK_NEAREST_CENTROID,
61
};
62
63
using json = nlohmann::json;
64
65
// ---------------------------------------------------------------------------
66
67
/** Content of a TINShift file. */
68
class TINShiftJSONFile {
69
  public:
70
    /** Parse the provided serialized JSON content and return an object.
71
     *
72
     * @throws ParsingException in case of error.
73
     */
74
    static std::unique_ptr<TINShiftJSONFile> parse(const std::string &text);
75
76
    /** Get file type. Should always be "triangulation_file" */
77
0
    const std::string &fileType() const { return mFileType; }
78
79
    /** Get the version of the format. At time of writing, only "1.0" is known
80
     */
81
0
    const std::string &formatVersion() const { return mFormatVersion; }
82
83
    /** Get brief descriptive name of the deformation model. */
84
0
    const std::string &name() const { return mName; }
85
86
    /** Get a string identifying the version of the deformation model.
87
     * The format for specifying version is defined by the agency
88
     * responsible for the deformation model. */
89
0
    const std::string &version() const { return mVersion; }
90
91
    /** Get a string identifying the license of the file.
92
     * e.g "Create Commons Attribution 4.0 International" */
93
0
    const std::string &license() const { return mLicense; }
94
95
    /** Get a text description of the model. Intended to be longer than name()
96
     */
97
0
    const std::string &description() const { return mDescription; }
98
99
    /** Get a text description of the model. Intended to be longer than name()
100
     */
101
0
    const std::string &publicationDate() const { return mPublicationDate; }
102
103
0
    const enum FallbackStrategy &fallbackStrategy() const {
104
0
        return mFallbackStrategy;
105
0
    }
106
107
    /** Basic information on the agency responsible for the model. */
108
    struct Authority {
109
        std::string name{};
110
        std::string url{};
111
        std::string address{};
112
        std::string email{};
113
    };
114
115
    /** Get basic information on the agency responsible for the model. */
116
0
    const Authority &authority() const { return mAuthority; }
117
118
    /** Hyperlink related to the model. */
119
    struct Link {
120
        /** URL holding the information */
121
        std::string href{};
122
123
        /** Relationship to the dataset. e.g. "about", "source", "license",
124
         * "metadata" */
125
        std::string rel{};
126
127
        /** Mime type */
128
        std::string type{};
129
130
        /** Description of the link */
131
        std::string title{};
132
    };
133
134
    /** Get links to related information. */
135
0
    const std::vector<Link> links() const { return mLinks; }
136
137
    /** Get a string identifying the CRS of source coordinates in the
138
     * vertices. Typically "EPSG:XXXX". If the transformation is for vertical
139
     * component, this should be the code for a compound CRS (can be
140
     * EPSG:XXXX+YYYY where XXXX is the code of the horizontal CRS and YYYY
141
     * the code of the vertical CRS).
142
     * For example, for the KKJ->ETRS89 transformation, this is EPSG:2393
143
     * ("KKJ / Finland Uniform Coordinate System").
144
     * The input coordinates are assumed to
145
     * be passed in the "normalized for visualisation" / "GIS friendly" order,
146
     * that is longitude, latitude for geographic coordinates and
147
     * easting, northing for projected coordinates.
148
     * This may be empty for unspecified CRS.
149
     */
150
0
    const std::string &inputCRS() const { return mInputCRS; }
151
152
    /** Get a string identifying the CRS of target coordinates in the
153
     * vertices. Typically "EPSG:XXXX". If the transformation is for vertical
154
     * component, this should be the code for a compound CRS (can be
155
     * EPSG:XXXX+YYYY where XXXX is the code of the horizontal CRS and YYYY
156
     * the code of the vertical CRS).
157
     * For example, for the KKJ->ETRS89 transformation, this is EPSG:3067
158
     * ("ETRS89 / TM35FIN(E,N)").
159
     * The output coordinates will be
160
     * returned in the "normalized for visualisation" / "GIS friendly" order,
161
     * that is longitude, latitude for geographic coordinates and
162
     * easting, northing for projected coordinates.
163
     * This may be empty for unspecified CRS.
164
     */
165
0
    const std::string &outputCRS() const { return mOutputCRS; }
166
167
    /** Return whether horizontal coordinates are transformed. */
168
0
    bool transformHorizontalComponent() const {
169
0
        return mTransformHorizontalComponent;
170
0
    }
171
172
    /** Return whether vertical coordinates are transformed. */
173
0
    bool transformVerticalComponent() const {
174
0
        return mTransformVerticalComponent;
175
0
    }
176
177
    /** Indices of vertices of a triangle */
178
    struct VertexIndices {
179
        /** Index of first vertex */
180
        unsigned idx1;
181
        /** Index of second vertex */
182
        unsigned idx2;
183
        /** Index of third vertex */
184
        unsigned idx3;
185
    };
186
187
    /** Return number of elements per vertex of vertices() */
188
0
    unsigned verticesColumnCount() const { return mVerticesColumnCount; }
189
190
    /** Return description of triangulation vertices.
191
     * Each vertex is described by verticesColumnCount() consecutive values.
192
     * They are respectively:
193
     * - the source X value
194
     * - the source Y value
195
     * - (if transformHorizontalComponent() is true) the target X value
196
     * - (if transformHorizontalComponent() is true) the target Y value
197
     * - (if transformVerticalComponent() is true) the delta Z value (to go from
198
     * source to target Z)
199
     *
200
     * X is assumed to be a longitude (in degrees) or easting value.
201
     * Y is assumed to be a latitude (in degrees) or northing value.
202
     */
203
0
    const std::vector<double> &vertices() const { return mVertices; }
204
205
    /** Return triangles*/
206
0
    const std::vector<VertexIndices> &triangles() const { return mTriangles; }
207
208
  private:
209
0
    TINShiftJSONFile() = default;
210
211
    std::string mFileType{};
212
    std::string mFormatVersion{};
213
    std::string mName{};
214
    std::string mVersion{};
215
    std::string mLicense{};
216
    std::string mDescription{};
217
    std::string mPublicationDate{};
218
    enum FallbackStrategy mFallbackStrategy {};
219
    Authority mAuthority{};
220
    std::vector<Link> mLinks{};
221
    std::string mInputCRS{};
222
    std::string mOutputCRS{};
223
    bool mTransformHorizontalComponent = false;
224
    bool mTransformVerticalComponent = false;
225
    unsigned mVerticesColumnCount = 0;
226
    std::vector<double> mVertices{};
227
    std::vector<VertexIndices> mTriangles{};
228
};
229
230
// ---------------------------------------------------------------------------
231
232
/** Class to evaluate the transformation of a coordinate */
233
class TINShiftJSONEvaluator : public TINShiftEvaluator {
234
  public:
235
    /** Constructor. */
236
    explicit TINShiftJSONEvaluator(std::unique_ptr<TINShiftJSONFile> &&fileIn);
237
238
    /** Get file */
239
0
    const TINShiftJSONFile &file() const { return *(mFile.get()); }
240
241
    /** Evaluate displacement of a position given by (x,y,z,t) and
242
     * return it in (x_out,y_out_,z_out).
243
     */
244
    bool forward(double x, double y, double z, double &x_out, double &y_out,
245
                 double &z_out) override;
246
247
    /** Apply inverse transformation. */
248
    bool inverse(double x, double y, double z, double &x_out, double &y_out,
249
                 double &z_out) override;
250
251
  private:
252
    std::unique_ptr<TINShiftJSONFile> mFile;
253
254
    // Reused between invocations to save memory allocations
255
    std::vector<unsigned> mTriangleIndices{};
256
257
    std::unique_ptr<NS_PROJ::QuadTree::QuadTree<unsigned>> mQuadTreeForward{};
258
    std::unique_ptr<NS_PROJ::QuadTree::QuadTree<unsigned>> mQuadTreeInverse{};
259
};
260
261
// ---------------------------------------------------------------------------
262
263
} // namespace TINSHIFT_JSON_NAMESPACE
264
265
// ---------------------------------------------------------------------------
266
267
#include "tinshift_json_impl.hpp"
268
269
#endif // TINSHIFT_JSON_HPP