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 
37 #include <pdal/PointTable.hpp>
38 #include <io/LasReader.hpp>
39 #include "Support.hpp"
40 
41 namespace pdal
42 {
43 
TEST(PointTable,resolveType)44 TEST(PointTable, resolveType)
45 {
46     using namespace Dimension;
47 
48     PointTable table;
49     PointLayoutPtr layout(table.layout());
50 
51     // Start with a default-defined dimension.
52     layout->registerDim(Id::X);
53     EXPECT_EQ(layout->dimSize(Id::X), 8u);
54     EXPECT_EQ(layout->dimType(Id::X), Type::Double);
55 
56     layout->registerDim(Id::X, Type::Signed32);
57     EXPECT_EQ(layout->dimSize(Id::X), 8u);
58     EXPECT_EQ(layout->dimType(Id::X), Type::Double);
59 
60     layout->registerDim(Dimension::Id::X, Type::Unsigned8);
61     EXPECT_EQ(layout->dimSize(Id::X), 8u);
62     EXPECT_EQ(layout->dimType(Id::X), Type::Double);
63 
64     /// Build as we go.
65     layout->registerDim(Id::Intensity, Type::Unsigned8);
66     EXPECT_EQ(layout->dimSize(Id::Intensity), 1u);
67     EXPECT_EQ(layout->dimType(Id::Intensity), Type::Unsigned8);
68 
69     layout->registerDim(Id::Intensity, Type::Unsigned8);
70     EXPECT_EQ(layout->dimSize(Id::Intensity), 1u);
71     EXPECT_EQ(layout->dimType(Id::Intensity), Type::Unsigned8);
72 
73     layout->registerDim(Id::Intensity, Type::Signed8);
74     // Signed 8 and Unsigned 8 should yield signed 16.
75     EXPECT_EQ(layout->dimSize(Id::Intensity), 2u);
76     EXPECT_EQ(layout->dimType(Id::Intensity), Type::Signed16);
77 
78     layout->registerDim(Id::Intensity, Type::Signed16);
79     EXPECT_EQ(layout->dimSize(Id::Intensity), 2u);
80     EXPECT_EQ(layout->dimType(Id::Intensity), Type::Signed16);
81 
82     layout->registerDim(Id::Intensity, Type::Float);
83     EXPECT_EQ(layout->dimSize(Id::Intensity), 4u);
84     EXPECT_EQ(layout->dimType(Id::Intensity), Type::Float);
85 
86     layout->registerDim(Id::Intensity, Type::Double);
87     EXPECT_EQ(layout->dimSize(Id::Intensity), 8u);
88     EXPECT_EQ(layout->dimType(Id::Intensity), Type::Double);
89 
90     ///
91     layout->registerDim(Id::Red, Type::Unsigned16);
92     EXPECT_EQ(layout->dimSize(Id::Red), 2u);
93     EXPECT_EQ(layout->dimType(Id::Red), Type::Unsigned16);
94 
95     layout->registerDim(Id::Red, Type::Signed8);
96     EXPECT_EQ(layout->dimSize(Id::Red), 4u);
97     EXPECT_EQ(layout->dimType(Id::Red), Type::Signed32);
98 
99     layout->registerDim(Id::Red, Type::Signed16);
100     EXPECT_EQ(layout->dimSize(Id::Red), 4u);
101     EXPECT_EQ(layout->dimType(Id::Red), Type::Signed32);
102 
103     layout->registerDim(Id::Red, Type::Double);
104     EXPECT_EQ(layout->dimSize(Id::Red), 8u);
105     EXPECT_EQ(layout->dimType(Id::Red), Type::Double);
106 }
107 
TEST(PointTable,userView)108 TEST(PointTable, userView)
109 {
110     class UserTable : public PointTable
111     {
112     private:
113         double m_x;
114         double m_y;
115         double m_z;
116 
117     public:
118         PointId addPoint()
119             { return 0; }
120         char *getPoint(PointId idx)
121             { return NULL; }
122         void setFieldInternal(Dimension::Id id, PointId idx,
123             const void *value)
124         {
125             if (id == Dimension::Id::X)
126                m_x = *(const double *)value;
127             else if (id == Dimension::Id::Y)
128                m_y = *(const double *)value;
129             else if (id == Dimension::Id::Z)
130                m_z = *(const double *)value;
131         }
132         void getFieldInternal(Dimension::Id id, PointId idx,
133             void *value) const
134         {
135             if (id == Dimension::Id::X)
136                *(double *)value = m_x;
137             else if (id == Dimension::Id::Y)
138                *(double *)value = m_y;
139             else if (id == Dimension::Id::Z)
140                *(double *)value = m_z;
141         }
142     };
143 
144     LasReader reader;
145 
146     Options opts;
147     opts.add("filename", Support::datapath("las/simple.las"));
148     opts.add("count", 100);
149 
150     reader.setOptions(opts);
151 
152     PointTable defTable;
153     reader.prepare(defTable);
154     PointViewSet viewSet = reader.execute(defTable);
155     PointViewPtr defView = *viewSet.begin();
156 
157     bool called(false);
158     auto readCb = [defView, &called](PointView& customView, PointId id)
159     {
160         called = true;
161         double xDef = defView->getFieldAs<double>(Dimension::Id::X, id);
162         double yDef = defView->getFieldAs<double>(Dimension::Id::Y, id);
163         double zDef = defView->getFieldAs<double>(Dimension::Id::Z, id);
164 
165         double x = customView.getFieldAs<double>(Dimension::Id::X, id);
166         double y = customView.getFieldAs<double>(Dimension::Id::Y, id);
167         double z = customView.getFieldAs<double>(Dimension::Id::Z, id);
168 
169         EXPECT_DOUBLE_EQ(xDef, x);
170         EXPECT_DOUBLE_EQ(yDef, y);
171         EXPECT_DOUBLE_EQ(zDef, z);
172     };
173 
174     reader.setReadCb(readCb);
175     UserTable table;
176 
177     reader.prepare(table);
178     reader.execute(table);
179     EXPECT_TRUE(called);
180 }
181 
TEST(PointTable,srs)182 TEST(PointTable, srs)
183 {
184    SpatialReference srs1("GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]]");
185 
186    SpatialReference srs2("PROJCS[\"WGS 84 / UTM zone 17N\",GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433],AUTHORITY[\"EPSG\",\"4326\"]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",-81],PARAMETER[\"scale_factor\",0.9996],PARAMETER[\"false_easting\",500000],PARAMETER[\"false_northing\",0],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],AUTHORITY[\"EPSG\",\"32617\"]]");
187 
188     PointTable table;
189 
190     table.addSpatialReference(srs1);
191     table.addSpatialReference(srs1);
192     EXPECT_TRUE(table.spatialReferenceUnique());
193     EXPECT_EQ(table.anySpatialReference(), srs1);
194 
195     table.addSpatialReference(srs2);
196     EXPECT_FALSE(table.spatialReferenceUnique());
197     EXPECT_EQ(table.anySpatialReference(), srs2);
198     EXPECT_EQ(table.m_spatialRefs.size(), 2u);
199 
200     table.addSpatialReference(srs1);
201     EXPECT_FALSE(table.spatialReferenceUnique());
202     EXPECT_EQ(table.anySpatialReference(), srs1);
203     EXPECT_EQ(table.m_spatialRefs.size(), 2u);
204 }
205 
simpleTest(PointTableRef table)206 void simpleTest(PointTableRef table)
207 {
208     PointLayoutPtr layout = table.layout();
209 
210     layout->registerDim(Dimension::Id::X);
211     layout->registerDim(Dimension::Id::Y);
212     layout->registerDim(Dimension::Id::Z);
213     layout->registerDim(Dimension::Id::Intensity);
214     layout->registerDim(Dimension::Id::Blue);
215 
216     PointView v(table);
217     for (PointId id = 0; id < 10000; id++)
218     {
219         if (id % 200 < 100)
220         {
221             v.setField(Dimension::Id::X, id, id);
222             v.setField(Dimension::Id::Y, id, id + 1);
223             v.setField(Dimension::Id::Z, id, id + 2);
224             v.setField(Dimension::Id::Intensity, id, (id * 100) % 6523);
225         }
226         else
227             v.setField(Dimension::Id::Blue, id, 0);
228     }
229 
230     for (PointId id = 0; id < 10000; id++)
231     {
232         if (id % 200 < 100)
233         {
234             EXPECT_EQ(id, v.getFieldAs<PointId>(Dimension::Id::X, id));
235             EXPECT_EQ(id + 1, v.getFieldAs<PointId>(Dimension::Id::Y, id));
236             EXPECT_EQ(id + 2, v.getFieldAs<PointId>(Dimension::Id::Z, id));
237             EXPECT_EQ((id * 100) % 6523,
238                 v.getFieldAs<PointId>(Dimension::Id::Intensity, id));
239         }
240         else
241         {
242             EXPECT_EQ(0U, v.getFieldAs<PointId>(Dimension::Id::X, id));
243             EXPECT_EQ(0U, v.getFieldAs<PointId>(Dimension::Id::Y, id));
244             EXPECT_EQ(0U, v.getFieldAs<PointId>(Dimension::Id::Z, id));
245             EXPECT_EQ(0U, v.getFieldAs<PointId>(Dimension::Id::Intensity, id));
246         }
247     }
248 }
249 
250 
TEST(PointTable,simple)251 TEST(PointTable, simple)
252 {
253     PointTable t;
254     simpleTest(t);
255 }
256 
TEST(PointTable,layoutLimit)257 TEST(PointTable, layoutLimit)
258 {
259     PointTable t;
260     PointLayoutPtr layout = t.layout();
261     layout->setAllowedDims({ "X", "Z"});
262 
263     layout->registerDim(Dimension::Id::X);
264     layout->registerDim(Dimension::Id::Y);
265     layout->registerDim(Dimension::Id::Z);
266     layout->registerDim(Dimension::Id::Intensity);
267     layout->registerDim(Dimension::Id::Blue);
268     t.finalize();
269 
270     PointView v(t);
271     for (PointId id = 0; id < 1000; id++)
272     {
273         if (id % 200 < 100)
274         {
275             v.setField(Dimension::Id::X, id, id);
276             v.setField(Dimension::Id::Y, id, id + 1);
277             v.setField(Dimension::Id::Z, id, id + 2);
278             v.setField(Dimension::Id::Intensity, id, (id * 100) % 6523);
279         }
280         else
281         {
282             v.setField(Dimension::Id::X, id, 0);
283             v.setField(Dimension::Id::Blue, id, id);
284         }
285     }
286 
287     for (PointId id = 0; id < 1000; id++)
288     {
289         if (id % 200 < 100)
290         {
291             EXPECT_EQ(id, v.getFieldAs<PointId>(Dimension::Id::X, id));
292             EXPECT_EQ(id + 1, v.getFieldAs<PointId>(Dimension::Id::Y, id));
293             EXPECT_EQ(id + 2, v.getFieldAs<PointId>(Dimension::Id::Z, id));
294         }
295         else
296         {
297             EXPECT_EQ(0U, v.getFieldAs<PointId>(Dimension::Id::X, id));
298             EXPECT_EQ(0U, v.getFieldAs<PointId>(Dimension::Id::Y, id));
299             EXPECT_EQ(0U, v.getFieldAs<PointId>(Dimension::Id::Z, id));
300         }
301         EXPECT_EQ(0U, v.getFieldAs<PointId>(Dimension::Id::Intensity, id));
302         EXPECT_EQ(0U, v.getFieldAs<PointId>(Dimension::Id::Blue, id));
303     }
304 }
305 
306 } // namespace
307