1 /******************************************************************************
2 *
3 * Project: PROJ
4 * Purpose: Test ISO19111:2019 implementation
5 * Author: Even Rouault <even dot rouault at spatialys dot com>
6 *
7 ******************************************************************************
8 * Copyright (c) 2018, Even Rouault <even dot rouault at spatialys dot com>
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 EVENT 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 #include "gtest_include.h"
30
31 #include <cstdio>
32 #include <limits>
33
34 #include "proj.h"
35 #include "proj_constants.h"
36 #include "proj_experimental.h"
37
38 #include "proj/common.hpp"
39 #include "proj/coordinateoperation.hpp"
40 #include "proj/coordinatesystem.hpp"
41 #include "proj/crs.hpp"
42 #include "proj/datum.hpp"
43 #include "proj/io.hpp"
44 #include "proj/metadata.hpp"
45 #include "proj/util.hpp"
46
47 #include <sqlite3.h>
48
49 using namespace osgeo::proj::common;
50 using namespace osgeo::proj::crs;
51 using namespace osgeo::proj::cs;
52 using namespace osgeo::proj::datum;
53 using namespace osgeo::proj::io;
54 using namespace osgeo::proj::metadata;
55 using namespace osgeo::proj::operation;
56 using namespace osgeo::proj::util;
57
58 namespace {
59
60 class CApi : public ::testing::Test {
61
DummyLogFunction(void *,int,const char *)62 static void DummyLogFunction(void *, int, const char *) {}
63
64 protected:
SetUp()65 void SetUp() override {
66 m_ctxt = proj_context_create();
67 proj_log_func(m_ctxt, nullptr, DummyLogFunction);
68 }
69
TearDown()70 void TearDown() override {
71 if (m_ctxt)
72 proj_context_destroy(m_ctxt);
73 }
74
createBoundCRS()75 static BoundCRSNNPtr createBoundCRS() {
76 return BoundCRS::create(
77 GeographicCRS::EPSG_4807, GeographicCRS::EPSG_4326,
78 Transformation::create(
79 PropertyMap(), GeographicCRS::EPSG_4807,
80 GeographicCRS::EPSG_4326, nullptr, PropertyMap(),
81 {OperationParameter::create(
82 PropertyMap().set(IdentifiedObject::NAME_KEY, "foo"))},
83 {ParameterValue::create(
84 Measure(1.0, UnitOfMeasure::SCALE_UNITY))},
85 {}));
86 }
87
createProjectedCRS()88 static ProjectedCRSNNPtr createProjectedCRS() {
89 PropertyMap propertiesCRS;
90 propertiesCRS.set(Identifier::CODESPACE_KEY, "EPSG")
91 .set(Identifier::CODE_KEY, 32631)
92 .set(IdentifiedObject::NAME_KEY, "WGS 84 / UTM zone 31N");
93 return ProjectedCRS::create(
94 propertiesCRS, GeographicCRS::EPSG_4326,
95 Conversion::createUTM(PropertyMap(), 31, true),
96 CartesianCS::createEastingNorthing(UnitOfMeasure::METRE));
97 }
98
createVerticalCRS()99 static VerticalCRSNNPtr createVerticalCRS() {
100 PropertyMap propertiesVDatum;
101 propertiesVDatum.set(Identifier::CODESPACE_KEY, "EPSG")
102 .set(Identifier::CODE_KEY, 5101)
103 .set(IdentifiedObject::NAME_KEY, "Ordnance Datum Newlyn");
104 auto vdatum = VerticalReferenceFrame::create(propertiesVDatum);
105 PropertyMap propertiesCRS;
106 propertiesCRS.set(Identifier::CODESPACE_KEY, "EPSG")
107 .set(Identifier::CODE_KEY, 5701)
108 .set(IdentifiedObject::NAME_KEY, "ODN height");
109 return VerticalCRS::create(
110 propertiesCRS, vdatum,
111 VerticalCS::createGravityRelatedHeight(UnitOfMeasure::METRE));
112 }
113
createCompoundCRS()114 static CompoundCRSNNPtr createCompoundCRS() {
115 PropertyMap properties;
116 properties.set(Identifier::CODESPACE_KEY, "codespace")
117 .set(Identifier::CODE_KEY, "code")
118 .set(IdentifiedObject::NAME_KEY, "horizontal + vertical");
119 return CompoundCRS::create(
120 properties,
121 std::vector<CRSNNPtr>{createProjectedCRS(), createVerticalCRS()});
122 }
123
124 PJ_CONTEXT *m_ctxt = nullptr;
125
126 struct ObjectKeeper {
127 PJ *m_obj = nullptr;
ObjectKeeper__anon29fdcccb0111::CApi::ObjectKeeper128 explicit ObjectKeeper(PJ *obj) : m_obj(obj) {}
~ObjectKeeper__anon29fdcccb0111::CApi::ObjectKeeper129 ~ObjectKeeper() { proj_destroy(m_obj); }
130
131 ObjectKeeper(const ObjectKeeper &) = delete;
132 ObjectKeeper &operator=(const ObjectKeeper &) = delete;
133 };
134
135 struct PjContextKeeper {
136 PJ_CONTEXT *m_ctxt = nullptr;
PjContextKeeper__anon29fdcccb0111::CApi::PjContextKeeper137 explicit PjContextKeeper(PJ_CONTEXT *ctxt) : m_ctxt(ctxt) {}
~PjContextKeeper__anon29fdcccb0111::CApi::PjContextKeeper138 ~PjContextKeeper() { proj_context_destroy(m_ctxt); }
139
140 PjContextKeeper(const PjContextKeeper &) = delete;
141 PjContextKeeper &operator=(const PjContextKeeper &) = delete;
142 };
143
144 struct ContextKeeper {
145 PJ_OPERATION_FACTORY_CONTEXT *m_op_ctxt = nullptr;
ContextKeeper__anon29fdcccb0111::CApi::ContextKeeper146 explicit ContextKeeper(PJ_OPERATION_FACTORY_CONTEXT *op_ctxt)
147 : m_op_ctxt(op_ctxt) {}
~ContextKeeper__anon29fdcccb0111::CApi::ContextKeeper148 ~ContextKeeper() { proj_operation_factory_context_destroy(m_op_ctxt); }
149
150 ContextKeeper(const ContextKeeper &) = delete;
151 ContextKeeper &operator=(const ContextKeeper &) = delete;
152 };
153
154 struct ObjListKeeper {
155 PJ_OBJ_LIST *m_res = nullptr;
ObjListKeeper__anon29fdcccb0111::CApi::ObjListKeeper156 explicit ObjListKeeper(PJ_OBJ_LIST *res) : m_res(res) {}
~ObjListKeeper__anon29fdcccb0111::CApi::ObjListKeeper157 ~ObjListKeeper() { proj_list_destroy(m_res); }
158
159 ObjListKeeper(const ObjListKeeper &) = delete;
160 ObjListKeeper &operator=(const ObjListKeeper &) = delete;
161 };
162 };
163
164 // ---------------------------------------------------------------------------
165
TEST_F(CApi,proj_create)166 TEST_F(CApi, proj_create) {
167 proj_destroy(nullptr);
168 EXPECT_EQ(proj_create(m_ctxt, "invalid"), nullptr);
169 {
170 auto obj =
171 proj_create(m_ctxt, GeographicCRS::EPSG_4326
172 ->exportToWKT(WKTFormatter::create().get())
173 .c_str());
174 ObjectKeeper keeper(obj);
175 EXPECT_NE(obj, nullptr);
176
177 // Check that functions that operate on 'non-C++' PJ don't crash
178 PJ_COORD coord;
179 coord.xyzt.x = 0;
180 coord.xyzt.y = 0;
181 coord.xyzt.z = 0;
182 coord.xyzt.t = 0;
183 EXPECT_EQ(proj_trans(obj, PJ_FWD, coord).xyzt.x,
184 std::numeric_limits<double>::infinity());
185
186 EXPECT_EQ(proj_geod(obj, coord, coord).xyzt.x,
187 std::numeric_limits<double>::infinity());
188 EXPECT_EQ(proj_lp_dist(obj, coord, coord),
189 std::numeric_limits<double>::infinity());
190
191 auto info = proj_pj_info(obj);
192 EXPECT_EQ(info.id, nullptr);
193 ASSERT_NE(info.description, nullptr);
194 EXPECT_EQ(info.description, std::string("WGS 84"));
195 ASSERT_NE(info.definition, nullptr);
196 EXPECT_EQ(info.definition, std::string(""));
197 }
198 {
199 auto obj = proj_create(m_ctxt, "EPSG:4326");
200 ObjectKeeper keeper(obj);
201 EXPECT_NE(obj, nullptr);
202 }
203 }
204
205 // ---------------------------------------------------------------------------
206
TEST_F(CApi,proj_create_from_wkt)207 TEST_F(CApi, proj_create_from_wkt) {
208
209 {
210 EXPECT_EQ(
211 proj_create_from_wkt(m_ctxt, "invalid", nullptr, nullptr, nullptr),
212 nullptr);
213 }
214 {
215 PROJ_STRING_LIST warningList = nullptr;
216 PROJ_STRING_LIST errorList = nullptr;
217 EXPECT_EQ(proj_create_from_wkt(m_ctxt, "invalid", nullptr, &warningList,
218 &errorList),
219 nullptr);
220 EXPECT_EQ(warningList, nullptr);
221 proj_string_list_destroy(warningList);
222 EXPECT_NE(errorList, nullptr);
223 proj_string_list_destroy(errorList);
224 }
225 {
226 auto obj = proj_create_from_wkt(
227 m_ctxt,
228 GeographicCRS::EPSG_4326->exportToWKT(WKTFormatter::create().get())
229 .c_str(),
230 nullptr, nullptr, nullptr);
231 ObjectKeeper keeper(obj);
232 EXPECT_NE(obj, nullptr);
233 }
234 {
235 auto obj = proj_create_from_wkt(
236 m_ctxt,
237 "GEOGCS[\"WGS 84\",\n"
238 " DATUM[\"WGS_1984\",\n"
239 " SPHEROID[\"WGS 84\",6378137,298.257223563,\"unused\"]],\n"
240 " PRIMEM[\"Greenwich\",0],\n"
241 " UNIT[\"degree\",0.0174532925199433]]",
242 nullptr, nullptr, nullptr);
243 ObjectKeeper keeper(obj);
244 EXPECT_NE(obj, nullptr);
245 }
246 {
247 PROJ_STRING_LIST warningList = nullptr;
248 PROJ_STRING_LIST errorList = nullptr;
249 auto obj = proj_create_from_wkt(
250 m_ctxt,
251 "GEOGCS[\"WGS 84\",\n"
252 " DATUM[\"WGS_1984\",\n"
253 " SPHEROID[\"WGS 84\",6378137,298.257223563,\"unused\"]],\n"
254 " PRIMEM[\"Greenwich\",0],\n"
255 " UNIT[\"degree\",0.0174532925199433]]",
256 nullptr, &warningList, &errorList);
257 ObjectKeeper keeper(obj);
258 EXPECT_NE(obj, nullptr);
259 EXPECT_EQ(warningList, nullptr);
260 proj_string_list_destroy(warningList);
261 EXPECT_NE(errorList, nullptr);
262 proj_string_list_destroy(errorList);
263 }
264 {
265 PROJ_STRING_LIST warningList = nullptr;
266 PROJ_STRING_LIST errorList = nullptr;
267 const char *const options[] = {"STRICT=NO", nullptr};
268 auto obj = proj_create_from_wkt(
269 m_ctxt,
270 "GEOGCS[\"WGS 84\",\n"
271 " DATUM[\"WGS_1984\",\n"
272 " SPHEROID[\"WGS 84\",6378137,298.257223563,\"unused\"]],\n"
273 " PRIMEM[\"Greenwich\",0],\n"
274 " UNIT[\"degree\",0.0174532925199433]]",
275 options, &warningList, &errorList);
276 ObjectKeeper keeper(obj);
277 EXPECT_NE(obj, nullptr);
278 EXPECT_EQ(warningList, nullptr);
279 proj_string_list_destroy(warningList);
280 EXPECT_NE(errorList, nullptr);
281 proj_string_list_destroy(errorList);
282 }
283 {
284 PROJ_STRING_LIST warningList = nullptr;
285 PROJ_STRING_LIST errorList = nullptr;
286 auto obj = proj_create_from_wkt(
287 m_ctxt,
288 GeographicCRS::EPSG_4326->exportToWKT(WKTFormatter::create().get())
289 .c_str(),
290 nullptr, &warningList, &errorList);
291 ObjectKeeper keeper(obj);
292 EXPECT_NE(obj, nullptr);
293 EXPECT_EQ(warningList, nullptr);
294 EXPECT_EQ(errorList, nullptr);
295 }
296 // Warnings: missing projection parameters
297 {
298 PROJ_STRING_LIST warningList = nullptr;
299 PROJ_STRING_LIST errorList = nullptr;
300 auto obj = proj_create_from_wkt(
301 m_ctxt, "PROJCS[\"test\",\n"
302 " GEOGCS[\"WGS 84\",\n"
303 " DATUM[\"WGS_1984\",\n"
304 " SPHEROID[\"WGS 84\",6378137,298.257223563]],\n"
305 " PRIMEM[\"Greenwich\",0],\n"
306 " UNIT[\"degree\",0.0174532925199433]],\n"
307 " PROJECTION[\"Transverse_Mercator\"],\n"
308 " PARAMETER[\"latitude_of_origin\",31],\n"
309 " UNIT[\"metre\",1]]",
310 nullptr, &warningList, &errorList);
311 ObjectKeeper keeper(obj);
312 EXPECT_NE(obj, nullptr);
313 EXPECT_NE(warningList, nullptr);
314 proj_string_list_destroy(warningList);
315 EXPECT_EQ(errorList, nullptr);
316 proj_string_list_destroy(errorList);
317 }
318 {
319 auto obj = proj_create_from_wkt(
320 m_ctxt, "PROJCS[\"test\",\n"
321 " GEOGCS[\"WGS 84\",\n"
322 " DATUM[\"WGS_1984\",\n"
323 " SPHEROID[\"WGS 84\",6378137,298.257223563]],\n"
324 " PRIMEM[\"Greenwich\",0],\n"
325 " UNIT[\"degree\",0.0174532925199433]],\n"
326 " PROJECTION[\"Transverse_Mercator\"],\n"
327 " PARAMETER[\"latitude_of_origin\",31],\n"
328 " UNIT[\"metre\",1]]",
329 nullptr, nullptr, nullptr);
330 ObjectKeeper keeper(obj);
331 EXPECT_NE(obj, nullptr);
332 }
333 }
334
335 // ---------------------------------------------------------------------------
336
TEST_F(CApi,proj_as_wkt)337 TEST_F(CApi, proj_as_wkt) {
338 auto obj = proj_create_from_wkt(
339 m_ctxt,
340 GeographicCRS::EPSG_4326->exportToWKT(WKTFormatter::create().get())
341 .c_str(),
342 nullptr, nullptr, nullptr);
343 ObjectKeeper keeper(obj);
344 ASSERT_NE(obj, nullptr);
345
346 {
347 auto wkt = proj_as_wkt(m_ctxt, obj, PJ_WKT2_2019, nullptr);
348 ASSERT_NE(wkt, nullptr);
349 EXPECT_TRUE(std::string(wkt).find("GEOGCRS[") == 0) << wkt;
350 }
351
352 {
353 auto wkt = proj_as_wkt(m_ctxt, obj, PJ_WKT2_2019_SIMPLIFIED, nullptr);
354 ASSERT_NE(wkt, nullptr);
355 EXPECT_TRUE(std::string(wkt).find("GEOGCRS[") == 0) << wkt;
356 EXPECT_TRUE(std::string(wkt).find("ANGULARUNIT[") == std::string::npos)
357 << wkt;
358 }
359
360 {
361 auto wkt = proj_as_wkt(m_ctxt, obj, PJ_WKT2_2015, nullptr);
362 ASSERT_NE(wkt, nullptr);
363 EXPECT_TRUE(std::string(wkt).find("GEODCRS[") == 0) << wkt;
364 }
365
366 {
367 auto wkt = proj_as_wkt(m_ctxt, obj, PJ_WKT2_2015_SIMPLIFIED, nullptr);
368 ASSERT_NE(wkt, nullptr);
369 EXPECT_TRUE(std::string(wkt).find("GEODCRS[") == 0) << wkt;
370 EXPECT_TRUE(std::string(wkt).find("ANGULARUNIT[") == std::string::npos)
371 << wkt;
372 }
373
374 {
375 auto wkt = proj_as_wkt(m_ctxt, obj, PJ_WKT1_GDAL, nullptr);
376 ASSERT_NE(wkt, nullptr);
377 EXPECT_TRUE(std::string(wkt).find("GEOGCS[\"WGS 84\"") == 0) << wkt;
378 }
379
380 {
381 auto wkt = proj_as_wkt(m_ctxt, obj, PJ_WKT1_ESRI, nullptr);
382 ASSERT_NE(wkt, nullptr);
383 EXPECT_TRUE(std::string(wkt).find("GEOGCS[\"GCS_WGS_1984\"") == 0)
384 << wkt;
385 }
386
387 // MULTILINE=NO
388 {
389 const char *const options[] = {"MULTILINE=NO", nullptr};
390 auto wkt = proj_as_wkt(m_ctxt, obj, PJ_WKT1_GDAL, options);
391 ASSERT_NE(wkt, nullptr);
392 EXPECT_TRUE(std::string(wkt).find("\n") == std::string::npos) << wkt;
393 }
394
395 // INDENTATION_WIDTH=2
396 {
397 const char *const options[] = {"INDENTATION_WIDTH=2", nullptr};
398 auto wkt = proj_as_wkt(m_ctxt, obj, PJ_WKT1_GDAL, options);
399 ASSERT_NE(wkt, nullptr);
400 EXPECT_TRUE(std::string(wkt).find("\n DATUM") != std::string::npos)
401 << wkt;
402 }
403
404 // OUTPUT_AXIS=NO
405 {
406 const char *const options[] = {"OUTPUT_AXIS=NO", nullptr};
407 auto wkt = proj_as_wkt(m_ctxt, obj, PJ_WKT1_GDAL, options);
408 ASSERT_NE(wkt, nullptr);
409 EXPECT_TRUE(std::string(wkt).find("AXIS") == std::string::npos) << wkt;
410 }
411
412 // OUTPUT_AXIS=AUTO
413 {
414 const char *const options[] = {"OUTPUT_AXIS=AUTO", nullptr};
415 auto wkt = proj_as_wkt(m_ctxt, obj, PJ_WKT1_GDAL, options);
416 ASSERT_NE(wkt, nullptr);
417 EXPECT_TRUE(std::string(wkt).find("AXIS") == std::string::npos) << wkt;
418 }
419
420 // OUTPUT_AXIS=YES
421 {
422 const char *const options[] = {"OUTPUT_AXIS=YES", nullptr};
423 auto wkt = proj_as_wkt(m_ctxt, obj, PJ_WKT1_GDAL, options);
424 ASSERT_NE(wkt, nullptr);
425 EXPECT_TRUE(std::string(wkt).find("AXIS") != std::string::npos) << wkt;
426 }
427
428 auto crs4979 = proj_create_from_wkt(
429 m_ctxt,
430 GeographicCRS::EPSG_4979->exportToWKT(WKTFormatter::create().get())
431 .c_str(),
432 nullptr, nullptr, nullptr);
433 ObjectKeeper keeper_crs4979(crs4979);
434 ASSERT_NE(crs4979, nullptr);
435
436 EXPECT_EQ(proj_as_wkt(m_ctxt, crs4979, PJ_WKT1_GDAL, nullptr), nullptr);
437
438 // STRICT=NO
439 {
440 const char *const options[] = {"STRICT=NO", nullptr};
441 auto wkt = proj_as_wkt(m_ctxt, crs4979, PJ_WKT1_GDAL, options);
442 ASSERT_NE(wkt, nullptr);
443 EXPECT_TRUE(std::string(wkt).find("GEOGCS[\"WGS 84\"") == 0) << wkt;
444 }
445
446 // ALLOW_ELLIPSOIDAL_HEIGHT_AS_VERTICAL_CRS=YES
447 {
448 const char *const options[] = {
449 "ALLOW_ELLIPSOIDAL_HEIGHT_AS_VERTICAL_CRS=YES", nullptr};
450 auto wkt = proj_as_wkt(m_ctxt, crs4979, PJ_WKT1_GDAL, options);
451 ASSERT_NE(wkt, nullptr);
452 EXPECT_TRUE(std::string(wkt).find(
453 "COMPD_CS[\"WGS 84 + Ellipsoid (metre)\"") == 0)
454 << wkt;
455 }
456
457 // unsupported option
458 {
459 const char *const options[] = {"unsupported=yes", nullptr};
460 auto wkt = proj_as_wkt(m_ctxt, obj, PJ_WKT2_2019, options);
461 EXPECT_EQ(wkt, nullptr);
462 }
463 }
464
465 // ---------------------------------------------------------------------------
466
TEST_F(CApi,proj_as_wkt_check_db_use)467 TEST_F(CApi, proj_as_wkt_check_db_use) {
468 auto obj = proj_create_from_wkt(
469 m_ctxt, "GEOGCS[\"AGD66\",DATUM[\"Australian_Geodetic_Datum_1966\","
470 "SPHEROID[\"Australian National Spheroid\",6378160,298.25]],"
471 "PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433]]",
472 nullptr, nullptr, nullptr);
473 ObjectKeeper keeper(obj);
474 ASSERT_NE(obj, nullptr);
475
476 auto wkt = proj_as_wkt(m_ctxt, obj, PJ_WKT1_ESRI, nullptr);
477 EXPECT_EQ(std::string(wkt),
478 "GEOGCS[\"GCS_Australian_1966\",DATUM[\"D_Australian_1966\","
479 "SPHEROID[\"Australian\",6378160.0,298.25]],"
480 "PRIMEM[\"Greenwich\",0.0],"
481 "UNIT[\"Degree\",0.0174532925199433]]");
482 }
483
484 // ---------------------------------------------------------------------------
485
TEST_F(CApi,proj_as_wkt_incompatible_WKT1)486 TEST_F(CApi, proj_as_wkt_incompatible_WKT1) {
487 auto wkt = createBoundCRS()->exportToWKT(WKTFormatter::create().get());
488 auto obj =
489 proj_create_from_wkt(m_ctxt, wkt.c_str(), nullptr, nullptr, nullptr);
490 ObjectKeeper keeper(obj);
491 ASSERT_NE(obj, nullptr) << wkt;
492
493 auto wkt1_GDAL = proj_as_wkt(m_ctxt, obj, PJ_WKT1_GDAL, nullptr);
494 ASSERT_EQ(wkt1_GDAL, nullptr);
495 }
496
497 // ---------------------------------------------------------------------------
498
TEST_F(CApi,proj_as_proj_string)499 TEST_F(CApi, proj_as_proj_string) {
500 auto obj = proj_create_from_wkt(
501 m_ctxt,
502 GeographicCRS::EPSG_4326->exportToWKT(WKTFormatter::create().get())
503 .c_str(),
504 nullptr, nullptr, nullptr);
505 ObjectKeeper keeper(obj);
506 ASSERT_NE(obj, nullptr);
507
508 {
509 auto proj_5 = proj_as_proj_string(m_ctxt, obj, PJ_PROJ_5, nullptr);
510 ASSERT_NE(proj_5, nullptr);
511 EXPECT_EQ(std::string(proj_5),
512 "+proj=longlat +datum=WGS84 +no_defs +type=crs");
513 }
514 {
515 auto proj_4 = proj_as_proj_string(m_ctxt, obj, PJ_PROJ_4, nullptr);
516 ASSERT_NE(proj_4, nullptr);
517 EXPECT_EQ(std::string(proj_4),
518 "+proj=longlat +datum=WGS84 +no_defs +type=crs");
519 }
520 }
521
522 // ---------------------------------------------------------------------------
523
TEST_F(CApi,proj_as_proj_string_incompatible_WKT1)524 TEST_F(CApi, proj_as_proj_string_incompatible_WKT1) {
525 auto obj = proj_create_from_wkt(
526 m_ctxt,
527 createBoundCRS()->exportToWKT(WKTFormatter::create().get()).c_str(),
528 nullptr, nullptr, nullptr);
529 ObjectKeeper keeper(obj);
530 ASSERT_NE(obj, nullptr);
531
532 auto str = proj_as_proj_string(m_ctxt, obj, PJ_PROJ_5, nullptr);
533 ASSERT_EQ(str, nullptr);
534 }
535
536 // ---------------------------------------------------------------------------
537
TEST_F(CApi,proj_as_proj_string_approx_tmerc_option_yes)538 TEST_F(CApi, proj_as_proj_string_approx_tmerc_option_yes) {
539 auto obj = proj_create(m_ctxt, "+proj=tmerc +type=crs");
540 ObjectKeeper keeper(obj);
541 ASSERT_NE(obj, nullptr);
542
543 const char *options[] = {"USE_APPROX_TMERC=YES", nullptr};
544 auto str = proj_as_proj_string(m_ctxt, obj, PJ_PROJ_4, options);
545 ASSERT_NE(str, nullptr);
546 EXPECT_EQ(str,
547 std::string("+proj=tmerc +approx +lat_0=0 +lon_0=0 +k=1 +x_0=0 "
548 "+y_0=0 +datum=WGS84 +units=m +no_defs +type=crs"));
549 }
550
551 // ---------------------------------------------------------------------------
552
TEST_F(CApi,proj_crs_create_bound_crs_to_WGS84)553 TEST_F(CApi, proj_crs_create_bound_crs_to_WGS84) {
554 auto crs = proj_create_from_database(m_ctxt, "EPSG", "4807",
555 PJ_CATEGORY_CRS, false, nullptr);
556 ObjectKeeper keeper(crs);
557 ASSERT_NE(crs, nullptr);
558
559 auto res = proj_crs_create_bound_crs_to_WGS84(m_ctxt, crs, nullptr);
560 ObjectKeeper keeper_res(res);
561 ASSERT_NE(res, nullptr);
562
563 auto proj_4 = proj_as_proj_string(m_ctxt, res, PJ_PROJ_4, nullptr);
564 ASSERT_NE(proj_4, nullptr);
565 EXPECT_EQ(std::string(proj_4),
566 "+proj=longlat +ellps=clrk80ign +pm=paris "
567 "+towgs84=-168,-60,320,0,0,0,0 +no_defs +type=crs");
568
569 auto base_crs = proj_get_source_crs(m_ctxt, res);
570 ObjectKeeper keeper_base_crs(base_crs);
571 ASSERT_NE(base_crs, nullptr);
572
573 auto hub_crs = proj_get_target_crs(m_ctxt, res);
574 ObjectKeeper keeper_hub_crs(hub_crs);
575 ASSERT_NE(hub_crs, nullptr);
576
577 auto transf = proj_crs_get_coordoperation(m_ctxt, res);
578 ObjectKeeper keeper_transf(transf);
579 ASSERT_NE(transf, nullptr);
580
581 std::vector<double> values(7, 0);
582 EXPECT_TRUE(proj_coordoperation_get_towgs84_values(m_ctxt, transf,
583 values.data(), 7, true));
584 auto expected = std::vector<double>{-168, -60, 320, 0, 0, 0, 0};
585 EXPECT_EQ(values, expected);
586
587 auto res2 = proj_crs_create_bound_crs(m_ctxt, base_crs, hub_crs, transf);
588 ObjectKeeper keeper_res2(res2);
589 ASSERT_NE(res2, nullptr);
590
591 EXPECT_TRUE(proj_is_equivalent_to(res, res2, PJ_COMP_STRICT));
592 }
593
594 // ---------------------------------------------------------------------------
595
TEST_F(CApi,proj_crs_create_bound_crs_to_WGS84_on_invalid_type)596 TEST_F(CApi, proj_crs_create_bound_crs_to_WGS84_on_invalid_type) {
597 auto wkt = createProjectedCRS()->derivingConversion()->exportToWKT(
598 WKTFormatter::create().get());
599 auto obj =
600 proj_create_from_wkt(m_ctxt, wkt.c_str(), nullptr, nullptr, nullptr);
601 ObjectKeeper keeper(obj);
602 ASSERT_NE(obj, nullptr) << wkt;
603
604 auto res = proj_crs_create_bound_crs_to_WGS84(m_ctxt, obj, nullptr);
605 ASSERT_EQ(res, nullptr);
606 }
607
608 // ---------------------------------------------------------------------------
609
TEST_F(CApi,proj_get_name)610 TEST_F(CApi, proj_get_name) {
611 auto obj = proj_create_from_wkt(
612 m_ctxt,
613 GeographicCRS::EPSG_4326->exportToWKT(WKTFormatter::create().get())
614 .c_str(),
615 nullptr, nullptr, nullptr);
616 ObjectKeeper keeper(obj);
617 ASSERT_NE(obj, nullptr);
618 auto name = proj_get_name(obj);
619 ASSERT_TRUE(name != nullptr);
620 EXPECT_EQ(name, std::string("WGS 84"));
621 EXPECT_EQ(name, proj_get_name(obj));
622 }
623
624 // ---------------------------------------------------------------------------
625
TEST_F(CApi,proj_get_id_auth_name)626 TEST_F(CApi, proj_get_id_auth_name) {
627 auto obj = proj_create_from_wkt(
628 m_ctxt,
629 GeographicCRS::EPSG_4326->exportToWKT(WKTFormatter::create().get())
630 .c_str(),
631 nullptr, nullptr, nullptr);
632 ObjectKeeper keeper(obj);
633 ASSERT_NE(obj, nullptr);
634 auto auth = proj_get_id_auth_name(obj, 0);
635 ASSERT_TRUE(auth != nullptr);
636 EXPECT_EQ(auth, std::string("EPSG"));
637 EXPECT_EQ(auth, proj_get_id_auth_name(obj, 0));
638 EXPECT_EQ(proj_get_id_auth_name(obj, -1), nullptr);
639 EXPECT_EQ(proj_get_id_auth_name(obj, 1), nullptr);
640 }
641
642 // ---------------------------------------------------------------------------
643
TEST_F(CApi,proj_get_id_code)644 TEST_F(CApi, proj_get_id_code) {
645 auto obj = proj_create_from_wkt(
646 m_ctxt,
647 GeographicCRS::EPSG_4326->exportToWKT(WKTFormatter::create().get())
648 .c_str(),
649 nullptr, nullptr, nullptr);
650 ObjectKeeper keeper(obj);
651 ASSERT_NE(obj, nullptr);
652 auto code = proj_get_id_code(obj, 0);
653 ASSERT_TRUE(code != nullptr);
654 EXPECT_EQ(code, std::string("4326"));
655 EXPECT_EQ(code, proj_get_id_code(obj, 0));
656 EXPECT_EQ(proj_get_id_code(obj, -1), nullptr);
657 EXPECT_EQ(proj_get_id_code(obj, 1), nullptr);
658 }
659
660 // ---------------------------------------------------------------------------
661
TEST_F(CApi,proj_get_type)662 TEST_F(CApi, proj_get_type) {
663 {
664 auto obj = proj_create_from_wkt(
665 m_ctxt,
666 GeographicCRS::EPSG_4326->exportToWKT(WKTFormatter::create().get())
667 .c_str(),
668 nullptr, nullptr, nullptr);
669 ObjectKeeper keeper(obj);
670 ASSERT_NE(obj, nullptr);
671 EXPECT_EQ(proj_get_type(obj), PJ_TYPE_GEOGRAPHIC_2D_CRS);
672 }
673 {
674 auto obj = proj_create_from_wkt(
675 m_ctxt,
676 GeographicCRS::EPSG_4979->exportToWKT(WKTFormatter::create().get())
677 .c_str(),
678 nullptr, nullptr, nullptr);
679 ObjectKeeper keeper(obj);
680 ASSERT_NE(obj, nullptr);
681 EXPECT_EQ(proj_get_type(obj), PJ_TYPE_GEOGRAPHIC_3D_CRS);
682 }
683 {
684 auto obj = proj_create_from_wkt(
685 m_ctxt,
686 GeographicCRS::EPSG_4978->exportToWKT(WKTFormatter::create().get())
687 .c_str(),
688 nullptr, nullptr, nullptr);
689 ObjectKeeper keeper(obj);
690 ASSERT_NE(obj, nullptr);
691 EXPECT_EQ(proj_get_type(obj), PJ_TYPE_GEOCENTRIC_CRS);
692 }
693 {
694 auto obj = proj_create_from_wkt(
695 m_ctxt, GeographicCRS::EPSG_4326->datum()
696 ->exportToWKT(WKTFormatter::create().get())
697 .c_str(),
698 nullptr, nullptr, nullptr);
699 ObjectKeeper keeper(obj);
700 ASSERT_NE(obj, nullptr);
701 EXPECT_EQ(proj_get_type(obj), PJ_TYPE_GEODETIC_REFERENCE_FRAME);
702 }
703 {
704 auto obj = proj_create_from_wkt(
705 m_ctxt, GeographicCRS::EPSG_4326->ellipsoid()
706 ->exportToWKT(WKTFormatter::create().get())
707 .c_str(),
708 nullptr, nullptr, nullptr);
709 ObjectKeeper keeper(obj);
710 ASSERT_NE(obj, nullptr);
711 EXPECT_EQ(proj_get_type(obj), PJ_TYPE_ELLIPSOID);
712 }
713 {
714 auto obj = proj_create_from_wkt(
715 m_ctxt, createProjectedCRS()
716 ->exportToWKT(WKTFormatter::create().get())
717 .c_str(),
718 nullptr, nullptr, nullptr);
719 ObjectKeeper keeper(obj);
720 ASSERT_NE(obj, nullptr);
721 EXPECT_EQ(proj_get_type(obj), PJ_TYPE_PROJECTED_CRS);
722 }
723 {
724 auto obj = proj_create_from_wkt(
725 m_ctxt, createVerticalCRS()
726 ->exportToWKT(WKTFormatter::create().get())
727 .c_str(),
728 nullptr, nullptr, nullptr);
729 ObjectKeeper keeper(obj);
730 ASSERT_NE(obj, nullptr);
731 EXPECT_EQ(proj_get_type(obj), PJ_TYPE_VERTICAL_CRS);
732 }
733 {
734 auto wkt = "TDATUM[\"Gregorian calendar\",\n"
735 " CALENDAR[\"proleptic Gregorian\"],\n"
736 " TIMEORIGIN[0000-01-01]]";
737
738 auto datum =
739 proj_create_from_wkt(m_ctxt, wkt, nullptr, nullptr, nullptr);
740 ObjectKeeper keeper(datum);
741 ASSERT_NE(datum, nullptr);
742 EXPECT_EQ(proj_get_type(datum), PJ_TYPE_TEMPORAL_DATUM);
743 }
744 {
745 auto wkt = "ENGINEERINGDATUM[\"Engineering datum\"]";
746 auto datum =
747 proj_create_from_wkt(m_ctxt, wkt, nullptr, nullptr, nullptr);
748 ObjectKeeper keeper(datum);
749 EXPECT_EQ(proj_get_type(datum), PJ_TYPE_ENGINEERING_DATUM);
750 }
751 {
752 auto wkt = "PDATUM[\"Mean Sea Level\",ANCHOR[\"1013.25 hPa at 15°C\"]]";
753 auto datum =
754 proj_create_from_wkt(m_ctxt, wkt, nullptr, nullptr, nullptr);
755 ObjectKeeper keeper(datum);
756 EXPECT_EQ(proj_get_type(datum), PJ_TYPE_PARAMETRIC_DATUM);
757 }
758 {
759 auto obj = proj_create_from_wkt(
760 m_ctxt, createVerticalCRS()
761 ->datum()
762 ->exportToWKT(WKTFormatter::create().get())
763 .c_str(),
764 nullptr, nullptr, nullptr);
765 ObjectKeeper keeper(obj);
766 ASSERT_NE(obj, nullptr);
767 EXPECT_EQ(proj_get_type(obj), PJ_TYPE_VERTICAL_REFERENCE_FRAME);
768 }
769 {
770 auto obj = proj_create_from_wkt(
771 m_ctxt, createProjectedCRS()
772 ->derivingConversion()
773 ->exportToWKT(WKTFormatter::create().get())
774 .c_str(),
775 nullptr, nullptr, nullptr);
776 ObjectKeeper keeper(obj);
777 ASSERT_NE(obj, nullptr);
778 EXPECT_EQ(proj_get_type(obj), PJ_TYPE_CONVERSION);
779 }
780 {
781 auto obj = proj_create_from_wkt(
782 m_ctxt,
783 createBoundCRS()->exportToWKT(WKTFormatter::create().get()).c_str(),
784 nullptr, nullptr, nullptr);
785 ObjectKeeper keeper(obj);
786 ASSERT_NE(obj, nullptr);
787 EXPECT_EQ(proj_get_type(obj), PJ_TYPE_BOUND_CRS);
788 }
789 {
790 auto obj = proj_create_from_wkt(
791 m_ctxt, createBoundCRS()
792 ->transformation()
793 ->exportToWKT(WKTFormatter::create().get())
794 .c_str(),
795 nullptr, nullptr, nullptr);
796 ObjectKeeper keeper(obj);
797 ASSERT_NE(obj, nullptr);
798 EXPECT_EQ(proj_get_type(obj), PJ_TYPE_TRANSFORMATION);
799 }
800 {
801 auto obj = proj_create_from_wkt(m_ctxt, "AUTHORITY[\"EPSG\", 4326]",
802 nullptr, nullptr, nullptr);
803 ObjectKeeper keeper(obj);
804 ASSERT_EQ(obj, nullptr);
805 }
806 }
807
808 // ---------------------------------------------------------------------------
809
TEST_F(CApi,proj_create_from_database)810 TEST_F(CApi, proj_create_from_database) {
811 {
812 auto crs = proj_create_from_database(m_ctxt, "EPSG", "-1",
813 PJ_CATEGORY_CRS, false, nullptr);
814 ASSERT_EQ(crs, nullptr);
815 }
816 {
817 auto crs = proj_create_from_database(m_ctxt, "EPSG", "4326",
818 PJ_CATEGORY_CRS, false, nullptr);
819 ASSERT_NE(crs, nullptr);
820 ObjectKeeper keeper(crs);
821 EXPECT_TRUE(proj_is_crs(crs));
822 EXPECT_FALSE(proj_is_deprecated(crs));
823 EXPECT_EQ(proj_get_type(crs), PJ_TYPE_GEOGRAPHIC_2D_CRS);
824
825 const char *code = proj_get_id_code(crs, 0);
826 ASSERT_NE(code, nullptr);
827 EXPECT_EQ(std::string(code), "4326");
828 }
829 {
830 auto crs = proj_create_from_database(m_ctxt, "EPSG", "6871",
831 PJ_CATEGORY_CRS, false, nullptr);
832 ASSERT_NE(crs, nullptr);
833 ObjectKeeper keeper(crs);
834 EXPECT_TRUE(proj_is_crs(crs));
835 EXPECT_EQ(proj_get_type(crs), PJ_TYPE_COMPOUND_CRS);
836 }
837 {
838 auto ellipsoid = proj_create_from_database(
839 m_ctxt, "EPSG", "7030", PJ_CATEGORY_ELLIPSOID, false, nullptr);
840 ASSERT_NE(ellipsoid, nullptr);
841 ObjectKeeper keeper(ellipsoid);
842 EXPECT_EQ(proj_get_type(ellipsoid), PJ_TYPE_ELLIPSOID);
843 }
844 {
845 auto pm = proj_create_from_database(
846 m_ctxt, "EPSG", "8903", PJ_CATEGORY_PRIME_MERIDIAN, false, nullptr);
847 ASSERT_NE(pm, nullptr);
848 ObjectKeeper keeper(pm);
849 EXPECT_EQ(proj_get_type(pm), PJ_TYPE_PRIME_MERIDIAN);
850 }
851 {
852 auto datum = proj_create_from_database(
853 m_ctxt, "EPSG", "6326", PJ_CATEGORY_DATUM, false, nullptr);
854 ASSERT_NE(datum, nullptr);
855 ObjectKeeper keeper(datum);
856 EXPECT_EQ(proj_get_type(datum), PJ_TYPE_GEODETIC_REFERENCE_FRAME);
857 }
858 {
859 // International Terrestrial Reference Frame 2008
860 auto datum = proj_create_from_database(
861 m_ctxt, "EPSG", "1061", PJ_CATEGORY_DATUM, false, nullptr);
862 ASSERT_NE(datum, nullptr);
863 ObjectKeeper keeper(datum);
864 EXPECT_EQ(proj_get_type(datum),
865 PJ_TYPE_DYNAMIC_GEODETIC_REFERENCE_FRAME);
866 EXPECT_EQ(proj_dynamic_datum_get_frame_reference_epoch(m_ctxt, datum),
867 2005.0);
868 }
869 {
870 // Norway Normal Null 2000
871 auto datum = proj_create_from_database(
872 m_ctxt, "EPSG", "1096", PJ_CATEGORY_DATUM, false, nullptr);
873 ASSERT_NE(datum, nullptr);
874 ObjectKeeper keeper(datum);
875 EXPECT_EQ(proj_get_type(datum),
876 PJ_TYPE_DYNAMIC_VERTICAL_REFERENCE_FRAME);
877 EXPECT_EQ(proj_dynamic_datum_get_frame_reference_epoch(m_ctxt, datum),
878 2000.0);
879 }
880 {
881 auto op = proj_create_from_database(m_ctxt, "EPSG", "16031",
882 PJ_CATEGORY_COORDINATE_OPERATION,
883 false, nullptr);
884 ASSERT_NE(op, nullptr);
885 ObjectKeeper keeper(op);
886 EXPECT_EQ(proj_get_type(op), PJ_TYPE_CONVERSION);
887
888 auto info = proj_pj_info(op);
889 EXPECT_NE(info.id, nullptr);
890 EXPECT_EQ(info.id, std::string("utm"));
891 ASSERT_NE(info.description, nullptr);
892 EXPECT_EQ(info.description, std::string("UTM zone 31N"));
893 ASSERT_NE(info.definition, nullptr);
894 EXPECT_EQ(info.definition, std::string("proj=utm zone=31 ellps=GRS80"));
895 EXPECT_EQ(info.accuracy, 0);
896 }
897 {
898 auto op = proj_create_from_database(m_ctxt, "EPSG", "1024",
899 PJ_CATEGORY_COORDINATE_OPERATION,
900 false, nullptr);
901 ASSERT_NE(op, nullptr);
902 ObjectKeeper keeper(op);
903 EXPECT_EQ(proj_get_type(op), PJ_TYPE_TRANSFORMATION);
904
905 auto info = proj_pj_info(op);
906 EXPECT_NE(info.id, nullptr);
907 EXPECT_EQ(info.id, std::string("pipeline"));
908 ASSERT_NE(info.description, nullptr);
909 EXPECT_EQ(info.description, std::string("MGI to ETRS89 (4)"));
910 ASSERT_NE(info.definition, nullptr);
911 EXPECT_EQ(
912 info.definition,
913 std::string("proj=pipeline step proj=axisswap "
914 "order=2,1 step proj=unitconvert xy_in=deg xy_out=rad "
915 "step proj=push v_3 "
916 "step proj=cart ellps=bessel step proj=helmert "
917 "x=601.705 y=84.263 z=485.227 rx=-4.7354 ry=-1.3145 "
918 "rz=-5.393 s=-2.3887 convention=coordinate_frame "
919 "step inv proj=cart ellps=GRS80 "
920 "step proj=pop v_3 "
921 "step proj=unitconvert xy_in=rad xy_out=deg "
922 "step proj=axisswap order=2,1"));
923 EXPECT_EQ(info.accuracy, 1);
924 }
925 }
926
927 // ---------------------------------------------------------------------------
928
TEST_F(CApi,proj_crs)929 TEST_F(CApi, proj_crs) {
930 auto crs = proj_create_from_wkt(
931 m_ctxt,
932 createProjectedCRS()
933 ->exportToWKT(
934 WKTFormatter::create(WKTFormatter::Convention::WKT1_GDAL).get())
935 .c_str(),
936 nullptr, nullptr, nullptr);
937 ASSERT_NE(crs, nullptr);
938 ObjectKeeper keeper(crs);
939 EXPECT_TRUE(proj_is_crs(crs));
940
941 auto geodCRS = proj_crs_get_geodetic_crs(m_ctxt, crs);
942 ASSERT_NE(geodCRS, nullptr);
943 ObjectKeeper keeper_geogCRS(geodCRS);
944 EXPECT_TRUE(proj_is_crs(geodCRS));
945 auto geogCRS_name = proj_get_name(geodCRS);
946 ASSERT_TRUE(geogCRS_name != nullptr);
947 EXPECT_EQ(geogCRS_name, std::string("WGS 84"));
948
949 auto h_datum = proj_crs_get_horizontal_datum(m_ctxt, crs);
950 ASSERT_NE(h_datum, nullptr);
951 ObjectKeeper keeper_h_datum(h_datum);
952
953 auto datum = proj_crs_get_datum(m_ctxt, crs);
954 ASSERT_NE(datum, nullptr);
955 ObjectKeeper keeper_datum(datum);
956
957 EXPECT_TRUE(proj_is_equivalent_to(h_datum, datum, PJ_COMP_STRICT));
958
959 auto datum_name = proj_get_name(datum);
960 ASSERT_TRUE(datum_name != nullptr);
961 EXPECT_EQ(datum_name, std::string("World Geodetic System 1984"));
962
963 auto ellipsoid = proj_get_ellipsoid(m_ctxt, crs);
964 ASSERT_NE(ellipsoid, nullptr);
965 ObjectKeeper keeper_ellipsoid(ellipsoid);
966 auto ellipsoid_name = proj_get_name(ellipsoid);
967 ASSERT_TRUE(ellipsoid_name != nullptr);
968 EXPECT_EQ(ellipsoid_name, std::string("WGS 84"));
969
970 auto ellipsoid_from_datum = proj_get_ellipsoid(m_ctxt, datum);
971 ASSERT_NE(ellipsoid_from_datum, nullptr);
972 ObjectKeeper keeper_ellipsoid_from_datum(ellipsoid_from_datum);
973
974 EXPECT_EQ(proj_get_ellipsoid(m_ctxt, ellipsoid), nullptr);
975 EXPECT_FALSE(proj_is_crs(ellipsoid));
976
977 double a;
978 double b;
979 int b_is_computed;
980 double rf;
981 EXPECT_TRUE(proj_ellipsoid_get_parameters(m_ctxt, ellipsoid, nullptr,
982 nullptr, nullptr, nullptr));
983 EXPECT_TRUE(proj_ellipsoid_get_parameters(m_ctxt, ellipsoid, &a, &b,
984 &b_is_computed, &rf));
985 EXPECT_FALSE(proj_ellipsoid_get_parameters(m_ctxt, crs, &a, &b,
986 &b_is_computed, &rf));
987 EXPECT_EQ(a, 6378137);
988 EXPECT_NEAR(b, 6356752.31424518, 1e-9);
989 EXPECT_EQ(b_is_computed, 1);
990 EXPECT_EQ(rf, 298.257223563);
991 auto id = proj_get_id_code(ellipsoid, 0);
992 ASSERT_TRUE(id != nullptr);
993 EXPECT_EQ(id, std::string("7030"));
994 }
995
996 // ---------------------------------------------------------------------------
997
TEST_F(CApi,proj_get_prime_meridian)998 TEST_F(CApi, proj_get_prime_meridian) {
999 auto crs = proj_create_from_wkt(
1000 m_ctxt,
1001 createProjectedCRS()
1002 ->exportToWKT(
1003 WKTFormatter::create(WKTFormatter::Convention::WKT1_GDAL).get())
1004 .c_str(),
1005 nullptr, nullptr, nullptr);
1006 ASSERT_NE(crs, nullptr);
1007 ObjectKeeper keeper(crs);
1008
1009 auto pm = proj_get_prime_meridian(m_ctxt, crs);
1010 ASSERT_NE(pm, nullptr);
1011 ObjectKeeper keeper_pm(pm);
1012 auto pm_name = proj_get_name(pm);
1013 ASSERT_TRUE(pm_name != nullptr);
1014 EXPECT_EQ(pm_name, std::string("Greenwich"));
1015
1016 EXPECT_EQ(proj_get_prime_meridian(m_ctxt, pm), nullptr);
1017
1018 EXPECT_TRUE(proj_prime_meridian_get_parameters(m_ctxt, pm, nullptr, nullptr,
1019 nullptr));
1020 double longitude = -1;
1021 double longitude_unit = 0;
1022 const char *longitude_unit_name = nullptr;
1023 EXPECT_TRUE(proj_prime_meridian_get_parameters(
1024 m_ctxt, pm, &longitude, &longitude_unit, &longitude_unit_name));
1025 EXPECT_EQ(longitude, 0);
1026 EXPECT_NEAR(longitude_unit, UnitOfMeasure::DEGREE.conversionToSI(), 1e-10);
1027 ASSERT_TRUE(longitude_unit_name != nullptr);
1028 EXPECT_EQ(longitude_unit_name, std::string("degree"));
1029
1030 auto datum = proj_crs_get_horizontal_datum(m_ctxt, crs);
1031 ASSERT_NE(datum, nullptr);
1032 ObjectKeeper keeper_datum(datum);
1033 auto pm_from_datum = proj_get_prime_meridian(m_ctxt, datum);
1034 ASSERT_NE(pm_from_datum, nullptr);
1035 ObjectKeeper keeper_pm_from_datum(pm_from_datum);
1036 }
1037
1038 // ---------------------------------------------------------------------------
1039
TEST_F(CApi,proj_crs_compound)1040 TEST_F(CApi, proj_crs_compound) {
1041 auto crs = proj_create_from_wkt(
1042 m_ctxt,
1043 createCompoundCRS()->exportToWKT(WKTFormatter::create().get()).c_str(),
1044 nullptr, nullptr, nullptr);
1045 ASSERT_NE(crs, nullptr);
1046 ObjectKeeper keeper(crs);
1047 EXPECT_EQ(proj_get_type(crs), PJ_TYPE_COMPOUND_CRS);
1048
1049 EXPECT_EQ(proj_crs_get_sub_crs(m_ctxt, crs, -1), nullptr);
1050 EXPECT_EQ(proj_crs_get_sub_crs(m_ctxt, crs, 2), nullptr);
1051
1052 auto subcrs_horiz = proj_crs_get_sub_crs(m_ctxt, crs, 0);
1053 ASSERT_NE(subcrs_horiz, nullptr);
1054 ObjectKeeper keeper_subcrs_horiz(subcrs_horiz);
1055 EXPECT_EQ(proj_get_type(subcrs_horiz), PJ_TYPE_PROJECTED_CRS);
1056 EXPECT_EQ(proj_crs_get_sub_crs(m_ctxt, subcrs_horiz, 0), nullptr);
1057
1058 auto subcrs_vertical = proj_crs_get_sub_crs(m_ctxt, crs, 1);
1059 ASSERT_NE(subcrs_vertical, nullptr);
1060 ObjectKeeper keeper_subcrs_vertical(subcrs_vertical);
1061 EXPECT_EQ(proj_get_type(subcrs_vertical), PJ_TYPE_VERTICAL_CRS);
1062 }
1063
1064 // ---------------------------------------------------------------------------
1065
TEST_F(CApi,proj_get_source_target_crs_bound_crs)1066 TEST_F(CApi, proj_get_source_target_crs_bound_crs) {
1067 auto crs = proj_create_from_wkt(
1068 m_ctxt,
1069 createBoundCRS()->exportToWKT(WKTFormatter::create().get()).c_str(),
1070 nullptr, nullptr, nullptr);
1071 ASSERT_NE(crs, nullptr);
1072 ObjectKeeper keeper(crs);
1073
1074 auto sourceCRS = proj_get_source_crs(m_ctxt, crs);
1075 ASSERT_NE(sourceCRS, nullptr);
1076 ObjectKeeper keeper_sourceCRS(sourceCRS);
1077 EXPECT_EQ(std::string(proj_get_name(sourceCRS)), "NTF (Paris)");
1078
1079 auto targetCRS = proj_get_target_crs(m_ctxt, crs);
1080 ASSERT_NE(targetCRS, nullptr);
1081 ObjectKeeper keeper_targetCRS(targetCRS);
1082 EXPECT_EQ(std::string(proj_get_name(targetCRS)), "WGS 84");
1083 }
1084
1085 // ---------------------------------------------------------------------------
1086
TEST_F(CApi,proj_get_source_target_crs_transformation)1087 TEST_F(CApi, proj_get_source_target_crs_transformation) {
1088 auto obj = proj_create_from_wkt(
1089 m_ctxt, createBoundCRS()
1090 ->transformation()
1091 ->exportToWKT(WKTFormatter::create().get())
1092 .c_str(),
1093 nullptr, nullptr, nullptr);
1094 ASSERT_NE(obj, nullptr);
1095 ObjectKeeper keeper(obj);
1096
1097 auto sourceCRS = proj_get_source_crs(m_ctxt, obj);
1098 ASSERT_NE(sourceCRS, nullptr);
1099 ObjectKeeper keeper_sourceCRS(sourceCRS);
1100 EXPECT_EQ(std::string(proj_get_name(sourceCRS)), "NTF (Paris)");
1101
1102 auto targetCRS = proj_get_target_crs(m_ctxt, obj);
1103 ASSERT_NE(targetCRS, nullptr);
1104 ObjectKeeper keeper_targetCRS(targetCRS);
1105 EXPECT_EQ(std::string(proj_get_name(targetCRS)), "WGS 84");
1106 }
1107
1108 // ---------------------------------------------------------------------------
1109
TEST_F(CApi,proj_get_source_crs_of_projected_crs)1110 TEST_F(CApi, proj_get_source_crs_of_projected_crs) {
1111 auto crs = proj_create_from_wkt(
1112 m_ctxt,
1113 createProjectedCRS()->exportToWKT(WKTFormatter::create().get()).c_str(),
1114 nullptr, nullptr, nullptr);
1115 ASSERT_NE(crs, nullptr);
1116 ObjectKeeper keeper(crs);
1117
1118 auto sourceCRS = proj_get_source_crs(m_ctxt, crs);
1119 ASSERT_NE(sourceCRS, nullptr);
1120 ObjectKeeper keeper_sourceCRS(sourceCRS);
1121 EXPECT_EQ(std::string(proj_get_name(sourceCRS)), "WGS 84");
1122 }
1123
1124 // ---------------------------------------------------------------------------
1125
TEST_F(CApi,proj_get_source_target_crs_conversion_without_crs)1126 TEST_F(CApi, proj_get_source_target_crs_conversion_without_crs) {
1127 auto obj = proj_create_from_database(m_ctxt, "EPSG", "16031",
1128 PJ_CATEGORY_COORDINATE_OPERATION,
1129 false, nullptr);
1130 ASSERT_NE(obj, nullptr);
1131 ObjectKeeper keeper(obj);
1132
1133 auto sourceCRS = proj_get_source_crs(m_ctxt, obj);
1134 ASSERT_EQ(sourceCRS, nullptr);
1135
1136 auto targetCRS = proj_get_target_crs(m_ctxt, obj);
1137 ASSERT_EQ(targetCRS, nullptr);
1138 }
1139
1140 // ---------------------------------------------------------------------------
1141
TEST_F(CApi,proj_get_source_target_crs_invalid_object)1142 TEST_F(CApi, proj_get_source_target_crs_invalid_object) {
1143 auto obj = proj_create_from_wkt(
1144 m_ctxt, "ELLIPSOID[\"WGS 84\",6378137,298.257223563]", nullptr, nullptr,
1145 nullptr);
1146 ASSERT_NE(obj, nullptr);
1147 ObjectKeeper keeper(obj);
1148
1149 auto sourceCRS = proj_get_source_crs(m_ctxt, obj);
1150 ASSERT_EQ(sourceCRS, nullptr);
1151
1152 auto targetCRS = proj_get_target_crs(m_ctxt, obj);
1153 ASSERT_EQ(targetCRS, nullptr);
1154 }
1155
1156 // ---------------------------------------------------------------------------
1157
1158 struct ListFreer {
1159 PROJ_STRING_LIST list;
ListFreer__anon29fdcccb0111::ListFreer1160 ListFreer(PROJ_STRING_LIST ptrIn) : list(ptrIn) {}
~ListFreer__anon29fdcccb0111::ListFreer1161 ~ListFreer() { proj_string_list_destroy(list); }
1162 ListFreer(const ListFreer &) = delete;
1163 ListFreer &operator=(const ListFreer &) = delete;
1164 };
1165
1166 // ---------------------------------------------------------------------------
1167
TEST_F(CApi,proj_get_authorities_from_database)1168 TEST_F(CApi, proj_get_authorities_from_database) {
1169 auto list = proj_get_authorities_from_database(m_ctxt);
1170 ListFreer feer(list);
1171 ASSERT_NE(list, nullptr);
1172 ASSERT_TRUE(list[0] != nullptr);
1173 EXPECT_EQ(list[0], std::string("EPSG"));
1174 ASSERT_TRUE(list[1] != nullptr);
1175 EXPECT_EQ(list[1], std::string("ESRI"));
1176 ASSERT_TRUE(list[2] != nullptr);
1177 EXPECT_EQ(list[2], std::string("IGNF"));
1178 ASSERT_TRUE(list[3] != nullptr);
1179 EXPECT_EQ(list[3], std::string("NKG"));
1180 ASSERT_TRUE(list[4] != nullptr);
1181 EXPECT_EQ(list[4], std::string("OGC"));
1182 ASSERT_TRUE(list[5] != nullptr);
1183 EXPECT_EQ(list[5], std::string("PROJ"));
1184 EXPECT_EQ(list[6], nullptr);
1185 }
1186
1187 // ---------------------------------------------------------------------------
1188
TEST_F(CApi,proj_get_codes_from_database)1189 TEST_F(CApi, proj_get_codes_from_database) {
1190
1191 auto listTypes =
1192 std::vector<PJ_TYPE>{PJ_TYPE_ELLIPSOID,
1193
1194 PJ_TYPE_PRIME_MERIDIAN,
1195
1196 PJ_TYPE_GEODETIC_REFERENCE_FRAME,
1197 PJ_TYPE_DYNAMIC_GEODETIC_REFERENCE_FRAME,
1198 PJ_TYPE_VERTICAL_REFERENCE_FRAME,
1199 PJ_TYPE_DYNAMIC_VERTICAL_REFERENCE_FRAME,
1200 PJ_TYPE_DATUM_ENSEMBLE,
1201 PJ_TYPE_TEMPORAL_DATUM,
1202 PJ_TYPE_ENGINEERING_DATUM,
1203 PJ_TYPE_PARAMETRIC_DATUM,
1204
1205 PJ_TYPE_CRS,
1206 PJ_TYPE_GEODETIC_CRS,
1207 PJ_TYPE_GEOCENTRIC_CRS,
1208 PJ_TYPE_GEOGRAPHIC_CRS,
1209 PJ_TYPE_GEOGRAPHIC_2D_CRS,
1210 PJ_TYPE_GEOGRAPHIC_3D_CRS,
1211 PJ_TYPE_VERTICAL_CRS,
1212 PJ_TYPE_PROJECTED_CRS,
1213 PJ_TYPE_COMPOUND_CRS,
1214 PJ_TYPE_TEMPORAL_CRS,
1215 PJ_TYPE_BOUND_CRS,
1216 PJ_TYPE_OTHER_CRS,
1217
1218 PJ_TYPE_CONVERSION,
1219 PJ_TYPE_TRANSFORMATION,
1220 PJ_TYPE_CONCATENATED_OPERATION,
1221 PJ_TYPE_OTHER_COORDINATE_OPERATION,
1222
1223 PJ_TYPE_UNKNOWN};
1224 for (const auto &type : listTypes) {
1225 auto list = proj_get_codes_from_database(m_ctxt, "EPSG", type, true);
1226 ListFreer feer(list);
1227 if (type == PJ_TYPE_TEMPORAL_CRS || type == PJ_TYPE_BOUND_CRS ||
1228 type == PJ_TYPE_UNKNOWN || type == PJ_TYPE_TEMPORAL_DATUM ||
1229 type == PJ_TYPE_ENGINEERING_DATUM ||
1230 type == PJ_TYPE_PARAMETRIC_DATUM) {
1231 EXPECT_EQ(list, nullptr) << type;
1232 } else {
1233 ASSERT_NE(list, nullptr) << type;
1234 ASSERT_NE(list[0], nullptr) << type;
1235 if (type == PJ_TYPE_DYNAMIC_GEODETIC_REFERENCE_FRAME ||
1236 type == PJ_TYPE_DYNAMIC_VERTICAL_REFERENCE_FRAME) {
1237 auto obj = proj_create_from_database(
1238 m_ctxt, "EPSG", list[0], PJ_CATEGORY_DATUM, false, nullptr);
1239 ASSERT_NE(obj, nullptr);
1240 ObjectKeeper keeper(obj);
1241 EXPECT_EQ(proj_get_type(obj), type) << type << " " << list[0];
1242 }
1243 }
1244 }
1245 }
1246
1247 // ---------------------------------------------------------------------------
1248
TEST_F(CApi,conversion)1249 TEST_F(CApi, conversion) {
1250 auto crs = proj_create_from_database(m_ctxt, "EPSG", "32631",
1251 PJ_CATEGORY_CRS, false, nullptr);
1252 ASSERT_NE(crs, nullptr);
1253 ObjectKeeper keeper(crs);
1254
1255 // invalid object type
1256 EXPECT_FALSE(proj_coordoperation_get_method_info(m_ctxt, crs, nullptr,
1257 nullptr, nullptr));
1258
1259 {
1260 auto conv = proj_crs_get_coordoperation(m_ctxt, crs);
1261 ASSERT_NE(conv, nullptr);
1262 ObjectKeeper keeper_conv(conv);
1263
1264 ASSERT_EQ(proj_crs_get_coordoperation(m_ctxt, conv), nullptr);
1265 }
1266
1267 auto conv = proj_crs_get_coordoperation(m_ctxt, crs);
1268 ASSERT_NE(conv, nullptr);
1269 ObjectKeeper keeper_conv(conv);
1270
1271 EXPECT_TRUE(proj_coordoperation_get_method_info(m_ctxt, conv, nullptr,
1272 nullptr, nullptr));
1273
1274 const char *methodName = nullptr;
1275 const char *methodAuthorityName = nullptr;
1276 const char *methodCode = nullptr;
1277 EXPECT_TRUE(proj_coordoperation_get_method_info(
1278 m_ctxt, conv, &methodName, &methodAuthorityName, &methodCode));
1279
1280 ASSERT_NE(methodName, nullptr);
1281 ASSERT_NE(methodAuthorityName, nullptr);
1282 ASSERT_NE(methodCode, nullptr);
1283 EXPECT_EQ(methodName, std::string("Transverse Mercator"));
1284 EXPECT_EQ(methodAuthorityName, std::string("EPSG"));
1285 EXPECT_EQ(methodCode, std::string("9807"));
1286
1287 EXPECT_EQ(proj_coordoperation_get_param_count(m_ctxt, conv), 5);
1288 EXPECT_EQ(proj_coordoperation_get_param_index(m_ctxt, conv, "foo"), -1);
1289 EXPECT_EQ(
1290 proj_coordoperation_get_param_index(m_ctxt, conv, "False easting"), 3);
1291
1292 EXPECT_FALSE(proj_coordoperation_get_param(
1293 m_ctxt, conv, -1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
1294 nullptr, nullptr, nullptr, nullptr));
1295 EXPECT_FALSE(proj_coordoperation_get_param(
1296 m_ctxt, conv, 5, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
1297 nullptr, nullptr, nullptr, nullptr));
1298
1299 const char *name = nullptr;
1300 const char *nameAuthorityName = nullptr;
1301 const char *nameCode = nullptr;
1302 double value = 0;
1303 const char *valueString = nullptr;
1304 double valueUnitConvFactor = 0;
1305 const char *valueUnitName = nullptr;
1306 const char *unitAuthName = nullptr;
1307 const char *unitCode = nullptr;
1308 const char *unitCategory = nullptr;
1309 EXPECT_TRUE(proj_coordoperation_get_param(
1310 m_ctxt, conv, 3, &name, &nameAuthorityName, &nameCode, &value,
1311 &valueString, &valueUnitConvFactor, &valueUnitName, &unitAuthName,
1312 &unitCode, &unitCategory));
1313 ASSERT_NE(name, nullptr);
1314 ASSERT_NE(nameAuthorityName, nullptr);
1315 ASSERT_NE(nameCode, nullptr);
1316 EXPECT_EQ(valueString, nullptr);
1317 ASSERT_NE(valueUnitName, nullptr);
1318 ASSERT_NE(unitAuthName, nullptr);
1319 ASSERT_NE(unitCategory, nullptr);
1320 ASSERT_NE(unitCategory, nullptr);
1321 EXPECT_EQ(name, std::string("False easting"));
1322 EXPECT_EQ(nameAuthorityName, std::string("EPSG"));
1323 EXPECT_EQ(nameCode, std::string("8806"));
1324 EXPECT_EQ(value, 500000.0);
1325 EXPECT_EQ(valueUnitConvFactor, 1.0);
1326 EXPECT_EQ(valueUnitName, std::string("metre"));
1327 EXPECT_EQ(unitAuthName, std::string("EPSG"));
1328 EXPECT_EQ(unitCode, std::string("9001"));
1329 EXPECT_EQ(unitCategory, std::string("linear"));
1330 }
1331
1332 // ---------------------------------------------------------------------------
1333
TEST_F(CApi,transformation_from_boundCRS)1334 TEST_F(CApi, transformation_from_boundCRS) {
1335 auto crs = proj_create_from_wkt(
1336 m_ctxt,
1337 createBoundCRS()->exportToWKT(WKTFormatter::create().get()).c_str(),
1338 nullptr, nullptr, nullptr);
1339 ASSERT_NE(crs, nullptr);
1340 ObjectKeeper keeper(crs);
1341
1342 auto transf = proj_crs_get_coordoperation(m_ctxt, crs);
1343 ASSERT_NE(transf, nullptr);
1344 ObjectKeeper keeper_transf(transf);
1345 }
1346
1347 // ---------------------------------------------------------------------------
1348
TEST_F(CApi,proj_coordoperation_get_grid_used)1349 TEST_F(CApi, proj_coordoperation_get_grid_used) {
1350 auto op = proj_create_from_database(m_ctxt, "EPSG", "1312",
1351 PJ_CATEGORY_COORDINATE_OPERATION, true,
1352 nullptr);
1353 ASSERT_NE(op, nullptr);
1354 ObjectKeeper keeper(op);
1355
1356 EXPECT_EQ(proj_coordoperation_get_grid_used_count(m_ctxt, op), 1);
1357 const char *shortName = nullptr;
1358 const char *fullName = nullptr;
1359 const char *packageName = nullptr;
1360 const char *url = nullptr;
1361 int directDownload = 0;
1362 int openLicense = 0;
1363 int available = 0;
1364 EXPECT_EQ(proj_coordoperation_get_grid_used(m_ctxt, op, -1, nullptr,
1365 nullptr, nullptr, nullptr,
1366 nullptr, nullptr, nullptr),
1367 0);
1368 EXPECT_EQ(proj_coordoperation_get_grid_used(m_ctxt, op, 1, nullptr, nullptr,
1369 nullptr, nullptr, nullptr,
1370 nullptr, nullptr),
1371 0);
1372 EXPECT_EQ(proj_coordoperation_get_grid_used(
1373 m_ctxt, op, 0, &shortName, &fullName, &packageName, &url,
1374 &directDownload, &openLicense, &available),
1375 1);
1376 ASSERT_NE(shortName, nullptr);
1377 ASSERT_NE(fullName, nullptr);
1378 ASSERT_NE(packageName, nullptr);
1379 ASSERT_NE(url, nullptr);
1380 EXPECT_EQ(shortName, std::string("ca_nrc_ntv1_can.tif"));
1381 // EXPECT_EQ(fullName, std::string(""));
1382 EXPECT_EQ(packageName, std::string(""));
1383 EXPECT_EQ(std::string(url), "https://cdn.proj.org/ca_nrc_ntv1_can.tif");
1384 EXPECT_EQ(directDownload, 1);
1385 EXPECT_EQ(openLicense, 1);
1386 }
1387
1388 // ---------------------------------------------------------------------------
1389
TEST_F(CApi,proj_coordoperation_is_instantiable)1390 TEST_F(CApi, proj_coordoperation_is_instantiable) {
1391 auto op = proj_create_from_database(m_ctxt, "EPSG", "1671",
1392 PJ_CATEGORY_COORDINATE_OPERATION, true,
1393 nullptr);
1394 ASSERT_NE(op, nullptr);
1395 ObjectKeeper keeper(op);
1396 EXPECT_EQ(proj_coordoperation_is_instantiable(m_ctxt, op), 1);
1397 }
1398
1399 // ---------------------------------------------------------------------------
1400
TEST_F(CApi,proj_create_operations)1401 TEST_F(CApi, proj_create_operations) {
1402 auto ctxt = proj_create_operation_factory_context(m_ctxt, nullptr);
1403 ASSERT_NE(ctxt, nullptr);
1404 ContextKeeper keeper_ctxt(ctxt);
1405
1406 auto source_crs = proj_create_from_database(
1407 m_ctxt, "EPSG", "4267", PJ_CATEGORY_CRS, false, nullptr); // NAD27
1408 ASSERT_NE(source_crs, nullptr);
1409 ObjectKeeper keeper_source_crs(source_crs);
1410
1411 auto target_crs = proj_create_from_database(
1412 m_ctxt, "EPSG", "4269", PJ_CATEGORY_CRS, false, nullptr); // NAD83
1413 ASSERT_NE(target_crs, nullptr);
1414 ObjectKeeper keeper_target_crs(target_crs);
1415
1416 proj_operation_factory_context_set_spatial_criterion(
1417 m_ctxt, ctxt, PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION);
1418
1419 proj_operation_factory_context_set_grid_availability_use(
1420 m_ctxt, ctxt, PROJ_GRID_AVAILABILITY_IGNORED);
1421
1422 auto res = proj_create_operations(m_ctxt, source_crs, target_crs, ctxt);
1423 ASSERT_NE(res, nullptr);
1424 ObjListKeeper keeper_res(res);
1425
1426 EXPECT_EQ(proj_list_get_count(res), 10);
1427
1428 EXPECT_EQ(proj_list_get(m_ctxt, res, -1), nullptr);
1429 EXPECT_EQ(proj_list_get(m_ctxt, res, proj_list_get_count(res)), nullptr);
1430 {
1431 auto op = proj_list_get(m_ctxt, res, 0);
1432 ASSERT_NE(op, nullptr);
1433 ObjectKeeper keeper_op(op);
1434 EXPECT_FALSE(
1435 proj_coordoperation_has_ballpark_transformation(m_ctxt, op));
1436 EXPECT_EQ(proj_get_name(op), std::string("NAD27 to NAD83 (3)"));
1437 }
1438
1439 {
1440 PJ_COORD coord;
1441 coord.xy.x = 40;
1442 coord.xy.y = -100;
1443 int idx = proj_get_suggested_operation(m_ctxt, res, PJ_FWD, coord);
1444 ASSERT_GE(idx, 0);
1445 ASSERT_LT(idx, proj_list_get_count(res));
1446 auto op = proj_list_get(m_ctxt, res, idx);
1447 ASSERT_NE(op, nullptr);
1448 ObjectKeeper keeper_op(op);
1449 // Transformation for USA
1450 EXPECT_EQ(proj_get_name(op), std::string("NAD27 to NAD83 (1)"));
1451 }
1452
1453 {
1454 PJ_COORD coord;
1455 coord.xy.x = 40;
1456 coord.xy.y = 10;
1457 int idx = proj_get_suggested_operation(m_ctxt, res, PJ_FWD, coord);
1458 EXPECT_GE(idx, -1);
1459 }
1460 }
1461
1462 // ---------------------------------------------------------------------------
1463
TEST_F(CApi,proj_get_suggested_operation_with_operations_without_area_of_use)1464 TEST_F(CApi, proj_get_suggested_operation_with_operations_without_area_of_use) {
1465 auto ctxt = proj_create_operation_factory_context(m_ctxt, nullptr);
1466 ASSERT_NE(ctxt, nullptr);
1467 ContextKeeper keeper_ctxt(ctxt);
1468
1469 // NAD83(2011) geocentric
1470 auto source_crs = proj_create_from_database(
1471 m_ctxt, "EPSG", "6317", PJ_CATEGORY_CRS, false, nullptr);
1472 ASSERT_NE(source_crs, nullptr);
1473 ObjectKeeper keeper_source_crs(source_crs);
1474
1475 // NAD83(2011) 2D
1476 auto target_crs = proj_create_from_database(
1477 m_ctxt, "EPSG", "6318", PJ_CATEGORY_CRS, false, nullptr);
1478 ASSERT_NE(target_crs, nullptr);
1479 ObjectKeeper keeper_target_crs(target_crs);
1480
1481 proj_operation_factory_context_set_spatial_criterion(
1482 m_ctxt, ctxt, PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION);
1483
1484 proj_operation_factory_context_set_grid_availability_use(
1485 m_ctxt, ctxt, PROJ_GRID_AVAILABILITY_IGNORED);
1486
1487 auto res = proj_create_operations(m_ctxt, source_crs, target_crs, ctxt);
1488 ASSERT_NE(res, nullptr);
1489 ObjListKeeper keeper_res(res);
1490
1491 PJ_COORD coord;
1492 coord.xyz.x = -463930;
1493 coord.xyz.y = -4414006;
1494 coord.xyz.z = 4562247;
1495 int idx = proj_get_suggested_operation(m_ctxt, res, PJ_FWD, coord);
1496 EXPECT_GE(idx, 0);
1497 }
1498
1499 // ---------------------------------------------------------------------------
1500
TEST_F(CApi,proj_create_operations_discard_superseded)1501 TEST_F(CApi, proj_create_operations_discard_superseded) {
1502 auto ctxt = proj_create_operation_factory_context(m_ctxt, nullptr);
1503 ASSERT_NE(ctxt, nullptr);
1504 ContextKeeper keeper_ctxt(ctxt);
1505
1506 auto source_crs = proj_create_from_database(
1507 m_ctxt, "EPSG", "4203", PJ_CATEGORY_CRS, false, nullptr); // AGD84
1508 ASSERT_NE(source_crs, nullptr);
1509 ObjectKeeper keeper_source_crs(source_crs);
1510
1511 auto target_crs = proj_create_from_database(
1512 m_ctxt, "EPSG", "4326", PJ_CATEGORY_CRS, false, nullptr); // WGS84
1513 ASSERT_NE(target_crs, nullptr);
1514 ObjectKeeper keeper_target_crs(target_crs);
1515
1516 proj_operation_factory_context_set_spatial_criterion(
1517 m_ctxt, ctxt, PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION);
1518
1519 proj_operation_factory_context_set_grid_availability_use(
1520 m_ctxt, ctxt, PROJ_GRID_AVAILABILITY_IGNORED);
1521
1522 proj_operation_factory_context_set_discard_superseded(m_ctxt, ctxt, true);
1523
1524 auto res = proj_create_operations(m_ctxt, source_crs, target_crs, ctxt);
1525 ASSERT_NE(res, nullptr);
1526 ObjListKeeper keeper_res(res);
1527
1528 EXPECT_EQ(proj_list_get_count(res), 4);
1529 }
1530
1531 // ---------------------------------------------------------------------------
1532
TEST_F(CApi,proj_create_operations_dont_discard_superseded)1533 TEST_F(CApi, proj_create_operations_dont_discard_superseded) {
1534 auto ctxt = proj_create_operation_factory_context(m_ctxt, nullptr);
1535 ASSERT_NE(ctxt, nullptr);
1536 ContextKeeper keeper_ctxt(ctxt);
1537
1538 auto source_crs = proj_create_from_database(
1539 m_ctxt, "EPSG", "4203", PJ_CATEGORY_CRS, false, nullptr); // AGD84
1540 ASSERT_NE(source_crs, nullptr);
1541 ObjectKeeper keeper_source_crs(source_crs);
1542
1543 auto target_crs = proj_create_from_database(
1544 m_ctxt, "EPSG", "4326", PJ_CATEGORY_CRS, false, nullptr); // WGS84
1545 ASSERT_NE(target_crs, nullptr);
1546 ObjectKeeper keeper_target_crs(target_crs);
1547
1548 proj_operation_factory_context_set_spatial_criterion(
1549 m_ctxt, ctxt, PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION);
1550
1551 proj_operation_factory_context_set_grid_availability_use(
1552 m_ctxt, ctxt, PROJ_GRID_AVAILABILITY_IGNORED);
1553
1554 proj_operation_factory_context_set_discard_superseded(m_ctxt, ctxt, false);
1555
1556 auto res = proj_create_operations(m_ctxt, source_crs, target_crs, ctxt);
1557 ASSERT_NE(res, nullptr);
1558 ObjListKeeper keeper_res(res);
1559
1560 EXPECT_EQ(proj_list_get_count(res), 5);
1561 }
1562
1563 // ---------------------------------------------------------------------------
1564
TEST_F(CApi,proj_create_operations_with_pivot)1565 TEST_F(CApi, proj_create_operations_with_pivot) {
1566
1567 auto source_crs = proj_create_from_database(
1568 m_ctxt, "EPSG", "4326", PJ_CATEGORY_CRS, false, nullptr); // WGS84
1569 ASSERT_NE(source_crs, nullptr);
1570 ObjectKeeper keeper_source_crs(source_crs);
1571
1572 auto target_crs = proj_create_from_database(
1573 m_ctxt, "EPSG", "6668", PJ_CATEGORY_CRS, false, nullptr); // JGD2011
1574 ASSERT_NE(target_crs, nullptr);
1575 ObjectKeeper keeper_target_crs(target_crs);
1576
1577 // There is no direct transformations between both
1578
1579 // Default behavior: allow any pivot
1580 {
1581 auto ctxt = proj_create_operation_factory_context(m_ctxt, nullptr);
1582 ASSERT_NE(ctxt, nullptr);
1583 ContextKeeper keeper_ctxt(ctxt);
1584
1585 auto res = proj_create_operations(m_ctxt, source_crs, target_crs, ctxt);
1586 ASSERT_NE(res, nullptr);
1587 ObjListKeeper keeper_res(res);
1588 EXPECT_EQ(proj_list_get_count(res), 1);
1589 auto op = proj_list_get(m_ctxt, res, 0);
1590 ASSERT_NE(op, nullptr);
1591 ObjectKeeper keeper_op(op);
1592
1593 EXPECT_EQ(
1594 proj_get_name(op),
1595 std::string(
1596 "Inverse of JGD2000 to WGS 84 (1) + JGD2000 to JGD2011 (2)"));
1597 }
1598
1599 // Disallow pivots
1600 {
1601 auto ctxt = proj_create_operation_factory_context(m_ctxt, nullptr);
1602 ASSERT_NE(ctxt, nullptr);
1603 ContextKeeper keeper_ctxt(ctxt);
1604 proj_operation_factory_context_set_allow_use_intermediate_crs(
1605 m_ctxt, ctxt, PROJ_INTERMEDIATE_CRS_USE_NEVER);
1606
1607 auto res = proj_create_operations(m_ctxt, source_crs, target_crs, ctxt);
1608 ASSERT_NE(res, nullptr);
1609 ObjListKeeper keeper_res(res);
1610 EXPECT_EQ(proj_list_get_count(res), 1);
1611 auto op = proj_list_get(m_ctxt, res, 0);
1612 ASSERT_NE(op, nullptr);
1613 ObjectKeeper keeper_op(op);
1614
1615 EXPECT_EQ(
1616 proj_get_name(op),
1617 std::string("Ballpark geographic offset from WGS 84 to JGD2011"));
1618 }
1619
1620 // Restrict pivot to Tokyo CRS
1621 {
1622 auto ctxt = proj_create_operation_factory_context(m_ctxt, "EPSG");
1623 ASSERT_NE(ctxt, nullptr);
1624 ContextKeeper keeper_ctxt(ctxt);
1625
1626 const char *pivots[] = {"EPSG", "4301", nullptr};
1627 proj_operation_factory_context_set_allowed_intermediate_crs(
1628 m_ctxt, ctxt, pivots);
1629 proj_operation_factory_context_set_spatial_criterion(
1630 m_ctxt, ctxt, PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION);
1631 proj_operation_factory_context_set_grid_availability_use(
1632 m_ctxt, ctxt, PROJ_GRID_AVAILABILITY_IGNORED);
1633
1634 auto res = proj_create_operations(m_ctxt, source_crs, target_crs, ctxt);
1635 ASSERT_NE(res, nullptr);
1636 ObjListKeeper keeper_res(res);
1637 EXPECT_EQ(proj_list_get_count(res), 8);
1638 auto op = proj_list_get(m_ctxt, res, 0);
1639 ASSERT_NE(op, nullptr);
1640 ObjectKeeper keeper_op(op);
1641
1642 EXPECT_EQ(
1643 proj_get_name(op),
1644 std::string(
1645 "Inverse of Tokyo to WGS 84 (108) + Tokyo to JGD2011 (2)"));
1646 }
1647
1648 // Restrict pivot to JGD2000
1649 {
1650 auto ctxt = proj_create_operation_factory_context(m_ctxt, "any");
1651 ASSERT_NE(ctxt, nullptr);
1652 ContextKeeper keeper_ctxt(ctxt);
1653
1654 const char *pivots[] = {"EPSG", "4612", nullptr};
1655 proj_operation_factory_context_set_allowed_intermediate_crs(
1656 m_ctxt, ctxt, pivots);
1657 proj_operation_factory_context_set_spatial_criterion(
1658 m_ctxt, ctxt, PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION);
1659 proj_operation_factory_context_set_grid_availability_use(
1660 m_ctxt, ctxt, PROJ_GRID_AVAILABILITY_IGNORED);
1661 proj_operation_factory_context_set_allow_use_intermediate_crs(
1662 m_ctxt, ctxt, PROJ_INTERMEDIATE_CRS_USE_ALWAYS);
1663
1664 auto res = proj_create_operations(m_ctxt, source_crs, target_crs, ctxt);
1665 ASSERT_NE(res, nullptr);
1666 ObjListKeeper keeper_res(res);
1667 // includes results from ESRI
1668 EXPECT_EQ(proj_list_get_count(res), 4);
1669 auto op = proj_list_get(m_ctxt, res, 0);
1670 ASSERT_NE(op, nullptr);
1671 ObjectKeeper keeper_op(op);
1672
1673 EXPECT_EQ(
1674 proj_get_name(op),
1675 std::string(
1676 "Inverse of JGD2000 to WGS 84 (1) + JGD2000 to JGD2011 (2)"));
1677 }
1678 }
1679
1680 // ---------------------------------------------------------------------------
1681
TEST_F(CApi,proj_create_operations_allow_ballpark_transformations)1682 TEST_F(CApi, proj_create_operations_allow_ballpark_transformations) {
1683 auto ctxt = proj_create_operation_factory_context(m_ctxt, nullptr);
1684 ASSERT_NE(ctxt, nullptr);
1685 ContextKeeper keeper_ctxt(ctxt);
1686
1687 auto source_crs = proj_create_from_database(
1688 m_ctxt, "EPSG", "4267", PJ_CATEGORY_CRS, false, nullptr); // NAD27
1689 ASSERT_NE(source_crs, nullptr);
1690 ObjectKeeper keeper_source_crs(source_crs);
1691
1692 auto target_crs = proj_create_from_database(
1693 m_ctxt, "EPSG", "4258", PJ_CATEGORY_CRS, false, nullptr); // ETRS89
1694 ASSERT_NE(target_crs, nullptr);
1695 ObjectKeeper keeper_target_crs(target_crs);
1696
1697 proj_operation_factory_context_set_spatial_criterion(
1698 m_ctxt, ctxt, PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION);
1699
1700 proj_operation_factory_context_set_grid_availability_use(
1701 m_ctxt, ctxt, PROJ_GRID_AVAILABILITY_IGNORED);
1702
1703 // Default: allowed implicitly
1704 {
1705 auto res = proj_create_operations(m_ctxt, source_crs, target_crs, ctxt);
1706 ASSERT_NE(res, nullptr);
1707 ObjListKeeper keeper_res(res);
1708
1709 EXPECT_EQ(proj_list_get_count(res), 1);
1710 }
1711
1712 // Allow explicitly
1713 {
1714 proj_operation_factory_context_set_allow_ballpark_transformations(
1715 m_ctxt, ctxt, true);
1716
1717 auto res = proj_create_operations(m_ctxt, source_crs, target_crs, ctxt);
1718 ASSERT_NE(res, nullptr);
1719 ObjListKeeper keeper_res(res);
1720
1721 EXPECT_EQ(proj_list_get_count(res), 1);
1722 }
1723
1724 // Disallow
1725 {
1726 proj_operation_factory_context_set_allow_ballpark_transformations(
1727 m_ctxt, ctxt, false);
1728
1729 auto res = proj_create_operations(m_ctxt, source_crs, target_crs, ctxt);
1730 ASSERT_NE(res, nullptr);
1731 ObjListKeeper keeper_res(res);
1732
1733 EXPECT_EQ(proj_list_get_count(res), 0);
1734 }
1735 }
1736
1737 // ---------------------------------------------------------------------------
1738
TEST_F(CApi,proj_context_set_database_path_null)1739 TEST_F(CApi, proj_context_set_database_path_null) {
1740
1741 EXPECT_TRUE(
1742 proj_context_set_database_path(m_ctxt, nullptr, nullptr, nullptr));
1743 auto source_crs = proj_create_from_database(m_ctxt, "EPSG", "4326",
1744 PJ_CATEGORY_CRS, false,
1745 nullptr); // WGS84
1746 ASSERT_NE(source_crs, nullptr);
1747 ObjectKeeper keeper_source_crs(source_crs);
1748 }
1749
1750 // ---------------------------------------------------------------------------
1751
TEST_F(CApi,proj_context_set_database_path_main_memory_one_aux)1752 TEST_F(CApi, proj_context_set_database_path_main_memory_one_aux) {
1753
1754 auto c_path = proj_context_get_database_path(m_ctxt);
1755 ASSERT_TRUE(c_path != nullptr);
1756 std::string path(c_path);
1757 const char *aux_db_list[] = {path.c_str(), nullptr};
1758
1759 // This is super exotic and a miracle that it works. :memory: as the
1760 // main DB is empty. The real stuff is in the aux_db_list. No view
1761 // is created in the ':memory:' internal DB, but as there's only one
1762 // aux DB its tables and views can be directly queried...
1763 // If that breaks at some point, that wouldn't be a big issue.
1764 // Keeping that one as I had a hard time figuring out why it worked !
1765 // The real thing is tested by the C++
1766 // factory::attachExtraDatabases_auxiliary
1767 EXPECT_TRUE(proj_context_set_database_path(m_ctxt, ":memory:", aux_db_list,
1768 nullptr));
1769
1770 auto source_crs = proj_create_from_database(m_ctxt, "EPSG", "4326",
1771 PJ_CATEGORY_CRS, false,
1772 nullptr); // WGS84
1773 ASSERT_NE(source_crs, nullptr);
1774 ObjectKeeper keeper_source_crs(source_crs);
1775 }
1776
1777 // ---------------------------------------------------------------------------
1778
TEST_F(CApi,proj_context_set_database_path_error_1)1779 TEST_F(CApi, proj_context_set_database_path_error_1) {
1780
1781 EXPECT_FALSE(proj_context_set_database_path(m_ctxt, "i_do_not_exist.db",
1782 nullptr, nullptr));
1783
1784 // We will eventually re-open on the default DB
1785 auto source_crs = proj_create_from_database(m_ctxt, "EPSG", "4326",
1786 PJ_CATEGORY_CRS, false,
1787 nullptr); // WGS84
1788 ASSERT_NE(source_crs, nullptr);
1789 ObjectKeeper keeper_source_crs(source_crs);
1790 }
1791
1792 // ---------------------------------------------------------------------------
1793
TEST_F(CApi,proj_context_set_database_path_error_2)1794 TEST_F(CApi, proj_context_set_database_path_error_2) {
1795
1796 const char *aux_db_list[] = {"i_do_not_exist.db", nullptr};
1797 EXPECT_FALSE(
1798 proj_context_set_database_path(m_ctxt, nullptr, aux_db_list, nullptr));
1799
1800 // We will eventually re-open on the default DB
1801 auto source_crs = proj_create_from_database(m_ctxt, "EPSG", "4326",
1802 PJ_CATEGORY_CRS, false,
1803 nullptr); // WGS84
1804 ASSERT_NE(source_crs, nullptr);
1805 ObjectKeeper keeper_source_crs(source_crs);
1806 }
1807
1808 // ---------------------------------------------------------------------------
1809
TEST_F(CApi,proj_context_guess_wkt_dialect)1810 TEST_F(CApi, proj_context_guess_wkt_dialect) {
1811
1812 EXPECT_EQ(proj_context_guess_wkt_dialect(nullptr, "LOCAL_CS[\"foo\"]"),
1813 PJ_GUESSED_WKT1_GDAL);
1814
1815 EXPECT_EQ(proj_context_guess_wkt_dialect(
1816 nullptr,
1817 "GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_"
1818 "1984\",6378137.0,298.257223563]],PRIMEM[\"Greenwich\",0.0],"
1819 "UNIT[\"Degree\",0.0174532925199433]]"),
1820 PJ_GUESSED_WKT1_ESRI);
1821
1822 EXPECT_EQ(proj_context_guess_wkt_dialect(
1823 nullptr,
1824 "GEOGCRS[\"WGS 84\",\n"
1825 " DATUM[\"World Geodetic System 1984\",\n"
1826 " ELLIPSOID[\"WGS 84\",6378137,298.257223563]],\n"
1827 " CS[ellipsoidal,2],\n"
1828 " AXIS[\"geodetic latitude (Lat)\",north],\n"
1829 " AXIS[\"geodetic longitude (Lon)\",east],\n"
1830 " UNIT[\"degree\",0.0174532925199433]]"),
1831 PJ_GUESSED_WKT2_2019);
1832
1833 EXPECT_EQ(proj_context_guess_wkt_dialect(
1834 nullptr,
1835 "GEODCRS[\"WGS 84\",\n"
1836 " DATUM[\"World Geodetic System 1984\",\n"
1837 " ELLIPSOID[\"WGS 84\",6378137,298.257223563]],\n"
1838 " CS[ellipsoidal,2],\n"
1839 " AXIS[\"geodetic latitude (Lat)\",north],\n"
1840 " AXIS[\"geodetic longitude (Lon)\",east],\n"
1841 " UNIT[\"degree\",0.0174532925199433]]"),
1842 PJ_GUESSED_WKT2_2015);
1843
1844 EXPECT_EQ(proj_context_guess_wkt_dialect(nullptr, "foo"),
1845 PJ_GUESSED_NOT_WKT);
1846 }
1847
1848 // ---------------------------------------------------------------------------
1849
TEST_F(CApi,proj_create_from_name)1850 TEST_F(CApi, proj_create_from_name) {
1851 /*
1852 PJ_OBJ_LIST PROJ_DLL *proj_create_from_name(
1853 PJ_CONTEXT *ctx,
1854 const char *auth_name,
1855 const char *searchedName,
1856 const PJ_TYPE* types,
1857 size_t typesCount,
1858 int approximateMatch,
1859 size_t limitResultCount,
1860 const char* const *options); */
1861 {
1862 auto res = proj_create_from_name(m_ctxt, nullptr, "WGS 84", nullptr, 0,
1863 false, 0, nullptr);
1864 ASSERT_NE(res, nullptr);
1865 ObjListKeeper keeper_res(res);
1866 EXPECT_EQ(proj_list_get_count(res), 5);
1867 }
1868 {
1869 auto res = proj_create_from_name(m_ctxt, "xx", "WGS 84", nullptr, 0,
1870 false, 0, nullptr);
1871 ASSERT_NE(res, nullptr);
1872 ObjListKeeper keeper_res(res);
1873 EXPECT_EQ(proj_list_get_count(res), 0);
1874 }
1875 {
1876 const PJ_TYPE types[] = {PJ_TYPE_GEODETIC_CRS, PJ_TYPE_PROJECTED_CRS};
1877 auto res = proj_create_from_name(m_ctxt, nullptr, "WGS 84", types, 2,
1878 true, 10, nullptr);
1879 ASSERT_NE(res, nullptr);
1880 ObjListKeeper keeper_res(res);
1881 EXPECT_EQ(proj_list_get_count(res), 10);
1882 }
1883 }
1884
1885 // ---------------------------------------------------------------------------
1886
TEST_F(CApi,proj_identify)1887 TEST_F(CApi, proj_identify) {
1888 auto obj = proj_create_from_wkt(
1889 m_ctxt,
1890 GeographicCRS::EPSG_4807->exportToWKT(WKTFormatter::create().get())
1891 .c_str(),
1892 nullptr, nullptr, nullptr);
1893 ObjectKeeper keeper(obj);
1894 ASSERT_NE(obj, nullptr);
1895 {
1896 auto res = proj_identify(m_ctxt, obj, nullptr, nullptr, nullptr);
1897 ObjListKeeper keeper_res(res);
1898 EXPECT_EQ(proj_list_get_count(res), 1);
1899 }
1900 {
1901 int *confidence = nullptr;
1902 auto res = proj_identify(m_ctxt, obj, "EPSG", nullptr, &confidence);
1903 ObjListKeeper keeper_res(res);
1904 EXPECT_EQ(proj_list_get_count(res), 1);
1905 EXPECT_EQ(confidence[0], 100);
1906 proj_int_list_destroy(confidence);
1907 }
1908 {
1909 auto objEllps = proj_create_from_wkt(
1910 m_ctxt,
1911 Ellipsoid::GRS1980->exportToWKT(WKTFormatter::create().get())
1912 .c_str(),
1913 nullptr, nullptr, nullptr);
1914 ObjectKeeper keeperEllps(objEllps);
1915 ASSERT_NE(objEllps, nullptr);
1916 auto res = proj_identify(m_ctxt, objEllps, nullptr, nullptr, nullptr);
1917 ObjListKeeper keeper_res(res);
1918 EXPECT_EQ(res, nullptr);
1919 }
1920 {
1921 auto obj2 = proj_create(
1922 m_ctxt, "+proj=longlat +datum=WGS84 +no_defs +type=crs");
1923 ObjectKeeper keeper2(obj2);
1924 ASSERT_NE(obj2, nullptr);
1925 int *confidence = nullptr;
1926 auto res = proj_identify(m_ctxt, obj2, nullptr, nullptr, &confidence);
1927 ObjListKeeper keeper_res(res);
1928 EXPECT_EQ(proj_list_get_count(res), 4);
1929 proj_int_list_destroy(confidence);
1930 }
1931 {
1932 auto obj2 = proj_create_from_database(m_ctxt, "IGNF", "ETRS89UTM28",
1933 PJ_CATEGORY_CRS, false, nullptr);
1934 ObjectKeeper keeper2(obj2);
1935 ASSERT_NE(obj2, nullptr);
1936 int *confidence = nullptr;
1937 auto res = proj_identify(m_ctxt, obj2, "EPSG", nullptr, &confidence);
1938 ObjListKeeper keeper_res(res);
1939 EXPECT_EQ(proj_list_get_count(res), 1);
1940 auto gotCRS = proj_list_get(m_ctxt, res, 0);
1941 ASSERT_NE(gotCRS, nullptr);
1942 ObjectKeeper keeper_gotCRS(gotCRS);
1943 auto auth = proj_get_id_auth_name(gotCRS, 0);
1944 ASSERT_TRUE(auth != nullptr);
1945 EXPECT_EQ(auth, std::string("EPSG"));
1946 auto code = proj_get_id_code(gotCRS, 0);
1947 ASSERT_TRUE(code != nullptr);
1948 EXPECT_EQ(code, std::string("25828"));
1949 EXPECT_EQ(confidence[0], 70);
1950 proj_int_list_destroy(confidence);
1951 }
1952 }
1953
1954 // ---------------------------------------------------------------------------
1955
TEST_F(CApi,proj_get_area_of_use)1956 TEST_F(CApi, proj_get_area_of_use) {
1957 {
1958 auto crs = proj_create_from_database(m_ctxt, "EPSG", "4326",
1959 PJ_CATEGORY_CRS, false, nullptr);
1960 ASSERT_NE(crs, nullptr);
1961 ObjectKeeper keeper(crs);
1962 EXPECT_TRUE(proj_get_area_of_use(m_ctxt, crs, nullptr, nullptr, nullptr,
1963 nullptr, nullptr));
1964 const char *name = nullptr;
1965 double w;
1966 double s;
1967 double e;
1968 double n;
1969 EXPECT_TRUE(proj_get_area_of_use(m_ctxt, crs, &w, &s, &e, &n, &name));
1970 EXPECT_EQ(w, -180);
1971 EXPECT_EQ(s, -90);
1972 EXPECT_EQ(e, 180);
1973 EXPECT_EQ(n, 90);
1974 ASSERT_TRUE(name != nullptr);
1975 EXPECT_EQ(std::string(name), "World.");
1976 }
1977 {
1978 auto obj = proj_create(m_ctxt, "+proj=longlat +type=crs");
1979 ObjectKeeper keeper(obj);
1980 ASSERT_NE(obj, nullptr);
1981 EXPECT_FALSE(proj_get_area_of_use(m_ctxt, obj, nullptr, nullptr,
1982 nullptr, nullptr, nullptr));
1983 }
1984 }
1985
1986 // ---------------------------------------------------------------------------
1987
TEST_F(CApi,proj_coordoperation_get_accuracy)1988 TEST_F(CApi, proj_coordoperation_get_accuracy) {
1989 {
1990 auto crs = proj_create_from_database(m_ctxt, "EPSG", "4326",
1991 PJ_CATEGORY_CRS, false, nullptr);
1992 ASSERT_NE(crs, nullptr);
1993 ObjectKeeper keeper(crs);
1994 EXPECT_EQ(proj_coordoperation_get_accuracy(m_ctxt, crs), -1.0);
1995 }
1996 {
1997 auto obj = proj_create_from_database(m_ctxt, "EPSG", "1170",
1998 PJ_CATEGORY_COORDINATE_OPERATION,
1999 false, nullptr);
2000 ASSERT_NE(obj, nullptr);
2001 ObjectKeeper keeper(obj);
2002 EXPECT_EQ(proj_coordoperation_get_accuracy(m_ctxt, obj), 16.0);
2003 }
2004 {
2005 auto obj = proj_create(m_ctxt, "+proj=helmert");
2006 ObjectKeeper keeper(obj);
2007 ASSERT_NE(obj, nullptr);
2008 EXPECT_EQ(proj_coordoperation_get_accuracy(m_ctxt, obj), -1.0);
2009 }
2010 }
2011
2012 // ---------------------------------------------------------------------------
2013
TEST_F(CApi,proj_create_geographic_crs)2014 TEST_F(CApi, proj_create_geographic_crs) {
2015
2016 auto cs = proj_create_ellipsoidal_2D_cs(
2017 m_ctxt, PJ_ELLPS2D_LATITUDE_LONGITUDE, nullptr, 0);
2018 ObjectKeeper keeper_cs(cs);
2019 ASSERT_NE(cs, nullptr);
2020
2021 {
2022 auto obj = proj_create_geographic_crs(
2023 m_ctxt, "WGS 84", "World Geodetic System 1984", "WGS 84", 6378137,
2024 298.257223563, "Greenwich", 0.0, "Degree", 0.0174532925199433, cs);
2025 ObjectKeeper keeper(obj);
2026 ASSERT_NE(obj, nullptr);
2027
2028 auto objRef =
2029 proj_create(m_ctxt, GeographicCRS::EPSG_4326
2030 ->exportToWKT(WKTFormatter::create().get())
2031 .c_str());
2032 ObjectKeeper keeperobjRef(objRef);
2033 EXPECT_NE(objRef, nullptr);
2034
2035 EXPECT_TRUE(proj_is_equivalent_to(obj, objRef, PJ_COMP_EQUIVALENT));
2036
2037 auto datum = proj_crs_get_datum(m_ctxt, obj);
2038 ObjectKeeper keeper_datum(datum);
2039 ASSERT_NE(datum, nullptr);
2040
2041 auto obj2 =
2042 proj_create_geographic_crs_from_datum(m_ctxt, "WGS 84", datum, cs);
2043 ObjectKeeper keeperObj(obj2);
2044 ASSERT_NE(obj2, nullptr);
2045
2046 EXPECT_TRUE(proj_is_equivalent_to(obj, obj2, PJ_COMP_STRICT));
2047 }
2048 {
2049 auto obj =
2050 proj_create_geographic_crs(m_ctxt, nullptr, nullptr, nullptr, 1.0,
2051 0.0, nullptr, 0.0, nullptr, 0.0, cs);
2052 ObjectKeeper keeper(obj);
2053 ASSERT_NE(obj, nullptr);
2054 }
2055
2056 // Datum with GDAL_WKT1 spelling: special case of WGS_1984
2057 {
2058 auto obj = proj_create_geographic_crs(
2059 m_ctxt, "WGS 84", "WGS_1984", "WGS 84", 6378137, 298.257223563,
2060 "Greenwich", 0.0, "Degree", 0.0174532925199433, cs);
2061 ObjectKeeper keeper(obj);
2062 ASSERT_NE(obj, nullptr);
2063
2064 auto objRef =
2065 proj_create(m_ctxt, GeographicCRS::EPSG_4326
2066 ->exportToWKT(WKTFormatter::create().get())
2067 .c_str());
2068 ObjectKeeper keeperobjRef(objRef);
2069 EXPECT_NE(objRef, nullptr);
2070
2071 EXPECT_TRUE(proj_is_equivalent_to(obj, objRef, PJ_COMP_EQUIVALENT));
2072 }
2073
2074 // Datum with GDAL_WKT1 spelling: database query
2075 {
2076 auto obj = proj_create_geographic_crs(
2077 m_ctxt, "NAD83", "North_American_Datum_1983", "GRS 1980", 6378137,
2078 298.257222101, "Greenwich", 0.0, "Degree", 0.0174532925199433, cs);
2079 ObjectKeeper keeper(obj);
2080 ASSERT_NE(obj, nullptr);
2081
2082 auto objRef =
2083 proj_create(m_ctxt, GeographicCRS::EPSG_4269
2084 ->exportToWKT(WKTFormatter::create().get())
2085 .c_str());
2086 ObjectKeeper keeperobjRef(objRef);
2087 EXPECT_NE(objRef, nullptr);
2088
2089 EXPECT_TRUE(proj_is_equivalent_to(obj, objRef, PJ_COMP_EQUIVALENT));
2090 }
2091
2092 // Datum with GDAL_WKT1 spelling: database query in alias_name table
2093 {
2094 auto crs = proj_create_geographic_crs(
2095 m_ctxt, "S-JTSK (Ferro)",
2096 "System_Jednotne_Trigonometricke_Site_Katastralni_Ferro",
2097 "Bessel 1841", 6377397.155, 299.1528128, "Ferro",
2098 -17.66666666666667, "Degree", 0.0174532925199433, cs);
2099 ObjectKeeper keeper(crs);
2100 ASSERT_NE(crs, nullptr);
2101
2102 auto datum = proj_crs_get_datum(m_ctxt, crs);
2103 ASSERT_NE(datum, nullptr);
2104 ObjectKeeper keeper_datum(datum);
2105
2106 auto datum_name = proj_get_name(datum);
2107 ASSERT_TRUE(datum_name != nullptr);
2108 EXPECT_EQ(datum_name,
2109 std::string("System of the Unified Trigonometrical Cadastral "
2110 "Network (Ferro)"));
2111 }
2112
2113 // WKT1 with (deprecated)
2114 {
2115 auto crs = proj_create_geographic_crs(
2116 m_ctxt, "SAD69 (deprecated)", "South_American_Datum_1969",
2117 "GRS 1967", 6378160, 298.247167427, "Greenwich", 0, "Degree",
2118 0.0174532925199433, cs);
2119 ObjectKeeper keeper(crs);
2120 ASSERT_NE(crs, nullptr);
2121
2122 auto name = proj_get_name(crs);
2123 ASSERT_TRUE(name != nullptr);
2124 EXPECT_EQ(name, std::string("SAD69"));
2125 EXPECT_TRUE(proj_is_deprecated(crs));
2126 }
2127 }
2128
2129 // ---------------------------------------------------------------------------
2130
TEST_F(CApi,proj_create_geocentric_crs)2131 TEST_F(CApi, proj_create_geocentric_crs) {
2132 {
2133 auto obj = proj_create_geocentric_crs(
2134 m_ctxt, "WGS 84", "World Geodetic System 1984", "WGS 84", 6378137,
2135 298.257223563, "Greenwich", 0.0, "Degree", 0.0174532925199433,
2136 "Metre", 1.0);
2137 ObjectKeeper keeper(obj);
2138 ASSERT_NE(obj, nullptr);
2139
2140 auto objRef =
2141 proj_create(m_ctxt, GeographicCRS::EPSG_4978
2142 ->exportToWKT(WKTFormatter::create().get())
2143 .c_str());
2144 ObjectKeeper keeperobjRef(objRef);
2145 EXPECT_NE(objRef, nullptr);
2146
2147 EXPECT_TRUE(proj_is_equivalent_to(obj, objRef, PJ_COMP_EQUIVALENT));
2148
2149 auto datum = proj_crs_get_datum(m_ctxt, obj);
2150 ObjectKeeper keeper_datum(datum);
2151 ASSERT_NE(datum, nullptr);
2152
2153 auto obj2 = proj_create_geocentric_crs_from_datum(m_ctxt, "WGS 84",
2154 datum, "Metre", 1.0);
2155 ObjectKeeper keeperObj(obj2);
2156 ASSERT_NE(obj2, nullptr);
2157
2158 EXPECT_TRUE(proj_is_equivalent_to(obj, obj2, PJ_COMP_STRICT));
2159 }
2160 {
2161 auto obj = proj_create_geocentric_crs(m_ctxt, nullptr, nullptr, nullptr,
2162 1.0, 0.0, nullptr, 0.0, nullptr,
2163 0.0, nullptr, 0.0);
2164 ObjectKeeper keeper(obj);
2165 ASSERT_NE(obj, nullptr);
2166 }
2167 }
2168
2169 // ---------------------------------------------------------------------------
2170
TEST_F(CApi,check_coord_op_obj_can_be_used_with_proj_trans)2171 TEST_F(CApi, check_coord_op_obj_can_be_used_with_proj_trans) {
2172
2173 {
2174 auto projCRS = proj_create_conversion_utm(m_ctxt, 31, true);
2175 ObjectKeeper keeper_projCRS(projCRS);
2176 ASSERT_NE(projCRS, nullptr);
2177
2178 PJ_COORD coord;
2179 coord.xyzt.x = proj_torad(3.0);
2180 coord.xyzt.y = 0;
2181 coord.xyzt.z = 0;
2182 coord.xyzt.t = 0;
2183 EXPECT_NEAR(proj_trans(projCRS, PJ_FWD, coord).xyzt.x, 500000.0, 1e-9);
2184 }
2185 }
2186
2187 // ---------------------------------------------------------------------------
2188
TEST_F(CApi,proj_create_projections)2189 TEST_F(CApi, proj_create_projections) {
2190
2191 /* BEGIN: Generated by scripts/create_c_api_projections.py*/
2192 {
2193 auto projCRS = proj_create_conversion_utm(m_ctxt, 0, 0);
2194 ObjectKeeper keeper_projCRS(projCRS);
2195 ASSERT_NE(projCRS, nullptr);
2196 }
2197 {
2198 auto projCRS = proj_create_conversion_transverse_mercator(
2199 m_ctxt, 0, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2200 ObjectKeeper keeper_projCRS(projCRS);
2201 ASSERT_NE(projCRS, nullptr);
2202 }
2203 {
2204 auto projCRS =
2205 proj_create_conversion_gauss_schreiber_transverse_mercator(
2206 m_ctxt, 0, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre",
2207 1.0);
2208 ObjectKeeper keeper_projCRS(projCRS);
2209 ASSERT_NE(projCRS, nullptr);
2210 }
2211 {
2212 auto projCRS =
2213 proj_create_conversion_transverse_mercator_south_oriented(
2214 m_ctxt, 0, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre",
2215 1.0);
2216 ObjectKeeper keeper_projCRS(projCRS);
2217 ASSERT_NE(projCRS, nullptr);
2218 }
2219 {
2220 auto projCRS = proj_create_conversion_two_point_equidistant(
2221 m_ctxt, 0, 0, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre",
2222 1.0);
2223 ObjectKeeper keeper_projCRS(projCRS);
2224 ASSERT_NE(projCRS, nullptr);
2225 }
2226 {
2227 auto projCRS = proj_create_conversion_tunisia_mapping_grid(
2228 m_ctxt, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2229 ObjectKeeper keeper_projCRS(projCRS);
2230 ASSERT_NE(projCRS, nullptr);
2231 }
2232 {
2233 auto projCRS = proj_create_conversion_albers_equal_area(
2234 m_ctxt, 0, 0, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre",
2235 1.0);
2236 ObjectKeeper keeper_projCRS(projCRS);
2237 ASSERT_NE(projCRS, nullptr);
2238 }
2239 {
2240 auto projCRS = proj_create_conversion_lambert_conic_conformal_1sp(
2241 m_ctxt, 0, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2242 ObjectKeeper keeper_projCRS(projCRS);
2243 ASSERT_NE(projCRS, nullptr);
2244 }
2245 {
2246 auto projCRS = proj_create_conversion_lambert_conic_conformal_2sp(
2247 m_ctxt, 0, 0, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre",
2248 1.0);
2249 ObjectKeeper keeper_projCRS(projCRS);
2250 ASSERT_NE(projCRS, nullptr);
2251 }
2252 {
2253 auto projCRS =
2254 proj_create_conversion_lambert_conic_conformal_2sp_michigan(
2255 m_ctxt, 0, 0, 0, 0, 0, 0, 0, "Degree", 0.0174532925199433,
2256 "Metre", 1.0);
2257 ObjectKeeper keeper_projCRS(projCRS);
2258 ASSERT_NE(projCRS, nullptr);
2259 }
2260 {
2261 auto projCRS =
2262 proj_create_conversion_lambert_conic_conformal_2sp_belgium(
2263 m_ctxt, 0, 0, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre",
2264 1.0);
2265 ObjectKeeper keeper_projCRS(projCRS);
2266 ASSERT_NE(projCRS, nullptr);
2267 }
2268 {
2269 auto projCRS = proj_create_conversion_azimuthal_equidistant(
2270 m_ctxt, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2271 ObjectKeeper keeper_projCRS(projCRS);
2272 ASSERT_NE(projCRS, nullptr);
2273 }
2274 {
2275 auto projCRS = proj_create_conversion_guam_projection(
2276 m_ctxt, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2277 ObjectKeeper keeper_projCRS(projCRS);
2278 ASSERT_NE(projCRS, nullptr);
2279 }
2280 {
2281 auto projCRS = proj_create_conversion_bonne(
2282 m_ctxt, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2283 ObjectKeeper keeper_projCRS(projCRS);
2284 ASSERT_NE(projCRS, nullptr);
2285 }
2286 {
2287 auto projCRS =
2288 proj_create_conversion_lambert_cylindrical_equal_area_spherical(
2289 m_ctxt, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2290 ObjectKeeper keeper_projCRS(projCRS);
2291 ASSERT_NE(projCRS, nullptr);
2292 }
2293 {
2294 auto projCRS = proj_create_conversion_lambert_cylindrical_equal_area(
2295 m_ctxt, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2296 ObjectKeeper keeper_projCRS(projCRS);
2297 ASSERT_NE(projCRS, nullptr);
2298 }
2299 {
2300 auto projCRS = proj_create_conversion_cassini_soldner(
2301 m_ctxt, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2302 ObjectKeeper keeper_projCRS(projCRS);
2303 ASSERT_NE(projCRS, nullptr);
2304 }
2305 {
2306 auto projCRS = proj_create_conversion_equidistant_conic(
2307 m_ctxt, 0, 0, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre",
2308 1.0);
2309 ObjectKeeper keeper_projCRS(projCRS);
2310 ASSERT_NE(projCRS, nullptr);
2311 }
2312 {
2313 auto projCRS = proj_create_conversion_eckert_i(
2314 m_ctxt, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2315 ObjectKeeper keeper_projCRS(projCRS);
2316 ASSERT_NE(projCRS, nullptr);
2317 }
2318 {
2319 auto projCRS = proj_create_conversion_eckert_ii(
2320 m_ctxt, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2321 ObjectKeeper keeper_projCRS(projCRS);
2322 ASSERT_NE(projCRS, nullptr);
2323 }
2324 {
2325 auto projCRS = proj_create_conversion_eckert_iii(
2326 m_ctxt, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2327 ObjectKeeper keeper_projCRS(projCRS);
2328 ASSERT_NE(projCRS, nullptr);
2329 }
2330 {
2331 auto projCRS = proj_create_conversion_eckert_iv(
2332 m_ctxt, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2333 ObjectKeeper keeper_projCRS(projCRS);
2334 ASSERT_NE(projCRS, nullptr);
2335 }
2336 {
2337 auto projCRS = proj_create_conversion_eckert_v(
2338 m_ctxt, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2339 ObjectKeeper keeper_projCRS(projCRS);
2340 ASSERT_NE(projCRS, nullptr);
2341 }
2342 {
2343 auto projCRS = proj_create_conversion_eckert_vi(
2344 m_ctxt, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2345 ObjectKeeper keeper_projCRS(projCRS);
2346 ASSERT_NE(projCRS, nullptr);
2347 }
2348 {
2349 auto projCRS = proj_create_conversion_equidistant_cylindrical(
2350 m_ctxt, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2351 ObjectKeeper keeper_projCRS(projCRS);
2352 ASSERT_NE(projCRS, nullptr);
2353 }
2354 {
2355 auto projCRS = proj_create_conversion_equidistant_cylindrical_spherical(
2356 m_ctxt, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2357 ObjectKeeper keeper_projCRS(projCRS);
2358 ASSERT_NE(projCRS, nullptr);
2359 }
2360 {
2361 auto projCRS = proj_create_conversion_gall(
2362 m_ctxt, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2363 ObjectKeeper keeper_projCRS(projCRS);
2364 ASSERT_NE(projCRS, nullptr);
2365 }
2366 {
2367 auto projCRS = proj_create_conversion_goode_homolosine(
2368 m_ctxt, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2369 ObjectKeeper keeper_projCRS(projCRS);
2370 ASSERT_NE(projCRS, nullptr);
2371 }
2372 {
2373 auto projCRS = proj_create_conversion_interrupted_goode_homolosine(
2374 m_ctxt, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2375 ObjectKeeper keeper_projCRS(projCRS);
2376 ASSERT_NE(projCRS, nullptr);
2377 }
2378 {
2379 auto projCRS = proj_create_conversion_geostationary_satellite_sweep_x(
2380 m_ctxt, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2381 ObjectKeeper keeper_projCRS(projCRS);
2382 ASSERT_NE(projCRS, nullptr);
2383 }
2384 {
2385 auto projCRS = proj_create_conversion_geostationary_satellite_sweep_y(
2386 m_ctxt, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2387 ObjectKeeper keeper_projCRS(projCRS);
2388 ASSERT_NE(projCRS, nullptr);
2389 }
2390 {
2391 auto projCRS = proj_create_conversion_gnomonic(
2392 m_ctxt, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2393 ObjectKeeper keeper_projCRS(projCRS);
2394 ASSERT_NE(projCRS, nullptr);
2395 }
2396 {
2397 auto projCRS = proj_create_conversion_hotine_oblique_mercator_variant_a(
2398 m_ctxt, 0, 0, 0, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre",
2399 1.0);
2400 ObjectKeeper keeper_projCRS(projCRS);
2401 ASSERT_NE(projCRS, nullptr);
2402 }
2403 {
2404 auto projCRS = proj_create_conversion_hotine_oblique_mercator_variant_b(
2405 m_ctxt, 0, 0, 0, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre",
2406 1.0);
2407 ObjectKeeper keeper_projCRS(projCRS);
2408 ASSERT_NE(projCRS, nullptr);
2409 }
2410 {
2411 auto projCRS =
2412 proj_create_conversion_hotine_oblique_mercator_two_point_natural_origin(
2413 m_ctxt, 0, 0, 0, 0, 0, 0, 0, 0, "Degree", 0.0174532925199433,
2414 "Metre", 1.0);
2415 ObjectKeeper keeper_projCRS(projCRS);
2416 ASSERT_NE(projCRS, nullptr);
2417 }
2418 {
2419 auto projCRS = proj_create_conversion_laborde_oblique_mercator(
2420 m_ctxt, 0, 0, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre",
2421 1.0);
2422 ObjectKeeper keeper_projCRS(projCRS);
2423 ASSERT_NE(projCRS, nullptr);
2424 }
2425 {
2426 auto projCRS = proj_create_conversion_international_map_world_polyconic(
2427 m_ctxt, 0, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2428 ObjectKeeper keeper_projCRS(projCRS);
2429 ASSERT_NE(projCRS, nullptr);
2430 }
2431 {
2432 auto projCRS = proj_create_conversion_krovak_north_oriented(
2433 m_ctxt, 0, 0, 0, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre",
2434 1.0);
2435 ObjectKeeper keeper_projCRS(projCRS);
2436 ASSERT_NE(projCRS, nullptr);
2437 }
2438 {
2439 auto projCRS =
2440 proj_create_conversion_krovak(m_ctxt, 0, 0, 0, 0, 0, 0, 0, "Degree",
2441 0.0174532925199433, "Metre", 1.0);
2442 ObjectKeeper keeper_projCRS(projCRS);
2443 ASSERT_NE(projCRS, nullptr);
2444 }
2445 {
2446 auto projCRS = proj_create_conversion_lambert_azimuthal_equal_area(
2447 m_ctxt, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2448 ObjectKeeper keeper_projCRS(projCRS);
2449 ASSERT_NE(projCRS, nullptr);
2450 }
2451 {
2452 auto projCRS = proj_create_conversion_miller_cylindrical(
2453 m_ctxt, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2454 ObjectKeeper keeper_projCRS(projCRS);
2455 ASSERT_NE(projCRS, nullptr);
2456 }
2457 {
2458 auto projCRS = proj_create_conversion_mercator_variant_a(
2459 m_ctxt, 0, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2460 ObjectKeeper keeper_projCRS(projCRS);
2461 ASSERT_NE(projCRS, nullptr);
2462 }
2463 {
2464 auto projCRS = proj_create_conversion_mercator_variant_b(
2465 m_ctxt, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2466 ObjectKeeper keeper_projCRS(projCRS);
2467 ASSERT_NE(projCRS, nullptr);
2468 }
2469 {
2470 auto projCRS =
2471 proj_create_conversion_popular_visualisation_pseudo_mercator(
2472 m_ctxt, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2473 ObjectKeeper keeper_projCRS(projCRS);
2474 ASSERT_NE(projCRS, nullptr);
2475 }
2476 {
2477 auto projCRS = proj_create_conversion_mollweide(
2478 m_ctxt, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2479 ObjectKeeper keeper_projCRS(projCRS);
2480 ASSERT_NE(projCRS, nullptr);
2481 }
2482 {
2483 auto projCRS = proj_create_conversion_new_zealand_mapping_grid(
2484 m_ctxt, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2485 ObjectKeeper keeper_projCRS(projCRS);
2486 ASSERT_NE(projCRS, nullptr);
2487 }
2488 {
2489 auto projCRS = proj_create_conversion_oblique_stereographic(
2490 m_ctxt, 0, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2491 ObjectKeeper keeper_projCRS(projCRS);
2492 ASSERT_NE(projCRS, nullptr);
2493 }
2494 {
2495 auto projCRS = proj_create_conversion_orthographic(
2496 m_ctxt, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2497 ObjectKeeper keeper_projCRS(projCRS);
2498 ASSERT_NE(projCRS, nullptr);
2499 }
2500 {
2501 auto projCRS = proj_create_conversion_american_polyconic(
2502 m_ctxt, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2503 ObjectKeeper keeper_projCRS(projCRS);
2504 ASSERT_NE(projCRS, nullptr);
2505 }
2506 {
2507 auto projCRS = proj_create_conversion_polar_stereographic_variant_a(
2508 m_ctxt, 0, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2509 ObjectKeeper keeper_projCRS(projCRS);
2510 ASSERT_NE(projCRS, nullptr);
2511 }
2512 {
2513 auto projCRS = proj_create_conversion_polar_stereographic_variant_b(
2514 m_ctxt, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2515 ObjectKeeper keeper_projCRS(projCRS);
2516 ASSERT_NE(projCRS, nullptr);
2517 }
2518 {
2519 auto projCRS = proj_create_conversion_robinson(
2520 m_ctxt, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2521 ObjectKeeper keeper_projCRS(projCRS);
2522 ASSERT_NE(projCRS, nullptr);
2523 }
2524 {
2525 auto projCRS = proj_create_conversion_sinusoidal(
2526 m_ctxt, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2527 ObjectKeeper keeper_projCRS(projCRS);
2528 ASSERT_NE(projCRS, nullptr);
2529 }
2530 {
2531 auto projCRS = proj_create_conversion_stereographic(
2532 m_ctxt, 0, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2533 ObjectKeeper keeper_projCRS(projCRS);
2534 ASSERT_NE(projCRS, nullptr);
2535 }
2536 {
2537 auto projCRS = proj_create_conversion_van_der_grinten(
2538 m_ctxt, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2539 ObjectKeeper keeper_projCRS(projCRS);
2540 ASSERT_NE(projCRS, nullptr);
2541 }
2542 {
2543 auto projCRS = proj_create_conversion_wagner_i(
2544 m_ctxt, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2545 ObjectKeeper keeper_projCRS(projCRS);
2546 ASSERT_NE(projCRS, nullptr);
2547 }
2548 {
2549 auto projCRS = proj_create_conversion_wagner_ii(
2550 m_ctxt, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2551 ObjectKeeper keeper_projCRS(projCRS);
2552 ASSERT_NE(projCRS, nullptr);
2553 }
2554 {
2555 auto projCRS = proj_create_conversion_wagner_iii(
2556 m_ctxt, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2557 ObjectKeeper keeper_projCRS(projCRS);
2558 ASSERT_NE(projCRS, nullptr);
2559 }
2560 {
2561 auto projCRS = proj_create_conversion_wagner_iv(
2562 m_ctxt, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2563 ObjectKeeper keeper_projCRS(projCRS);
2564 ASSERT_NE(projCRS, nullptr);
2565 }
2566 {
2567 auto projCRS = proj_create_conversion_wagner_v(
2568 m_ctxt, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2569 ObjectKeeper keeper_projCRS(projCRS);
2570 ASSERT_NE(projCRS, nullptr);
2571 }
2572 {
2573 auto projCRS = proj_create_conversion_wagner_vi(
2574 m_ctxt, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2575 ObjectKeeper keeper_projCRS(projCRS);
2576 ASSERT_NE(projCRS, nullptr);
2577 }
2578 {
2579 auto projCRS = proj_create_conversion_wagner_vii(
2580 m_ctxt, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2581 ObjectKeeper keeper_projCRS(projCRS);
2582 ASSERT_NE(projCRS, nullptr);
2583 }
2584 {
2585 auto projCRS = proj_create_conversion_quadrilateralized_spherical_cube(
2586 m_ctxt, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2587 ObjectKeeper keeper_projCRS(projCRS);
2588 ASSERT_NE(projCRS, nullptr);
2589 }
2590 {
2591 auto projCRS = proj_create_conversion_spherical_cross_track_height(
2592 m_ctxt, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2593 ObjectKeeper keeper_projCRS(projCRS);
2594 ASSERT_NE(projCRS, nullptr);
2595 }
2596 {
2597 auto projCRS = proj_create_conversion_equal_earth(
2598 m_ctxt, 0, 0, 0, "Degree", 0.0174532925199433, "Metre", 1.0);
2599 ObjectKeeper keeper_projCRS(projCRS);
2600 ASSERT_NE(projCRS, nullptr);
2601 }
2602 {
2603 auto projCRS = proj_create_conversion_vertical_perspective(
2604 m_ctxt, 0, 0, 0, 0, 0, 0, "Degree", 0.0174532925199433, "Metre",
2605 1.0);
2606 ObjectKeeper keeper_projCRS(projCRS);
2607 ASSERT_NE(projCRS, nullptr);
2608 }
2609 {
2610 auto projCRS = proj_create_conversion_pole_rotation_grib_convention(
2611 m_ctxt, 0, 0, 0, "Degree", 0.0174532925199433);
2612 ObjectKeeper keeper_projCRS(projCRS);
2613 ASSERT_NE(projCRS, nullptr);
2614 }
2615
2616 /* END: Generated by scripts/create_c_api_projections.py*/
2617 }
2618
2619 // ---------------------------------------------------------------------------
2620
TEST_F(CApi,proj_cs_get_axis_info)2621 TEST_F(CApi, proj_cs_get_axis_info) {
2622 {
2623 auto crs = proj_create_from_database(m_ctxt, "EPSG", "4326",
2624 PJ_CATEGORY_CRS, false, nullptr);
2625 ASSERT_NE(crs, nullptr);
2626 ObjectKeeper keeper(crs);
2627
2628 auto cs = proj_crs_get_coordinate_system(m_ctxt, crs);
2629 ASSERT_NE(cs, nullptr);
2630 ObjectKeeper keeperCs(cs);
2631
2632 EXPECT_EQ(proj_cs_get_type(m_ctxt, cs), PJ_CS_TYPE_ELLIPSOIDAL);
2633
2634 EXPECT_EQ(proj_cs_get_axis_count(m_ctxt, cs), 2);
2635
2636 EXPECT_FALSE(proj_cs_get_axis_info(m_ctxt, cs, -1, nullptr, nullptr,
2637 nullptr, nullptr, nullptr, nullptr,
2638 nullptr));
2639
2640 EXPECT_FALSE(proj_cs_get_axis_info(m_ctxt, cs, 2, nullptr, nullptr,
2641 nullptr, nullptr, nullptr, nullptr,
2642 nullptr));
2643
2644 EXPECT_TRUE(proj_cs_get_axis_info(m_ctxt, cs, 0, nullptr, nullptr,
2645 nullptr, nullptr, nullptr, nullptr,
2646 nullptr));
2647
2648 const char *name = nullptr;
2649 const char *abbrev = nullptr;
2650 const char *direction = nullptr;
2651 double unitConvFactor = 0.0;
2652 const char *unitName = nullptr;
2653 const char *unitAuthority = nullptr;
2654 const char *unitCode = nullptr;
2655
2656 EXPECT_TRUE(proj_cs_get_axis_info(
2657 m_ctxt, cs, 0, &name, &abbrev, &direction, &unitConvFactor,
2658 &unitName, &unitAuthority, &unitCode));
2659 ASSERT_NE(name, nullptr);
2660 ASSERT_NE(abbrev, nullptr);
2661 ASSERT_NE(direction, nullptr);
2662 ASSERT_NE(unitName, nullptr);
2663 ASSERT_NE(unitAuthority, nullptr);
2664 ASSERT_NE(unitCode, nullptr);
2665 EXPECT_EQ(std::string(name), "Geodetic latitude");
2666 EXPECT_EQ(std::string(abbrev), "Lat");
2667 EXPECT_EQ(std::string(direction), "north");
2668 EXPECT_EQ(unitConvFactor, 0.017453292519943295) << unitConvFactor;
2669 EXPECT_EQ(std::string(unitName), "degree");
2670 EXPECT_EQ(std::string(unitAuthority), "EPSG");
2671 EXPECT_EQ(std::string(unitCode), "9122");
2672 }
2673
2674 // Non CRS object
2675 {
2676 auto obj = proj_create_from_database(m_ctxt, "EPSG", "1170",
2677 PJ_CATEGORY_COORDINATE_OPERATION,
2678 false, nullptr);
2679 ASSERT_NE(obj, nullptr);
2680 ObjectKeeper keeper(obj);
2681 EXPECT_EQ(proj_crs_get_coordinate_system(m_ctxt, obj), nullptr);
2682
2683 EXPECT_EQ(proj_cs_get_type(m_ctxt, obj), PJ_CS_TYPE_UNKNOWN);
2684
2685 EXPECT_EQ(proj_cs_get_axis_count(m_ctxt, obj), -1);
2686
2687 EXPECT_FALSE(proj_cs_get_axis_info(m_ctxt, obj, 0, nullptr, nullptr,
2688 nullptr, nullptr, nullptr, nullptr,
2689 nullptr));
2690 }
2691 }
2692
2693 // ---------------------------------------------------------------------------
2694
TEST_F(CApi,proj_context_get_database_metadata)2695 TEST_F(CApi, proj_context_get_database_metadata) {
2696 EXPECT_TRUE(proj_context_get_database_metadata(m_ctxt, "IGNF.VERSION") !=
2697 nullptr);
2698
2699 EXPECT_TRUE(proj_context_get_database_metadata(m_ctxt, "FOO") == nullptr);
2700 }
2701
2702 // ---------------------------------------------------------------------------
2703
TEST_F(CApi,proj_clone)2704 TEST_F(CApi, proj_clone) {
2705 auto obj = proj_create(m_ctxt, "+proj=longlat");
2706 ObjectKeeper keeper(obj);
2707 ASSERT_NE(obj, nullptr);
2708
2709 auto clone = proj_clone(m_ctxt, obj);
2710 ObjectKeeper keeperClone(clone);
2711 ASSERT_NE(clone, nullptr);
2712
2713 EXPECT_TRUE(proj_is_equivalent_to(obj, clone, PJ_COMP_STRICT));
2714 }
2715
2716 // ---------------------------------------------------------------------------
2717
TEST_F(CApi,proj_crs_alter_geodetic_crs)2718 TEST_F(CApi, proj_crs_alter_geodetic_crs) {
2719 auto projCRS = proj_create_from_wkt(
2720 m_ctxt,
2721 createProjectedCRS()->exportToWKT(WKTFormatter::create().get()).c_str(),
2722 nullptr, nullptr, nullptr);
2723 ObjectKeeper keeper(projCRS);
2724 ASSERT_NE(projCRS, nullptr);
2725
2726 auto newGeodCRS = proj_create(m_ctxt, "+proj=longlat +type=crs");
2727 ObjectKeeper keeper_newGeodCRS(newGeodCRS);
2728 ASSERT_NE(newGeodCRS, nullptr);
2729
2730 auto geodCRS = proj_crs_get_geodetic_crs(m_ctxt, projCRS);
2731 ObjectKeeper keeper_geodCRS(geodCRS);
2732 ASSERT_NE(geodCRS, nullptr);
2733
2734 auto geodCRSAltered =
2735 proj_crs_alter_geodetic_crs(m_ctxt, geodCRS, newGeodCRS);
2736 ObjectKeeper keeper_geodCRSAltered(geodCRSAltered);
2737 ASSERT_NE(geodCRSAltered, nullptr);
2738 EXPECT_TRUE(
2739 proj_is_equivalent_to(geodCRSAltered, newGeodCRS, PJ_COMP_STRICT));
2740
2741 {
2742 auto projCRSAltered =
2743 proj_crs_alter_geodetic_crs(m_ctxt, projCRS, newGeodCRS);
2744 ObjectKeeper keeper_projCRSAltered(projCRSAltered);
2745 ASSERT_NE(projCRSAltered, nullptr);
2746
2747 EXPECT_EQ(proj_get_type(projCRSAltered), PJ_TYPE_PROJECTED_CRS);
2748
2749 auto projCRSAltered_geodCRS =
2750 proj_crs_get_geodetic_crs(m_ctxt, projCRSAltered);
2751 ObjectKeeper keeper_projCRSAltered_geodCRS(projCRSAltered_geodCRS);
2752 ASSERT_NE(projCRSAltered_geodCRS, nullptr);
2753
2754 EXPECT_TRUE(proj_is_equivalent_to(projCRSAltered_geodCRS, newGeodCRS,
2755 PJ_COMP_STRICT));
2756 }
2757
2758 // Check that proj_crs_alter_geodetic_crs preserves deprecation flag
2759 {
2760 auto projCRSDeprecated =
2761 proj_alter_name(m_ctxt, projCRS, "new name (deprecated)");
2762 ObjectKeeper keeper_projCRSDeprecated(projCRSDeprecated);
2763 ASSERT_NE(projCRSDeprecated, nullptr);
2764
2765 auto projCRSAltered =
2766 proj_crs_alter_geodetic_crs(m_ctxt, projCRSDeprecated, newGeodCRS);
2767 ObjectKeeper keeper_projCRSAltered(projCRSAltered);
2768 ASSERT_NE(projCRSAltered, nullptr);
2769
2770 EXPECT_EQ(proj_get_name(projCRSAltered), std::string("new name"));
2771 EXPECT_TRUE(proj_is_deprecated(projCRSAltered));
2772 }
2773 }
2774
2775 // ---------------------------------------------------------------------------
2776
TEST_F(CApi,proj_crs_alter_cs_angular_unit)2777 TEST_F(CApi, proj_crs_alter_cs_angular_unit) {
2778 auto crs = proj_create_from_wkt(
2779 m_ctxt,
2780 GeographicCRS::EPSG_4326->exportToWKT(WKTFormatter::create().get())
2781 .c_str(),
2782 nullptr, nullptr, nullptr);
2783 ObjectKeeper keeper(crs);
2784 ASSERT_NE(crs, nullptr);
2785
2786 {
2787 auto alteredCRS = proj_crs_alter_cs_angular_unit(m_ctxt, crs, "my unit",
2788 2, nullptr, nullptr);
2789 ObjectKeeper keeper_alteredCRS(alteredCRS);
2790 ASSERT_NE(alteredCRS, nullptr);
2791
2792 auto cs = proj_crs_get_coordinate_system(m_ctxt, alteredCRS);
2793 ASSERT_NE(cs, nullptr);
2794 ObjectKeeper keeperCs(cs);
2795 double unitConvFactor = 0.0;
2796 const char *unitName = nullptr;
2797
2798 EXPECT_TRUE(proj_cs_get_axis_info(m_ctxt, cs, 0, nullptr, nullptr,
2799 nullptr, &unitConvFactor, &unitName,
2800 nullptr, nullptr));
2801 ASSERT_NE(unitName, nullptr);
2802 EXPECT_EQ(unitConvFactor, 2) << unitConvFactor;
2803 EXPECT_EQ(std::string(unitName), "my unit");
2804 }
2805
2806 {
2807 auto alteredCRS = proj_crs_alter_cs_angular_unit(
2808 m_ctxt, crs, "my unit", 2, "my auth", "my code");
2809 ObjectKeeper keeper_alteredCRS(alteredCRS);
2810 ASSERT_NE(alteredCRS, nullptr);
2811
2812 auto cs = proj_crs_get_coordinate_system(m_ctxt, alteredCRS);
2813 ASSERT_NE(cs, nullptr);
2814 ObjectKeeper keeperCs(cs);
2815 double unitConvFactor = 0.0;
2816 const char *unitName = nullptr;
2817 const char *unitAuthName = nullptr;
2818 const char *unitCode = nullptr;
2819
2820 EXPECT_TRUE(proj_cs_get_axis_info(m_ctxt, cs, 0, nullptr, nullptr,
2821 nullptr, &unitConvFactor, &unitName,
2822 &unitAuthName, &unitCode));
2823 ASSERT_NE(unitName, nullptr);
2824 EXPECT_EQ(unitConvFactor, 2) << unitConvFactor;
2825 EXPECT_EQ(std::string(unitName), "my unit");
2826 ASSERT_NE(unitAuthName, nullptr);
2827 EXPECT_EQ(std::string(unitAuthName), "my auth");
2828 ASSERT_NE(unitCode, nullptr);
2829 EXPECT_EQ(std::string(unitCode), "my code");
2830 }
2831 }
2832
2833 // ---------------------------------------------------------------------------
2834
TEST_F(CApi,proj_crs_alter_cs_linear_unit)2835 TEST_F(CApi, proj_crs_alter_cs_linear_unit) {
2836 auto crs = proj_create_from_wkt(
2837 m_ctxt,
2838 createProjectedCRS()->exportToWKT(WKTFormatter::create().get()).c_str(),
2839 nullptr, nullptr, nullptr);
2840 ObjectKeeper keeper(crs);
2841 ASSERT_NE(crs, nullptr);
2842
2843 {
2844 auto alteredCRS = proj_crs_alter_cs_linear_unit(m_ctxt, crs, "my unit",
2845 2, nullptr, nullptr);
2846 ObjectKeeper keeper_alteredCRS(alteredCRS);
2847 ASSERT_NE(alteredCRS, nullptr);
2848
2849 auto cs = proj_crs_get_coordinate_system(m_ctxt, alteredCRS);
2850 ASSERT_NE(cs, nullptr);
2851 ObjectKeeper keeperCs(cs);
2852 double unitConvFactor = 0.0;
2853 const char *unitName = nullptr;
2854
2855 EXPECT_TRUE(proj_cs_get_axis_info(m_ctxt, cs, 0, nullptr, nullptr,
2856 nullptr, &unitConvFactor, &unitName,
2857 nullptr, nullptr));
2858 ASSERT_NE(unitName, nullptr);
2859 EXPECT_EQ(unitConvFactor, 2) << unitConvFactor;
2860 EXPECT_EQ(std::string(unitName), "my unit");
2861 }
2862
2863 {
2864 auto alteredCRS = proj_crs_alter_cs_linear_unit(
2865 m_ctxt, crs, "my unit", 2, "my auth", "my code");
2866 ObjectKeeper keeper_alteredCRS(alteredCRS);
2867 ASSERT_NE(alteredCRS, nullptr);
2868
2869 auto cs = proj_crs_get_coordinate_system(m_ctxt, alteredCRS);
2870 ASSERT_NE(cs, nullptr);
2871 ObjectKeeper keeperCs(cs);
2872 double unitConvFactor = 0.0;
2873 const char *unitName = nullptr;
2874 const char *unitAuthName = nullptr;
2875 const char *unitCode = nullptr;
2876
2877 EXPECT_TRUE(proj_cs_get_axis_info(m_ctxt, cs, 0, nullptr, nullptr,
2878 nullptr, &unitConvFactor, &unitName,
2879 &unitAuthName, &unitCode));
2880 ASSERT_NE(unitName, nullptr);
2881 EXPECT_EQ(unitConvFactor, 2) << unitConvFactor;
2882 EXPECT_EQ(std::string(unitName), "my unit");
2883 ASSERT_NE(unitAuthName, nullptr);
2884 EXPECT_EQ(std::string(unitAuthName), "my auth");
2885 ASSERT_NE(unitCode, nullptr);
2886 EXPECT_EQ(std::string(unitCode), "my code");
2887 }
2888 }
2889
2890 // ---------------------------------------------------------------------------
2891
TEST_F(CApi,proj_crs_alter_parameters_linear_unit)2892 TEST_F(CApi, proj_crs_alter_parameters_linear_unit) {
2893 auto crs = proj_create_from_wkt(
2894 m_ctxt,
2895 createProjectedCRS()->exportToWKT(WKTFormatter::create().get()).c_str(),
2896 nullptr, nullptr, nullptr);
2897 ObjectKeeper keeper(crs);
2898 ASSERT_NE(crs, nullptr);
2899
2900 {
2901 auto alteredCRS = proj_crs_alter_parameters_linear_unit(
2902 m_ctxt, crs, "my unit", 2, nullptr, nullptr, false);
2903 ObjectKeeper keeper_alteredCRS(alteredCRS);
2904 ASSERT_NE(alteredCRS, nullptr);
2905
2906 auto wkt = proj_as_wkt(m_ctxt, alteredCRS, PJ_WKT2_2019, nullptr);
2907 ASSERT_NE(wkt, nullptr);
2908 EXPECT_TRUE(std::string(wkt).find("500000") != std::string::npos)
2909 << wkt;
2910 EXPECT_TRUE(std::string(wkt).find("\"my unit\",2") != std::string::npos)
2911 << wkt;
2912 }
2913
2914 {
2915 auto alteredCRS = proj_crs_alter_parameters_linear_unit(
2916 m_ctxt, crs, "my unit", 2, nullptr, nullptr, true);
2917 ObjectKeeper keeper_alteredCRS(alteredCRS);
2918 ASSERT_NE(alteredCRS, nullptr);
2919
2920 auto wkt = proj_as_wkt(m_ctxt, alteredCRS, PJ_WKT2_2019, nullptr);
2921 ASSERT_NE(wkt, nullptr);
2922 EXPECT_TRUE(std::string(wkt).find("250000") != std::string::npos)
2923 << wkt;
2924 EXPECT_TRUE(std::string(wkt).find("\"my unit\",2") != std::string::npos)
2925 << wkt;
2926 }
2927 }
2928
2929 // ---------------------------------------------------------------------------
2930
TEST_F(CApi,proj_create_engineering_crs)2931 TEST_F(CApi, proj_create_engineering_crs) {
2932
2933 auto crs = proj_create_engineering_crs(m_ctxt, "name");
2934 ObjectKeeper keeper(crs);
2935 ASSERT_NE(crs, nullptr);
2936 auto wkt = proj_as_wkt(m_ctxt, crs, PJ_WKT1_GDAL, nullptr);
2937 ASSERT_NE(wkt, nullptr);
2938 EXPECT_EQ(std::string(wkt), "LOCAL_CS[\"name\",\n"
2939 " UNIT[\"metre\",1,\n"
2940 " AUTHORITY[\"EPSG\",\"9001\"]],\n"
2941 " AXIS[\"Easting\",EAST],\n"
2942 " AXIS[\"Northing\",NORTH]]")
2943 << wkt;
2944 }
2945
2946 // ---------------------------------------------------------------------------
2947
TEST_F(CApi,proj_alter_name)2948 TEST_F(CApi, proj_alter_name) {
2949
2950 auto cs = proj_create_ellipsoidal_2D_cs(
2951 m_ctxt, PJ_ELLPS2D_LONGITUDE_LATITUDE, nullptr, 0);
2952 ObjectKeeper keeper_cs(cs);
2953 ASSERT_NE(cs, nullptr);
2954
2955 auto obj = proj_create_geographic_crs(
2956 m_ctxt, "WGS 84", "World Geodetic System 1984", "WGS 84", 6378137,
2957 298.257223563, "Greenwich", 0.0, "Degree", 0.0174532925199433, cs);
2958 ObjectKeeper keeper(obj);
2959 ASSERT_NE(obj, nullptr);
2960
2961 {
2962 auto alteredObj = proj_alter_name(m_ctxt, obj, "new name");
2963 ObjectKeeper keeper_alteredObj(alteredObj);
2964 ASSERT_NE(alteredObj, nullptr);
2965
2966 EXPECT_EQ(std::string(proj_get_name(alteredObj)), "new name");
2967 EXPECT_FALSE(proj_is_deprecated(alteredObj));
2968 }
2969
2970 {
2971 auto alteredObj = proj_alter_name(m_ctxt, obj, "new name (deprecated)");
2972 ObjectKeeper keeper_alteredObj(alteredObj);
2973 ASSERT_NE(alteredObj, nullptr);
2974
2975 EXPECT_EQ(std::string(proj_get_name(alteredObj)), "new name");
2976 EXPECT_TRUE(proj_is_deprecated(alteredObj));
2977 }
2978 }
2979
2980 // ---------------------------------------------------------------------------
2981
TEST_F(CApi,proj_alter_id)2982 TEST_F(CApi, proj_alter_id) {
2983
2984 auto cs = proj_create_ellipsoidal_2D_cs(
2985 m_ctxt, PJ_ELLPS2D_LONGITUDE_LATITUDE, nullptr, 0);
2986 ObjectKeeper keeper_cs(cs);
2987 ASSERT_NE(cs, nullptr);
2988
2989 auto obj = proj_create_geographic_crs(
2990 m_ctxt, "WGS 84", "World Geodetic System 1984", "WGS 84", 6378137,
2991 298.257223563, "Greenwich", 0.0, "Degree", 0.0174532925199433, cs);
2992 ObjectKeeper keeper(obj);
2993 ASSERT_NE(obj, nullptr);
2994
2995 auto alteredObj = proj_alter_id(m_ctxt, obj, "auth", "code");
2996 ObjectKeeper keeper_alteredObj(alteredObj);
2997 ASSERT_NE(alteredObj, nullptr);
2998
2999 EXPECT_EQ(std::string(proj_get_id_auth_name(alteredObj, 0)), "auth");
3000 EXPECT_EQ(std::string(proj_get_id_code(alteredObj, 0)), "code");
3001 }
3002
3003 // ---------------------------------------------------------------------------
3004
TEST_F(CApi,proj_create_projected_crs)3005 TEST_F(CApi, proj_create_projected_crs) {
3006
3007 PJ_PARAM_DESCRIPTION param;
3008 param.name = "param name";
3009 param.auth_name = nullptr;
3010 param.code = nullptr;
3011 param.value = 0.99;
3012 param.unit_name = nullptr;
3013 param.unit_conv_factor = 1.0;
3014 param.unit_type = PJ_UT_SCALE;
3015
3016 auto conv = proj_create_conversion(m_ctxt, "conv", "conv auth", "conv code",
3017 "method", "method auth", "method code",
3018 1, ¶m);
3019 ObjectKeeper keeper_conv(conv);
3020 ASSERT_NE(conv, nullptr);
3021
3022 auto geog_cs = proj_create_ellipsoidal_2D_cs(
3023 m_ctxt, PJ_ELLPS2D_LONGITUDE_LATITUDE, nullptr, 0);
3024 ObjectKeeper keeper_geog_cs(geog_cs);
3025 ASSERT_NE(geog_cs, nullptr);
3026
3027 auto geogCRS = proj_create_geographic_crs(
3028 m_ctxt, "WGS 84", "World Geodetic System 1984", "WGS 84", 6378137,
3029 298.257223563, "Greenwich", 0.0, "Degree", 0.0174532925199433, geog_cs);
3030 ObjectKeeper keeper_geogCRS(geogCRS);
3031 ASSERT_NE(geogCRS, nullptr);
3032
3033 auto cs = proj_create_cartesian_2D_cs(m_ctxt, PJ_CART2D_EASTING_NORTHING,
3034 nullptr, 0);
3035 ObjectKeeper keeper_cs(cs);
3036 ASSERT_NE(cs, nullptr);
3037
3038 auto projCRS =
3039 proj_create_projected_crs(m_ctxt, "my CRS", geogCRS, conv, cs);
3040 ObjectKeeper keeper_projCRS(projCRS);
3041 ASSERT_NE(projCRS, nullptr);
3042 }
3043
3044 // ---------------------------------------------------------------------------
3045
TEST_F(CApi,proj_create_transformation)3046 TEST_F(CApi, proj_create_transformation) {
3047
3048 PJ_PARAM_DESCRIPTION param;
3049 param.name = "param name";
3050 param.auth_name = nullptr;
3051 param.code = nullptr;
3052 param.value = 0.99;
3053 param.unit_name = nullptr;
3054 param.unit_conv_factor = 1.0;
3055 param.unit_type = PJ_UT_SCALE;
3056
3057 auto geog_cs = proj_create_ellipsoidal_2D_cs(
3058 m_ctxt, PJ_ELLPS2D_LONGITUDE_LATITUDE, nullptr, 0);
3059 ObjectKeeper keeper_geog_cs(geog_cs);
3060 ASSERT_NE(geog_cs, nullptr);
3061
3062 auto source_crs = proj_create_geographic_crs(
3063 m_ctxt, "Source CRS", "World Geodetic System 1984", "WGS 84", 6378137,
3064 298.257223563, "Greenwich", 0.0, "Degree", 0.0174532925199433, geog_cs);
3065 ObjectKeeper keeper_source_crs(source_crs);
3066 ASSERT_NE(source_crs, nullptr);
3067
3068 auto target_crs = proj_create_geographic_crs(
3069 m_ctxt, "WGS 84", "World Geodetic System 1984", "WGS 84", 6378137,
3070 298.257223563, "Greenwich", 0.0, "Degree", 0.0174532925199433, geog_cs);
3071 ObjectKeeper keeper_target_crs(target_crs);
3072 ASSERT_NE(target_crs, nullptr);
3073
3074 auto interp_crs = proj_create_geographic_crs(
3075 m_ctxt, "Interpolation CRS", "World Geodetic System 1984", "WGS 84",
3076 6378137, 298.257223563, "Greenwich", 0.0, "Degree", 0.0174532925199433,
3077 geog_cs);
3078 ObjectKeeper keeper_interp_crs(interp_crs);
3079 ASSERT_NE(interp_crs, nullptr);
3080
3081 {
3082 auto transf = proj_create_transformation(
3083 m_ctxt, "transf", "transf auth", "transf code", source_crs,
3084 target_crs, interp_crs, "method", "method auth", "method code", 1,
3085 ¶m, 0);
3086 ObjectKeeper keeper_transf(transf);
3087 ASSERT_NE(transf, nullptr);
3088
3089 EXPECT_EQ(proj_coordoperation_get_param_count(m_ctxt, transf), 1);
3090
3091 auto got_source_crs = proj_get_source_crs(m_ctxt, transf);
3092 ObjectKeeper keeper_got_source_crs(got_source_crs);
3093 ASSERT_NE(got_source_crs, nullptr);
3094 EXPECT_TRUE(
3095 proj_is_equivalent_to(source_crs, got_source_crs, PJ_COMP_STRICT));
3096
3097 auto got_target_crs = proj_get_target_crs(m_ctxt, transf);
3098 ObjectKeeper keeper_got_target_crs(got_target_crs);
3099 ASSERT_NE(got_target_crs, nullptr);
3100 EXPECT_TRUE(
3101 proj_is_equivalent_to(target_crs, got_target_crs, PJ_COMP_STRICT));
3102 }
3103
3104 {
3105 auto transf = proj_create_transformation(
3106 m_ctxt, "transf", "transf auth", "transf code", source_crs,
3107 target_crs, nullptr, "method", "method auth", "method code", 1,
3108 ¶m, -1);
3109 ObjectKeeper keeper_transf(transf);
3110 ASSERT_NE(transf, nullptr);
3111 }
3112 }
3113
3114 // ---------------------------------------------------------------------------
3115
TEST_F(CApi,proj_create_compound_crs)3116 TEST_F(CApi, proj_create_compound_crs) {
3117
3118 auto horiz_cs = proj_create_ellipsoidal_2D_cs(
3119 m_ctxt, PJ_ELLPS2D_LONGITUDE_LATITUDE, nullptr, 0);
3120 ObjectKeeper keeper_horiz_cs(horiz_cs);
3121 ASSERT_NE(horiz_cs, nullptr);
3122
3123 auto horiz_crs = proj_create_geographic_crs(
3124 m_ctxt, "WGS 84", "World Geodetic System 1984", "WGS 84", 6378137,
3125 298.257223563, "Greenwich", 0.0, "Degree", 0.0174532925199433,
3126 horiz_cs);
3127 ObjectKeeper keeper_horiz_crs(horiz_crs);
3128 ASSERT_NE(horiz_crs, nullptr);
3129
3130 auto vert_crs = proj_create_vertical_crs(m_ctxt, "myVertCRS", "myVertDatum",
3131 nullptr, 0.0);
3132 ObjectKeeper keeper_vert_crs(vert_crs);
3133 ASSERT_NE(vert_crs, nullptr);
3134
3135 EXPECT_EQ(proj_get_name(vert_crs), std::string("myVertCRS"));
3136
3137 auto compound_crs =
3138 proj_create_compound_crs(m_ctxt, "myCompoundCRS", horiz_crs, vert_crs);
3139 ObjectKeeper keeper_compound_crss(compound_crs);
3140 ASSERT_NE(compound_crs, nullptr);
3141
3142 EXPECT_EQ(proj_get_name(compound_crs), std::string("myCompoundCRS"));
3143
3144 auto subcrs_horiz = proj_crs_get_sub_crs(m_ctxt, compound_crs, 0);
3145 ASSERT_NE(subcrs_horiz, nullptr);
3146 ObjectKeeper keeper_subcrs_horiz(subcrs_horiz);
3147 EXPECT_TRUE(proj_is_equivalent_to(subcrs_horiz, horiz_crs, PJ_COMP_STRICT));
3148
3149 auto subcrs_vert = proj_crs_get_sub_crs(m_ctxt, compound_crs, 1);
3150 ASSERT_NE(subcrs_vert, nullptr);
3151 ObjectKeeper keeper_subcrs_vert(subcrs_vert);
3152 EXPECT_TRUE(proj_is_equivalent_to(subcrs_vert, vert_crs, PJ_COMP_STRICT));
3153 }
3154
3155 // ---------------------------------------------------------------------------
3156
TEST_F(CApi,proj_convert_conversion_to_other_method)3157 TEST_F(CApi, proj_convert_conversion_to_other_method) {
3158 {
3159 auto geog_cs = proj_create_ellipsoidal_2D_cs(
3160 m_ctxt, PJ_ELLPS2D_LONGITUDE_LATITUDE, nullptr, 0);
3161 ObjectKeeper keeper_geog_cs(geog_cs);
3162 ASSERT_NE(geog_cs, nullptr);
3163
3164 auto geogCRS = proj_create_geographic_crs(
3165 m_ctxt, "WGS 84", "World Geodetic System 1984", "WGS 84", 6378137,
3166 298.257223563, "Greenwich", 0.0, "Degree", 0.0174532925199433,
3167 geog_cs);
3168 ObjectKeeper keeper_geogCRS(geogCRS);
3169 ASSERT_NE(geogCRS, nullptr);
3170
3171 auto cs = proj_create_cartesian_2D_cs(
3172 m_ctxt, PJ_CART2D_EASTING_NORTHING, nullptr, 0);
3173 ObjectKeeper keeper_cs(cs);
3174 ASSERT_NE(cs, nullptr);
3175
3176 auto conv = proj_create_conversion_mercator_variant_a(
3177 m_ctxt, 0, 1, 0.99, 2, 3, "Degree", 0.0174532925199433, "Metre",
3178 1.0);
3179 ObjectKeeper keeper_conv(conv);
3180 ASSERT_NE(conv, nullptr);
3181
3182 auto projCRS =
3183 proj_create_projected_crs(m_ctxt, "my CRS", geogCRS, conv, cs);
3184 ObjectKeeper keeper_projCRS(projCRS);
3185 ASSERT_NE(projCRS, nullptr);
3186
3187 // Wrong object type
3188 EXPECT_EQ(
3189 proj_convert_conversion_to_other_method(
3190 m_ctxt, projCRS, EPSG_CODE_METHOD_MERCATOR_VARIANT_B, nullptr),
3191 nullptr);
3192
3193 auto conv_in_proj = proj_crs_get_coordoperation(m_ctxt, projCRS);
3194 ObjectKeeper keeper_conv_in_proj(conv_in_proj);
3195 ASSERT_NE(conv_in_proj, nullptr);
3196
3197 // 3rd and 4th argument both 0/null
3198 EXPECT_EQ(proj_convert_conversion_to_other_method(m_ctxt, conv_in_proj,
3199 0, nullptr),
3200 nullptr);
3201
3202 auto new_conv = proj_convert_conversion_to_other_method(
3203 m_ctxt, conv_in_proj, EPSG_CODE_METHOD_MERCATOR_VARIANT_B, nullptr);
3204 ObjectKeeper keeper_new_conv(new_conv);
3205 ASSERT_NE(new_conv, nullptr);
3206
3207 EXPECT_FALSE(
3208 proj_is_equivalent_to(new_conv, conv_in_proj, PJ_COMP_STRICT));
3209 EXPECT_TRUE(
3210 proj_is_equivalent_to(new_conv, conv_in_proj, PJ_COMP_EQUIVALENT));
3211
3212 auto new_conv_from_name = proj_convert_conversion_to_other_method(
3213 m_ctxt, conv_in_proj, 0, EPSG_NAME_METHOD_MERCATOR_VARIANT_B);
3214 ObjectKeeper keeper_new_conv_from_name(new_conv_from_name);
3215 ASSERT_NE(new_conv_from_name, nullptr);
3216
3217 EXPECT_TRUE(proj_is_equivalent_to(new_conv, new_conv_from_name,
3218 PJ_COMP_STRICT));
3219
3220 auto new_conv_back = proj_convert_conversion_to_other_method(
3221 m_ctxt, conv_in_proj, 0, EPSG_NAME_METHOD_MERCATOR_VARIANT_A);
3222 ObjectKeeper keeper_new_conv_back(new_conv_back);
3223 ASSERT_NE(new_conv_back, nullptr);
3224
3225 EXPECT_TRUE(
3226 proj_is_equivalent_to(conv_in_proj, new_conv_back, PJ_COMP_STRICT));
3227 }
3228 }
3229
3230 // ---------------------------------------------------------------------------
3231
TEST_F(CApi,proj_get_non_deprecated)3232 TEST_F(CApi, proj_get_non_deprecated) {
3233 auto crs = proj_create_from_database(m_ctxt, "EPSG", "4226",
3234 PJ_CATEGORY_CRS, false, nullptr);
3235 ObjectKeeper keeper(crs);
3236 ASSERT_NE(crs, nullptr);
3237
3238 auto list = proj_get_non_deprecated(m_ctxt, crs);
3239 ASSERT_NE(list, nullptr);
3240 ObjListKeeper keeper_list(list);
3241 EXPECT_EQ(proj_list_get_count(list), 2);
3242 }
3243
3244 // ---------------------------------------------------------------------------
3245
TEST_F(CApi,proj_query_geodetic_crs_from_datum)3246 TEST_F(CApi, proj_query_geodetic_crs_from_datum) {
3247 {
3248 auto list = proj_query_geodetic_crs_from_datum(m_ctxt, nullptr, "EPSG",
3249 "6326", nullptr);
3250 ASSERT_NE(list, nullptr);
3251 ObjListKeeper keeper_list(list);
3252 EXPECT_GE(proj_list_get_count(list), 3);
3253 }
3254 {
3255 auto list = proj_query_geodetic_crs_from_datum(m_ctxt, "EPSG", "EPSG",
3256 "6326", "geographic 2D");
3257 ASSERT_NE(list, nullptr);
3258 ObjListKeeper keeper_list(list);
3259 EXPECT_EQ(proj_list_get_count(list), 1);
3260 }
3261 }
3262
3263 // ---------------------------------------------------------------------------
3264
TEST_F(CApi,proj_uom_get_info_from_database)3265 TEST_F(CApi, proj_uom_get_info_from_database) {
3266 {
3267 EXPECT_FALSE(proj_uom_get_info_from_database(
3268 m_ctxt, "auth", "code", nullptr, nullptr, nullptr));
3269 }
3270 {
3271 EXPECT_TRUE(proj_uom_get_info_from_database(m_ctxt, "EPSG", "9001",
3272 nullptr, nullptr, nullptr));
3273 }
3274 {
3275 const char *name = nullptr;
3276 double conv_factor = 0.0;
3277 const char *category = nullptr;
3278 EXPECT_TRUE(proj_uom_get_info_from_database(
3279 m_ctxt, "EPSG", "9001", &name, &conv_factor, &category));
3280 ASSERT_NE(name, nullptr);
3281 ASSERT_NE(category, nullptr);
3282 EXPECT_EQ(std::string(name), "metre");
3283 EXPECT_EQ(conv_factor, 1.0);
3284 EXPECT_EQ(std::string(category), "linear");
3285 }
3286 {
3287 const char *name = nullptr;
3288 double conv_factor = 0.0;
3289 const char *category = nullptr;
3290 EXPECT_TRUE(proj_uom_get_info_from_database(
3291 m_ctxt, "EPSG", "9102", &name, &conv_factor, &category));
3292 ASSERT_NE(name, nullptr);
3293 ASSERT_NE(category, nullptr);
3294 EXPECT_EQ(std::string(name), "degree");
3295 EXPECT_NEAR(conv_factor, UnitOfMeasure::DEGREE.conversionToSI(), 1e-10);
3296 EXPECT_EQ(std::string(category), "angular");
3297 }
3298 }
3299
3300 // ---------------------------------------------------------------------------
3301
TEST_F(CApi,proj_grid_get_info_from_database)3302 TEST_F(CApi, proj_grid_get_info_from_database) {
3303 {
3304 EXPECT_FALSE(proj_grid_get_info_from_database(m_ctxt, "xxx", nullptr,
3305 nullptr, nullptr, nullptr,
3306 nullptr, nullptr));
3307 }
3308 {
3309 EXPECT_TRUE(proj_grid_get_info_from_database(
3310 m_ctxt, "au_icsm_GDA94_GDA2020_conformal.tif", nullptr, nullptr,
3311 nullptr, nullptr, nullptr, nullptr));
3312 }
3313 {
3314 const char *full_name = nullptr;
3315 const char *package_name = nullptr;
3316 const char *url = nullptr;
3317 int direct_download = 0;
3318 int open_license = 0;
3319 int available = 0;
3320 EXPECT_TRUE(proj_grid_get_info_from_database(
3321 m_ctxt, "au_icsm_GDA94_GDA2020_conformal.tif", &full_name,
3322 &package_name, &url, &direct_download, &open_license, &available));
3323 ASSERT_NE(full_name, nullptr);
3324 // empty string expected as the file is not in test data
3325 EXPECT_TRUE(full_name[0] == 0);
3326 ASSERT_NE(package_name, nullptr);
3327 EXPECT_TRUE(package_name[0] == 0); // empty string expected
3328 ASSERT_NE(url, nullptr);
3329 EXPECT_EQ(std::string(url),
3330 "https://cdn.proj.org/au_icsm_GDA94_GDA2020_conformal.tif");
3331 EXPECT_EQ(direct_download, 1);
3332 EXPECT_EQ(open_license, 1);
3333 }
3334 // Same test as above, but with PROJ 6 grid name
3335 {
3336 const char *full_name = nullptr;
3337 const char *package_name = nullptr;
3338 const char *url = nullptr;
3339 int direct_download = 0;
3340 int open_license = 0;
3341 int available = 0;
3342 EXPECT_TRUE(proj_grid_get_info_from_database(
3343 m_ctxt, "GDA94_GDA2020_conformal.gsb", &full_name, &package_name,
3344 &url, &direct_download, &open_license, &available));
3345 ASSERT_NE(full_name, nullptr);
3346 // empty string expected as the file is not in test data
3347 EXPECT_TRUE(full_name[0] == 0);
3348 ASSERT_NE(package_name, nullptr);
3349 EXPECT_TRUE(package_name[0] == 0); // empty string expected
3350 ASSERT_NE(url, nullptr);
3351 EXPECT_EQ(std::string(url),
3352 "https://cdn.proj.org/au_icsm_GDA94_GDA2020_conformal.tif");
3353 EXPECT_EQ(direct_download, 1);
3354 EXPECT_EQ(open_license, 1);
3355 }
3356 }
3357
3358 // ---------------------------------------------------------------------------
3359
TEST_F(CApi,proj_create_cartesian_2D_cs)3360 TEST_F(CApi, proj_create_cartesian_2D_cs) {
3361 {
3362 auto cs = proj_create_cartesian_2D_cs(
3363 m_ctxt, PJ_CART2D_EASTING_NORTHING, nullptr, 0);
3364 ObjectKeeper keeper_cs(cs);
3365 ASSERT_NE(cs, nullptr);
3366 }
3367 {
3368 auto cs = proj_create_cartesian_2D_cs(
3369 m_ctxt, PJ_CART2D_NORTHING_EASTING, nullptr, 0);
3370 ObjectKeeper keeper_cs(cs);
3371 ASSERT_NE(cs, nullptr);
3372 }
3373 {
3374 auto cs = proj_create_cartesian_2D_cs(
3375 m_ctxt, PJ_CART2D_NORTH_POLE_EASTING_SOUTH_NORTHING_SOUTH, nullptr,
3376 0);
3377 ObjectKeeper keeper_cs(cs);
3378 ASSERT_NE(cs, nullptr);
3379 }
3380 {
3381 auto cs = proj_create_cartesian_2D_cs(
3382 m_ctxt, PJ_CART2D_SOUTH_POLE_EASTING_NORTH_NORTHING_NORTH, nullptr,
3383 0);
3384 ObjectKeeper keeper_cs(cs);
3385 ASSERT_NE(cs, nullptr);
3386 }
3387 {
3388 auto cs = proj_create_cartesian_2D_cs(
3389 m_ctxt, PJ_CART2D_WESTING_SOUTHING, nullptr, 0);
3390 ObjectKeeper keeper_cs(cs);
3391 ASSERT_NE(cs, nullptr);
3392 }
3393 }
3394
3395 // ---------------------------------------------------------------------------
3396
TEST_F(CApi,proj_get_crs_info_list_from_database)3397 TEST_F(CApi, proj_get_crs_info_list_from_database) {
3398 { proj_crs_info_list_destroy(nullptr); }
3399
3400 { proj_get_crs_list_parameters_destroy(nullptr); }
3401
3402 // All null parameters
3403 {
3404 auto list = proj_get_crs_info_list_from_database(nullptr, nullptr,
3405 nullptr, nullptr);
3406 ASSERT_NE(list, nullptr);
3407 ASSERT_NE(list[0], nullptr);
3408 EXPECT_NE(list[0]->auth_name, nullptr);
3409 EXPECT_NE(list[0]->code, nullptr);
3410 EXPECT_NE(list[0]->name, nullptr);
3411 proj_crs_info_list_destroy(list);
3412 }
3413
3414 // Default parameters
3415 {
3416 int result_count = 0;
3417 auto params = proj_get_crs_list_parameters_create();
3418 auto list = proj_get_crs_info_list_from_database(m_ctxt, "EPSG", params,
3419 &result_count);
3420 proj_get_crs_list_parameters_destroy(params);
3421 ASSERT_NE(list, nullptr);
3422 EXPECT_GT(result_count, 1);
3423 EXPECT_EQ(list[result_count], nullptr);
3424 bool found4326 = false;
3425 bool found4978 = false;
3426 bool found4979 = false;
3427 bool found32631 = false;
3428 bool found3855 = false;
3429 bool found3901 = false;
3430 for (int i = 0; i < result_count; i++) {
3431 auto code = std::string(list[i]->code);
3432 if (code == "4326") {
3433 found4326 = true;
3434 EXPECT_EQ(std::string(list[i]->auth_name), "EPSG");
3435 EXPECT_EQ(std::string(list[i]->name), "WGS 84");
3436 EXPECT_EQ(list[i]->type, PJ_TYPE_GEOGRAPHIC_2D_CRS);
3437 EXPECT_EQ(list[i]->deprecated, 0);
3438 EXPECT_EQ(list[i]->bbox_valid, 1);
3439 EXPECT_EQ(list[i]->west_lon_degree, -180.0);
3440 EXPECT_EQ(list[i]->south_lat_degree, -90.0);
3441 EXPECT_EQ(list[i]->east_lon_degree, 180.0);
3442 EXPECT_EQ(list[i]->north_lat_degree, 90.0);
3443 EXPECT_EQ(std::string(list[i]->area_name), "World.");
3444 EXPECT_EQ(list[i]->projection_method_name, nullptr);
3445 } else if (code == "4978") {
3446 found4978 = true;
3447 EXPECT_EQ(list[i]->type, PJ_TYPE_GEOCENTRIC_CRS);
3448 } else if (code == "4979") {
3449 found4979 = true;
3450 EXPECT_EQ(list[i]->type, PJ_TYPE_GEOGRAPHIC_3D_CRS);
3451 } else if (code == "32631") {
3452 found32631 = true;
3453 EXPECT_EQ(list[i]->type, PJ_TYPE_PROJECTED_CRS);
3454 EXPECT_EQ(std::string(list[i]->projection_method_name),
3455 "Transverse Mercator");
3456 } else if (code == "3855") {
3457 found3855 = true;
3458 EXPECT_EQ(list[i]->type, PJ_TYPE_VERTICAL_CRS);
3459 } else if (code == "3901") {
3460 found3901 = true;
3461 EXPECT_EQ(list[i]->type, PJ_TYPE_COMPOUND_CRS);
3462 }
3463 EXPECT_EQ(list[i]->deprecated, 0);
3464 }
3465 EXPECT_TRUE(found4326);
3466 EXPECT_TRUE(found4978);
3467 EXPECT_TRUE(found4979);
3468 EXPECT_TRUE(found32631);
3469 EXPECT_TRUE(found3855);
3470 EXPECT_TRUE(found3901);
3471 proj_crs_info_list_destroy(list);
3472 }
3473
3474 // Filter on only geodetic crs
3475 {
3476 int result_count = 0;
3477 auto params = proj_get_crs_list_parameters_create();
3478 params->typesCount = 1;
3479 auto type = PJ_TYPE_GEODETIC_CRS;
3480 params->types = &type;
3481 auto list = proj_get_crs_info_list_from_database(m_ctxt, "EPSG", params,
3482 &result_count);
3483 bool foundGeog2D = false;
3484 bool foundGeog3D = false;
3485 bool foundGeocentric = false;
3486 for (int i = 0; i < result_count; i++) {
3487 foundGeog2D |= list[i]->type == PJ_TYPE_GEOGRAPHIC_2D_CRS;
3488 foundGeog3D |= list[i]->type == PJ_TYPE_GEOGRAPHIC_3D_CRS;
3489 foundGeocentric |= list[i]->type == PJ_TYPE_GEOCENTRIC_CRS;
3490 EXPECT_TRUE(list[i]->type == PJ_TYPE_GEOGRAPHIC_2D_CRS ||
3491 list[i]->type == PJ_TYPE_GEOGRAPHIC_3D_CRS ||
3492 list[i]->type == PJ_TYPE_GEOCENTRIC_CRS);
3493 }
3494 EXPECT_TRUE(foundGeog2D);
3495 EXPECT_TRUE(foundGeog3D);
3496 EXPECT_TRUE(foundGeocentric);
3497 proj_get_crs_list_parameters_destroy(params);
3498 proj_crs_info_list_destroy(list);
3499 }
3500
3501 // Filter on only geographic crs
3502 {
3503 int result_count = 0;
3504 auto params = proj_get_crs_list_parameters_create();
3505 params->typesCount = 1;
3506 auto type = PJ_TYPE_GEOGRAPHIC_CRS;
3507 params->types = &type;
3508 auto list = proj_get_crs_info_list_from_database(m_ctxt, "EPSG", params,
3509 &result_count);
3510 bool foundGeog2D = false;
3511 bool foundGeog3D = false;
3512 for (int i = 0; i < result_count; i++) {
3513 foundGeog2D |= list[i]->type == PJ_TYPE_GEOGRAPHIC_2D_CRS;
3514 foundGeog3D |= list[i]->type == PJ_TYPE_GEOGRAPHIC_3D_CRS;
3515 EXPECT_TRUE(list[i]->type == PJ_TYPE_GEOGRAPHIC_2D_CRS ||
3516 list[i]->type == PJ_TYPE_GEOGRAPHIC_3D_CRS);
3517 }
3518 EXPECT_TRUE(foundGeog2D);
3519 EXPECT_TRUE(foundGeog3D);
3520 proj_get_crs_list_parameters_destroy(params);
3521 proj_crs_info_list_destroy(list);
3522 }
3523
3524 // Filter on only geographic 2D crs and projected CRS
3525 {
3526 int result_count = 0;
3527 auto params = proj_get_crs_list_parameters_create();
3528 params->typesCount = 2;
3529 const PJ_TYPE types[] = {PJ_TYPE_GEOGRAPHIC_2D_CRS,
3530 PJ_TYPE_PROJECTED_CRS};
3531 params->types = types;
3532 auto list = proj_get_crs_info_list_from_database(m_ctxt, "EPSG", params,
3533 &result_count);
3534 bool foundGeog2D = false;
3535 bool foundProjected = false;
3536 for (int i = 0; i < result_count; i++) {
3537 foundGeog2D |= list[i]->type == PJ_TYPE_GEOGRAPHIC_2D_CRS;
3538 foundProjected |= list[i]->type == PJ_TYPE_PROJECTED_CRS;
3539 EXPECT_TRUE(list[i]->type == PJ_TYPE_GEOGRAPHIC_2D_CRS ||
3540 list[i]->type == PJ_TYPE_PROJECTED_CRS);
3541 }
3542 EXPECT_TRUE(foundGeog2D);
3543 EXPECT_TRUE(foundProjected);
3544 proj_get_crs_list_parameters_destroy(params);
3545 proj_crs_info_list_destroy(list);
3546 }
3547
3548 // Filter on bbox (inclusion)
3549 {
3550 int result_count = 0;
3551 auto params = proj_get_crs_list_parameters_create();
3552 params->bbox_valid = 1;
3553 params->west_lon_degree = 2;
3554 params->south_lat_degree = 49;
3555 params->east_lon_degree = 2.1;
3556 params->north_lat_degree = 49.1;
3557 params->typesCount = 1;
3558 auto type = PJ_TYPE_PROJECTED_CRS;
3559 params->types = &type;
3560 auto list = proj_get_crs_info_list_from_database(m_ctxt, "EPSG", params,
3561 &result_count);
3562 ASSERT_NE(list, nullptr);
3563 EXPECT_GT(result_count, 1);
3564 for (int i = 0; i < result_count; i++) {
3565 if (list[i]->west_lon_degree < list[i]->east_lon_degree) {
3566 EXPECT_LE(list[i]->west_lon_degree, params->west_lon_degree);
3567 EXPECT_GE(list[i]->east_lon_degree, params->east_lon_degree);
3568 }
3569 EXPECT_LE(list[i]->south_lat_degree, params->south_lat_degree);
3570 EXPECT_GE(list[i]->north_lat_degree, params->north_lat_degree);
3571 }
3572 proj_get_crs_list_parameters_destroy(params);
3573 proj_crs_info_list_destroy(list);
3574 }
3575
3576 // Filter on bbox (intersection)
3577 {
3578 int result_count = 0;
3579 auto params = proj_get_crs_list_parameters_create();
3580 params->bbox_valid = 1;
3581 params->west_lon_degree = 2;
3582 params->south_lat_degree = 49;
3583 params->east_lon_degree = 2.1;
3584 params->north_lat_degree = 49.1;
3585 params->crs_area_of_use_contains_bbox = 0;
3586 params->typesCount = 1;
3587 auto type = PJ_TYPE_PROJECTED_CRS;
3588 params->types = &type;
3589 auto list = proj_get_crs_info_list_from_database(m_ctxt, "EPSG", params,
3590 &result_count);
3591 ASSERT_NE(list, nullptr);
3592 EXPECT_GT(result_count, 1);
3593 for (int i = 0; i < result_count; i++) {
3594 if (list[i]->west_lon_degree < list[i]->east_lon_degree) {
3595 EXPECT_LE(list[i]->west_lon_degree, params->west_lon_degree);
3596 EXPECT_GE(list[i]->east_lon_degree, params->east_lon_degree);
3597 }
3598 EXPECT_LE(list[i]->south_lat_degree, params->north_lat_degree);
3599 EXPECT_GE(list[i]->north_lat_degree, params->south_lat_degree);
3600 }
3601 proj_get_crs_list_parameters_destroy(params);
3602 proj_crs_info_list_destroy(list);
3603 }
3604 }
3605
3606 // ---------------------------------------------------------------------------
3607
TEST_F(CApi,proj_get_units_from_database)3608 TEST_F(CApi, proj_get_units_from_database) {
3609 { proj_unit_list_destroy(nullptr); }
3610
3611 {
3612 auto list = proj_get_units_from_database(nullptr, nullptr, nullptr,
3613 true, nullptr);
3614 ASSERT_NE(list, nullptr);
3615 ASSERT_NE(list[0], nullptr);
3616 ASSERT_NE(list[0]->auth_name, nullptr);
3617 ASSERT_NE(list[0]->code, nullptr);
3618 ASSERT_NE(list[0]->name, nullptr);
3619 proj_unit_list_destroy(list);
3620 }
3621
3622 {
3623 int result_count = 0;
3624 auto list = proj_get_units_from_database(nullptr, "EPSG", "linear",
3625 false, &result_count);
3626 ASSERT_NE(list, nullptr);
3627 EXPECT_GT(result_count, 1);
3628 EXPECT_EQ(list[result_count], nullptr);
3629 bool found9001 = false;
3630 for (int i = 0; i < result_count; i++) {
3631 EXPECT_EQ(std::string(list[i]->auth_name), "EPSG");
3632 if (std::string(list[i]->code) == "9001") {
3633 EXPECT_EQ(std::string(list[i]->name), "metre");
3634 EXPECT_EQ(std::string(list[i]->category), "linear");
3635 EXPECT_EQ(list[i]->conv_factor, 1.0);
3636 ASSERT_NE(list[i]->proj_short_name, nullptr);
3637 EXPECT_EQ(std::string(list[i]->proj_short_name), "m");
3638 EXPECT_EQ(list[i]->deprecated, 0);
3639 found9001 = true;
3640 }
3641 EXPECT_EQ(list[i]->deprecated, 0);
3642 }
3643 EXPECT_TRUE(found9001);
3644 proj_unit_list_destroy(list);
3645 }
3646 }
3647
3648 // ---------------------------------------------------------------------------
3649
TEST_F(CApi,proj_normalize_for_visualization)3650 TEST_F(CApi, proj_normalize_for_visualization) {
3651
3652 {
3653 auto P = proj_create(m_ctxt, "+proj=utm +zone=31 +ellps=WGS84");
3654 ObjectKeeper keeper_P(P);
3655 ASSERT_NE(P, nullptr);
3656 auto Pnormalized = proj_normalize_for_visualization(m_ctxt, P);
3657 ObjectKeeper keeper_Pnormalized(Pnormalized);
3658 EXPECT_EQ(Pnormalized, nullptr);
3659 }
3660
3661 auto P = proj_create_crs_to_crs(m_ctxt, "EPSG:4326", "EPSG:32631", nullptr);
3662 ObjectKeeper keeper_P(P);
3663 ASSERT_NE(P, nullptr);
3664 auto Pnormalized = proj_normalize_for_visualization(m_ctxt, P);
3665 ObjectKeeper keeper_Pnormalized(Pnormalized);
3666 ASSERT_NE(Pnormalized, nullptr);
3667 auto projstr = proj_as_proj_string(m_ctxt, Pnormalized, PJ_PROJ_5, nullptr);
3668 ASSERT_NE(projstr, nullptr);
3669 EXPECT_EQ(std::string(projstr),
3670 "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad "
3671 "+step +proj=utm +zone=31 +ellps=WGS84");
3672 }
3673
3674 // ---------------------------------------------------------------------------
3675
TEST_F(CApi,proj_normalize_for_visualization_with_alternatives)3676 TEST_F(CApi, proj_normalize_for_visualization_with_alternatives) {
3677
3678 auto P = proj_create_crs_to_crs(m_ctxt, "EPSG:4326", "EPSG:3003", nullptr);
3679 ObjectKeeper keeper_P(P);
3680 ASSERT_NE(P, nullptr);
3681 auto Pnormalized = proj_normalize_for_visualization(m_ctxt, P);
3682 ObjectKeeper keeper_Pnormalized(Pnormalized);
3683 ASSERT_NE(Pnormalized, nullptr);
3684
3685 {
3686 PJ_COORD c;
3687 // Approximately Roma
3688 c.lpz.lam = 12.5;
3689 c.lpz.phi = 42;
3690 c.lpz.z = 0;
3691 c = proj_trans(Pnormalized, PJ_FWD, c);
3692 EXPECT_NEAR(c.xy.x, 1789912.46264783037, 1e-8);
3693 EXPECT_NEAR(c.xy.y, 4655716.25402576849, 1e-8);
3694 auto projstr = proj_pj_info(Pnormalized).definition;
3695 ASSERT_NE(projstr, nullptr);
3696 EXPECT_EQ(std::string(projstr),
3697 "proj=pipeline step proj=unitconvert xy_in=deg xy_out=rad "
3698 "step proj=push v_3 step proj=cart ellps=WGS84 "
3699 "step inv proj=helmert x=-104.1 y=-49.1 z=-9.9 rx=0.971 "
3700 "ry=-2.917 rz=0.714 s=-11.68 convention=position_vector "
3701 "step inv proj=cart ellps=intl step proj=pop v_3 "
3702 "step proj=tmerc lat_0=0 lon_0=9 k=0.9996 x_0=1500000 "
3703 "y_0=0 ellps=intl");
3704 }
3705
3706 {
3707 PJ_COORD c;
3708 // Approximately Roma
3709 c.xyz.x = 1789912.46264783037;
3710 c.xyz.y = 4655716.25402576849;
3711 c.xyz.z = 0;
3712 c = proj_trans(Pnormalized, PJ_INV, c);
3713 EXPECT_NEAR(c.lp.lam, 12.5, 1e-8);
3714 EXPECT_NEAR(c.lp.phi, 42, 1e-8);
3715 }
3716 }
3717
3718 // ---------------------------------------------------------------------------
3719
TEST_F(CApi,proj_normalize_for_visualization_with_alternatives_reverse)3720 TEST_F(CApi, proj_normalize_for_visualization_with_alternatives_reverse) {
3721
3722 auto P = proj_create_crs_to_crs(m_ctxt, "EPSG:3003", "EPSG:4326", nullptr);
3723 ObjectKeeper keeper_P(P);
3724 ASSERT_NE(P, nullptr);
3725 auto Pnormalized = proj_normalize_for_visualization(m_ctxt, P);
3726 ObjectKeeper keeper_Pnormalized(Pnormalized);
3727 ASSERT_NE(Pnormalized, nullptr);
3728
3729 PJ_COORD c;
3730 // Approximately Roma
3731 c.xyz.x = 1789912.46264783037;
3732 c.xyz.y = 4655716.25402576849;
3733 c.xyz.z = 0;
3734 c = proj_trans(Pnormalized, PJ_FWD, c);
3735 EXPECT_NEAR(c.lp.lam, 12.5, 1e-8);
3736 EXPECT_NEAR(c.lp.phi, 42, 1e-8);
3737 }
3738
3739 // ---------------------------------------------------------------------------
3740
TEST_F(CApi,proj_normalize_for_visualization_on_crs)3741 TEST_F(CApi, proj_normalize_for_visualization_on_crs) {
3742
3743 auto P = proj_create(m_ctxt, "EPSG:4326");
3744 ObjectKeeper keeper_P(P);
3745 ASSERT_NE(P, nullptr);
3746 auto Pnormalized = proj_normalize_for_visualization(m_ctxt, P);
3747 ObjectKeeper keeper_Pnormalized(Pnormalized);
3748 ASSERT_NE(Pnormalized, nullptr);
3749 EXPECT_EQ(proj_get_id_code(Pnormalized, 0), nullptr);
3750
3751 auto cs = proj_crs_get_coordinate_system(m_ctxt, Pnormalized);
3752 ASSERT_NE(cs, nullptr);
3753 ObjectKeeper keeperCs(cs);
3754
3755 const char *name = nullptr;
3756 ASSERT_TRUE(proj_cs_get_axis_info(m_ctxt, cs, 0, &name, nullptr, nullptr,
3757 nullptr, nullptr, nullptr, nullptr));
3758 ASSERT_NE(name, nullptr);
3759 EXPECT_EQ(std::string(name), "Geodetic longitude");
3760 }
3761
3762 // ---------------------------------------------------------------------------
3763
TEST_F(CApi,proj_coordoperation_create_inverse)3764 TEST_F(CApi, proj_coordoperation_create_inverse) {
3765
3766 auto P = proj_create(
3767 m_ctxt, "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
3768 "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push "
3769 "+v_3 +step +proj=cart +ellps=evrst30 +step +proj=helmert "
3770 "+x=293 +y=836 +z=318 +rx=0.5 +ry=1.6 +rz=-2.8 +s=2.1 "
3771 "+convention=position_vector +step +inv +proj=cart "
3772 "+ellps=WGS84 +step +proj=pop +v_3 +step +proj=unitconvert "
3773 "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1");
3774 ObjectKeeper keeper_P(P);
3775 ASSERT_NE(P, nullptr);
3776 auto Pinversed = proj_coordoperation_create_inverse(m_ctxt, P);
3777 ObjectKeeper keeper_Pinversed(Pinversed);
3778 ASSERT_NE(Pinversed, nullptr);
3779
3780 const char *options[] = {"MULTILINE=YES", "INDENTATION_WIDTH=4",
3781 "MAX_LINE_LENGTH=40", nullptr};
3782 auto projstr = proj_as_proj_string(m_ctxt, Pinversed, PJ_PROJ_5, options);
3783 ASSERT_NE(projstr, nullptr);
3784 const char *expected_projstr = "+proj=pipeline\n"
3785 " +step +proj=axisswap +order=2,1\n"
3786 " +step +proj=unitconvert +xy_in=deg\n"
3787 " +xy_out=rad\n"
3788 " +step +proj=push +v_3\n"
3789 " +step +proj=cart +ellps=WGS84\n"
3790 " +step +inv +proj=helmert +x=293\n"
3791 " +y=836 +z=318 +rx=0.5 +ry=1.6\n"
3792 " +rz=-2.8 +s=2.1\n"
3793 " +convention=position_vector\n"
3794 " +step +inv +proj=cart +ellps=evrst30\n"
3795 " +step +proj=pop +v_3\n"
3796 " +step +proj=unitconvert +xy_in=rad\n"
3797 " +xy_out=deg\n"
3798 " +step +proj=axisswap +order=2,1";
3799 EXPECT_EQ(std::string(projstr), expected_projstr);
3800 }
3801
3802 // ---------------------------------------------------------------------------
3803
TEST_F(CApi,proj_get_remarks)3804 TEST_F(CApi, proj_get_remarks) {
3805 // Transformation
3806 {
3807 auto co = proj_create_from_database(m_ctxt, "EPSG", "8048",
3808 PJ_CATEGORY_COORDINATE_OPERATION,
3809 false, nullptr);
3810 ObjectKeeper keeper(co);
3811 ASSERT_NE(co, nullptr);
3812
3813 auto remarks = proj_get_remarks(co);
3814 ASSERT_NE(remarks, nullptr);
3815 EXPECT_TRUE(std::string(remarks).find(
3816 "Scale difference in ppb where 1/billion = 1E-9.") == 0)
3817 << remarks;
3818 }
3819
3820 // Conversion
3821 {
3822 auto co = proj_create_from_database(m_ctxt, "EPSG", "3811",
3823 PJ_CATEGORY_COORDINATE_OPERATION,
3824 false, nullptr);
3825 ObjectKeeper keeper(co);
3826 ASSERT_NE(co, nullptr);
3827
3828 auto remarks = proj_get_remarks(co);
3829 ASSERT_NE(remarks, nullptr);
3830 EXPECT_EQ(remarks, std::string("Replaces Lambert 2005."));
3831 }
3832 }
3833
3834 // ---------------------------------------------------------------------------
3835
TEST_F(CApi,proj_get_scope)3836 TEST_F(CApi, proj_get_scope) {
3837 // Transformation
3838 {
3839 auto co = proj_create_from_database(m_ctxt, "EPSG", "8048",
3840 PJ_CATEGORY_COORDINATE_OPERATION,
3841 false, nullptr);
3842 ObjectKeeper keeper(co);
3843 ASSERT_NE(co, nullptr);
3844
3845 auto scope = proj_get_scope(co);
3846 ASSERT_NE(scope, nullptr);
3847 EXPECT_EQ(scope,
3848 std::string("Transformation of GDA94 coordinates that have "
3849 "been derived through GNSS CORS."));
3850 }
3851
3852 // Conversion
3853 {
3854 auto co = proj_create_from_database(m_ctxt, "EPSG", "3811",
3855 PJ_CATEGORY_COORDINATE_OPERATION,
3856 false, nullptr);
3857 ObjectKeeper keeper(co);
3858 ASSERT_NE(co, nullptr);
3859
3860 auto scope = proj_get_scope(co);
3861 ASSERT_NE(scope, nullptr);
3862 EXPECT_EQ(scope,
3863 std::string("Engineering survey, topographic mapping."));
3864 }
3865
3866 {
3867 auto P = proj_create(m_ctxt, "+proj=noop");
3868 ObjectKeeper keeper(P);
3869 ASSERT_NE(P, nullptr);
3870 auto scope = proj_get_scope(P);
3871 ASSERT_EQ(scope, nullptr);
3872 }
3873 }
3874
3875 // ---------------------------------------------------------------------------
3876
TEST_F(CApi,proj_concatoperation_get_step)3877 TEST_F(CApi, proj_concatoperation_get_step) {
3878 // Test on a non concatenated operation
3879 {
3880 auto co = proj_create_from_database(m_ctxt, "EPSG", "8048",
3881 PJ_CATEGORY_COORDINATE_OPERATION,
3882 false, nullptr);
3883 ObjectKeeper keeper(co);
3884 ASSERT_NE(co, nullptr);
3885 ASSERT_NE(proj_get_type(co), PJ_TYPE_CONCATENATED_OPERATION);
3886
3887 ASSERT_EQ(proj_concatoperation_get_step_count(m_ctxt, co), 0);
3888 ASSERT_EQ(proj_concatoperation_get_step(m_ctxt, co, 0), nullptr);
3889 }
3890 // Test on a concatenated operation
3891 {
3892 auto ctxt = proj_create_operation_factory_context(m_ctxt, nullptr);
3893 ASSERT_NE(ctxt, nullptr);
3894 ContextKeeper keeper_ctxt(ctxt);
3895
3896 // GDA94 / MGA zone 56
3897 auto source_crs = proj_create_from_database(
3898 m_ctxt, "EPSG", "28356", PJ_CATEGORY_CRS, false, nullptr);
3899 ASSERT_NE(source_crs, nullptr);
3900 ObjectKeeper keeper_source_crs(source_crs);
3901
3902 // GDA2020 / MGA zone 56
3903 auto target_crs = proj_create_from_database(
3904 m_ctxt, "EPSG", "7856", PJ_CATEGORY_CRS, false, nullptr);
3905 ASSERT_NE(target_crs, nullptr);
3906 ObjectKeeper keeper_target_crs(target_crs);
3907
3908 proj_operation_factory_context_set_spatial_criterion(
3909 m_ctxt, ctxt, PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION);
3910
3911 proj_operation_factory_context_set_grid_availability_use(
3912 m_ctxt, ctxt, PROJ_GRID_AVAILABILITY_IGNORED);
3913
3914 auto res = proj_create_operations(m_ctxt, source_crs, target_crs, ctxt);
3915 ASSERT_NE(res, nullptr);
3916 ObjListKeeper keeper_res(res);
3917
3918 ASSERT_GT(proj_list_get_count(res), 0);
3919
3920 auto op = proj_list_get(m_ctxt, res, 0);
3921 ASSERT_NE(op, nullptr);
3922 ObjectKeeper keeper_op(op);
3923
3924 ASSERT_EQ(proj_get_type(op), PJ_TYPE_CONCATENATED_OPERATION);
3925 ASSERT_EQ(proj_concatoperation_get_step_count(m_ctxt, op), 3);
3926
3927 EXPECT_EQ(proj_concatoperation_get_step(m_ctxt, op, -1), nullptr);
3928 EXPECT_EQ(proj_concatoperation_get_step(m_ctxt, op, 3), nullptr);
3929
3930 auto step = proj_concatoperation_get_step(m_ctxt, op, 1);
3931 ASSERT_NE(step, nullptr);
3932 ObjectKeeper keeper_step(step);
3933
3934 const char *scope = proj_get_scope(step);
3935 EXPECT_NE(scope, nullptr);
3936 EXPECT_NE(std::string(scope), std::string());
3937
3938 const char *remarks = proj_get_remarks(step);
3939 EXPECT_NE(remarks, nullptr);
3940 EXPECT_NE(std::string(remarks), std::string());
3941 }
3942 }
3943
3944 // ---------------------------------------------------------------------------
3945
TEST_F(CApi,proj_as_projjson)3946 TEST_F(CApi, proj_as_projjson) {
3947 auto obj = proj_create(
3948 m_ctxt,
3949 Ellipsoid::WGS84->exportToJSON(JSONFormatter::create().get()).c_str());
3950 ObjectKeeper keeper(obj);
3951 ASSERT_NE(obj, nullptr);
3952
3953 {
3954 auto projjson = proj_as_projjson(m_ctxt, obj, nullptr);
3955 ASSERT_NE(projjson, nullptr);
3956 EXPECT_EQ(std::string(projjson),
3957 "{\n"
3958 " \"$schema\": "
3959 "\"https://proj.org/schemas/v0.2/projjson.schema.json\",\n"
3960 " \"type\": \"Ellipsoid\",\n"
3961 " \"name\": \"WGS 84\",\n"
3962 " \"semi_major_axis\": 6378137,\n"
3963 " \"inverse_flattening\": 298.257223563,\n"
3964 " \"id\": {\n"
3965 " \"authority\": \"EPSG\",\n"
3966 " \"code\": 7030\n"
3967 " }\n"
3968 "}");
3969 }
3970 {
3971 const char *const options[] = {"INDENTATION_WIDTH=4", "SCHEMA=",
3972 nullptr};
3973 auto projjson = proj_as_projjson(m_ctxt, obj, options);
3974 ASSERT_NE(projjson, nullptr);
3975 EXPECT_EQ(std::string(projjson),
3976 "{\n"
3977 " \"type\": \"Ellipsoid\",\n"
3978 " \"name\": \"WGS 84\",\n"
3979 " \"semi_major_axis\": 6378137,\n"
3980 " \"inverse_flattening\": 298.257223563,\n"
3981 " \"id\": {\n"
3982 " \"authority\": \"EPSG\",\n"
3983 " \"code\": 7030\n"
3984 " }\n"
3985 "}");
3986 }
3987 {
3988 const char *const options[] = {"MULTILINE=NO", "SCHEMA=", nullptr};
3989 auto projjson = proj_as_projjson(m_ctxt, obj, options);
3990 ASSERT_NE(projjson, nullptr);
3991 EXPECT_EQ(std::string(projjson),
3992 "{\"type\":\"Ellipsoid\",\"name\":\"WGS 84\","
3993 "\"semi_major_axis\":6378137,"
3994 "\"inverse_flattening\":298.257223563,"
3995 "\"id\":{\"authority\":\"EPSG\",\"code\":7030}}");
3996 }
3997 }
3998
3999 // ---------------------------------------------------------------------------
4000
4001 struct Fixture_proj_context_set_autoclose_database : public CApi {
test__anon29fdcccb0111::Fixture_proj_context_set_autoclose_database4002 void test(bool autoclose) {
4003 proj_context_set_autoclose_database(m_ctxt, autoclose);
4004
4005 auto c_path = proj_context_get_database_path(m_ctxt);
4006 ASSERT_TRUE(c_path != nullptr);
4007 std::string path(c_path);
4008
4009 FILE *f = fopen(path.c_str(), "rb");
4010 ASSERT_NE(f, nullptr);
4011 fseek(f, 0, SEEK_END);
4012 auto length = ftell(f);
4013 std::string content;
4014 content.resize(static_cast<size_t>(length));
4015 fseek(f, 0, SEEK_SET);
4016 auto read_bytes = fread(&content[0], 1, content.size(), f);
4017 ASSERT_EQ(read_bytes, content.size());
4018 fclose(f);
4019 const char *tempdir = getenv("TEMP");
4020 if (!tempdir) {
4021 tempdir = getenv("TMP");
4022 }
4023 if (!tempdir) {
4024 tempdir = "/tmp";
4025 }
4026 std::string tmp_filename(
4027 std::string(tempdir) +
4028 "/test_proj_context_set_autoclose_database.db");
4029 f = fopen(tmp_filename.c_str(), "wb");
4030 if (!f) {
4031 std::cerr << "Cannot create " << tmp_filename << std::endl;
4032 return;
4033 }
4034 fwrite(content.data(), 1, content.size(), f);
4035 fclose(f);
4036
4037 {
4038 sqlite3 *db = nullptr;
4039 sqlite3_open_v2(tmp_filename.c_str(), &db, SQLITE_OPEN_READWRITE,
4040 nullptr);
4041 ASSERT_NE(db, nullptr);
4042 ASSERT_TRUE(sqlite3_exec(db, "UPDATE geodetic_crs SET name = 'foo' "
4043 "WHERE auth_name = 'EPSG' and code = "
4044 "'4326'",
4045 nullptr, nullptr, nullptr) == SQLITE_OK);
4046 sqlite3_close(db);
4047 }
4048
4049 EXPECT_TRUE(proj_context_set_database_path(m_ctxt, tmp_filename.c_str(),
4050 nullptr, nullptr));
4051 {
4052 auto crs = proj_create_from_database(
4053 m_ctxt, "EPSG", "4326", PJ_CATEGORY_CRS, false, nullptr);
4054 ObjectKeeper keeper(crs);
4055 ASSERT_NE(crs, nullptr);
4056 EXPECT_EQ(proj_get_name(crs), std::string("foo"));
4057 }
4058
4059 {
4060 sqlite3 *db = nullptr;
4061 sqlite3_open_v2(tmp_filename.c_str(), &db, SQLITE_OPEN_READWRITE,
4062 nullptr);
4063 ASSERT_NE(db, nullptr);
4064 ASSERT_TRUE(sqlite3_exec(db, "UPDATE geodetic_crs SET name = 'bar' "
4065 "WHERE auth_name = 'EPSG' and code = "
4066 "'4326'",
4067 nullptr, nullptr, nullptr) == SQLITE_OK);
4068 sqlite3_close(db);
4069 }
4070 {
4071 auto crs = proj_create_from_database(
4072 m_ctxt, "EPSG", "4326", PJ_CATEGORY_CRS, false, nullptr);
4073 ObjectKeeper keeper(crs);
4074 ASSERT_NE(crs, nullptr);
4075 EXPECT_EQ(proj_get_name(crs),
4076 std::string(autoclose ? "bar" : "foo"));
4077 }
4078
4079 if (!autoclose) {
4080 proj_context_destroy(m_ctxt);
4081 m_ctxt = nullptr;
4082 }
4083 std::remove(tmp_filename.c_str());
4084 }
4085 };
4086
TEST_F(Fixture_proj_context_set_autoclose_database,proj_context_set_autoclose_database_true)4087 TEST_F(Fixture_proj_context_set_autoclose_database,
4088 proj_context_set_autoclose_database_true) {
4089 test(true);
4090 }
4091
TEST_F(Fixture_proj_context_set_autoclose_database,proj_context_set_autoclose_database_false)4092 TEST_F(Fixture_proj_context_set_autoclose_database,
4093 proj_context_set_autoclose_database_false) {
4094 test(false);
4095 }
4096
4097 // ---------------------------------------------------------------------------
4098
TEST_F(CApi,proj_context_copy_from_default)4099 TEST_F(CApi, proj_context_copy_from_default) {
4100 auto c_path = proj_context_get_database_path(m_ctxt);
4101 ASSERT_TRUE(c_path != nullptr);
4102 std::string path(c_path);
4103
4104 FILE *f = fopen(path.c_str(), "rb");
4105 ASSERT_NE(f, nullptr);
4106 fseek(f, 0, SEEK_END);
4107 auto length = ftell(f);
4108 std::string content;
4109 content.resize(static_cast<size_t>(length));
4110 fseek(f, 0, SEEK_SET);
4111 auto read_bytes = fread(&content[0], 1, content.size(), f);
4112 ASSERT_EQ(read_bytes, content.size());
4113 fclose(f);
4114 const char *tempdir = getenv("TEMP");
4115 if (!tempdir) {
4116 tempdir = getenv("TMP");
4117 }
4118 if (!tempdir) {
4119 tempdir = "/tmp";
4120 }
4121 std::string tmp_filename(std::string(tempdir) +
4122 "/test_proj_context_set_autoclose_database.db");
4123 f = fopen(tmp_filename.c_str(), "wb");
4124 if (!f) {
4125 std::cerr << "Cannot create " << tmp_filename << std::endl;
4126 return;
4127 }
4128 fwrite(content.data(), 1, content.size(), f);
4129 fclose(f);
4130
4131 auto c_default_path = proj_context_get_database_path(nullptr);
4132 std::string default_path(c_default_path ? c_default_path : "");
4133 EXPECT_TRUE(proj_context_set_database_path(nullptr, tmp_filename.c_str(),
4134 nullptr, nullptr));
4135
4136 PJ_CONTEXT *new_ctx = proj_context_create();
4137 EXPECT_TRUE(proj_context_set_database_path(
4138 nullptr, default_path.empty() ? nullptr : default_path.c_str(), nullptr,
4139 nullptr));
4140
4141 EXPECT_NE(new_ctx, nullptr);
4142 PjContextKeeper keeper_ctxt(new_ctx);
4143 auto c_new_path = proj_context_get_database_path(new_ctx);
4144 ASSERT_TRUE(c_new_path != nullptr);
4145 std::string new_db_path(c_new_path);
4146 ASSERT_EQ(new_db_path, tmp_filename);
4147 }
4148
4149 // ---------------------------------------------------------------------------
4150
TEST_F(CApi,proj_context_clone)4151 TEST_F(CApi, proj_context_clone) {
4152 int new_init_rules =
4153 proj_context_get_use_proj4_init_rules(NULL, 0) > 0 ? 0 : 1;
4154 PJ_CONTEXT *new_ctx = proj_context_create();
4155 EXPECT_NE(new_ctx, nullptr);
4156 PjContextKeeper keeper_ctxt(new_ctx);
4157 proj_context_use_proj4_init_rules(new_ctx, new_init_rules);
4158 PJ_CONTEXT *clone_ctx = proj_context_clone(new_ctx);
4159 EXPECT_NE(clone_ctx, nullptr);
4160 PjContextKeeper keeper_clone_ctxt(clone_ctx);
4161 ASSERT_EQ(proj_context_get_use_proj4_init_rules(new_ctx, 0),
4162 proj_context_get_use_proj4_init_rules(clone_ctx, 0));
4163 EXPECT_NE(proj_context_get_use_proj4_init_rules(NULL, 0),
4164 proj_context_get_use_proj4_init_rules(clone_ctx, 0));
4165 }
4166
4167 // ---------------------------------------------------------------------------
4168
TEST_F(CApi,proj_create_crs_to_crs_from_pj)4169 TEST_F(CApi, proj_create_crs_to_crs_from_pj) {
4170
4171 auto src = proj_create(m_ctxt, "EPSG:4326");
4172 ObjectKeeper keeper_src(src);
4173 ASSERT_NE(src, nullptr);
4174
4175 auto dst = proj_create(m_ctxt, "EPSG:32631");
4176 ObjectKeeper keeper_dst(dst);
4177 ASSERT_NE(dst, nullptr);
4178
4179 auto P = proj_create_crs_to_crs_from_pj(m_ctxt, src, dst, nullptr, nullptr);
4180 ObjectKeeper keeper_P(P);
4181 ASSERT_NE(P, nullptr);
4182 auto Pnormalized = proj_normalize_for_visualization(m_ctxt, P);
4183 ObjectKeeper keeper_Pnormalized(Pnormalized);
4184 ASSERT_NE(Pnormalized, nullptr);
4185 auto projstr = proj_as_proj_string(m_ctxt, Pnormalized, PJ_PROJ_5, nullptr);
4186 ASSERT_NE(projstr, nullptr);
4187 EXPECT_EQ(std::string(projstr),
4188 "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad "
4189 "+step +proj=utm +zone=31 +ellps=WGS84");
4190 }
4191
4192 // ---------------------------------------------------------------------------
4193
4194 static void
check_axis_is_latitude(PJ_CONTEXT * ctx,PJ * cs,int axis_number,const char * unit_name="degree",double unit_conv_factor=0.017453292519943295,const char * auth="EPSG",const char * code="9122")4195 check_axis_is_latitude(PJ_CONTEXT *ctx, PJ *cs, int axis_number,
4196 const char *unit_name = "degree",
4197 double unit_conv_factor = 0.017453292519943295,
4198 const char *auth = "EPSG", const char *code = "9122") {
4199
4200 const char *name = nullptr;
4201 const char *abbrev = nullptr;
4202 const char *direction = nullptr;
4203 double unitConvFactor = 0.0;
4204 const char *unitName = nullptr;
4205 const char *unitAuthority = nullptr;
4206 const char *unitCode = nullptr;
4207
4208 EXPECT_TRUE(proj_cs_get_axis_info(ctx, cs, axis_number, &name, &abbrev,
4209 &direction, &unitConvFactor, &unitName,
4210 &unitAuthority, &unitCode));
4211 ASSERT_NE(name, nullptr);
4212 ASSERT_NE(abbrev, nullptr);
4213 ASSERT_NE(direction, nullptr);
4214 ASSERT_NE(unitName, nullptr);
4215 if (auth) {
4216 ASSERT_NE(unitAuthority, nullptr);
4217 ASSERT_NE(unitCode, nullptr);
4218 }
4219 EXPECT_EQ(std::string(name), "Latitude");
4220 EXPECT_EQ(std::string(abbrev), "lat");
4221 EXPECT_EQ(std::string(direction), "north");
4222 EXPECT_EQ(unitConvFactor, unit_conv_factor) << unitConvFactor;
4223 EXPECT_EQ(std::string(unitName), unit_name);
4224 if (auth) {
4225 EXPECT_EQ(std::string(unitAuthority), auth);
4226 EXPECT_EQ(std::string(unitCode), code);
4227 }
4228 }
4229
4230 // ---------------------------------------------------------------------------
4231
4232 static void
check_axis_is_longitude(PJ_CONTEXT * ctx,PJ * cs,int axis_number,const char * unit_name="degree",double unit_conv_factor=0.017453292519943295,const char * auth="EPSG",const char * code="9122")4233 check_axis_is_longitude(PJ_CONTEXT *ctx, PJ *cs, int axis_number,
4234 const char *unit_name = "degree",
4235 double unit_conv_factor = 0.017453292519943295,
4236 const char *auth = "EPSG", const char *code = "9122") {
4237
4238 const char *name = nullptr;
4239 const char *abbrev = nullptr;
4240 const char *direction = nullptr;
4241 double unitConvFactor = 0.0;
4242 const char *unitName = nullptr;
4243 const char *unitAuthority = nullptr;
4244 const char *unitCode = nullptr;
4245
4246 EXPECT_TRUE(proj_cs_get_axis_info(ctx, cs, axis_number, &name, &abbrev,
4247 &direction, &unitConvFactor, &unitName,
4248 &unitAuthority, &unitCode));
4249 ASSERT_NE(name, nullptr);
4250 ASSERT_NE(abbrev, nullptr);
4251 ASSERT_NE(direction, nullptr);
4252 ASSERT_NE(unitName, nullptr);
4253 if (auth) {
4254 ASSERT_NE(unitAuthority, nullptr);
4255 ASSERT_NE(unitCode, nullptr);
4256 }
4257 EXPECT_EQ(std::string(name), "Longitude");
4258 EXPECT_EQ(std::string(abbrev), "lon");
4259 EXPECT_EQ(std::string(direction), "east");
4260 EXPECT_EQ(unitConvFactor, unit_conv_factor) << unitConvFactor;
4261 EXPECT_EQ(std::string(unitName), unit_name);
4262 if (auth) {
4263 EXPECT_EQ(std::string(unitAuthority), auth);
4264 EXPECT_EQ(std::string(unitCode), code);
4265 }
4266 }
4267
4268 // ---------------------------------------------------------------------------
4269
check_axis_is_height(PJ_CONTEXT * ctx,PJ * cs,int axis_number,const char * unit_name="metre",double unit_conv_factor=1,const char * auth="EPSG",const char * code="9001")4270 static void check_axis_is_height(PJ_CONTEXT *ctx, PJ *cs, int axis_number,
4271 const char *unit_name = "metre",
4272 double unit_conv_factor = 1,
4273 const char *auth = "EPSG",
4274 const char *code = "9001") {
4275
4276 const char *name = nullptr;
4277 const char *abbrev = nullptr;
4278 const char *direction = nullptr;
4279 double unitConvFactor = 0.0;
4280 const char *unitName = nullptr;
4281 const char *unitAuthority = nullptr;
4282 const char *unitCode = nullptr;
4283
4284 EXPECT_TRUE(proj_cs_get_axis_info(ctx, cs, axis_number, &name, &abbrev,
4285 &direction, &unitConvFactor, &unitName,
4286 &unitAuthority, &unitCode));
4287 ASSERT_NE(name, nullptr);
4288 ASSERT_NE(abbrev, nullptr);
4289 ASSERT_NE(direction, nullptr);
4290 ASSERT_NE(unitName, nullptr);
4291 if (auth) {
4292 ASSERT_NE(unitAuthority, nullptr);
4293 ASSERT_NE(unitCode, nullptr);
4294 }
4295 EXPECT_EQ(std::string(name), "Ellipsoidal height");
4296 EXPECT_EQ(std::string(abbrev), "h");
4297 EXPECT_EQ(std::string(direction), "up");
4298 EXPECT_EQ(unitConvFactor, unit_conv_factor) << unitConvFactor;
4299 EXPECT_EQ(std::string(unitName), unit_name);
4300 if (auth) {
4301 EXPECT_EQ(std::string(unitAuthority), auth);
4302 EXPECT_EQ(std::string(unitCode), code);
4303 }
4304 }
4305
4306 // ---------------------------------------------------------------------------
4307
TEST_F(CApi,proj_create_ellipsoidal_3D_cs)4308 TEST_F(CApi, proj_create_ellipsoidal_3D_cs) {
4309
4310 {
4311 auto cs = proj_create_ellipsoidal_3D_cs(
4312 m_ctxt, PJ_ELLPS3D_LATITUDE_LONGITUDE_HEIGHT, nullptr, 0, nullptr,
4313 0);
4314 ObjectKeeper keeper_cs(cs);
4315 ASSERT_NE(cs, nullptr);
4316
4317 EXPECT_EQ(proj_cs_get_type(m_ctxt, cs), PJ_CS_TYPE_ELLIPSOIDAL);
4318
4319 EXPECT_EQ(proj_cs_get_axis_count(m_ctxt, cs), 3);
4320
4321 check_axis_is_latitude(m_ctxt, cs, 0);
4322
4323 check_axis_is_longitude(m_ctxt, cs, 1);
4324
4325 check_axis_is_height(m_ctxt, cs, 2);
4326 }
4327
4328 {
4329 auto cs = proj_create_ellipsoidal_3D_cs(
4330 m_ctxt, PJ_ELLPS3D_LONGITUDE_LATITUDE_HEIGHT, "foo", 0.5, "bar",
4331 0.6);
4332 ObjectKeeper keeper_cs(cs);
4333 ASSERT_NE(cs, nullptr);
4334
4335 EXPECT_EQ(proj_cs_get_type(m_ctxt, cs), PJ_CS_TYPE_ELLIPSOIDAL);
4336
4337 EXPECT_EQ(proj_cs_get_axis_count(m_ctxt, cs), 3);
4338
4339 check_axis_is_longitude(m_ctxt, cs, 0, "foo", 0.5, nullptr, nullptr);
4340
4341 check_axis_is_latitude(m_ctxt, cs, 1, "foo", 0.5, nullptr, nullptr);
4342
4343 check_axis_is_height(m_ctxt, cs, 2, "bar", 0.6, nullptr, nullptr);
4344 }
4345 }
4346
4347 // ---------------------------------------------------------------------------
4348
TEST_F(CApi,proj_crs_promote_to_3D)4349 TEST_F(CApi, proj_crs_promote_to_3D) {
4350
4351 auto crs2D =
4352 proj_create(m_ctxt, GeographicCRS::EPSG_4326
4353 ->exportToWKT(WKTFormatter::create().get())
4354 .c_str());
4355 ObjectKeeper keeper_crs2D(crs2D);
4356 EXPECT_NE(crs2D, nullptr);
4357
4358 auto crs3D = proj_crs_promote_to_3D(m_ctxt, nullptr, crs2D);
4359 ObjectKeeper keeper_crs3D(crs3D);
4360 EXPECT_NE(crs3D, nullptr);
4361
4362 auto cs = proj_crs_get_coordinate_system(m_ctxt, crs3D);
4363 ASSERT_NE(cs, nullptr);
4364 ObjectKeeper keeperCs(cs);
4365 EXPECT_EQ(proj_cs_get_axis_count(m_ctxt, cs), 3);
4366
4367 auto code = proj_get_id_code(crs3D, 0);
4368 ASSERT_TRUE(code != nullptr);
4369 EXPECT_EQ(code, std::string("4979"));
4370 }
4371
4372 // ---------------------------------------------------------------------------
4373
TEST_F(CApi,proj_crs_demote_to_2D)4374 TEST_F(CApi, proj_crs_demote_to_2D) {
4375
4376 auto crs3D =
4377 proj_create(m_ctxt, GeographicCRS::EPSG_4979
4378 ->exportToWKT(WKTFormatter::create().get())
4379 .c_str());
4380 ObjectKeeper keeper_crs3D(crs3D);
4381 EXPECT_NE(crs3D, nullptr);
4382
4383 auto crs2D = proj_crs_demote_to_2D(m_ctxt, nullptr, crs3D);
4384 ObjectKeeper keeper_crs2D(crs2D);
4385 EXPECT_NE(crs2D, nullptr);
4386
4387 auto cs = proj_crs_get_coordinate_system(m_ctxt, crs2D);
4388 ASSERT_NE(cs, nullptr);
4389 ObjectKeeper keeperCs(cs);
4390 EXPECT_EQ(proj_cs_get_axis_count(m_ctxt, cs), 2);
4391
4392 auto code = proj_get_id_code(crs2D, 0);
4393 ASSERT_TRUE(code != nullptr);
4394 EXPECT_EQ(code, std::string("4326"));
4395 }
4396
4397 // ---------------------------------------------------------------------------
4398
TEST_F(CApi,proj_crs_create_projected_3D_crs_from_2D)4399 TEST_F(CApi, proj_crs_create_projected_3D_crs_from_2D) {
4400
4401 auto projCRS = proj_create_from_database(m_ctxt, "EPSG", "32631",
4402 PJ_CATEGORY_CRS, false, nullptr);
4403 ASSERT_NE(projCRS, nullptr);
4404 ObjectKeeper keeper_projCRS(projCRS);
4405
4406 {
4407 auto geog3DCRS = proj_create_from_database(
4408 m_ctxt, "EPSG", "4979", PJ_CATEGORY_CRS, false, nullptr);
4409 ASSERT_NE(geog3DCRS, nullptr);
4410 ObjectKeeper keeper_geog3DCRS(geog3DCRS);
4411
4412 auto crs3D = proj_crs_create_projected_3D_crs_from_2D(
4413 m_ctxt, nullptr, projCRS, geog3DCRS);
4414 ObjectKeeper keeper_crs3D(crs3D);
4415 EXPECT_NE(crs3D, nullptr);
4416
4417 EXPECT_EQ(proj_get_type(crs3D), PJ_TYPE_PROJECTED_CRS);
4418
4419 EXPECT_EQ(std::string(proj_get_name(crs3D)),
4420 std::string(proj_get_name(projCRS)));
4421
4422 auto cs = proj_crs_get_coordinate_system(m_ctxt, crs3D);
4423 ASSERT_NE(cs, nullptr);
4424 ObjectKeeper keeperCs(cs);
4425 EXPECT_EQ(proj_cs_get_axis_count(m_ctxt, cs), 3);
4426 }
4427
4428 {
4429 auto crs3D = proj_crs_create_projected_3D_crs_from_2D(m_ctxt, nullptr,
4430 projCRS, nullptr);
4431 ObjectKeeper keeper_crs3D(crs3D);
4432 EXPECT_NE(crs3D, nullptr);
4433
4434 EXPECT_EQ(proj_get_type(crs3D), PJ_TYPE_PROJECTED_CRS);
4435
4436 EXPECT_EQ(std::string(proj_get_name(crs3D)),
4437 std::string(proj_get_name(projCRS)));
4438
4439 auto cs = proj_crs_get_coordinate_system(m_ctxt, crs3D);
4440 ASSERT_NE(cs, nullptr);
4441 ObjectKeeper keeperCs(cs);
4442 EXPECT_EQ(proj_cs_get_axis_count(m_ctxt, cs), 3);
4443 }
4444 }
4445
4446 // ---------------------------------------------------------------------------
4447
TEST_F(CApi,proj_crs_create_bound_vertical_crs)4448 TEST_F(CApi, proj_crs_create_bound_vertical_crs) {
4449
4450 auto vert_crs = proj_create_vertical_crs(m_ctxt, "myVertCRS", "myVertDatum",
4451 nullptr, 0.0);
4452 ObjectKeeper keeper_vert_crs(vert_crs);
4453 ASSERT_NE(vert_crs, nullptr);
4454
4455 auto crs4979 = proj_create_from_wkt(
4456 m_ctxt,
4457 GeographicCRS::EPSG_4979->exportToWKT(WKTFormatter::create().get())
4458 .c_str(),
4459 nullptr, nullptr, nullptr);
4460 ObjectKeeper keeper_crs4979(crs4979);
4461 ASSERT_NE(crs4979, nullptr);
4462
4463 auto bound_crs = proj_crs_create_bound_vertical_crs(m_ctxt, vert_crs,
4464 crs4979, "foo.gtx");
4465 ObjectKeeper keeper_bound_crs(bound_crs);
4466 ASSERT_NE(bound_crs, nullptr);
4467
4468 auto projCRS = proj_create_from_database(m_ctxt, "EPSG", "32631",
4469 PJ_CATEGORY_CRS, false, nullptr);
4470 ASSERT_NE(projCRS, nullptr);
4471 ObjectKeeper keeper_projCRS(projCRS);
4472
4473 auto compound_crs =
4474 proj_create_compound_crs(m_ctxt, "myCompoundCRS", projCRS, bound_crs);
4475 ObjectKeeper keeper_compound_crss(compound_crs);
4476 ASSERT_NE(compound_crs, nullptr);
4477
4478 auto proj_4 = proj_as_proj_string(m_ctxt, compound_crs, PJ_PROJ_4, nullptr);
4479 ASSERT_NE(proj_4, nullptr);
4480 EXPECT_EQ(std::string(proj_4),
4481 "+proj=utm +zone=31 +datum=WGS84 +units=m +geoidgrids=foo.gtx "
4482 "+vunits=m +no_defs +type=crs");
4483 }
4484
4485 // ---------------------------------------------------------------------------
4486
TEST_F(CApi,proj_create_crs_to_crs_with_only_ballpark_transformations)4487 TEST_F(CApi, proj_create_crs_to_crs_with_only_ballpark_transformations) {
4488 // ETRS89 / UTM zone 31N + EGM96 height to WGS 84 (G1762)
4489 auto P =
4490 proj_create_crs_to_crs(m_ctxt, "EPSG:25831+5773", "EPSG:7665", nullptr);
4491 ObjectKeeper keeper_P(P);
4492 ASSERT_NE(P, nullptr);
4493 auto Pnormalized = proj_normalize_for_visualization(m_ctxt, P);
4494 ObjectKeeper keeper_Pnormalized(Pnormalized);
4495 ASSERT_NE(Pnormalized, nullptr);
4496
4497 PJ_COORD coord;
4498 coord.xyzt.x = 500000;
4499 coord.xyzt.y = 4500000;
4500 coord.xyzt.z = 0;
4501 coord.xyzt.t = 0;
4502 coord = proj_trans(Pnormalized, PJ_FWD, coord);
4503 EXPECT_NEAR(coord.xyzt.x, 3.0, 1e-9);
4504 EXPECT_NEAR(coord.xyzt.y, 40.65085651660555, 1e-9);
4505 EXPECT_NEAR(coord.xyzt.z, 47.72600023608570, 1e-3);
4506 }
4507
4508 // ---------------------------------------------------------------------------
4509
TEST_F(CApi,proj_create_crs_to_crs_from_custom_compound_crs_with_NAD83_2011_and_geoidgrid_ref_against_WGS84_to_WGS84_G1762)4510 TEST_F(
4511 CApi,
4512 proj_create_crs_to_crs_from_custom_compound_crs_with_NAD83_2011_and_geoidgrid_ref_against_WGS84_to_WGS84_G1762) {
4513
4514 PJ *P;
4515
4516 PJ *inCrsH = proj_create_from_database(m_ctxt, "EPSG", "6340",
4517 PJ_CATEGORY_CRS, false, nullptr);
4518 ASSERT_NE(inCrsH, nullptr);
4519
4520 PJ *inDummyCrs = proj_create_vertical_crs(m_ctxt, "VerticalDummyCrs",
4521 "DummyDatum", "metre", 1.0);
4522 ASSERT_NE(inDummyCrs, nullptr);
4523
4524 auto crs4979 = proj_create_from_database(m_ctxt, "EPSG", "4979",
4525 PJ_CATEGORY_CRS, false, nullptr);
4526 ASSERT_NE(crs4979, nullptr);
4527
4528 PJ *inCrsV = proj_crs_create_bound_vertical_crs(m_ctxt, inDummyCrs, crs4979,
4529 "egm96_15.gtx");
4530 ASSERT_NE(inCrsV, nullptr);
4531 proj_destroy(inDummyCrs);
4532 proj_destroy(crs4979);
4533
4534 PJ *inCompound =
4535 proj_create_compound_crs(m_ctxt, "Compound", inCrsH, inCrsV);
4536 ASSERT_NE(inCompound, nullptr);
4537 proj_destroy(inCrsH);
4538 proj_destroy(inCrsV);
4539
4540 PJ *outCrs = proj_create(m_ctxt, "EPSG:7665");
4541 ASSERT_NE(outCrs, nullptr);
4542
4543 // In this particular case, PROJ computes a transformation from NAD83(2011)
4544 // (EPSG:6318) to WGS84 (EPSG:4979) for the initial horizontal adjustment
4545 // before the geoidgrids application. There are 6 candidate transformations
4546 // for that in subzones of the US and one last no-op transformation flagged
4547 // as ballpark. That one used to be eliminated because by
4548 // proj_create_crs_to_crs() because there were non Ballpark transformations
4549 // available. This resulted thus in an error when transforming outside of
4550 // those few subzones.
4551 P = proj_create_crs_to_crs_from_pj(m_ctxt, inCompound, outCrs, nullptr,
4552 nullptr);
4553 ASSERT_NE(P, nullptr);
4554 proj_destroy(inCompound);
4555 proj_destroy(outCrs);
4556
4557 PJ_COORD in_coord;
4558 in_coord.xyzt.x = 350499.911;
4559 in_coord.xyzt.y = 3884807.956;
4560 in_coord.xyzt.z = 150.072;
4561 in_coord.xyzt.t = 2010;
4562
4563 PJ_COORD outcoord = proj_trans(P, PJ_FWD, in_coord);
4564 proj_destroy(P);
4565
4566 EXPECT_NEAR(outcoord.xyzt.x, 35.09499307271, 1e-9);
4567 EXPECT_NEAR(outcoord.xyzt.y, -118.64014868921, 1e-9);
4568 EXPECT_NEAR(outcoord.xyzt.z, 117.655, 1e-3);
4569 }
4570
4571 // ---------------------------------------------------------------------------
4572
TEST_F(CApi,proj_create_crs_to_crs_from_custom_compound_crs_with_NAD83_2011_and_geoidgrid_ref_against_NAD83_2011_to_WGS84_G1762)4573 TEST_F(
4574 CApi,
4575 proj_create_crs_to_crs_from_custom_compound_crs_with_NAD83_2011_and_geoidgrid_ref_against_NAD83_2011_to_WGS84_G1762) {
4576
4577 PJ *P;
4578
4579 // NAD83(2011) 2D
4580 PJ *inCrsH = proj_create_from_database(m_ctxt, "EPSG", "6318",
4581 PJ_CATEGORY_CRS, false, nullptr);
4582 ASSERT_NE(inCrsH, nullptr);
4583
4584 PJ *inDummyCrs = proj_create_vertical_crs(m_ctxt, "VerticalDummyCrs",
4585 "DummyDatum", "metre", 1.0);
4586 ASSERT_NE(inDummyCrs, nullptr);
4587
4588 // NAD83(2011) 3D
4589 PJ *inGeog3DCRS = proj_create_from_database(
4590 m_ctxt, "EPSG", "6319", PJ_CATEGORY_CRS, false, nullptr);
4591 ASSERT_NE(inCrsH, nullptr);
4592
4593 // Note: this is actually a bad example since we tell here that egm96_15.gtx
4594 // is referenced against NAD83(2011)
4595 PJ *inCrsV = proj_crs_create_bound_vertical_crs(
4596 m_ctxt, inDummyCrs, inGeog3DCRS, "egm96_15.gtx");
4597 ASSERT_NE(inCrsV, nullptr);
4598 proj_destroy(inDummyCrs);
4599 proj_destroy(inGeog3DCRS);
4600
4601 PJ *inCompound =
4602 proj_create_compound_crs(m_ctxt, "Compound", inCrsH, inCrsV);
4603 ASSERT_NE(inCompound, nullptr);
4604 proj_destroy(inCrsH);
4605 proj_destroy(inCrsV);
4606
4607 // WGS84 (G1762)
4608 PJ *outCrs = proj_create(m_ctxt, "EPSG:7665");
4609 ASSERT_NE(outCrs, nullptr);
4610
4611 P = proj_create_crs_to_crs_from_pj(m_ctxt, inCompound, outCrs, nullptr,
4612 nullptr);
4613 ASSERT_NE(P, nullptr);
4614 proj_destroy(inCompound);
4615 proj_destroy(outCrs);
4616
4617 PJ_COORD in_coord;
4618 in_coord.xyzt.x = 35;
4619 in_coord.xyzt.y = -118;
4620 in_coord.xyzt.z = 0;
4621 in_coord.xyzt.t = 2010;
4622
4623 PJ_COORD outcoord = proj_trans(P, PJ_FWD, in_coord);
4624 proj_destroy(P);
4625
4626 EXPECT_NEAR(outcoord.xyzt.x, 35.000003665064803, 1e-9);
4627 EXPECT_NEAR(outcoord.xyzt.y, -118.00001414221214, 1e-9);
4628 EXPECT_NEAR(outcoord.xyzt.z, -32.8110, 1e-3);
4629 }
4630
4631 // ---------------------------------------------------------------------------
4632
TEST_F(CApi,proj_create_vertical_crs_ex)4633 TEST_F(CApi, proj_create_vertical_crs_ex) {
4634
4635 // NAD83(2011) / UTM zone 11N
4636 auto horiz_crs = proj_create_from_database(m_ctxt, "EPSG", "6340",
4637 PJ_CATEGORY_CRS, false, nullptr);
4638 ObjectKeeper keeper_horiz_crs(horiz_crs);
4639 ASSERT_NE(horiz_crs, nullptr);
4640
4641 const char *options[] = {"ACCURACY=123", nullptr};
4642 auto vert_crs = proj_create_vertical_crs_ex(
4643 m_ctxt, "myVertCRS (ftUS)", "myVertDatum", nullptr, nullptr,
4644 "US survey foot", 0.304800609601219, "PROJ @foo.gtx", nullptr, nullptr,
4645 nullptr, options);
4646 ObjectKeeper keeper_vert_crs(vert_crs);
4647 ASSERT_NE(vert_crs, nullptr);
4648
4649 auto compound =
4650 proj_create_compound_crs(m_ctxt, "Compound", horiz_crs, vert_crs);
4651 ObjectKeeper keeper_compound(compound);
4652 ASSERT_NE(compound, nullptr);
4653
4654 // NAD83(2011) 3D
4655 PJ *geog_crs = proj_create(m_ctxt, "EPSG:6319");
4656 ObjectKeeper keeper_geog_crs(geog_crs);
4657 ASSERT_NE(geog_crs, nullptr);
4658
4659 PJ_OPERATION_FACTORY_CONTEXT *ctxt =
4660 proj_create_operation_factory_context(m_ctxt, nullptr);
4661 ASSERT_NE(ctxt, nullptr);
4662 ContextKeeper keeper_ctxt(ctxt);
4663 proj_operation_factory_context_set_grid_availability_use(
4664 m_ctxt, ctxt, PROJ_GRID_AVAILABILITY_IGNORED);
4665 proj_operation_factory_context_set_spatial_criterion(
4666 m_ctxt, ctxt, PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION);
4667 PJ_OBJ_LIST *operations =
4668 proj_create_operations(m_ctxt, compound, geog_crs, ctxt);
4669 ASSERT_NE(operations, nullptr);
4670 ObjListKeeper keeper_operations(operations);
4671 EXPECT_GE(proj_list_get_count(operations), 1);
4672 auto P = proj_list_get(m_ctxt, operations, 0);
4673 ObjectKeeper keeper_transform(P);
4674
4675 auto name = proj_get_name(P);
4676 ASSERT_TRUE(name != nullptr);
4677 EXPECT_EQ(name,
4678 std::string("Inverse of UTM zone 11N + "
4679 "Transformation from myVertCRS (ftUS) to myVertCRS + "
4680 "Transformation from myVertCRS to NAD83(2011)"));
4681
4682 auto proj_5 = proj_as_proj_string(m_ctxt, P, PJ_PROJ_5, nullptr);
4683 ASSERT_NE(proj_5, nullptr);
4684 EXPECT_EQ(std::string(proj_5),
4685 "+proj=pipeline "
4686 "+step +inv +proj=utm +zone=11 +ellps=GRS80 "
4687 "+step +proj=unitconvert +z_in=us-ft +z_out=m "
4688 "+step +proj=vgridshift +grids=@foo.gtx +multiplier=1 "
4689 "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
4690 "+step +proj=axisswap +order=2,1");
4691
4692 ASSERT_EQ(proj_coordoperation_get_accuracy(m_ctxt, P), 123.0);
4693 }
4694
4695 // ---------------------------------------------------------------------------
4696
TEST_F(CApi,proj_create_vertical_crs_ex_with_geog_crs)4697 TEST_F(CApi, proj_create_vertical_crs_ex_with_geog_crs) {
4698
4699 // NAD83(2011) / UTM zone 11N
4700 auto horiz_crs = proj_create_from_database(m_ctxt, "EPSG", "6340",
4701 PJ_CATEGORY_CRS, false, nullptr);
4702 ObjectKeeper keeper_horiz_crs(horiz_crs);
4703 ASSERT_NE(horiz_crs, nullptr);
4704
4705 // WGS84
4706 PJ *wgs84 = proj_create(m_ctxt, "EPSG:4979");
4707 ObjectKeeper keeper_wgs84(wgs84);
4708 ASSERT_NE(wgs84, nullptr);
4709
4710 auto vert_crs = proj_create_vertical_crs_ex(
4711 m_ctxt, "myVertCRS", "myVertDatum", nullptr, nullptr, "US survey foot",
4712 0.304800609601219, "PROJ @foo.gtx", nullptr, nullptr, wgs84, nullptr);
4713 ObjectKeeper keeper_vert_crs(vert_crs);
4714 ASSERT_NE(vert_crs, nullptr);
4715
4716 auto compound =
4717 proj_create_compound_crs(m_ctxt, "Compound", horiz_crs, vert_crs);
4718 ObjectKeeper keeper_compound(compound);
4719 ASSERT_NE(compound, nullptr);
4720
4721 // NAD83(2011) 3D
4722 PJ *geog_crs = proj_create(m_ctxt, "EPSG:6319");
4723 ObjectKeeper keeper_geog_crs(geog_crs);
4724 ASSERT_NE(geog_crs, nullptr);
4725
4726 PJ_OPERATION_FACTORY_CONTEXT *ctxt =
4727 proj_create_operation_factory_context(m_ctxt, nullptr);
4728 ASSERT_NE(ctxt, nullptr);
4729 ContextKeeper keeper_ctxt(ctxt);
4730 proj_operation_factory_context_set_grid_availability_use(
4731 m_ctxt, ctxt, PROJ_GRID_AVAILABILITY_IGNORED);
4732 proj_operation_factory_context_set_spatial_criterion(
4733 m_ctxt, ctxt, PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION);
4734 PJ_OBJ_LIST *operations =
4735 proj_create_operations(m_ctxt, compound, geog_crs, ctxt);
4736 ASSERT_NE(operations, nullptr);
4737 ObjListKeeper keeper_operations(operations);
4738 EXPECT_GE(proj_list_get_count(operations), 1);
4739 auto P = proj_list_get(m_ctxt, operations, 0);
4740 ObjectKeeper keeper_transform(P);
4741
4742 auto name = proj_get_name(P);
4743 ASSERT_TRUE(name != nullptr);
4744 EXPECT_EQ(
4745 name,
4746 std::string("Inverse of UTM zone 11N + "
4747 "Ballpark geographic offset from NAD83(2011) to WGS 84 + "
4748 "Transformation from myVertCRS to myVertCRS (metre) + "
4749 "Transformation from myVertCRS (metre) to WGS 84 + "
4750 "Ballpark geographic offset from WGS 84 to NAD83(2011)"));
4751
4752 auto proj_5 = proj_as_proj_string(m_ctxt, P, PJ_PROJ_5, nullptr);
4753 ASSERT_NE(proj_5, nullptr);
4754 EXPECT_EQ(std::string(proj_5),
4755 "+proj=pipeline "
4756 "+step +inv +proj=utm +zone=11 +ellps=GRS80 "
4757 "+step +proj=unitconvert +z_in=us-ft +z_out=m "
4758 "+step +proj=vgridshift +grids=@foo.gtx +multiplier=1 "
4759 "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
4760 "+step +proj=axisswap +order=2,1");
4761
4762 // Check that we get the same results after an export of compoundCRS to
4763 // PROJJSON and a re-import from it.
4764 auto projjson = proj_as_projjson(m_ctxt, compound, nullptr);
4765 ASSERT_NE(projjson, nullptr);
4766 auto compound_from_projjson = proj_create(m_ctxt, projjson);
4767 ObjectKeeper keeper_compound_from_projjson(compound_from_projjson);
4768 ASSERT_NE(compound_from_projjson, nullptr);
4769
4770 PJ_OBJ_LIST *operations2 =
4771 proj_create_operations(m_ctxt, compound_from_projjson, geog_crs, ctxt);
4772 ASSERT_NE(operations2, nullptr);
4773 ObjListKeeper keeper_operations2(operations2);
4774 EXPECT_GE(proj_list_get_count(operations2), 1);
4775 auto P2 = proj_list_get(m_ctxt, operations2, 0);
4776 ObjectKeeper keeper_transform2(P2);
4777
4778 auto name_bis = proj_get_name(P2);
4779 ASSERT_TRUE(name_bis != nullptr);
4780 EXPECT_EQ(std::string(name_bis), std::string(name));
4781
4782 auto proj_5_bis = proj_as_proj_string(m_ctxt, P2, PJ_PROJ_5, nullptr);
4783 ASSERT_NE(proj_5_bis, nullptr);
4784 EXPECT_EQ(std::string(proj_5_bis), std::string(proj_5));
4785 }
4786
4787 // ---------------------------------------------------------------------------
4788
TEST_F(CApi,proj_create_vertical_crs_ex_implied_accuracy)4789 TEST_F(CApi, proj_create_vertical_crs_ex_implied_accuracy) {
4790
4791 PJ *crsH = proj_create(m_ctxt, "EPSG:4283"); // GDA94
4792 ASSERT_NE(crsH, nullptr);
4793 ObjectKeeper keeper_crsH(crsH);
4794 PJ *crsV = proj_create(m_ctxt, "EPSG:5711"); // AHD height
4795 ASSERT_NE(crsV, nullptr);
4796 ObjectKeeper keeper_crsV(crsV);
4797 PJ *crsGeoid = proj_create(m_ctxt, "EPSG:4939"); // GDA94 3D
4798 ASSERT_NE(crsGeoid, nullptr);
4799 ObjectKeeper keeper_crsGeoid(crsGeoid);
4800
4801 PJ *vertDatum = proj_crs_get_datum(m_ctxt, crsV);
4802 ObjectKeeper keeper_vertDatum(vertDatum);
4803 const char *vertDatumName = proj_get_name(vertDatum);
4804 const char *vertDatumAuthority = proj_get_id_auth_name(vertDatum, 0);
4805 const char *vertDatumCode = proj_get_id_code(vertDatum, 0);
4806 PJ *crsVGeoid = proj_create_vertical_crs_ex(
4807 m_ctxt, "Vertical", vertDatumName, vertDatumAuthority, vertDatumCode,
4808 "metre", 1.0, "PROJ au_ga_AUSGeoid09_V1.01.tif", nullptr, nullptr,
4809 crsGeoid, nullptr);
4810 ObjectKeeper keeper_crsVGeoid(crsVGeoid);
4811 PJ *crsCompoundGeoid = proj_create_compound_crs(
4812 m_ctxt, "Compound with geoid", crsH, crsVGeoid);
4813 ObjectKeeper keeper_crsCompoundGeoid(crsCompoundGeoid);
4814
4815 PJ_OPERATION_FACTORY_CONTEXT *ctxt =
4816 proj_create_operation_factory_context(m_ctxt, nullptr);
4817 ASSERT_NE(ctxt, nullptr);
4818 ContextKeeper keeper_ctxt(ctxt);
4819 proj_operation_factory_context_set_grid_availability_use(
4820 m_ctxt, ctxt, PROJ_GRID_AVAILABILITY_IGNORED);
4821 proj_operation_factory_context_set_spatial_criterion(
4822 m_ctxt, ctxt, PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION);
4823 PJ_OBJ_LIST *operations =
4824 proj_create_operations(m_ctxt, crsCompoundGeoid, crsGeoid, ctxt);
4825 ASSERT_NE(operations, nullptr);
4826 ObjListKeeper keeper_operations(operations);
4827 EXPECT_GE(proj_list_get_count(operations), 1);
4828 PJ *transform = proj_list_get(m_ctxt, operations, 0);
4829 ObjectKeeper keeper_transform(transform);
4830
4831 // This is the accuracy of operations EPSG:5656 / 5657
4832 ASSERT_EQ(proj_coordoperation_get_accuracy(m_ctxt, transform), 0.15);
4833 }
4834
4835 // ---------------------------------------------------------------------------
4836
TEST_F(CApi,proj_create_derived_geographic_crs)4837 TEST_F(CApi, proj_create_derived_geographic_crs) {
4838
4839 PJ *crs_4326 = proj_create(m_ctxt, "EPSG:4326");
4840 ObjectKeeper keeper_crs_4326(crs_4326);
4841 ASSERT_NE(crs_4326, nullptr);
4842
4843 PJ *conversion = proj_create_conversion_pole_rotation_grib_convention(
4844 m_ctxt, 2, 3, 4, "Degree", 0.0174532925199433);
4845 ObjectKeeper keeper_conversion(conversion);
4846 ASSERT_NE(conversion, nullptr);
4847
4848 PJ *cs = proj_crs_get_coordinate_system(m_ctxt, crs_4326);
4849 ObjectKeeper keeper_cs(cs);
4850 ASSERT_NE(cs, nullptr);
4851
4852 ASSERT_EQ(
4853 proj_create_derived_geographic_crs(m_ctxt, "my rotated CRS",
4854 conversion, // wrong type of object
4855 conversion, cs),
4856 nullptr);
4857
4858 ASSERT_EQ(
4859 proj_create_derived_geographic_crs(m_ctxt, "my rotated CRS", crs_4326,
4860 crs_4326, // wrong type of object
4861 cs),
4862 nullptr);
4863
4864 ASSERT_EQ(proj_create_derived_geographic_crs(
4865 m_ctxt, "my rotated CRS", crs_4326, conversion,
4866 conversion // wrong type of object
4867 ),
4868 nullptr);
4869
4870 PJ *derived_crs = proj_create_derived_geographic_crs(
4871 m_ctxt, "my rotated CRS", crs_4326, conversion, cs);
4872 ObjectKeeper keeper_derived_crs(derived_crs);
4873 ASSERT_NE(derived_crs, nullptr);
4874
4875 EXPECT_FALSE(proj_is_derived_crs(m_ctxt, crs_4326));
4876 EXPECT_TRUE(proj_is_derived_crs(m_ctxt, derived_crs));
4877
4878 auto wkt = proj_as_wkt(m_ctxt, derived_crs, PJ_WKT2_2019, nullptr);
4879 const char *expected_wkt =
4880 "GEOGCRS[\"my rotated CRS\",\n"
4881 " BASEGEOGCRS[\"WGS 84\",\n"
4882 " DATUM[\"World Geodetic System 1984\",\n"
4883 " ELLIPSOID[\"WGS 84\",6378137,298.257223563,\n"
4884 " LENGTHUNIT[\"metre\",1]]],\n"
4885 " PRIMEM[\"Greenwich\",0,\n"
4886 " ANGLEUNIT[\"degree\",0.0174532925199433]]],\n"
4887 " DERIVINGCONVERSION[\"Pole rotation (GRIB convention)\",\n"
4888 " METHOD[\"Pole rotation (GRIB convention)\"],\n"
4889 " PARAMETER[\"Latitude of the southern pole (GRIB "
4890 "convention)\",2,\n"
4891 " ANGLEUNIT[\"degree\",0.0174532925199433,\n"
4892 " ID[\"EPSG\",9122]]],\n"
4893 " PARAMETER[\"Longitude of the southern pole (GRIB "
4894 "convention)\",3,\n"
4895 " ANGLEUNIT[\"degree\",0.0174532925199433,\n"
4896 " ID[\"EPSG\",9122]]],\n"
4897 " PARAMETER[\"Axis rotation (GRIB convention)\",4,\n"
4898 " ANGLEUNIT[\"degree\",0.0174532925199433,\n"
4899 " ID[\"EPSG\",9122]]]],\n"
4900 " CS[ellipsoidal,2],\n"
4901 " AXIS[\"geodetic latitude (Lat)\",north,\n"
4902 " ORDER[1],\n"
4903 " ANGLEUNIT[\"degree\",0.0174532925199433,\n"
4904 " ID[\"EPSG\",9122]]],\n"
4905 " AXIS[\"geodetic longitude (Lon)\",east,\n"
4906 " ORDER[2],\n"
4907 " ANGLEUNIT[\"degree\",0.0174532925199433,\n"
4908 " ID[\"EPSG\",9122]]]]";
4909
4910 ASSERT_NE(wkt, nullptr);
4911 EXPECT_EQ(wkt, std::string(expected_wkt));
4912
4913 auto proj_5 = proj_as_proj_string(m_ctxt, derived_crs, PJ_PROJ_5, nullptr);
4914 ASSERT_NE(proj_5, nullptr);
4915 EXPECT_EQ(proj_5, std::string("+proj=ob_tran +o_proj=longlat +o_lon_p=-4 "
4916 "+o_lat_p=-2 +lon_0=3 +datum=WGS84 +no_defs "
4917 "+type=crs"));
4918 }
4919
4920 // ---------------------------------------------------------------------------
4921
TEST_F(CApi,proj_context_set_sqlite3_vfs_name)4922 TEST_F(CApi, proj_context_set_sqlite3_vfs_name) {
4923
4924 PJ_CONTEXT *ctx = proj_context_create();
4925 proj_log_func(ctx, nullptr, [](void *, int, const char *) -> void {});
4926
4927 // Set a dummy VFS and check it is taken into account
4928 // (failure to open proj.db)
4929 proj_context_set_sqlite3_vfs_name(ctx, "dummy_vfs_name");
4930 ASSERT_EQ(proj_create(ctx, "EPSG:4326"), nullptr);
4931
4932 // Restore default VFS
4933 proj_context_set_sqlite3_vfs_name(ctx, nullptr);
4934 PJ *crs_4326 = proj_create(ctx, "EPSG:4326");
4935 ASSERT_NE(crs_4326, nullptr);
4936 proj_destroy(crs_4326);
4937
4938 proj_context_destroy(ctx);
4939 }
4940
4941 // ---------------------------------------------------------------------------
4942
TEST_F(CApi,proj_context_set_sqlite3_vfs_name__from_global_context)4943 TEST_F(CApi, proj_context_set_sqlite3_vfs_name__from_global_context) {
4944
4945 // Set a dummy VFS and check it is taken into account
4946 // (failure to open proj.db)
4947 proj_context_set_sqlite3_vfs_name(nullptr, "dummy_vfs_name");
4948
4949 PJ_CONTEXT *ctx = proj_context_create();
4950 proj_log_func(ctx, nullptr, [](void *, int, const char *) -> void {});
4951
4952 ASSERT_EQ(proj_create(ctx, "EPSG:4326"), nullptr);
4953
4954 // Restore default VFS
4955 proj_context_set_sqlite3_vfs_name(nullptr, nullptr);
4956 proj_context_destroy(ctx);
4957 }
4958
4959 // ---------------------------------------------------------------------------
4960
TEST_F(CApi,use_proj4_init_rules)4961 TEST_F(CApi, use_proj4_init_rules) {
4962 PJ_CONTEXT *ctx = proj_context_create();
4963 proj_context_use_proj4_init_rules(ctx, true);
4964 ASSERT_TRUE(proj_context_get_use_proj4_init_rules(ctx, true));
4965 proj_context_use_proj4_init_rules(ctx, false);
4966 ASSERT_TRUE(!proj_context_get_use_proj4_init_rules(ctx, true));
4967 proj_context_destroy(ctx);
4968 }
4969
4970 // ---------------------------------------------------------------------------
4971
TEST_F(CApi,use_proj4_init_rules_from_global_context)4972 TEST_F(CApi, use_proj4_init_rules_from_global_context) {
4973
4974 int initial_rules = proj_context_get_use_proj4_init_rules(nullptr, true);
4975 proj_context_use_proj4_init_rules(nullptr, true);
4976 PJ_CONTEXT *ctx = proj_context_create();
4977 ASSERT_TRUE(proj_context_get_use_proj4_init_rules(ctx, true));
4978 proj_context_destroy(ctx);
4979 proj_context_use_proj4_init_rules(nullptr, false);
4980 ctx = proj_context_create();
4981 ASSERT_TRUE(!proj_context_get_use_proj4_init_rules(ctx, true));
4982 proj_context_destroy(ctx);
4983 proj_context_use_proj4_init_rules(nullptr, initial_rules);
4984 }
4985
4986 // ---------------------------------------------------------------------------
4987
TEST_F(CApi,proj_is_equivalent_to_with_ctx)4988 TEST_F(CApi, proj_is_equivalent_to_with_ctx) {
4989 auto from_epsg = proj_create_from_database(m_ctxt, "EPSG", "7844",
4990 PJ_CATEGORY_CRS, false, nullptr);
4991 ObjectKeeper keeper_from_epsg(from_epsg);
4992 ASSERT_NE(from_epsg, nullptr);
4993
4994 auto wkt = "GEOGCRS[\"GDA2020\",\n"
4995 " DATUM[\"GDA2020\",\n"
4996 " ELLIPSOID[\"GRS_1980\",6378137,298.257222101,\n"
4997 " LENGTHUNIT[\"metre\",1]]],\n"
4998 " PRIMEM[\"Greenwich\",0,\n"
4999 " ANGLEUNIT[\"Degree\",0.0174532925199433]],\n"
5000 " CS[ellipsoidal,2],\n"
5001 " AXIS[\"geodetic latitude (Lat)\",north,\n"
5002 " ORDER[1],\n"
5003 " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
5004 " AXIS[\"geodetic longitude (Lon)\",east,\n"
5005 " ORDER[2],\n"
5006 " ANGLEUNIT[\"degree\",0.0174532925199433]]]";
5007 auto from_wkt =
5008 proj_create_from_wkt(m_ctxt, wkt, nullptr, nullptr, nullptr);
5009 ObjectKeeper keeper_from_wkt(from_wkt);
5010 EXPECT_NE(from_wkt, nullptr);
5011
5012 EXPECT_TRUE(proj_is_equivalent_to_with_ctx(m_ctxt, from_epsg, from_wkt,
5013 PJ_COMP_EQUIVALENT));
5014 }
5015
5016 // ---------------------------------------------------------------------------
5017
TEST_F(CApi,datum_ensemble)5018 TEST_F(CApi, datum_ensemble) {
5019 auto wkt =
5020 "GEOGCRS[\"ETRS89\","
5021 " ENSEMBLE[\"European Terrestrial Reference System 1989 ensemble\","
5022 " MEMBER[\"European Terrestrial Reference Frame 1989\"],"
5023 " MEMBER[\"European Terrestrial Reference Frame 1990\"],"
5024 " MEMBER[\"European Terrestrial Reference Frame 1991\"],"
5025 " MEMBER[\"European Terrestrial Reference Frame 1992\"],"
5026 " MEMBER[\"European Terrestrial Reference Frame 1993\"],"
5027 " MEMBER[\"European Terrestrial Reference Frame 1994\"],"
5028 " MEMBER[\"European Terrestrial Reference Frame 1996\"],"
5029 " MEMBER[\"European Terrestrial Reference Frame 1997\"],"
5030 " MEMBER[\"European Terrestrial Reference Frame 2000\"],"
5031 " MEMBER[\"European Terrestrial Reference Frame 2005\"],"
5032 " MEMBER[\"European Terrestrial Reference Frame 2014\"],"
5033 " ELLIPSOID[\"GRS 1980\",6378137,298.257222101,"
5034 " LENGTHUNIT[\"metre\",1]],"
5035 " ENSEMBLEACCURACY[0.1]],"
5036 " PRIMEM[\"Greenwich\",0,"
5037 " ANGLEUNIT[\"degree\",0.0174532925199433]],"
5038 " CS[ellipsoidal,2],"
5039 " AXIS[\"geodetic latitude (Lat)\",north,"
5040 " ORDER[1],"
5041 " ANGLEUNIT[\"degree\",0.0174532925199433]],"
5042 " AXIS[\"geodetic longitude (Lon)\",east,"
5043 " ORDER[2],"
5044 " ANGLEUNIT[\"degree\",0.0174532925199433]]]";
5045 auto from_wkt =
5046 proj_create_from_wkt(m_ctxt, wkt, nullptr, nullptr, nullptr);
5047 ObjectKeeper keeper_from_wkt(from_wkt);
5048 EXPECT_NE(from_wkt, nullptr);
5049
5050 auto datum = proj_crs_get_datum(m_ctxt, from_wkt);
5051 ObjectKeeper keeper_datum(datum);
5052 ASSERT_EQ(datum, nullptr);
5053
5054 auto datum_ensemble = proj_crs_get_datum_ensemble(m_ctxt, from_wkt);
5055 ObjectKeeper keeper_datum_ensemble(datum_ensemble);
5056 ASSERT_NE(datum_ensemble, nullptr);
5057
5058 ASSERT_EQ(proj_datum_ensemble_get_member_count(m_ctxt, datum_ensemble), 11);
5059 ASSERT_EQ(proj_datum_ensemble_get_member(m_ctxt, datum_ensemble, -1),
5060 nullptr);
5061 ASSERT_EQ(proj_datum_ensemble_get_member(m_ctxt, datum_ensemble, 11),
5062 nullptr);
5063
5064 {
5065 auto member = proj_datum_ensemble_get_member(m_ctxt, datum_ensemble, 0);
5066 ObjectKeeper keeper_member(member);
5067 ASSERT_NE(member, nullptr);
5068
5069 EXPECT_EQ(proj_get_name(member),
5070 std::string("European Terrestrial Reference Frame 1989"));
5071 }
5072
5073 {
5074 auto member =
5075 proj_datum_ensemble_get_member(m_ctxt, datum_ensemble, 10);
5076 ObjectKeeper keeper_member(member);
5077 ASSERT_NE(member, nullptr);
5078
5079 EXPECT_EQ(proj_get_name(member),
5080 std::string("European Terrestrial Reference Frame 2014"));
5081 }
5082
5083 ASSERT_EQ(proj_datum_ensemble_get_accuracy(m_ctxt, datum_ensemble), 0.1);
5084
5085 auto datum_forced = proj_crs_get_datum_forced(m_ctxt, from_wkt);
5086 ObjectKeeper keeper_datum_forced(datum_forced);
5087 ASSERT_NE(datum_forced, nullptr);
5088
5089 EXPECT_EQ(proj_get_name(datum_forced),
5090 std::string("European Terrestrial Reference System 1989"));
5091
5092 auto cs = proj_crs_get_coordinate_system(m_ctxt, from_wkt);
5093 ObjectKeeper keeper_cs(cs);
5094 EXPECT_NE(cs, nullptr);
5095
5096 {
5097 auto built_crs = proj_create_geographic_crs_from_datum(
5098 m_ctxt, proj_get_name(from_wkt), datum_ensemble, cs);
5099 ObjectKeeper keeper_built_crs(built_crs);
5100 EXPECT_NE(built_crs, nullptr);
5101
5102 EXPECT_TRUE(proj_is_equivalent_to_with_ctx(m_ctxt, built_crs, from_wkt,
5103 PJ_COMP_EQUIVALENT));
5104 }
5105
5106 {
5107 auto built_crs = proj_create_geocentric_crs_from_datum(
5108 m_ctxt, proj_get_name(from_wkt), datum_ensemble, "metre", 1.0);
5109 ObjectKeeper keeper_built_crs(built_crs);
5110 EXPECT_NE(built_crs, nullptr);
5111 }
5112 }
5113
5114 } // namespace
5115