1 /***************************************************************************
2                qgscoordinatetransform_p.h
3                --------------------------
4     begin                : July 2016
5     copyright            : (C) 2016 Nyall Dawson
6     email                : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 #ifndef QGSCOORDINATETRANSFORMPRIVATE_H
18 #define QGSCOORDINATETRANSFORMPRIVATE_H
19 
20 #define SIP_NO_FILE
21 #include "qgsconfig.h"
22 
23 /// @cond PRIVATE
24 
25 //
26 //  W A R N I N G
27 //  -------------
28 //
29 // This file is not part of the QGIS API.  It exists purely as an
30 // implementation detail.  This header file may change from version to
31 // version without notice, or even be removed.
32 //
33 
34 #include <QSharedData>
35 
36 struct PJconsts;
37 typedef struct PJconsts PJ;
38 typedef PJ *ProjData;
39 
40 #include "qgscoordinatereferencesystem.h"
41 #include "qgscoordinatetransformcontext.h"
42 
43 class QgsCoordinateTransformPrivate : public QSharedData
44 {
45 
46   public:
47 
48     explicit QgsCoordinateTransformPrivate();
49 
50     QgsCoordinateTransformPrivate( const QgsCoordinateReferenceSystem &source,
51                                    const QgsCoordinateReferenceSystem &destination,
52                                    const QgsCoordinateTransformContext &context );
53 
54     QgsCoordinateTransformPrivate( const QgsCoordinateReferenceSystem &source,
55                                    const QgsCoordinateReferenceSystem &destination,
56                                    int sourceDatumTransform,
57                                    int destDatumTransform );
58 
59     QgsCoordinateTransformPrivate( const QgsCoordinateTransformPrivate &other );
60 
61     ~QgsCoordinateTransformPrivate();
62 
63     bool checkValidity();
64 
65     void invalidate();
66 
67     bool initialize();
68 
69     void calculateTransforms( const QgsCoordinateTransformContext &context );
70 
71     ProjData threadLocalProjData();
72 
73     int mAvailableOpCount = -1;
74     ProjData threadLocalFallbackProjData();
75 
76     // Only meant to be called by QgsCoordinateTransform::removeFromCacheObjectsBelongingToCurrentThread()
77     bool removeObjectsBelongingToCurrentThread( void *pj_context );
78 
79     /**
80      * Flag to indicate whether the transform is valid (ie has a valid
81      * source and destination crs)
82      */
83     bool mIsValid = false;
84 
85     /**
86      * Flag to indicate that the source and destination coordinate systems are
87      * equal and not transformation needs to be done
88      */
89     bool mShortCircuit = false;
90 
91     //! QgsCoordinateReferenceSystem of the source (layer) coordinate system
92     QgsCoordinateReferenceSystem mSourceCRS;
93 
94     //! QgsCoordinateReferenceSystem of the destination (map canvas) coordinate system
95     QgsCoordinateReferenceSystem mDestCRS;
96 
97     Q_DECL_DEPRECATED QString mSourceProjString;
98     Q_DECL_DEPRECATED QString mDestProjString;
99 
100     Q_DECL_DEPRECATED int mSourceDatumTransform = -1;
101     Q_DECL_DEPRECATED int mDestinationDatumTransform = -1;
102     QString mProjCoordinateOperation;
103     bool mShouldReverseCoordinateOperation = false;
104     bool mAllowFallbackTransforms = true;
105 
106     bool mSourceIsDynamic = false;
107     bool mDestIsDynamic = false;
108     double mSourceCoordinateEpoch = std::numeric_limits< double >::quiet_NaN();
109     double mDestCoordinateEpoch = std::numeric_limits< double >::quiet_NaN();
110     double mDefaultTime = std::numeric_limits< double >::quiet_NaN();
111 
112     //! True if the proj transform corresponds to the reverse direction, and must be flipped when transforming...
113     bool mIsReversed = false;
114 
115     QReadWriteLock mProjLock;
116     QMap < uintptr_t, ProjData > mProjProjections;
117     QMap < uintptr_t, ProjData > mProjFallbackProjections;
118 
119     /**
120      * Sets a custom handler to use when a coordinate transform is created between \a sourceCrs and
121      * \a destinationCrs, yet the coordinate operation requires a transform \a grid which is not present
122      * on the system.
123      *
124      * \since QGIS 3.8
125      */
126     static void setCustomMissingRequiredGridHandler( const std::function< void( const QgsCoordinateReferenceSystem &sourceCrs,
127         const QgsCoordinateReferenceSystem &destinationCrs,
128         const QgsDatumTransform::GridDetails &grid )> &handler );
129 
130     /**
131      * Sets a custom handler to use when a coordinate transform is created between \a sourceCrs and
132      * \a destinationCrs, yet a preferred (more accurate?) operation is available which could not
133      * be created on the system (e.g. due to missing transform grids).
134      *
135      * \a preferredOperation gives the details of the preferred coordinate operation, and
136      * \a availableOperation gives the details of the actual operation to be used during the
137      * transform.
138      *
139      * \since QGIS 3.8
140      */
141     static void setCustomMissingPreferredGridHandler( const std::function< void( const QgsCoordinateReferenceSystem &sourceCrs,
142         const QgsCoordinateReferenceSystem &destinationCrs,
143         const QgsDatumTransform::TransformDetails &preferredOperation,
144         const QgsDatumTransform::TransformDetails &availableOperation )> &handler );
145 
146     /**
147      * Sets a custom handler to use when a coordinate transform was required between \a sourceCrs and
148      * \a destinationCrs, yet the coordinate operation could not be created. The \a error argument
149      * specifies the error message obtained.
150      *
151      * \since QGIS 3.8
152      */
153     static void setCustomCoordinateOperationCreationErrorHandler( const std::function< void( const QgsCoordinateReferenceSystem &sourceCrs,
154         const QgsCoordinateReferenceSystem &destinationCrs,
155         const QString &error )> &handler );
156 
157     /**
158      * Sets a custom handler to use when a coordinate operation was specified for use between \a sourceCrs and
159      * \a destinationCrs by the transform context, yet the coordinate operation could not be created. The \a desiredOperation argument
160      * specifies the desired transform details as specified by the context.
161      *
162      * \since QGIS 3.8
163      */
164     static void setCustomMissingGridUsedByContextHandler( const std::function< void( const QgsCoordinateReferenceSystem &sourceCrs,
165         const QgsCoordinateReferenceSystem &destinationCrs,
166         const QgsDatumTransform::TransformDetails &desiredOperation )> &handler );
167 
168     /**
169      * Sets a custom \a handler to use when the desired coordinate operation for use between \a sourceCrs and
170      * \a destinationCrs is a dynamic CRS to dynamic CRS transform, not currently supported by PROJ.
171      *
172      * \since QGIS 3.20
173      */
174     static void setDynamicCrsToDynamicCrsWarningHandler( const std::function< void( const QgsCoordinateReferenceSystem &sourceCrs,
175         const QgsCoordinateReferenceSystem &destinationCrs )> &handler );
176 
177   private:
178 
179     void freeProj();
180 
181     static std::function< void( const QgsCoordinateReferenceSystem &sourceCrs,
182                                 const QgsCoordinateReferenceSystem &destinationCrs,
183                                 const QgsDatumTransform::GridDetails &grid )> sMissingRequiredGridHandler;
184 
185     static std::function< void( const QgsCoordinateReferenceSystem &sourceCrs,
186                                 const QgsCoordinateReferenceSystem &destinationCrs,
187                                 const QgsDatumTransform::TransformDetails &preferredOperation,
188                                 const QgsDatumTransform::TransformDetails &availableOperation )> sMissingPreferredGridHandler;
189 
190     static std::function< void( const QgsCoordinateReferenceSystem &sourceCrs,
191                                 const QgsCoordinateReferenceSystem &destinationCrs,
192                                 const QString &error )> sCoordinateOperationCreationErrorHandler;
193 
194     static std::function< void( const QgsCoordinateReferenceSystem &sourceCrs,
195                                 const QgsCoordinateReferenceSystem &destinationCrs,
196                                 const QgsDatumTransform::TransformDetails &desiredOperation )> sMissingGridUsedByContextHandler;
197 
198     static std::function< void( const QgsCoordinateReferenceSystem &sourceCrs,
199                                 const QgsCoordinateReferenceSystem &destinationCrs )> sDynamicCrsToDynamicCrsWarningHandler;
200 
201     QgsCoordinateTransformPrivate &operator= ( const QgsCoordinateTransformPrivate & ) = delete;
202 };
203 
204 /// @endcond
205 
206 #endif // QGSCOORDINATETRANSFORMPRIVATE_H
207