Skip to content

Commit 5131258

Browse files
committed
QgsCoordinateTransformContext is implicitly shared
1 parent f7b315f commit 5131258

5 files changed

+176
-25
lines changed

python/core/qgscoordinatetransformcontext.sip

+12
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111

1212

13+
1314
class QgsCoordinateTransformContext
1415
{
1516
%Docstring
@@ -26,6 +27,10 @@ class QgsCoordinateTransformContext
2627
addSourceDatumTransform() then this datum transform will be used. The same logic
2728
applies for destination CRS transforms set using addDestinationDatumTransform().
2829

30+
.. note::
31+
32+
QgsCoordinateTransformContext objects are implicitly shared.
33+
2934
.. versionadded:: 3.0
3035
%End
3136

@@ -39,6 +44,13 @@ class QgsCoordinateTransformContext
3944
Constructor for QgsCoordinateTransformContext.
4045
%End
4146

47+
QgsCoordinateTransformContext( const QgsCoordinateTransformContext &rhs );
48+
%Docstring
49+
Copy constructor
50+
%End
51+
52+
53+
4254
void clear();
4355
%Docstring
4456
Clears all stored transform information from the context.

src/core/qgscoordinatetransformcontext.cpp

+30-12
Original file line numberDiff line numberDiff line change
@@ -16,71 +16,89 @@
1616
***************************************************************************/
1717

1818
#include "qgscoordinatetransformcontext.h"
19+
#include "qgscoordinatetransformcontext_p.h"
20+
QgsCoordinateTransformContext::QgsCoordinateTransformContext()
21+
: d( new QgsCoordinateTransformContextPrivate() )
22+
{}
23+
24+
QgsCoordinateTransformContext::QgsCoordinateTransformContext( const QgsCoordinateTransformContext &rhs ) //NOLINT
25+
: d( rhs.d )
26+
{}
27+
28+
QgsCoordinateTransformContext &QgsCoordinateTransformContext::operator=( const QgsCoordinateTransformContext &rhs ) //NOLINT
29+
{
30+
d = rhs.d;
31+
return *this;
32+
}
1933

2034
void QgsCoordinateTransformContext::clear()
2135
{
22-
mSourceDestDatumTransforms.clear();
23-
mSourceDatumTransforms.clear();
24-
mDestDatumTransforms.clear();
36+
d.detach();
37+
d->mSourceDestDatumTransforms.clear();
38+
d->mSourceDatumTransforms.clear();
39+
d->mDestDatumTransforms.clear();
2540
}
2641

2742
QMap<QString, int> QgsCoordinateTransformContext::sourceDatumTransforms() const
2843
{
29-
return mSourceDatumTransforms;
44+
return d->mSourceDatumTransforms;
3045
}
3146

3247
bool QgsCoordinateTransformContext::addSourceDatumTransform( const QgsCoordinateReferenceSystem &crs, int transform )
3348
{
3449
if ( !crs.isValid() )
3550
return false;
3651

52+
d.detach();
3753
if ( transform == -1 )
3854
{
39-
mSourceDatumTransforms.remove( crs.authid() );
55+
d->mSourceDatumTransforms.remove( crs.authid() );
4056
return true;
4157
}
4258

43-
mSourceDatumTransforms.insert( crs.authid(), transform );
59+
d->mSourceDatumTransforms.insert( crs.authid(), transform );
4460
return true;
4561
}
4662

4763
QMap<QString, int> QgsCoordinateTransformContext::destinationDatumTransforms() const
4864
{
49-
return mDestDatumTransforms;
65+
return d->mDestDatumTransforms;
5066
}
5167

5268
bool QgsCoordinateTransformContext::addDestinationDatumTransform( const QgsCoordinateReferenceSystem &crs, int transform )
5369
{
5470
if ( !crs.isValid() )
5571
return false;
5672

73+
d.detach();
5774
if ( transform == -1 )
5875
{
59-
mDestDatumTransforms.remove( crs.authid() );
76+
d->mDestDatumTransforms.remove( crs.authid() );
6077
return true;
6178
}
6279

63-
mDestDatumTransforms.insert( crs.authid(), transform );
80+
d->mDestDatumTransforms.insert( crs.authid(), transform );
6481
return true;
6582
}
6683

6784
QMap<QPair<QString, QString>, QPair<int, int> > QgsCoordinateTransformContext::sourceDestinationDatumTransforms() const
6885
{
69-
return mSourceDestDatumTransforms;
86+
return d->mSourceDestDatumTransforms;
7087
}
7188

7289
bool QgsCoordinateTransformContext::addSourceDestinationDatumTransform( const QgsCoordinateReferenceSystem &sourceCrs, const QgsCoordinateReferenceSystem &destinationCrs, int sourceTransform, int destinationTransform )
7390
{
7491
if ( !sourceCrs.isValid() || !destinationCrs.isValid() )
7592
return false;
7693

94+
d.detach();
7795
if ( sourceTransform == -1 || destinationTransform == -1 )
7896
{
79-
mSourceDestDatumTransforms.remove( qMakePair( sourceCrs.authid(), destinationCrs.authid() ) );
97+
d->mSourceDestDatumTransforms.remove( qMakePair( sourceCrs.authid(), destinationCrs.authid() ) );
8098
return true;
8199
}
82100

83-
mSourceDestDatumTransforms.insert( qMakePair( sourceCrs.authid(), destinationCrs.authid() ), qMakePair( sourceTransform, destinationTransform ) );
101+
d->mSourceDestDatumTransforms.insert( qMakePair( sourceCrs.authid(), destinationCrs.authid() ), qMakePair( sourceTransform, destinationTransform ) );
84102
return true;
85103
}
86104

src/core/qgscoordinatetransformcontext.h

+22-13
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,13 @@
2020

2121
#include "qgis_core.h"
2222
#include "qgis.h"
23-
#include "qgscoordinatereferencesystem.h"
23+
#include "qgscoordinatetransformcontext_p.h"
24+
25+
/***************************************************************************
26+
* This class is considered CRITICAL and any change MUST be accompanied with
27+
* full unit tests in testqgsfeature.cpp.
28+
* See details in QEP #17
29+
****************************************************************************/
2430

2531
/**
2632
* \class QgsCoordinateTransformContext
@@ -38,6 +44,8 @@
3844
* addSourceDatumTransform() then this datum transform will be used. The same logic
3945
* applies for destination CRS transforms set using addDestinationDatumTransform().
4046
*
47+
* \note QgsCoordinateTransformContext objects are implicitly shared.
48+
*
4149
* \since QGIS 3.0
4250
*/
4351

@@ -48,7 +56,18 @@ class CORE_EXPORT QgsCoordinateTransformContext
4856
/**
4957
* Constructor for QgsCoordinateTransformContext.
5058
*/
51-
QgsCoordinateTransformContext() = default;
59+
QgsCoordinateTransformContext();
60+
61+
/**
62+
* Copy constructor
63+
*/
64+
QgsCoordinateTransformContext( const QgsCoordinateTransformContext &rhs );
65+
66+
/**
67+
* Assignment operator
68+
*/
69+
QgsCoordinateTransformContext &operator=( const QgsCoordinateTransformContext &rhs ) SIP_SKIP;
70+
5271

5372
/**
5473
* Clears all stored transform information from the context.
@@ -156,17 +175,7 @@ class CORE_EXPORT QgsCoordinateTransformContext
156175

157176
private:
158177

159-
/**
160-
* Mapping for datum transforms to use for source/destination CRS pairs.
161-
* Matching records from this map will take precedence over other transform maps.
162-
*/
163-
QMap< QPair< QString, QString >, QPair< int, int > > mSourceDestDatumTransforms;
164-
165-
//! Mapping for datum transforms to use for source CRS
166-
QMap< QString, int > mSourceDatumTransforms;
167-
168-
//! Mapping for datum transforms to use for destination CRS
169-
QMap< QString, int > mDestDatumTransforms;
178+
QExplicitlySharedDataPointer<QgsCoordinateTransformContextPrivate> d;
170179

171180
};
172181

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/***************************************************************************
2+
qgscoordinatetransformcontext_p.h
3+
-------------------------------
4+
begin : November 2017
5+
copyright : (C) 2017 by 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+
18+
#ifndef QGSCOORDINATETRANSFORMCONTEXT_PRIVATE_H
19+
#define QGSCOORDINATETRANSFORMCONTEXT_PRIVATE_H
20+
21+
/// @cond PRIVATE
22+
23+
//
24+
// W A R N I N G
25+
// -------------
26+
//
27+
// This file is not part of the QGIS API. It exists purely as an
28+
// implementation detail. This header file may change from version to
29+
// version without notice, or even be removed.
30+
//
31+
32+
/***************************************************************************
33+
* This class is considered CRITICAL and any change MUST be accompanied with
34+
* full unit tests in testqgsfeature.cpp.
35+
* See details in QEP #17
36+
****************************************************************************/
37+
38+
#include "qgscoordinatereferencesystem.h"
39+
40+
41+
class QgsCoordinateTransformContextPrivate : public QSharedData
42+
{
43+
44+
public:
45+
46+
QgsCoordinateTransformContextPrivate() = default;
47+
48+
QgsCoordinateTransformContextPrivate( const QgsCoordinateTransformContextPrivate &other )
49+
: QSharedData( other )
50+
, mSourceDestDatumTransforms( other.mSourceDestDatumTransforms )
51+
, mSourceDatumTransforms( other.mSourceDatumTransforms )
52+
, mDestDatumTransforms( other.mDestDatumTransforms )
53+
{
54+
}
55+
56+
/**
57+
* Mapping for datum transforms to use for source/destination CRS pairs.
58+
* Matching records from this map will take precedence over other transform maps.
59+
*/
60+
QMap< QPair< QString, QString >, QPair< int, int > > mSourceDestDatumTransforms;
61+
62+
//! Mapping for datum transforms to use for source CRS
63+
QMap< QString, int > mSourceDatumTransforms;
64+
65+
//! Mapping for datum transforms to use for destination CRS
66+
QMap< QString, int > mDestDatumTransforms;
67+
68+
};
69+
70+
71+
/// @endcond
72+
73+
74+
#endif // QGSCOORDINATETRANSFORMCONTEXT_PRIVATE_H
75+
76+
77+
78+

tests/src/core/testqgscoordinatetransform.cpp

+34
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "qgscoordinatetransform.h"
1818
#include "qgsapplication.h"
1919
#include "qgsrectangle.h"
20+
#include "qgscoordinatetransformcontext.h"
2021
#include <QObject>
2122
#include "qgstest.h"
2223
#include "qgsexception.h"
@@ -33,6 +34,7 @@ class TestQgsCoordinateTransform: public QObject
3334
void assignment();
3435
void isValid();
3536
void isShortCircuited();
37+
void contextShared();
3638

3739
private:
3840

@@ -178,6 +180,38 @@ void TestQgsCoordinateTransform::isShortCircuited()
178180
QVERIFY( tr5.isShortCircuited() );
179181
}
180182

183+
void TestQgsCoordinateTransform::contextShared()
184+
{
185+
//test implicit sharing of QgsCoordinateTransformContext
186+
QgsCoordinateTransformContext original;
187+
original.addDestinationDatumTransform( QgsCoordinateReferenceSystem( 3111 ), 1 );
188+
189+
QgsCoordinateTransformContext copy( original );
190+
QMap< QString, int > expected;
191+
expected.insert( "EPSG:3111", 1 );
192+
QCOMPARE( original.destinationDatumTransforms(), expected );
193+
QCOMPARE( copy.destinationDatumTransforms(), expected );
194+
195+
// trigger detach
196+
copy.addDestinationDatumTransform( QgsCoordinateReferenceSystem( 3111 ), 2 );
197+
QCOMPARE( original.destinationDatumTransforms(), expected );
198+
199+
expected.insert( "EPSG:3111", 2 );
200+
QCOMPARE( copy.destinationDatumTransforms(), expected );
201+
202+
// copy via assignment
203+
QgsCoordinateTransformContext copy2;
204+
copy2 = original;
205+
expected.insert( "EPSG:3111", 1 );
206+
QCOMPARE( original.destinationDatumTransforms(), expected );
207+
QCOMPARE( copy2.destinationDatumTransforms(), expected );
208+
209+
copy2.addDestinationDatumTransform( QgsCoordinateReferenceSystem( 3111 ), 3 );
210+
QCOMPARE( original.destinationDatumTransforms(), expected );
211+
expected.insert( "EPSG:3111", 3 );
212+
QCOMPARE( copy2.destinationDatumTransforms(), expected );
213+
}
214+
181215

182216
void TestQgsCoordinateTransform::transformBoundingBox()
183217
{

0 commit comments

Comments
 (0)