1 /******************************************************************************
2 * Copyright (c) 2011, Michael P. Gerlek (mpg@flaxen.com)
3 *
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following
8 * conditions are met:
9 *
10 *     * Redistributions of source code must retain the above copyright
11 *       notice, this list of conditions and the following disclaimer.
12 *     * Redistributions in binary form must reproduce the above copyright
13 *       notice, this list of conditions and the following disclaimer in
14 *       the documentation and/or other materials provided
15 *       with the distribution.
16 *     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
17 *       names of its contributors may be used to endorse or promote
18 *       products derived from this software without specific prior
19 *       written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
32 * OF SUCH DAMAGE.
33 ****************************************************************************/
34 
35 #include <pdal/pdal_test_main.hpp>
36 #include <pdal/PDALUtils.hpp>
37 #include <pdal/SrsBounds.hpp>
38 #include <pdal/util/Bounds.hpp>
39 #include <pdal/util/ProgramArgs.hpp>
40 
41 using namespace pdal;
42 
TEST(BoundsTest,test_ctor)43 TEST(BoundsTest, test_ctor)
44 {
45     BOX3D b1;
46     EXPECT_TRUE(b1.empty());
47 
48     b1.clear();
49     BOX3D b2;
50     EXPECT_EQ(b1, b2);
51 }
52 
TEST(BoundsTest,test_equals)53 TEST(BoundsTest, test_equals)
54 {
55     BOX2D b1(1,2,3,4);
56     BOX2D b2(1,2,3,4);
57     BOX2D b3(1,2,3,6);
58 
59     EXPECT_TRUE(b1 == b1);
60     EXPECT_TRUE(b1 == b2);
61     EXPECT_TRUE(b1 != b3);
62     EXPECT_TRUE(b2 != b3);
63 
64     BOX3D b4(1,2,3,4,5,6);
65     BOX3D b5(1,2,3,4,5,6);
66     BOX3D b6(1,2,3,4,5,7);
67 
68     EXPECT_TRUE(b4 == b4);
69     EXPECT_TRUE(b4 == b5);
70     EXPECT_TRUE(b5 == b4);
71     EXPECT_TRUE(b4 != b6);
72     EXPECT_TRUE(b6 == b6);
73 }
74 
TEST(BoundsTest,test_copy)75 TEST(BoundsTest, test_copy)
76 {
77     BOX2D b1(1,2,3,4);
78     BOX2D b2(b1);
79     EXPECT_TRUE(b1==b2);
80 
81     BOX3D b3(1,2,3,4,5,6);
82     BOX3D b4(b3);
83     EXPECT_TRUE(b1==b2);
84 }
85 
TEST(BoundsTest,test_accessor)86 TEST(BoundsTest, test_accessor)
87 {
88     BOX2D b1(1,2,3,4);
89 	EXPECT_DOUBLE_EQ(b1.minx, 1.0);
90     EXPECT_DOUBLE_EQ(b1.miny, 2.0);
91 	EXPECT_DOUBLE_EQ(b1.maxx, 3.0);
92 	EXPECT_DOUBLE_EQ(b1.maxy, 4.0);
93 
94     BOX3D b2(1,2,3,4,5,6);
95 	EXPECT_DOUBLE_EQ(b2.minx, 1.0);
96 	EXPECT_DOUBLE_EQ(b2.miny, 2.0);
97 	EXPECT_DOUBLE_EQ(b2.minz, 3.0);
98 	EXPECT_DOUBLE_EQ(b2.maxx, 4.0);
99 	EXPECT_DOUBLE_EQ(b2.maxy, 5.0);
100 	EXPECT_DOUBLE_EQ(b2.maxz, 6.0);
101 }
102 
TEST(BoundsTest,test_clip)103 TEST(BoundsTest, test_clip)
104 {
105     BOX2D r1(0,0,10,10);
106     BOX2D r2(1,1,11,11);
107     r1.clip(r2);
108 
109     BOX2D r3(1,1,10,10);
110     EXPECT_TRUE(r1==r3);
111 
112     BOX2D r4(2,4,6,8);
113     r1.clip(r4);
114 
115     EXPECT_TRUE(r1==r4);
116 
117     BOX2D r5(20,40,60,80);
118     r1.clip(r5);
119 
120     // BUG: seems wrong -- need to better define semantics of clip, etc
121     // .clip() can make an invalid bounds, this should be fixed.
122     BOX2D r6(20,6, 40,8);
123 
124 	EXPECT_DOUBLE_EQ(r1.minx, 20);
125 	EXPECT_DOUBLE_EQ(r1.maxx, 6);
126 	EXPECT_DOUBLE_EQ(r1.miny, 40);
127 	EXPECT_DOUBLE_EQ(r1.maxy, 8);
128 
129 //ABELL - Need BOX3D example.
130 }
131 
TEST(BoundsTest,test_intersect)132 TEST(BoundsTest, test_intersect)
133 {
134     BOX2D r1(0,0,10,10);
135     BOX2D r2(1,1,11,11);
136     BOX2D r3(100,100,101,101);
137     BOX2D r4(2,4,6,8);
138 
139     EXPECT_TRUE(r1.overlaps(r1));
140 
141     EXPECT_TRUE(r1.overlaps(r2));
142     EXPECT_TRUE(r2.overlaps(r1));
143 
144     EXPECT_TRUE(!r1.overlaps(r3));
145     EXPECT_TRUE(!r3.overlaps(r1));
146 
147     EXPECT_TRUE(r1.contains(r1));
148     EXPECT_TRUE(!r1.contains(r2));
149     EXPECT_TRUE(r1.contains(r4));
150 
151 //ABELL - Need BOX3D example.
152 }
153 
TEST(BoundsTest,test_grow)154 TEST(BoundsTest, test_grow)
155 {
156     BOX2D r1(50,51,100,101);
157     BOX2D r2(0,1,10,201);
158 
159     r1.grow(r2);
160 
161     BOX2D r3(0,1,100,201);
162     EXPECT_TRUE(r1 == r3);
163 //ABELL - Need BOX3D example.
164 }
165 
TEST(BoundsTest,test_static)166 TEST(BoundsTest, test_static)
167 {
168     BOX2D t(BOX2D::getDefaultSpatialExtent());
169     double mind = (std::numeric_limits<double>::lowest)();
170     double maxd = (std::numeric_limits<double>::max)();
171     EXPECT_DOUBLE_EQ(t.minx, mind);
172     EXPECT_DOUBLE_EQ(t.maxx, maxd);
173     EXPECT_DOUBLE_EQ(t.miny, mind);
174     EXPECT_DOUBLE_EQ(t.maxy, maxd);
175 
176     BOX3D u = BOX3D::getDefaultSpatialExtent();
177     EXPECT_DOUBLE_EQ(u.minx, mind);
178     EXPECT_DOUBLE_EQ(u.maxx, maxd);
179     EXPECT_DOUBLE_EQ(u.miny, mind);
180     EXPECT_DOUBLE_EQ(u.maxy, maxd);
181     EXPECT_DOUBLE_EQ(u.minz, mind);
182     EXPECT_DOUBLE_EQ(u.maxz, maxd);
183 }
184 
TEST(BoundsTest,test_invalid)185 TEST(BoundsTest, test_invalid)
186 {
187     BOX2D t;
188     double mind = (std::numeric_limits<double>::lowest)();
189     double maxd = (std::numeric_limits<double>::max)();
190     EXPECT_DOUBLE_EQ(t.minx, maxd);
191     EXPECT_DOUBLE_EQ(t.maxx, mind);
192     EXPECT_DOUBLE_EQ(t.miny, maxd);
193     EXPECT_DOUBLE_EQ(t.maxy, mind);
194 
195     BOX3D u;
196     EXPECT_DOUBLE_EQ(u.minx, maxd);
197     EXPECT_DOUBLE_EQ(u.maxx, mind);
198     EXPECT_DOUBLE_EQ(u.miny, maxd);
199     EXPECT_DOUBLE_EQ(u.maxy, mind);
200     EXPECT_DOUBLE_EQ(u.minz, maxd);
201     EXPECT_DOUBLE_EQ(u.maxz, mind);
202 }
203 
TEST(BoundsTest,test_output)204 TEST(BoundsTest, test_output)
205 {
206     const BOX2D b2(1,2,101,102);
207     const BOX3D b3(1.1,2.2,3.3,101.1,102.2,103.3);
208 
209     std::stringstream ss2(std::stringstream::in | std::stringstream::out);
210     std::stringstream ss3(std::stringstream::in | std::stringstream::out);
211 
212     ss2 << b2;
213     ss3 << b3;
214 
215     const std::string out2 = ss2.str();
216     const std::string out3 = ss3.str();
217 
218     EXPECT_EQ(out2, "([1, 101], [2, 102])");
219     EXPECT_EQ(out3, "([1.1, 101.1], [2.2, 102.2], [3.3, 103.3])");
220 }
221 
222 
TEST(BoundsTest,test_input)223 TEST(BoundsTest, test_input)
224 {
225     std::stringstream ss("([1.1, 101.1], [2.2, 102.2], [3.3, 103.3])",
226         std::stringstream::in | std::stringstream::out);
227 
228     BOX3D rr;
229     ss >> rr;
230     BOX3D r(1.1,2.2,3.3,101.1,102.2,103.3);
231     EXPECT_TRUE(r == rr);
232 }
233 
TEST(BoundsTest,test_parse)234 TEST(BoundsTest, test_parse)
235 {
236     std::istringstream iss1("([1,101],[2,102],[3,103])");
237     std::istringstream iss2("([1, 101], [2, 102], [3, 103])");
238 
239     BOX3D b1;
240     BOX3D b2;
241 
242     iss1 >> b1;
243     iss2 >> b2;
244 
245     EXPECT_EQ(b1, b2);
246 }
247 
TEST(BoundsTest,test_wkt)248 TEST(BoundsTest, test_wkt)
249 {
250     BOX2D b(1.1,2.2,101.1,102.2);
251     std::string out = "POLYGON ((1.1 2.2, 1.1 102.2, 101.1 102.2, 101.1 2.2, 1.1 2.2))";
252     EXPECT_EQ(b.toWKT(1), out);
253 
254     BOX3D b2(1.1,2.2,3.3,101.1,102.2,103.3);
255     std::string out2 = "POLYHEDRON Z ( ((1.1 2.2 3.3, 101.1 2.2 3.3, 101.1 102.2 3.3, 1.1 102.2 3.3, 1.1 2.2 3.3, )), ((1.1 2.2 3.3, 101.1 2.2 3.3, 101.1 2.2 103.3, 1.1 2.2 103.3, 1.1 2.2 3.3, )), ((101.1 2.2 3.3, 101.1 102.2 3.3, 101.1 102.2 103.3, 101.1 2.2 103.3, 101.1 2.2 3.3, )), ((101.1 102.2 3.3, 1.1 102.2 3.3, 1.1 102.2 103.3, 101.1 102.2 103.3, 101.1 102.2 3.3, )), ((1.1 102.2 3.3, 1.1 2.2 3.3, 1.1 2.2 103.3, 1.1 102.2 103.3, 1.1 102.2 3.3, )), ((1.1 2.2 103.3, 101.1 2.2 103.3, 101.1 102.2 103.3, 1.1 102.2 103.3, 1.1 2.2 103.3, )) )";
256     EXPECT_EQ(b2.toWKT(1), out2);
257 }
TEST(BoundsTest,test_json)258 TEST(BoundsTest, test_json)
259 {
260     BOX2D b(1.1,2.2,101.1,102.2);
261     std::string out = "{\"bbox\":[1.1, 2.2, 101.1,102.2]}";
262     EXPECT_EQ(b.toGeoJSON(1), out);
263 }
264 
TEST(BoundsTest,test_2d_input)265 TEST(BoundsTest, test_2d_input)
266 {
267     std::stringstream ss("([1.1, 101.1], [2.2, 102.2])", std::stringstream::in | std::stringstream::out);
268     BOX2D rr;
269     ss >> rr;
270     BOX2D r(1.1,2.2,101.1,102.2);
271     EXPECT_EQ(r, rr);
272 }
273 
TEST(BoundsTest,test_precisionloss)274 TEST(BoundsTest, test_precisionloss)
275 {
276     const BOX2D b1(0.123456789,0.0,0,0);
277     EXPECT_DOUBLE_EQ(b1.minx, 0.123456789);
278 
279     // convert it to a string, which is what happens
280     // when you do something like:
281     //   options.getValueOrDefault<BOX3D>("bounds", BOX3D());
282     std::ostringstream oss;
283     oss << b1;
284 
285     // convert it back
286     std::istringstream iss(oss.str());
287     BOX2D b2;
288     iss >> b2;
289 
290     EXPECT_DOUBLE_EQ(b2.minx, 0.123456789);
291 }
292 
293 namespace
294 {
295     std::string fancySrs =
296     R"SRS(
297         COMPD_CS["OSGB36 / British National Grid + ODN",
298          PROJCS["OSGB 1936 / British National Grid",
299              GEOGCS["OSGB 1936",
300                  DATUM["OSGB_1936",
301                      SPHEROID["Airy 1830",6377563.396,299.3249646,
302                          AUTHORITY["EPSG","7001"]],
303                      TOWGS84[375,-111,431,0,0,0,0],
304                      AUTHORITY["EPSG","6277"]],
305                  PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],
306                  UNIT["DMSH",0.0174532925199433,AUTHORITY["EPSG","9108"]],
307                  AXIS["Lat",NORTH],
308                  AXIS["Long",EAST],
309                  AUTHORITY["EPSG","4277"]],
310              PROJECTION["Transverse_Mercator"],
311              PARAMETER["latitude_of_origin",49],
312              PARAMETER["central_meridian",-2],
313              PARAMETER["scale_factor",0.999601272],
314              PARAMETER["false_easting",400000],
315              PARAMETER["false_northing",-100000],
316              UNIT["metre",1,AUTHORITY["EPSG","9001"]],
317              AXIS["E",EAST],
318              AXIS["N",NORTH],
319              AUTHORITY["EPSG","27700"]],
320          VERT_CS["Newlyn",
321              VERT_DATUM["Ordnance Datum Newlyn",2005,AUTHORITY["EPSG","5101"]],
322              UNIT["metre",1,AUTHORITY["EPSG","9001"]],
323              AXIS["Up",UP],
324              AUTHORITY["EPSG","5701"]],
325          AUTHORITY["EPSG","7405"]]
326     )SRS";
327 }
328 
TEST(BoundsTest,b1)329 TEST(BoundsTest, b1)
330 {
331     std::string s("([0,1],[0,1])");
332 
333     Bounds b;
334 
335     Utils::fromString(s, b);
336     EXPECT_FALSE(b.is3d());
337     EXPECT_TRUE(b.to3d().empty());
338 
339     BOX2D box = b.to2d();
340     EXPECT_EQ(box.minx, 0.0);
341     EXPECT_EQ(box.miny, 0.0);
342     EXPECT_EQ(box.maxx, 1.0);
343     EXPECT_EQ(box.maxy, 1.0);
344 
345     std::string t("([+0e0,1.00000],[0,1e0]) / EPSG:2596");
346 
347     SrsBounds sb;
348     Utils::fromString(t, sb);
349 
350     EXPECT_FALSE(sb.is3d());
351     EXPECT_TRUE(sb.to3d().empty());
352 
353     box = sb.to2d();
354     EXPECT_EQ(box.minx, 0.0);
355     EXPECT_EQ(box.miny, 0.0);
356     EXPECT_EQ(box.maxx, 1.0);
357     EXPECT_EQ(box.maxy, 1.0);
358 
359     EXPECT_NE(std::string::npos,
360         sb.spatialReference().getWKT().find("Krassowsky 1940"));
361 
362     Utils::fromString("([0, -1.00000],[0,-1e0] ) / " + fancySrs, sb);
363 
364     EXPECT_FALSE(sb.is3d());
365     EXPECT_TRUE(sb.to3d().empty());
366 
367     box = sb.to2d();
368     EXPECT_EQ(box.minx, 0.0);
369     EXPECT_EQ(box.miny, 0.0);
370     EXPECT_EQ(box.maxx, -1.0);
371     EXPECT_EQ(box.maxy, -1.0);
372     EXPECT_TRUE(sb.spatialReference().valid());
373     EXPECT_NE(std::string::npos,
374         sb.spatialReference().getWKT().find("Ordnance Datum Newlyn"));
375 }
376 
TEST(BoundsTest,fromstring)377 TEST(BoundsTest, fromstring)
378 {
379     ProgramArgs a;
380     BOX2D box;
381     a.add("bounds", "BOX", box);
382 
383     std::string badbox("[0, 1]");
384     EXPECT_THROW(a.parse({"--bounds", badbox}), arg_error);
385 }
386 
TEST(BoundsTest,b2)387 TEST(BoundsTest, b2)
388 {
389     std::string s("([0,1],[0,1], [0,2])");
390     Bounds b;
391 
392     Utils::fromString(s, b);
393     EXPECT_TRUE(b.is3d());
394 
395     BOX2D box = b.to2d();
396     EXPECT_EQ(box.minx, 0.0);
397     EXPECT_EQ(box.miny, 0.0);
398     EXPECT_EQ(box.maxx, 1.0);
399     EXPECT_EQ(box.maxy, 1.0);
400 
401     BOX3D box3 = b.to3d();
402     EXPECT_EQ(box3.minx, 0.0);
403     EXPECT_EQ(box3.miny, 0.0);
404     EXPECT_EQ(box3.maxx, 1.0);
405     EXPECT_EQ(box3.maxy, 1.0);
406     EXPECT_EQ(box3.minz, 0.0);
407     EXPECT_EQ(box3.maxz, 2.0);
408 
409     SrsBounds sb;
410     std::string t("([+0,1],[0,1.0000], [-0e0,2]) / EPSG:2596");
411     Utils::fromString(t, sb);
412     EXPECT_TRUE(sb.is3d());
413     box3 = sb.to3d();
414     EXPECT_EQ(box3.minx, 0.0);
415     EXPECT_EQ(box3.miny, 0.0);
416     EXPECT_EQ(box3.maxx, 1.0);
417     EXPECT_EQ(box3.maxy, 1.0);
418     EXPECT_EQ(box3.minz, 0.0);
419     EXPECT_EQ(box3.maxz, 2.0);
420 
421     EXPECT_NE(std::string::npos,
422         sb.spatialReference().getWKT().find("Krassowsky 1940"));
423 
424     Utils::fromString("([0,1],[0,1], [0,2]) / " + fancySrs, sb);
425     EXPECT_TRUE(sb.is3d());
426 
427     box3 = sb.to3d();
428     EXPECT_EQ(box3.minx, 0.0);
429     EXPECT_EQ(box3.miny, 0.0);
430     EXPECT_EQ(box3.minz, 0.0);
431     EXPECT_EQ(box3.maxx, 1.0);
432     EXPECT_EQ(box3.maxy, 1.0);
433     EXPECT_EQ(box3.maxz, 2.0);
434     EXPECT_TRUE(sb.spatialReference().valid());
435     EXPECT_NE(std::string::npos,
436         sb.spatialReference().getWKT().find("Ordnance Datum Newlyn"));
437 }
438 
TEST(BoundsTest,bounds_insertion)439 TEST(BoundsTest, bounds_insertion)
440 {
441     std::string s;
442     std::ostringstream oss(s);
443     Bounds b;
444     oss << b;
445 }
446