1 /******************************************************************************
2  * Project:  PROJ.4
3  * Purpose:  Internal plumbing for the PROJ.4 library.
4  *
5  * Author:   Thomas Knudsen, <thokn@sdfe.dk>
6  *
7  ******************************************************************************
8  * Copyright (c) 2016, 2017, Thomas Knudsen / SDFE
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 COORD 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 #ifndef PROJ_INTERNAL_H
30 #define PROJ_INTERNAL_H
31 
32 #ifndef __cplusplus
33 #error "proj_internal.h can only be included from a C++ file"
34 #endif
35 
36 #ifndef ACCEPT_USE_OF_DEPRECATED_PROJ_API_H
37 #define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H
38 #endif
39 
40 #ifdef _MSC_VER
41 #  ifndef _CRT_SECURE_NO_DEPRECATE
42 #    define _CRT_SECURE_NO_DEPRECATE
43 #  endif
44 #  ifndef _CRT_NONSTDC_NO_DEPRECATE
45 #    define _CRT_NONSTDC_NO_DEPRECATE
46 #  endif
47 /* enable predefined math constants M_* for MS Visual Studio workaround */
48 #  ifndef _USE_MATH_DEFINES
49 #     define _USE_MATH_DEFINES
50 #  endif
51 #endif
52 
53 /* standard inclusions */
54 #include <limits.h>
55 #include <math.h>
56 #include <stddef.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 
61 #include "proj/common.hpp"
62 #include "proj/coordinateoperation.hpp"
63 
64 #include <string>
65 #include <vector>
66 
67 #include "proj.h"
68 
69 #ifdef PROJ_API_H
70 #error proj_internal.h must be included before proj_api.h
71 #endif
72 
73 #ifdef PROJ_RENAME_SYMBOLS
74 #include "proj_symbol_rename.h"
75 #endif
76 
77 #define STATIC_ASSERT(COND) ((void)sizeof(char[(COND) ? 1 : -1]))
78 
79 #ifndef PJ_TODEG
80 #define PJ_TODEG(rad)  ((rad)*180.0/M_PI)
81 #endif
82 #ifndef PJ_TORAD
83 #define PJ_TORAD(deg)  ((deg)*M_PI/180.0)
84 #endif
85 
86 /* Maximum latitudinal overshoot accepted */
87 #define PJ_EPS_LAT 1e-12
88 
89 #define C_NAMESPACE extern "C"
90 #define C_NAMESPACE_VAR extern "C"
91 
92 #ifndef NULL
93 #  define NULL 0
94 #endif
95 
96 #ifndef FALSE
97 #  define FALSE 0
98 #endif
99 
100 #ifndef TRUE
101 #  define TRUE  1
102 #endif
103 
104 #ifndef MAX
105 #  define MIN(a,b)      ((a<b) ? a : b)
106 #  define MAX(a,b)      ((a>b) ? a : b)
107 #endif
108 
109 #ifndef ABS
110 #  define ABS(x)        ((x<0) ? (-1*(x)) : x)
111 #endif
112 
113 #if INT_MAX == 2147483647
114 typedef int pj_int32;
115 #elif LONG_MAX == 2147483647
116 typedef long pj_int32;
117 #else
118 #warning It seems no 32-bit integer type is available
119 #endif
120 
121 /* maximum path/filename */
122 #ifndef MAX_PATH_FILENAME
123 #define MAX_PATH_FILENAME 1024
124 #endif
125 
126 /* If we still haven't got M_PI*, we rely on our own defines.
127  * For example, this is necessary when compiling with gcc and
128  * the -ansi flag.
129  */
130 #ifndef M_PI
131 #define M_PI            3.14159265358979323846
132 #define M_PI_2          1.57079632679489661923
133 #define M_PI_4          0.78539816339744830962
134 #define M_2_PI          0.63661977236758134308
135 #endif
136 
137 /* M_SQRT2 might be missing */
138 #ifndef M_SQRT2
139 #define M_SQRT2         1.41421356237309504880
140 #endif
141 
142 /* some more useful math constants and aliases */
143 #define M_FORTPI        M_PI_4                   /* pi/4 */
144 #define M_HALFPI        M_PI_2                   /* pi/2 */
145 #define M_PI_HALFPI     4.71238898038468985769   /* 1.5*pi */
146 #define M_TWOPI         6.28318530717958647693   /* 2*pi */
147 #define M_TWO_D_PI      M_2_PI                   /* 2/pi */
148 #define M_TWOPI_HALFPI  7.85398163397448309616   /* 2.5*pi */
149 
150 
151 /* maximum tag id length for +init and default files */
152 #ifndef ID_TAG_MAX
153 #define ID_TAG_MAX 50
154 #endif
155 
156 /* Use WIN32 as a standard windows 32 bit declaration */
157 #if defined(_WIN32) && !defined(WIN32)
158 #  define WIN32
159 #endif
160 
161 #if defined(_WINDOWS) && !defined(WIN32)
162 #  define WIN32
163 #endif
164 
165 /* directory delimiter for DOS support */
166 #ifdef WIN32
167 #define DIR_CHAR '\\'
168 #else
169 #define DIR_CHAR '/'
170 #endif
171 
172 enum pj_io_units {
173     PJ_IO_UNITS_WHATEVER  = 0,  /* Doesn't matter (or depends on pipeline neighbours) */
174     PJ_IO_UNITS_CLASSIC   = 1,  /* Scaled meters (right), projected system */
175     PJ_IO_UNITS_PROJECTED = 2,  /* Meters, projected system */
176     PJ_IO_UNITS_CARTESIAN = 3,  /* Meters, 3D cartesian system */
177     PJ_IO_UNITS_RADIANS   = 4,  /* Radians */
178     PJ_IO_UNITS_DEGREES   = 5,  /* Degrees */
179 
180 };
181 enum pj_io_units pj_left (PJ *P);
182 enum pj_io_units pj_right (PJ *P);
183 
184 PJ_COORD PROJ_DLL proj_coord_error (void);
185 
186 void proj_context_errno_set (PJ_CONTEXT *ctx, int err);
187 void PROJ_DLL proj_context_set (PJ *P, PJ_CONTEXT *ctx);
188 void proj_context_inherit (PJ *parent, PJ *child);
189 
190 struct projCppContext;
191 /* not sure why we need to export it, but mingw needs it */
192 void PROJ_DLL proj_context_delete_cpp_context(struct projCppContext* cppContext);
193 
194 PJ_COORD pj_fwd4d (PJ_COORD coo, PJ *P);
195 PJ_COORD pj_inv4d (PJ_COORD coo, PJ *P);
196 
197 PJ_COORD PROJ_DLL pj_approx_2D_trans (PJ *P, PJ_DIRECTION direction, PJ_COORD coo);
198 PJ_COORD PROJ_DLL pj_approx_3D_trans (PJ *P, PJ_DIRECTION direction, PJ_COORD coo);
199 
200 void PROJ_DLL proj_log_error (PJ *P, const char *fmt, ...);
201 void proj_log_debug (PJ *P, const char *fmt, ...);
202 void proj_log_trace (PJ *P, const char *fmt, ...);
203 
204 void proj_context_log_debug (PJ_CONTEXT *ctx, const char *fmt, ...);
205 
206 int pj_ellipsoid (PJ *);
207 void pj_inherit_ellipsoid_def (const PJ *src, PJ *dst);
208 int pj_calc_ellipsoid_params (PJ *P, double a, double es);
209 
210 /* Geographical to geocentric latitude - another of the "simple, but useful" */
211 PJ_COORD pj_geocentric_latitude (const PJ *P, PJ_DIRECTION direction, PJ_COORD coord);
212 
213 char  PROJ_DLL *pj_chomp (char *c);
214 char  PROJ_DLL *pj_shrink (char *c);
215 size_t pj_trim_argc (char *args);
216 char **pj_trim_argv (size_t argc, char *args);
217 char  *pj_make_args (size_t argc, char **argv);
218 
219 typedef struct { double r, i; } COMPLEX;
220 
221 /* Forward declarations and typedefs for stuff needed inside the PJ object */
222 struct PJconsts;
223 
224 union  PJ_COORD;
225 struct geod_geodesic;
226 struct ARG_list;
227 struct PJ_REGION_S;
228 typedef struct PJ_REGION_S  PJ_Region;
229 typedef struct ARG_list paralist;   /* parameter list */
230 
231 #ifndef PROJ_H
232 typedef struct PJconsts PJ;         /* the PJ object herself */
233 typedef union  PJ_COORD PJ_COORD;
234 #endif
235 
236 struct PJ_REGION_S {
237     double ll_long;        /* lower left corner coordinates (radians) */
238     double ll_lat;
239     double ur_long;        /* upper right corner coordinates (radians) */
240     double ur_lat;
241 };
242 
243 struct PJ_AREA {
244     int     bbox_set;
245     double  west_lon_degree;
246     double  south_lat_degree;
247     double  east_lon_degree;
248     double  north_lat_degree;
249 };
250 
251 struct projCtx_t;
252 typedef struct projCtx_t projCtx_t;
253 
254 /*****************************************************************************
255 
256     Some function types that are especially useful when working with PJs
257 
258 ******************************************************************************
259 
260 PJ_CONSTRUCTOR:
261 
262     A function taking a pointer-to-PJ as arg, and returning a pointer-to-PJ.
263     Historically called twice: First with a 0 argument, to allocate memory,
264     second with the first return value as argument, for actual setup.
265 
266 PJ_DESTRUCTOR:
267 
268     A function taking a pointer-to-PJ and an integer as args, then first
269     handling the deallocation of the PJ, afterwards handing the integer over
270     to the error reporting subsystem, and finally returning a null pointer in
271     support of the "return free (P)" (aka "get the hell out of here") idiom.
272 
273 PJ_OPERATOR:
274 
275     A function taking a PJ_COORD and a pointer-to-PJ as args, applying the
276     PJ to the PJ_COORD, and returning the resulting PJ_COORD.
277 
278 *****************************************************************************/
279 typedef    PJ       *(* PJ_CONSTRUCTOR) (PJ *);
280 typedef    PJ       *(* PJ_DESTRUCTOR)  (PJ *, int);
281 typedef    PJ_COORD  (* PJ_OPERATOR)    (PJ_COORD, PJ *);
282 /****************************************************************************/
283 
284 
285 /* datum_type values */
286 #define PJD_UNKNOWN   0
287 #define PJD_3PARAM    1
288 #define PJD_7PARAM    2
289 #define PJD_GRIDSHIFT 3
290 #define PJD_WGS84     4   /* WGS84 (or anything considered equivalent) */
291 
292 struct CoordOperation
293 {
294     int idxInOriginalList;
295     double minxSrc = 0.0;
296     double minySrc = 0.0;
297     double maxxSrc = 0.0;
298     double maxySrc = 0.0;
299     double minxDst = 0.0;
300     double minyDst = 0.0;
301     double maxxDst = 0.0;
302     double maxyDst = 0.0;
303     PJ* pj = nullptr;
304     std::string name{};
305     double accuracy = -1.0;
306     bool isOffshore = false;
307 
CoordOperationCoordOperation308     CoordOperation(int idxInOriginalListIn,
309                    double minxSrcIn, double minySrcIn, double maxxSrcIn, double maxySrcIn,
310                    double minxDstIn, double minyDstIn, double maxxDstIn, double maxyDstIn,
311                    PJ* pjIn, const std::string& nameIn, double accuracyIn, bool isOffshoreIn):
312         idxInOriginalList(idxInOriginalListIn),
313         minxSrc(minxSrcIn), minySrc(minySrcIn), maxxSrc(maxxSrcIn), maxySrc(maxySrcIn),
314         minxDst(minxDstIn), minyDst(minyDstIn), maxxDst(maxxDstIn), maxyDst(maxyDstIn),
315         pj(pjIn), name(nameIn),
316         accuracy(accuracyIn),
317         isOffshore(isOffshoreIn)
318     {
319     }
320 
321     CoordOperation(const CoordOperation&) = delete;
322 
CoordOperationCoordOperation323     CoordOperation(CoordOperation&& other):
324         idxInOriginalList(other.idxInOriginalList),
325         minxSrc(other.minxSrc), minySrc(other.minySrc), maxxSrc(other.maxxSrc), maxySrc(other.maxySrc),
326         minxDst(other.minxDst), minyDst(other.minyDst), maxxDst(other.maxxDst), maxyDst(other.maxyDst),
327         name(std::move(other.name)),
328         accuracy(other.accuracy),
329         isOffshore(other.isOffshore) {
330         pj = other.pj;
331         other.pj = nullptr;
332     }
333 
334     CoordOperation& operator=(const CoordOperation&) = delete;
335 
~CoordOperationCoordOperation336     ~CoordOperation()
337     {
338         proj_destroy(pj);
339     }
340 };
341 
342 enum class TMercAlgo
343 {
344     AUTO, // Poder/Engsager if far from central meridian, otherwise Evenden/Snyder
345     EVENDEN_SNYDER,
346     PODER_ENGSAGER,
347 };
348 
349 /* base projection data structure */
350 struct PJconsts {
351 
352     /*************************************************************************************
353 
354                          G E N E R A L   P A R A M E T E R   S T R U C T
355 
356     **************************************************************************************
357 
358         TODO: Need some description here - especially about the thread context...
359         This is the struct behind the PJ typedef
360 
361     **************************************************************************************/
362 
363     projCtx_t *ctx = nullptr;
364     const char *descr = nullptr;   /* From pj_list.h or individual PJ_*.c file */
365     paralist *params = nullptr;    /* Parameter list */
366     char *def_full = nullptr;      /* Full textual definition (usually 0 - set by proj_pj_info) */
367     PJconsts *parent = nullptr;    /* Parent PJ of pipeline steps - nullptr if not a pipeline step */
368 
369     /* For debugging / logging purposes */
370     char *def_size = nullptr;      /* Shape and size parameters extracted from params */
371     char *def_shape = nullptr;
372     char *def_spherification = nullptr;
373     char *def_ellps = nullptr;
374 
375     struct geod_geodesic *geod = nullptr;    /* For geodesic computations */
376     void *opaque = nullptr;                  /* Projection specific parameters, Defined in PJ_*.c */
377     int inverted = 0;                        /* Tell high level API functions to swap inv/fwd */
378 
379 
380     /*************************************************************************************
381 
382                           F U N C T I O N    P O I N T E R S
383 
384     **************************************************************************************
385 
386         For projection xxx, these are pointers to functions in the corresponding
387         PJ_xxx.c file.
388 
389         pj_init() delegates the setup of these to pj_projection_specific_setup_xxx(),
390         a name which is currently hidden behind the magic curtain of the PROJECTION
391         macro.
392 
393     **************************************************************************************/
394 
395 
396     PJ_XY  (*fwd)(PJ_LP,    PJ *) = nullptr;
397     PJ_LP  (*inv)(PJ_XY,    PJ *) = nullptr;
398     PJ_XYZ (*fwd3d)(PJ_LPZ, PJ *) = nullptr;
399     PJ_LPZ (*inv3d)(PJ_XYZ, PJ *) = nullptr;
400     PJ_OPERATOR fwd4d = nullptr;
401     PJ_OPERATOR inv4d = nullptr;
402 
403     PJ_DESTRUCTOR destructor = nullptr;
404     void   (*reassign_context)(PJ*, projCtx_t *) = nullptr;
405 
406 
407     /*************************************************************************************
408 
409                           E L L I P S O I D     P A R A M E T E R S
410 
411     **************************************************************************************
412 
413         Despite YAGNI, we add a large number of ellipsoidal shape parameters, which
414         are not yet set up in pj_init. They are, however, inexpensive to compute,
415         compared to the overall time taken for setting up the complex PJ object
416         (cf. e.g. https://en.wikipedia.org/wiki/Angular_eccentricity).
417 
418         But during single point projections it will often be a useful thing to have
419         these readily available without having to recompute at every pj_fwd / pj_inv
420         call.
421 
422         With this wide selection, we should be ready for quite a number of geodetic
423         algorithms, without having to incur further ABI breakage.
424 
425     **************************************************************************************/
426 
427     /* The linear parameters */
428 
429     double  a = 0.0;                   /* semimajor axis (radius if eccentricity==0) */
430     double  b = 0.0;                   /* semiminor axis */
431     double  ra = 0.0;                  /* 1/a */
432     double  rb = 0.0;                  /* 1/b */
433 
434     /* The eccentricities */
435 
436     double  alpha = 0.0;               /* angular eccentricity */
437     double  e = 0.0;                   /* first  eccentricity */
438     double  es = 0.0;                  /* first  eccentricity squared */
439     double  e2 = 0.0;                  /* second eccentricity */
440     double  e2s = 0.0;                 /* second eccentricity squared */
441     double  e3 = 0.0;                  /* third  eccentricity */
442     double  e3s = 0.0;                 /* third  eccentricity squared */
443     double  one_es = 0.0;              /* 1 - e^2 */
444     double  rone_es = 0.0;             /* 1/one_es */
445 
446 
447     /* The flattenings */
448     double  f = 0.0;                   /* first  flattening */
449     double  f2 = 0.0;                  /* second flattening */
450     double  n = 0.0;                   /* third  flattening */
451     double  rf = 0.0;                  /* 1/f  */
452     double  rf2 = 0.0;                 /* 1/f2 */
453     double  rn = 0.0;                   /* 1/n  */
454 
455     /* This one's for GRS80 */
456     double  J = 0.0;                   /* "Dynamic form factor" */
457 
458     double  es_orig = 0.0;    /* es and a before any +proj related adjustment */
459     double  a_orig = 0.0;
460 
461 
462     /*************************************************************************************
463 
464                           C O O R D I N A T E   H A N D L I N G
465 
466     **************************************************************************************/
467 
468     int  over = 0;                  /* Over-range flag */
469     int  geoc = 0;                  /* Geocentric latitude flag */
470     int  is_latlong = 0;            /* proj=latlong ... not really a projection at all */
471     int  is_geocent = 0;            /* proj=geocent ... not really a projection at all */
472     int  need_ellps = 0;            /* 0 for operations that are purely cartesian */
473     int  skip_fwd_prepare = 0;
474     int  skip_fwd_finalize = 0;
475     int  skip_inv_prepare = 0;
476     int  skip_inv_finalize = 0;
477 
478     enum pj_io_units left =  PJ_IO_UNITS_WHATEVER; /* Flags for input/output coordinate types */
479     enum pj_io_units right =  PJ_IO_UNITS_WHATEVER;
480 
481     /* These PJs are used for implementing cs2cs style coordinate handling in the 4D API */
482     PJ *axisswap = nullptr;
483     PJ *cart = nullptr;
484     PJ *cart_wgs84 = nullptr;
485     PJ *helmert = nullptr;
486     PJ *hgridshift = nullptr;
487     PJ *vgridshift = nullptr;
488 
489 
490     /*************************************************************************************
491 
492                        C A R T O G R A P H I C       O F F S E T S
493 
494     **************************************************************************************/
495 
496     double  lam0 = 0.0;    /* central meridian */
497     double  phi0 = 0.0;    /* central parallel */
498     double  x0 = 0.0;      /* false easting */
499     double  y0 = 0.0;      /* false northing  */
500     double  z0 = 0.0;      /* height origin */
501     double  t0 = 0.0;      /* time origin */
502 
503 
504     /*************************************************************************************
505 
506                                     S C A L I N G
507 
508     **************************************************************************************/
509 
510     double  k0 = 0.0;                  /* General scaling factor - e.g. the 0.9996 of UTM */
511     double  to_meter = 0.0, fr_meter = 0.0;        /* Plane coordinate scaling. Internal unit [m] */
512     double  vto_meter = 0.0, vfr_meter = 0.0;      /* Vertical scaling. Internal unit [m] */
513 
514 
515     /*************************************************************************************
516 
517                   D A T U M S   A N D   H E I G H T   S Y S T E M S
518 
519     **************************************************************************************
520 
521         It may be possible, and meaningful, to move the list parts of this up to the
522         PJ_CONTEXT level.
523 
524     **************************************************************************************/
525 
526     int     datum_type = PJD_UNKNOWN;  /* PJD_UNKNOWN/3PARAM/7PARAM/GRIDSHIFT/WGS84 */
527     double  datum_params[7] = {0,0,0,0,0,0,0}; /* Parameters for 3PARAM and 7PARAM */
528 
529     int     has_geoid_vgrids = 0;      /* used by legacy transform.cpp */
530     void*   hgrids_legacy = nullptr;   /* used by legacy transform.cpp. Is a pointer to a ListOfHGrids* */
531     void*   vgrids_legacy = nullptr;   /* used by legacy transform.cpp. Is a pointer to a ListOfVGrids* */
532 
533     double  from_greenwich = 0.0;       /* prime meridian offset (in radians) */
534     double  long_wrap_center = 0.0;     /* 0.0 for -180 to 180, actually in radians*/
535     int     is_long_wrap_set = 0;
536     char    axis[4] = {0,0,0,0};        /* Axis order, pj_transform/pj_adjust_axis */
537 
538     /*************************************************************************************
539      ISO-19111 interface
540     **************************************************************************************/
541 
542     NS_PROJ::common::IdentifiedObjectPtr iso_obj{};
543 
544     // cached results
545     mutable std::string lastWKT{};
546     mutable std::string lastPROJString{};
547     mutable std::string lastJSONString{};
548     mutable bool gridsNeededAsked = false;
549     mutable std::vector<NS_PROJ::operation::GridDescription> gridsNeeded{};
550 
551     /*************************************************************************************
552      proj_create_crs_to_crs() alternative coordinate operations
553     **************************************************************************************/
554     std::vector<CoordOperation> alternativeCoordinateOperations{};
555     int iCurCoordOp = -1;
556 
557     /*************************************************************************************
558 
559                  E N D   O F    G E N E R A L   P A R A M E T E R   S T R U C T
560 
561     **************************************************************************************/
562 
563     PJconsts();
564     PJconsts(const PJconsts &) = delete;
565     PJconsts &operator=(const PJconsts &) = delete;
566 };
567 
568 
569 
570 
571 /* Parameter list (a copy of the +proj=... etc. parameters) */
572 struct ARG_list {
573     paralist *next;
574     char used;
575 #if (defined(__GNUC__) && __GNUC__ >= 8) || (defined(__clang__) && __clang_major__ >= 9)
576     char param[]; /* variable-length member */
577     /* Safer to use [] for gcc 8. See https://github.com/OSGeo/proj.4/pull/1087 */
578     /* and https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86914 */
579 #else
580     char param[1]; /* variable-length member */
581 #endif
582 };
583 
584 
585 typedef union { double  f; int  i; char *s; } PROJVALUE;
586 
587 
588 struct PJ_DATUMS {
589     const char    *id;           /* datum keyword */
590     const char    *defn;         /* ie. "to_wgs84=..." */
591     const char    *ellipse_id;   /* ie from ellipse table */
592     const char    *comments;     /* EPSG code, etc */
593 };
594 
595 
596 struct DERIVS {
597     double x_l, x_p;       /* derivatives of x for lambda-phi */
598     double y_l, y_p;       /* derivatives of y for lambda-phi */
599 };
600 
601 struct FACTORS {
602     struct DERIVS der;
603     double h, k;           /* meridional, parallel scales */
604     double omega, thetap;  /* angular distortion, theta prime */
605     double conv;           /* convergence */
606     double s;              /* areal scale factor */
607     double a, b;           /* max-min scale error */
608     int    code;           /* always 0 */
609 };
610 
611 /* library errors */
612 #define PJD_ERR_NO_ARGS                  -1
613 #define PJD_ERR_NO_OPTION_IN_INIT_FILE   -2
614 #define PJD_ERR_NO_COLON_IN_INIT_STRING  -3
615 #define PJD_ERR_PROJ_NOT_NAMED           -4
616 #define PJD_ERR_UNKNOWN_PROJECTION_ID    -5
617 #define PJD_ERR_INVALID_ECCENTRICITY     -6
618 #define PJD_ERR_UNKNOWN_UNIT_ID          -7
619 #define PJD_ERR_INVALID_BOOLEAN_PARAM    -8
620 #define PJD_ERR_UNKNOWN_ELLP_PARAM       -9
621 #define PJD_ERR_REV_FLATTENING_IS_ZERO  -10
622 #define PJD_ERR_REF_RAD_LARGER_THAN_90  -11
623 #define PJD_ERR_ES_LESS_THAN_ZERO       -12
624 #define PJD_ERR_MAJOR_AXIS_NOT_GIVEN    -13
625 #define PJD_ERR_LAT_OR_LON_EXCEED_LIMIT -14
626 #define PJD_ERR_INVALID_X_OR_Y          -15
627 #define PJD_ERR_WRONG_FORMAT_DMS_VALUE  -16
628 #define PJD_ERR_NON_CONV_INV_MERI_DIST  -17
629 #define PJD_ERR_NON_CON_INV_PHI2        -18
630 #define PJD_ERR_ACOS_ASIN_ARG_TOO_LARGE -19
631 #define PJD_ERR_TOLERANCE_CONDITION     -20
632 #define PJD_ERR_CONIC_LAT_EQUAL         -21
633 #define PJD_ERR_LAT_LARGER_THAN_90      -22
634 #define PJD_ERR_LAT1_IS_ZERO            -23
635 #define PJD_ERR_LAT_TS_LARGER_THAN_90   -24
636 #define PJD_ERR_CONTROL_POINT_NO_DIST   -25
637 #define PJD_ERR_NO_ROTATION_PROJ        -26
638 #define PJD_ERR_W_OR_M_ZERO_OR_LESS     -27
639 #define PJD_ERR_LSAT_NOT_IN_RANGE       -28
640 #define PJD_ERR_PATH_NOT_IN_RANGE       -29
641 #define PJD_ERR_INVALID_H               -30
642 #define PJD_ERR_K_LESS_THAN_ZERO        -31
643 #define PJD_ERR_LAT_1_OR_2_ZERO_OR_90   -32
644 #define PJD_ERR_LAT_0_OR_ALPHA_EQ_90    -33
645 #define PJD_ERR_ELLIPSOID_USE_REQUIRED  -34
646 #define PJD_ERR_INVALID_UTM_ZONE        -35
647 /* -36 no longer used */
648 #define PJD_ERR_FAILED_TO_FIND_PROJ     -37
649 #define PJD_ERR_FAILED_TO_LOAD_GRID     -38
650 #define PJD_ERR_INVALID_M_OR_N          -39
651 #define PJD_ERR_N_OUT_OF_RANGE          -40
652 #define PJD_ERR_LAT_1_2_UNSPECIFIED     -41
653 #define PJD_ERR_ABS_LAT1_EQ_ABS_LAT2    -42
654 #define PJD_ERR_LAT_0_HALF_PI_FROM_MEAN -43
655 #define PJD_ERR_UNPARSEABLE_CS_DEF      -44
656 #define PJD_ERR_GEOCENTRIC              -45
657 #define PJD_ERR_UNKNOWN_PRIME_MERIDIAN  -46
658 #define PJD_ERR_AXIS                    -47
659 #define PJD_ERR_GRID_AREA               -48
660 #define PJD_ERR_INVALID_SWEEP_AXIS      -49
661 #define PJD_ERR_MALFORMED_PIPELINE      -50
662 #define PJD_ERR_UNIT_FACTOR_LESS_THAN_0 -51
663 #define PJD_ERR_INVALID_SCALE           -52
664 #define PJD_ERR_NON_CONVERGENT          -53
665 #define PJD_ERR_MISSING_ARGS            -54
666 #define PJD_ERR_LAT_0_IS_ZERO           -55
667 #define PJD_ERR_ELLIPSOIDAL_UNSUPPORTED -56
668 #define PJD_ERR_TOO_MANY_INITS          -57
669 #define PJD_ERR_INVALID_ARG             -58
670 #define PJD_ERR_INCONSISTENT_UNIT       -59
671 #define PJD_ERR_MUTUALLY_EXCLUSIVE_ARGS -60
672 #define PJD_ERR_GENERIC_ERROR           -61
673 #define PJD_ERR_NETWORK_ERROR           -62
674 /* NOTE: Remember to update src/strerrno.cpp, src/apps/gie.cpp and transient_error in */
675 /* src/transform.cpp when adding new value */
676 
677 // Legacy
678 struct projFileAPI_t;
679 
680 struct projCppContext;
681 
682 struct projNetworkCallbacksAndData
683 {
684     bool enabled = false;
685     bool enabled_env_variable_checked = false; // whereas we have checked PROJ_NETWORK env variable
686     proj_network_open_cbk_type open = nullptr;
687     proj_network_close_cbk_type close = nullptr;
688     proj_network_get_header_value_cbk_type get_header_value = nullptr;
689     proj_network_read_range_type read_range = nullptr;
690     void* user_data = nullptr;
691 };
692 
693 struct projGridChunkCache
694 {
695     bool enabled = true;
696     std::string filename{};
697     long long max_size = 300 * 1024 * 1024;
698     int ttl = 86400; // 1 day
699 };
700 
701 struct projFileApiCallbackAndData
702 {
703     PROJ_FILE_HANDLE* (*open_cbk)(PJ_CONTEXT *ctx, const char *filename, PROJ_OPEN_ACCESS access, void* user_data) = nullptr;
704     size_t           (*read_cbk)(PJ_CONTEXT *ctx, PROJ_FILE_HANDLE*, void* buffer, size_t size, void* user_data) = nullptr;
705     size_t           (*write_cbk)(PJ_CONTEXT *ctx, PROJ_FILE_HANDLE*, const void* buffer, size_t size, void* user_data) = nullptr;
706     int              (*seek_cbk)(PJ_CONTEXT *ctx, PROJ_FILE_HANDLE*, long long offset, int whence, void* user_data) = nullptr;
707     unsigned long long (*tell_cbk)(PJ_CONTEXT *ctx, PROJ_FILE_HANDLE*, void* user_data) = nullptr;
708     void             (*close_cbk)(PJ_CONTEXT *ctx, PROJ_FILE_HANDLE*, void* user_data) = nullptr;
709 
710     int (*exists_cbk)(PJ_CONTEXT *ctx, const char *filename, void* user_data) = nullptr;
711     int (*mkdir_cbk)(PJ_CONTEXT *ctx, const char *filename, void* user_data) = nullptr;
712     int (*unlink_cbk)(PJ_CONTEXT *ctx, const char *filename, void* user_data) = nullptr;
713     int (*rename_cbk)(PJ_CONTEXT *ctx, const char *oldPath, const char *newPath, void* user_data) = nullptr;
714 
715     void*            user_data = nullptr;
716 };
717 
718 /* proj thread context */
719 struct projCtx_t {
720     int     last_errno = 0;
721     int     debug_level = 0;
722     void    (*logger)(void *, int, const char *) = nullptr;
723     void    *logger_app_data = nullptr;
724     struct projFileAPI_t *fileapi_legacy = nullptr; // for proj_api.h legacy API
725     struct projCppContext* cpp_context = nullptr; /* internal context for C++ code */
726     int     use_proj4_init_rules = -1; /* -1 = unknown, 0 = no, 1 = yes */
727     int     epsg_file_exists = -1; /* -1 = unknown, 0 = no, 1 = yes */
728     std::string ca_bundle_path{};
729 
730     std::string env_var_proj_lib{}; // content of PROJ_LIB environment variable. Use Filemanager::getProjLibEnvVar() to access
731     std::vector<std::string> search_paths{};
732     const char **c_compat_paths = nullptr; // same, but for projinfo usage
733 
734     const char* (*file_finder_legacy) (const char*) = nullptr; // Only for proj_api compat. To remove once it is removed
735     const char* (*file_finder) (PJ_CONTEXT *, const char*, void* user_data) = nullptr;
736     void* file_finder_user_data = nullptr;
737 
738     bool defer_grid_opening = false; // set transiently by pj_obj_create()
739 
740     projFileApiCallbackAndData fileApi{};
741     std::string custom_sqlite3_vfs_name{};
742     std::string user_writable_directory{};
743 
744     // BEGIN ini file settings
745     bool iniFileLoaded = false;
746     std::string endpoint{};
747     projNetworkCallbacksAndData networking{};
748     projGridChunkCache gridChunkCache{};
749     TMercAlgo defaultTmercAlgo = TMercAlgo::PODER_ENGSAGER; // can be overridden by content of proj.ini
750     // END ini file settings
751 
752     int projStringParserCreateFromPROJStringRecursionCounter = 0; // to avoid potential infinite recursion in PROJStringParser::createFromPROJString()
753     int pipelineInitRecursiongCounter = 0; // to avoid potential infinite recursion in pipeline.cpp
754 
755 
756     projCtx_t() = default;
757     projCtx_t(const projCtx_t&);
758     ~projCtx_t();
759 
760     projCtx_t& operator= (const projCtx_t&) = delete;
761 
762     projCppContext* get_cpp_context();
763     void safeAutoCloseDbIfNeeded();
764     void set_search_paths(const std::vector<std::string>& search_paths_in);
765     void set_ca_bundle_path(const std::string& ca_bundle_path_in);
766 
767     static projCtx_t createDefault();
768 };
769 
770 /* Generate pj_list external or make list from include file */
771 #ifndef PJ_DATUMS__
772 C_NAMESPACE_VAR struct PJ_DATUMS pj_datums[];
773 #endif
774 
775 
776 
777 
778 
779 #ifdef PJ_LIB__
780 #define PROJ_HEAD(name, desc) static const char des_##name [] = desc
781 
782 #define OPERATION(name, NEED_ELLPS)                          \
783                                                              \
784 pj_projection_specific_setup_##name (PJ *P);                 \
785 C_NAMESPACE PJ *pj_##name (PJ *P);                           \
786                                                              \
787 C_NAMESPACE_VAR const char * const pj_s_##name = des_##name; \
788                                                              \
789 C_NAMESPACE PJ *pj_##name (PJ *P) {                          \
790     if (P)                                                   \
791         return pj_projection_specific_setup_##name (P);      \
792     P = pj_new();                                            \
793     if (nullptr==P)                                          \
794         return nullptr;                                      \
795     P->descr = des_##name;                                   \
796     P->need_ellps = NEED_ELLPS;                              \
797     P->left  = PJ_IO_UNITS_RADIANS;                          \
798     P->right = PJ_IO_UNITS_CLASSIC;                          \
799     return P;                                                \
800 }                                                            \
801                                                              \
802 PJ *pj_projection_specific_setup_##name (PJ *P)
803 
804 /* In ISO19000 lingo, an operation is either a conversion or a transformation */
805 #define CONVERSION(name, need_ellps)      OPERATION (name, need_ellps)
806 #define TRANSFORMATION(name, need_ellps)  OPERATION (name, need_ellps)
807 
808 /* In PROJ.4 a projection is a conversion taking angular input and giving scaled linear output */
809 #define PROJECTION(name) CONVERSION (name, 1)
810 
811 #endif /* def PJ_LIB__ */
812 
813 /* procedure prototypes */
814 double PROJ_DLL dmstor(const char *, char **);
815 double dmstor_ctx(projCtx_t *ctx, const char *, char **);
816 void   PROJ_DLL set_rtodms(int, int);
817 char  PROJ_DLL *rtodms(char *, double, int, int);
818 double PROJ_DLL adjlon(double);
819 double aacos(projCtx_t *,double);
820 double aasin(projCtx_t *,double);
821 double asqrt(double);
822 double aatan2(double, double);
823 
824 PROJVALUE PROJ_DLL pj_param(projCtx_t *ctx, paralist *, const char *);
825 paralist PROJ_DLL *pj_param_exists (paralist *list, const char *parameter);
826 paralist PROJ_DLL *pj_mkparam(const char *);
827 paralist *pj_mkparam_ws (const char *str, const char **next_str);
828 
829 
830 int PROJ_DLL pj_ell_set(projCtx_t *ctx, paralist *, double *, double *);
831 int pj_datum_set(projCtx_t *,paralist *, PJ *);
832 int pj_angular_units_set(paralist *, PJ *);
833 
834 paralist *pj_clone_paralist( const paralist* );
835 paralist *pj_search_initcache( const char *filekey );
836 void      pj_insert_initcache( const char *filekey, const paralist *list);
837 paralist *pj_expand_init(projCtx_t *ctx, paralist *init);
838 
839 void     *pj_dealloc_params (projCtx_t *ctx, paralist *start, int errlev);
840 
841 
842 double *pj_enfn(double);
843 double  pj_mlfn(double, double, double, const double *);
844 double  pj_inv_mlfn(projCtx_t *, double, double, const double *);
845 double  pj_qsfn(double, double, double);
846 double  pj_tsfn(double, double, double);
847 double  pj_msfn(double, double, double);
848 double  PROJ_DLL pj_phi2(projCtx_t *, const double, const double);
849 double  pj_qsfn_(double, PJ *);
850 double *pj_authset(double);
851 double  pj_authlat(double, double *);
852 
853 COMPLEX pj_zpoly1(COMPLEX, const COMPLEX *, int);
854 COMPLEX pj_zpolyd1(COMPLEX, const COMPLEX *, int, COMPLEX *);
855 
856 int pj_deriv(PJ_LP, double, const PJ *, struct DERIVS *);
857 int pj_factors(PJ_LP, const PJ *, double, struct FACTORS *);
858 
859 void  *proj_mdist_ini(double);
860 double proj_mdist(double, double, double, const void *);
861 double proj_inv_mdist(projCtx_t *ctx, double, const void *);
862 void  *pj_gauss_ini(double, double, double *,double *);
863 PJ_LP     pj_gauss(projCtx_t *, PJ_LP, const void *);
864 PJ_LP     pj_inv_gauss(projCtx_t *, PJ_LP, const void *);
865 
866 struct PJ_DATUMS           PROJ_DLL *pj_get_datums_ref( void );
867 
868 PJ *pj_new(void);
869 PJ *pj_default_destructor (PJ *P, int errlev);
870 
871 double PROJ_DLL pj_atof( const char* nptr );
872 double pj_strtod( const char *nptr, char **endptr );
873 void   pj_freeup_plain (PJ *P);
874 
875 PJ* pj_init_ctx_with_allow_init_epsg( projCtx_t *ctx, int argc, char **argv, int allow_init_epsg );
876 
877 std::string PROJ_DLL pj_add_type_crs_if_needed(const std::string& str);
878 std::string pj_double_quote_string_param_if_needed(const std::string& str);
879 
880 PJ *pj_create_internal (PJ_CONTEXT *ctx, const char *definition);
881 PJ *pj_create_argv_internal (PJ_CONTEXT *ctx, int argc, char **argv);
882 
883 // For use by projinfo
884 void pj_load_ini(PJ_CONTEXT* ctx);
885 
886 // Exported for testing purposes only
887 std::string PROJ_DLL pj_context_get_grid_cache_filename(PJ_CONTEXT *ctx);
888 
889 // For use by projsync
890 void PROJ_DLL pj_context_set_user_writable_directory(PJ_CONTEXT* ctx, const std::string& path);
891 std::string PROJ_DLL pj_get_relative_share_proj(PJ_CONTEXT *ctx);
892 
893 std::vector<CoordOperation> pj_create_prepared_operations(PJ_CONTEXT *ctx,
894                                                      const PJ *source_crs,
895                                                      const PJ *target_crs,
896                                                      PJ_OBJ_LIST* op_list);
897 
898 int pj_get_suggested_operation(PJ_CONTEXT *ctx,
899                                const std::vector<CoordOperation>& opList,
900                                const int iExcluded[2],
901                                PJ_DIRECTION direction,
902                                PJ_COORD coord);
903 
904 const PJ_UNITS *pj_list_linear_units();
905 const PJ_UNITS *pj_list_angular_units();
906 
907 void pj_clear_hgridshift_knowngrids_cache();
908 void pj_clear_vgridshift_knowngrids_cache();
909 
910 PJ_LP pj_generic_inverse_2d(PJ_XY xy, PJ *P, PJ_LP lpInitial);
911 
912 /* classic public API */
913 #include "proj_api.h"
914 
915 #endif /* ndef PROJ_INTERNAL_H */
916