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 "proj/io.hpp"
32 #include "proj/metadata.hpp"
33 #include "proj/util.hpp"
34
35 using namespace osgeo::proj::io;
36 using namespace osgeo::proj::metadata;
37 using namespace osgeo::proj::util;
38
39 // ---------------------------------------------------------------------------
40
TEST(metadata,citation)41 TEST(metadata, citation) {
42 Citation c("my citation");
43 Citation c2(c);
44 ASSERT_TRUE(c2.title().has_value());
45 ASSERT_EQ(*(c2.title()), "my citation");
46 }
47
48 // ---------------------------------------------------------------------------
49
equals(ExtentNNPtr extent1,ExtentNNPtr extent2)50 static bool equals(ExtentNNPtr extent1, ExtentNNPtr extent2) {
51 return extent1->contains(extent2) && extent2->contains(extent1);
52 }
53
equals(GeographicExtentNNPtr extent1,GeographicExtentNNPtr extent2)54 static bool equals(GeographicExtentNNPtr extent1,
55 GeographicExtentNNPtr extent2) {
56 return extent1->contains(extent2) && extent2->contains(extent1);
57 }
58
getBBox(ExtentNNPtr extent)59 static GeographicExtentNNPtr getBBox(ExtentNNPtr extent) {
60 assert(extent->geographicElements().size() == 1);
61 return extent->geographicElements()[0];
62 }
63
TEST(metadata,extent)64 TEST(metadata, extent) {
65 Extent::create(
66 optional<std::string>(), std::vector<GeographicExtentNNPtr>(),
67 std::vector<VerticalExtentNNPtr>(), std::vector<TemporalExtentNNPtr>());
68
69 auto world = Extent::createFromBBOX(-180, -90, 180, 90);
70 EXPECT_TRUE(world->isEquivalentTo(world.get()));
71 EXPECT_TRUE(world->contains(world));
72
73 auto west_hemisphere = Extent::createFromBBOX(-180, -90, 0, 90);
74 EXPECT_TRUE(!world->isEquivalentTo(west_hemisphere.get()));
75 EXPECT_TRUE(world->contains(west_hemisphere));
76 EXPECT_TRUE(!west_hemisphere->contains(world));
77
78 auto world_inter_world = world->intersection(world);
79 ASSERT_TRUE(world_inter_world != nullptr);
80 EXPECT_TRUE(equals(NN_CHECK_ASSERT(world_inter_world), world));
81
82 auto france = Extent::createFromBBOX(-5, 40, 12, 51);
83 EXPECT_TRUE(france->contains(france));
84 EXPECT_TRUE(world->contains(france));
85 EXPECT_TRUE(!france->contains(
86 world)); // We are only speaking about geography here ;-)
87 EXPECT_TRUE(world->intersects(france));
88 EXPECT_TRUE(france->intersects(world));
89
90 auto france_inter_france = france->intersection(france);
91 ASSERT_TRUE(france_inter_france != nullptr);
92 EXPECT_TRUE(equals(NN_CHECK_ASSERT(france_inter_france), france));
93
94 auto france_inter_world = france->intersection(world);
95 ASSERT_TRUE(france_inter_world != nullptr);
96 EXPECT_TRUE(equals(NN_CHECK_ASSERT(france_inter_world), france));
97
98 auto world_inter_france = world->intersection(france);
99 ASSERT_TRUE(world_inter_france != nullptr);
100 EXPECT_TRUE(equals(NN_CHECK_ASSERT(world_inter_france), france));
101
102 auto france_shifted =
103 Extent::createFromBBOX(-5 + 5, 40 + 5, 12 + 5, 51 + 5);
104 EXPECT_TRUE(france->intersects(france_shifted));
105 EXPECT_TRUE(france_shifted->intersects(france));
106 EXPECT_TRUE(!france->contains(france_shifted));
107 EXPECT_TRUE(!france_shifted->contains(france));
108
109 auto europe = Extent::createFromBBOX(-30, 25, 30, 70);
110 EXPECT_TRUE(europe->contains(france));
111 EXPECT_TRUE(!france->contains(europe));
112
113 auto france_inter_europe = france->intersection(europe);
114 ASSERT_TRUE(france_inter_europe != nullptr);
115 EXPECT_TRUE(equals(NN_CHECK_ASSERT(france_inter_europe), france));
116
117 auto europe_intersects_france = europe->intersection(france);
118 ASSERT_TRUE(europe_intersects_france != nullptr);
119 EXPECT_TRUE(equals(NN_CHECK_ASSERT(europe_intersects_france), france));
120
121 auto nz = Extent::createFromBBOX(155.0, -60.0, -170.0, -25.0);
122 EXPECT_TRUE(nz->contains(nz));
123 EXPECT_TRUE(world->contains(nz));
124 EXPECT_TRUE(nz->intersects(world));
125 EXPECT_TRUE(world->intersects(nz));
126 EXPECT_TRUE(!nz->contains(world));
127 EXPECT_TRUE(!nz->contains(france));
128 EXPECT_TRUE(!france->contains(nz));
129 EXPECT_TRUE(!nz->intersects(france));
130 EXPECT_TRUE(!france->intersects(nz));
131
132 {
133 auto nz_inter_world = nz->intersection(world);
134 ASSERT_TRUE(nz_inter_world != nullptr);
135 EXPECT_TRUE(equals(NN_CHECK_ASSERT(nz_inter_world), nz));
136 }
137
138 {
139 auto nz_inter_world = getBBox(nz)->intersection(getBBox(world));
140 ASSERT_TRUE(nz_inter_world != nullptr);
141 EXPECT_TRUE(equals(NN_CHECK_ASSERT(nz_inter_world), getBBox(nz)));
142 }
143
144 {
145 auto world_inter_nz = world->intersection(nz);
146 ASSERT_TRUE(world_inter_nz != nullptr);
147 EXPECT_TRUE(equals(NN_CHECK_ASSERT(world_inter_nz), nz));
148 }
149
150 {
151 auto world_inter_nz = getBBox(world)->intersection(getBBox(nz));
152 ASSERT_TRUE(world_inter_nz != nullptr);
153 EXPECT_TRUE(equals(NN_CHECK_ASSERT(world_inter_nz), getBBox(nz)));
154 }
155
156 EXPECT_TRUE(nz->intersection(france) == nullptr);
157 EXPECT_TRUE(france->intersection(nz) == nullptr);
158
159 auto bbox_antimeridian_north =
160 Extent::createFromBBOX(155.0, 10.0, -170.0, 30.0);
161 EXPECT_TRUE(!nz->contains(bbox_antimeridian_north));
162 EXPECT_TRUE(!bbox_antimeridian_north->contains(nz));
163 EXPECT_TRUE(!nz->intersects(bbox_antimeridian_north));
164 EXPECT_TRUE(!bbox_antimeridian_north->intersects(nz));
165 EXPECT_TRUE(!nz->intersection(bbox_antimeridian_north));
166 EXPECT_TRUE(!bbox_antimeridian_north->intersection(nz));
167
168 auto nz_pos_long = Extent::createFromBBOX(155.0, -60.0, 180.0, -25.0);
169 EXPECT_TRUE(nz->contains(nz_pos_long));
170 EXPECT_TRUE(!nz_pos_long->contains(nz));
171 EXPECT_TRUE(nz->intersects(nz_pos_long));
172 EXPECT_TRUE(nz_pos_long->intersects(nz));
173 auto nz_inter_nz_pos_long = nz->intersection(nz_pos_long);
174 ASSERT_TRUE(nz_inter_nz_pos_long != nullptr);
175 EXPECT_TRUE(equals(NN_CHECK_ASSERT(nz_inter_nz_pos_long), nz_pos_long));
176 auto nz_pos_long_inter_nz = nz_pos_long->intersection(nz);
177 ASSERT_TRUE(nz_pos_long_inter_nz != nullptr);
178 EXPECT_TRUE(equals(NN_CHECK_ASSERT(nz_pos_long_inter_nz), nz_pos_long));
179
180 auto nz_neg_long = Extent::createFromBBOX(-180.0, -60.0, -170.0, -25.0);
181 EXPECT_TRUE(nz->contains(nz_neg_long));
182 EXPECT_TRUE(!nz_neg_long->contains(nz));
183 EXPECT_TRUE(nz->intersects(nz_neg_long));
184 EXPECT_TRUE(nz_neg_long->intersects(nz));
185 auto nz_inter_nz_neg_long = nz->intersection(nz_neg_long);
186 ASSERT_TRUE(nz_inter_nz_neg_long != nullptr);
187 EXPECT_TRUE(equals(NN_CHECK_ASSERT(nz_inter_nz_neg_long), nz_neg_long));
188 auto nz_neg_long_inter_nz = nz_neg_long->intersection(nz);
189 ASSERT_TRUE(nz_neg_long_inter_nz != nullptr);
190 EXPECT_TRUE(equals(NN_CHECK_ASSERT(nz_neg_long_inter_nz), nz_neg_long));
191
192 auto nz_smaller = Extent::createFromBBOX(160, -55.0, -175.0, -30.0);
193 EXPECT_TRUE(nz->contains(nz_smaller));
194 EXPECT_TRUE(!nz_smaller->contains(nz));
195
196 auto nz_pos_long_shifted_west =
197 Extent::createFromBBOX(150.0, -60.0, 175.0, -25.0);
198 EXPECT_TRUE(!nz->contains(nz_pos_long_shifted_west));
199 EXPECT_TRUE(!nz_pos_long_shifted_west->contains(nz));
200 EXPECT_TRUE(nz->intersects(nz_pos_long_shifted_west));
201 EXPECT_TRUE(nz_pos_long_shifted_west->intersects(nz));
202
203 auto nz_smaller_shifted = Extent::createFromBBOX(165, -60.0, -170.0, -25.0);
204 EXPECT_TRUE(!nz_smaller->contains(nz_smaller_shifted));
205 EXPECT_TRUE(!nz_smaller_shifted->contains(nz_smaller));
206 EXPECT_TRUE(nz_smaller->intersects(nz_smaller_shifted));
207 EXPECT_TRUE(nz_smaller_shifted->intersects(nz_smaller));
208
209 auto nz_shifted = Extent::createFromBBOX(165.0, -60.0, -160.0, -25.0);
210 auto nz_intersect_nz_shifted = nz->intersection(nz_shifted);
211 ASSERT_TRUE(nz_intersect_nz_shifted != nullptr);
212 EXPECT_TRUE(equals(NN_CHECK_ASSERT(nz_intersect_nz_shifted),
213 Extent::createFromBBOX(165, -60.0, -170.0, -25.0)));
214
215 auto nz_inter_nz_smaller = nz->intersection(nz_smaller);
216 ASSERT_TRUE(nz_inter_nz_smaller != nullptr);
217 EXPECT_TRUE(equals(NN_CHECK_ASSERT(nz_inter_nz_smaller), nz_smaller));
218
219 auto nz_smaller_inter_nz = nz_smaller->intersection(nz);
220 ASSERT_TRUE(nz_smaller_inter_nz != nullptr);
221 EXPECT_TRUE(equals(NN_CHECK_ASSERT(nz_smaller_inter_nz), nz_smaller));
222
223 auto world_smaller = Extent::createFromBBOX(-179, -90, 179, 90);
224 EXPECT_TRUE(!world_smaller->contains(nz));
225 EXPECT_TRUE(!nz->contains(world_smaller));
226
227 auto nz_inter_world_smaller = nz->intersection(world_smaller);
228 ASSERT_TRUE(nz_inter_world_smaller != nullptr);
229 EXPECT_TRUE(equals(NN_CHECK_ASSERT(nz_inter_world_smaller),
230 Extent::createFromBBOX(155, -60, 179, -25)));
231
232 auto world_smaller_inter_nz = world_smaller->intersection(nz);
233 ASSERT_TRUE(world_smaller_inter_nz != nullptr);
234 EXPECT_TRUE(equals(NN_CHECK_ASSERT(world_smaller_inter_nz),
235 Extent::createFromBBOX(155, -60, 179, -25)));
236
237 auto world_smaller_east = Extent::createFromBBOX(-179, -90, 150, 90);
238 EXPECT_TRUE(!world_smaller_east->contains(nz));
239 EXPECT_TRUE(!nz->contains(world_smaller_east));
240
241 auto nz_inter_world_smaller_east = nz->intersection(world_smaller_east);
242 ASSERT_TRUE(nz_inter_world_smaller_east != nullptr);
243 EXPECT_EQ(nn_dynamic_pointer_cast<GeographicBoundingBox>(
244 nz_inter_world_smaller_east->geographicElements()[0])
245 ->westBoundLongitude(),
246 -179);
247 EXPECT_EQ(nn_dynamic_pointer_cast<GeographicBoundingBox>(
248 nz_inter_world_smaller_east->geographicElements()[0])
249 ->eastBoundLongitude(),
250 -170);
251 EXPECT_TRUE(equals(NN_CHECK_ASSERT(nz_inter_world_smaller_east),
252 Extent::createFromBBOX(-179, -60, -170, -25)));
253
254 auto world_smaller_east_inter_nz = world_smaller_east->intersection(nz);
255 ASSERT_TRUE(world_smaller_east_inter_nz != nullptr);
256 EXPECT_EQ(nn_dynamic_pointer_cast<GeographicBoundingBox>(
257 world_smaller_east_inter_nz->geographicElements()[0])
258 ->westBoundLongitude(),
259 -179);
260 EXPECT_EQ(nn_dynamic_pointer_cast<GeographicBoundingBox>(
261 world_smaller_east_inter_nz->geographicElements()[0])
262 ->eastBoundLongitude(),
263 -170);
264 EXPECT_TRUE(equals(NN_CHECK_ASSERT(world_smaller_east_inter_nz),
265 Extent::createFromBBOX(-179, -60, -170, -25)));
266
267 auto east_hemisphere = Extent::createFromBBOX(0, -90, 180, 90);
268 auto east_hemisphere_inter_nz = east_hemisphere->intersection(nz);
269 ASSERT_TRUE(east_hemisphere_inter_nz != nullptr);
270 EXPECT_TRUE(equals(NN_CHECK_ASSERT(east_hemisphere_inter_nz),
271 Extent::createFromBBOX(155.0, -60.0, 180.0, -25.0)));
272
273 auto minus_180_to_156 = Extent::createFromBBOX(-180, -90, 156, 90);
274 auto minus_180_to_156_inter_nz = minus_180_to_156->intersection(nz);
275 ASSERT_TRUE(minus_180_to_156_inter_nz != nullptr);
276 EXPECT_TRUE(equals(NN_CHECK_ASSERT(minus_180_to_156_inter_nz),
277 Extent::createFromBBOX(-180.0, -60.0, -170.0, -25.0)));
278 }
279
280 // ---------------------------------------------------------------------------
281
TEST(metadata,identifier_empty)282 TEST(metadata, identifier_empty) {
283 auto id(Identifier::create());
284 Identifier id2(*id);
285 ASSERT_TRUE(!id2.authority().has_value());
286 ASSERT_TRUE(id2.code().empty());
287 ASSERT_TRUE(!id2.codeSpace().has_value());
288 ASSERT_TRUE(!id2.version().has_value());
289 ASSERT_TRUE(!id2.description().has_value());
290 }
291
292 // ---------------------------------------------------------------------------
293
TEST(metadata,identifier_properties)294 TEST(metadata, identifier_properties) {
295 PropertyMap properties;
296 properties.set(Identifier::AUTHORITY_KEY, "authority");
297 properties.set(Identifier::CODESPACE_KEY, "codespace");
298 properties.set(Identifier::VERSION_KEY, "version");
299 properties.set(Identifier::DESCRIPTION_KEY, "description");
300 auto id(Identifier::create("my code", properties));
301 Identifier id2(*id);
302 ASSERT_TRUE(id2.authority().has_value());
303 ASSERT_EQ(*(id2.authority()->title()), "authority");
304 ASSERT_EQ(id2.code(), "my code");
305 ASSERT_TRUE(id2.codeSpace().has_value());
306 ASSERT_EQ(*(id2.codeSpace()), "codespace");
307 ASSERT_TRUE(id2.version().has_value());
308 ASSERT_EQ(*(id2.version()), "version");
309 ASSERT_TRUE(id2.description().has_value());
310 ASSERT_EQ(*(id2.description()), "description");
311 }
312
313 // ---------------------------------------------------------------------------
314
TEST(metadata,identifier_code_integer)315 TEST(metadata, identifier_code_integer) {
316 PropertyMap properties;
317 properties.set(Identifier::CODE_KEY, 1234);
318 auto id(Identifier::create(std::string(), properties));
319 ASSERT_EQ(id->code(), "1234");
320 }
321
322 // ---------------------------------------------------------------------------
323
TEST(metadata,identifier_code_string)324 TEST(metadata, identifier_code_string) {
325 PropertyMap properties;
326 properties.set(Identifier::CODE_KEY, "1234");
327 auto id(Identifier::create(std::string(), properties));
328 ASSERT_EQ(id->code(), "1234");
329 }
330
331 // ---------------------------------------------------------------------------
332
TEST(metadata,identifier_code_invalid_type)333 TEST(metadata, identifier_code_invalid_type) {
334 PropertyMap properties;
335 properties.set(Identifier::CODE_KEY, true);
336 ASSERT_THROW(Identifier::create(std::string(), properties),
337 InvalidValueTypeException);
338 }
339
340 // ---------------------------------------------------------------------------
341
TEST(metadata,identifier_authority_citation)342 TEST(metadata, identifier_authority_citation) {
343 PropertyMap properties;
344 properties.set(Identifier::AUTHORITY_KEY,
345 nn_make_shared<Citation>("authority"));
346 auto id(Identifier::create(std::string(), properties));
347 ASSERT_TRUE(id->authority().has_value());
348 ASSERT_EQ(*(id->authority()->title()), "authority");
349 }
350
351 // ---------------------------------------------------------------------------
352
TEST(metadata,identifier_authority_invalid_type)353 TEST(metadata, identifier_authority_invalid_type) {
354 PropertyMap properties;
355 properties.set(Identifier::AUTHORITY_KEY, true);
356 ASSERT_THROW(Identifier::create(std::string(), properties),
357 InvalidValueTypeException);
358 }
359
360 // ---------------------------------------------------------------------------
361
TEST(metadata,id)362 TEST(metadata, id) {
363 auto in_wkt = "ID[\"EPSG\",4946,1.5,\n"
364 " CITATION[\"my citation\"],\n"
365 " URI[\"urn:ogc:def:crs:EPSG::4946\"]]";
366 auto id =
367 nn_dynamic_pointer_cast<Identifier>(WKTParser().createFromWKT(in_wkt));
368 ASSERT_TRUE(id != nullptr);
369
370 EXPECT_TRUE(id->authority().has_value());
371 EXPECT_EQ(*(id->authority()->title()), "my citation");
372 EXPECT_EQ(*(id->codeSpace()), "EPSG");
373 EXPECT_EQ(id->code(), "4946");
374 EXPECT_TRUE(id->version().has_value());
375 EXPECT_EQ(*(id->version()), "1.5");
376 EXPECT_TRUE(id->uri().has_value());
377 EXPECT_EQ(*(id->uri()), "urn:ogc:def:crs:EPSG::4946");
378
379 auto got_wkt = id->exportToWKT(WKTFormatter::create().get());
380 EXPECT_EQ(got_wkt, in_wkt);
381 }
382
383 // ---------------------------------------------------------------------------
384
TEST(metadata,Identifier_isEquivalentName)385 TEST(metadata, Identifier_isEquivalentName) {
386 EXPECT_TRUE(Identifier::isEquivalentName("Central_Meridian",
387 "Central_- ()/Meridian"));
388
389 EXPECT_TRUE(Identifier::isEquivalentName("\xc3\xa1", "a"));
390
391 EXPECT_TRUE(Identifier::isEquivalentName("a", "\xc3\xa1"));
392
393 EXPECT_TRUE(Identifier::isEquivalentName("\xc3\xa4", "\xc3\xa1"));
394 }
395