Coverage Report

Created: 2025-06-13 06:29

/src/proj/src/transformations/tinshift.hpp
Line
Count
Source (jump to first uncovered line)
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_HPP
29
#define TINSHIFT_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
48
#ifndef TINSHIFT_NAMESPACE
49
#define TINSHIFT_NAMESPACE TINShift
50
#endif
51
52
#include "tinshift_exceptions.hpp"
53
54
namespace TINSHIFT_NAMESPACE {
55
56
enum FallbackStrategy {
57
    FALLBACK_NONE,
58
    FALLBACK_NEAREST_SIDE,
59
    FALLBACK_NEAREST_CENTROID,
60
};
61
62
using json = nlohmann::json;
63
64
// ---------------------------------------------------------------------------
65
66
/** Content of a TINShift file. */
67
class TINShiftFile {
68
  public:
69
    /** Parse the provided serialized JSON content and return an object.
70
     *
71
     * @throws ParsingException in case of error.
72
     */
73
    static std::unique_ptr<TINShiftFile> parse(const std::string &text);
74
75
    /** Get file type. Should always be "triangulation_file" */
76
0
    const std::string &fileType() const { return mFileType; }
77
78
    /** Get the version of the format. At time of writing, only "1.0" is known
79
     */
80
0
    const std::string &formatVersion() const { return mFormatVersion; }
81
82
    /** Get brief descriptive name of the deformation model. */
83
0
    const std::string &name() const { return mName; }
84
85
    /** Get a string identifying the version of the deformation model.
86
     * The format for specifying version is defined by the agency
87
     * responsible for the deformation model. */
88
0
    const std::string &version() const { return mVersion; }
89
90
    /** Get a string identifying the license of the file.
91
     * e.g "Create Commons Attribution 4.0 International" */
92
0
    const std::string &license() const { return mLicense; }
93
94
    /** Get a text description of the model. Intended to be longer than name()
95
     */
96
0
    const std::string &description() const { return mDescription; }
97
98
    /** Get a text description of the model. Intended to be longer than name()
99
     */
100
0
    const std::string &publicationDate() const { return mPublicationDate; }
101
102
0
    const enum FallbackStrategy &fallbackStrategy() const {
103
0
        return mFallbackStrategy;
104
0
    }
105
106
    /** Basic information on the agency responsible for the model. */
107
    struct Authority {
108
        std::string name{};
109
        std::string url{};
110
        std::string address{};
111
        std::string email{};
112
    };
113
114
    /** Get basic information on the agency responsible for the model. */
115
0
    const Authority &authority() const { return mAuthority; }
116
117
    /** Hyperlink related to the model. */
118
    struct Link {
119
        /** URL holding the information */
120
        std::string href{};
121
122
        /** Relationship to the dataset. e.g. "about", "source", "license",
123
         * "metadata" */
124
        std::string rel{};
125
126
        /** Mime type */
127
        std::string type{};
128
129
        /** Description of the link */
130
        std::string title{};
131
    };
132
133
    /** Get links to related information. */
134
0
    const std::vector<Link> links() const { return mLinks; }
135
136
    /** Get a string identifying the CRS of source coordinates in the
137
     * vertices. Typically "EPSG:XXXX". If the transformation is for vertical
138
     * component, this should be the code for a compound CRS (can be
139
     * EPSG:XXXX+YYYY where XXXX is the code of the horizontal CRS and YYYY
140
     * the code of the vertical CRS).
141
     * For example, for the KKJ->ETRS89 transformation, this is EPSG:2393
142
     * ("KKJ / Finland Uniform Coordinate System").
143
     * The input coordinates are assumed to
144
     * be passed in the "normalized for visualisation" / "GIS friendly" order,
145
     * that is longitude, latitude for geographic coordinates and
146
     * easting, northing for projected coordinates.
147
     * This may be empty for unspecified CRS.
148
     */
149
0
    const std::string &inputCRS() const { return mInputCRS; }
150
151
    /** Get a string identifying the CRS of target coordinates in the
152
     * vertices. Typically "EPSG:XXXX". If the transformation is for vertical
153
     * component, this should be the code for a compound CRS (can be
154
     * EPSG:XXXX+YYYY where XXXX is the code of the horizontal CRS and YYYY
155
     * the code of the vertical CRS).
156
     * For example, for the KKJ->ETRS89 transformation, this is EPSG:3067
157
     * ("ETRS89 / TM35FIN(E,N)").
158
     * The output coordinates will be
159
     * returned in the "normalized for visualisation" / "GIS friendly" order,
160
     * that is longitude, latitude for geographic coordinates and
161
     * easting, northing for projected coordinates.
162
     * This may be empty for unspecified CRS.
163
     */
164
0
    const std::string &outputCRS() const { return mOutputCRS; }
165
166
    /** Return whether horizontal coordinates are transformed. */
167
0
    bool transformHorizontalComponent() const {
168
0
        return mTransformHorizontalComponent;
169
0
    }
170
171
    /** Return whether vertical coordinates are transformed. */
172
0
    bool transformVerticalComponent() const {
173
0
        return mTransformVerticalComponent;
174
0
    }
175
176
    /** Indices of vertices of a triangle */
177
    struct VertexIndices {
178
        /** Index of first vertex */
179
        unsigned idx1;
180
        /** Index of second vertex */
181
        unsigned idx2;
182
        /** Index of third vertex */
183
        unsigned idx3;
184
    };
185
186
    /** Return number of elements per vertex of vertices() */
187
0
    unsigned verticesColumnCount() const { return mVerticesColumnCount; }
188
189
    /** Return description of triangulation vertices.
190
     * Each vertex is described by verticesColumnCount() consecutive values.
191
     * They are respectively:
192
     * - the source X value
193
     * - the source Y value
194
     * - (if transformHorizontalComponent() is true) the target X value
195
     * - (if transformHorizontalComponent() is true) the target Y value
196
     * - (if transformVerticalComponent() is true) the delta Z value (to go from
197
     * source to target Z)
198
     *
199
     * X is assumed to be a longitude (in degrees) or easting value.
200
     * Y is assumed to be a latitude (in degrees) or northing value.
201
     */
202
0
    const std::vector<double> &vertices() const { return mVertices; }
203
204
    /** Return triangles*/
205
0
    const std::vector<VertexIndices> &triangles() const { return mTriangles; }
206
207
  private:
208
0
    TINShiftFile() = default;
209
210
    std::string mFileType{};
211
    std::string mFormatVersion{};
212
    std::string mName{};
213
    std::string mVersion{};
214
    std::string mLicense{};
215
    std::string mDescription{};
216
    std::string mPublicationDate{};
217
    enum FallbackStrategy mFallbackStrategy {};
218
    Authority mAuthority{};
219
    std::vector<Link> mLinks{};
220
    std::string mInputCRS{};
221
    std::string mOutputCRS{};
222
    bool mTransformHorizontalComponent = false;
223
    bool mTransformVerticalComponent = false;
224
    unsigned mVerticesColumnCount = 0;
225
    std::vector<double> mVertices{};
226
    std::vector<VertexIndices> mTriangles{};
227
};
228
229
// ---------------------------------------------------------------------------
230
231
/** Class to evaluate the transformation of a coordinate */
232
class Evaluator {
233
  public:
234
    /** Constructor. */
235
    explicit Evaluator(std::unique_ptr<TINShiftFile> &&fileIn);
236
237
    /** Get file */
238
0
    const TINShiftFile &file() const { return *(mFile.get()); }
239
240
    /** Evaluate displacement of a position given by (x,y,z,t) and
241
     * return it in (x_out,y_out_,z_out).
242
     */
243
    bool forward(double x, double y, double z, double &x_out, double &y_out,
244
                 double &z_out);
245
246
    /** Apply inverse transformation. */
247
    bool inverse(double x, double y, double z, double &x_out, double &y_out,
248
                 double &z_out);
249
250
  private:
251
    std::unique_ptr<TINShiftFile> mFile;
252
253
    // Reused between invocations to save memory allocations
254
    std::vector<unsigned> mTriangleIndices{};
255
256
    std::unique_ptr<NS_PROJ::QuadTree::QuadTree<unsigned>> mQuadTreeForward{};
257
    std::unique_ptr<NS_PROJ::QuadTree::QuadTree<unsigned>> mQuadTreeInverse{};
258
};
259
260
// ---------------------------------------------------------------------------
261
262
} // namespace TINSHIFT_NAMESPACE
263
264
// ---------------------------------------------------------------------------
265
266
#include "tinshift_impl.hpp"
267
268
#endif // TINSHIFT_HPP