1 /******************************************************************************
2  * Copyright (c) 2019, Bradley J Chambers (brad.chambers@gmail.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. 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 "Support.hpp"
38 
39 #include <io/BufferReader.hpp>
40 #include <io/LasReader.hpp>
41 #include <io/PcdReader.hpp>
42 #include <io/PcdWriter.hpp>
43 #include <pdal/util/FileUtils.hpp>
44 
45 using namespace pdal;
46 
comparePcdPcd(const std::string & srcFilename,Options & pcdOptions,const std::string & dstFilename)47 void comparePcdPcd(const std::string& srcFilename, Options& pcdOptions,
48                    const std::string& dstFilename)
49 {
50     PcdReader t;
51     pcdOptions.add("filename", srcFilename);
52     t.setOptions(pcdOptions);
53 
54     PcdReader l;
55     Options lo;
56     lo.add("filename", dstFilename);
57     l.setOptions(lo);
58 
59     PointTable tt;
60     t.prepare(tt);
61     PointViewSet ts = t.execute(tt);
62     EXPECT_EQ(ts.size(), 1U);
63     PointViewPtr tv = *ts.begin();
64 
65     PointTable lt;
66     l.prepare(lt);
67     PointViewSet ls = l.execute(lt);
68     EXPECT_EQ(ls.size(), 1U);
69     PointViewPtr lv = *ls.begin();
70 
71     EXPECT_EQ(tv->size(), lv->size());
72 
73     // Validate some point data.
74     for (PointId i = 0; i < lv->size(); ++i)
75     {
76         EXPECT_DOUBLE_EQ(tv->getFieldAs<float>(Dimension::Id::X, i),
77                          lv->getFieldAs<float>(Dimension::Id::X, i));
78         EXPECT_DOUBLE_EQ(tv->getFieldAs<float>(Dimension::Id::Y, i),
79                          lv->getFieldAs<float>(Dimension::Id::Y, i));
80         EXPECT_DOUBLE_EQ(tv->getFieldAs<float>(Dimension::Id::Z, i),
81                          lv->getFieldAs<float>(Dimension::Id::Z, i));
82     }
83 }
84 
comparePcdPcd(const std::string & srcFilename,const std::string & dstFilename)85 void comparePcdPcd(const std::string& srcFilename,
86                    const std::string& dstFilename)
87 {
88     Options pcdOptions;
89 
90     comparePcdPcd(srcFilename, pcdOptions, dstFilename);
91 }
92 
compareLasPcd(const std::string & lasFilename,Options & pcdOptions,const std::string & pcdFilename)93 void compareLasPcd(const std::string& lasFilename, Options& pcdOptions,
94                    const std::string& pcdFilename)
95 {
96     PcdReader t;
97     pcdOptions.add("filename", pcdFilename);
98     t.setOptions(pcdOptions);
99 
100     LasReader l;
101     Options lo;
102     lo.add("filename", lasFilename);
103     l.setOptions(lo);
104 
105     PointTable tt;
106     t.prepare(tt);
107     PointViewSet ts = t.execute(tt);
108     EXPECT_EQ(ts.size(), 1U);
109     PointViewPtr tv = *ts.begin();
110 
111     PointTable lt;
112     l.prepare(lt);
113     PointViewSet ls = l.execute(lt);
114     EXPECT_EQ(ls.size(), 1U);
115     PointViewPtr lv = *ls.begin();
116 
117     EXPECT_EQ(tv->size(), lv->size());
118 
119     // Validate some point data.
120     for (PointId i = 0; i < lv->size(); ++i)
121     {
122         EXPECT_DOUBLE_EQ(tv->getFieldAs<float>(Dimension::Id::X, i),
123                          lv->getFieldAs<float>(Dimension::Id::X, i));
124         EXPECT_DOUBLE_EQ(tv->getFieldAs<float>(Dimension::Id::Y, i),
125                          lv->getFieldAs<float>(Dimension::Id::Y, i));
126         EXPECT_DOUBLE_EQ(tv->getFieldAs<float>(Dimension::Id::Z, i),
127                          lv->getFieldAs<float>(Dimension::Id::Z, i));
128     }
129 }
130 
compareLasPcd(const std::string & lasFilename,const std::string & pcdFilename)131 void compareLasPcd(const std::string& lasFilename,
132                    const std::string& pcdFilename)
133 {
134     Options pcdOptions;
135 
136     compareLasPcd(lasFilename, pcdOptions, pcdFilename);
137 }
138 
TEST(PcdWriterTest,pcd2pcd)139 TEST(PcdWriterTest, pcd2pcd)
140 {
141     std::string outfile(Support::temppath("utm17.pcd"));
142     std::string infile(Support::datapath("pcd/utm17_space.pcd"));
143 
144     FileUtils::deleteFile(outfile);
145 
146     PcdReader r;
147     Options ro;
148 
149     ro.add("filename", infile);
150     r.setOptions(ro);
151 
152     PcdWriter w;
153     Options wo;
154 
155     wo.add("filename", outfile);
156     wo.add("order", "X,Y,Z");
157     wo.add("precision", 2);
158     w.setOptions(wo);
159     w.setInput(r);
160 
161     PointTable t;
162 
163     w.prepare(t);
164     w.execute(t);
165 
166     comparePcdPcd(infile, outfile);
167 }
168 
TEST(PcdWriterTest,las2pcd)169 TEST(PcdWriterTest, las2pcd)
170 {
171     std::string outfile(Support::temppath("utm17.pcd"));
172     std::string infile(Support::datapath("las/utm17.las"));
173 
174     FileUtils::deleteFile(outfile);
175 
176     LasReader r;
177     Options ro;
178 
179     ro.add("filename", infile);
180     r.setOptions(ro);
181 
182     PcdWriter w;
183     Options wo;
184 
185     wo.add("filename", outfile);
186     wo.add("order", "X,Y,Z");
187     wo.add("precision", 2);
188     w.setOptions(wo);
189     w.setInput(r);
190 
191     PointTable t;
192 
193     w.prepare(t);
194     w.execute(t);
195 
196     compareLasPcd(infile, outfile);
197 }
198 
TEST(PcdWriterTest,precision)199 TEST(PcdWriterTest, precision)
200 {
201     using namespace Dimension;
202 
203     PointTable table;
204     table.layout()->registerDims({Id::X, Id::Y, Id::Z, Id::Intensity});
205 
206     PointViewPtr view(new PointView(table));
207     view->setField(Id::X, 0, 1);
208     view->setField(Id::Y, 0, 1);
209     view->setField(Id::Z, 0, 1);
210     view->setField(Id::Intensity, 0, 1);
211 
212     view->setField(Id::X, 1, 2.2222222222);
213     view->setField(Id::Y, 1, 2.2222222222);
214     view->setField(Id::Z, 1, 2.2222222222);
215     view->setField(Id::Intensity, 1, 2.22222222);
216 
217     view->setField(Id::X, 2, 3.33);
218     view->setField(Id::Y, 2, 3.33);
219     view->setField(Id::Z, 2, 3.33);
220     view->setField(Id::Intensity, 2, 3.33);
221 
222     BufferReader r;
223     r.addView(view);
224 
225     std::string outfile(Support::temppath("precision.pcd"));
226 
227     PcdWriter w;
228 
229     Options o;
230     o.add("precision", 5);
231     o.add("order", "X=Float:0,Y=Float:0,Z=Float:0,Intensity=Float:0");
232     o.add("filename", outfile);
233 
234     w.setInput(r);
235     w.setOptions(o);
236 
237     w.prepare(table);
238     w.execute(table);
239 
240     PcdReader pr;
241     Options po;
242     po.add("filename", outfile);
243     pr.setOptions(po);
244     PointTable t;
245     pr.prepare(t);
246     PointViewSet pvs = pr.execute(t);
247 
248     PointViewPtr v = *pvs.begin();
249     EXPECT_EQ(3U, v->size());
250 
251     // Validate some point data.
252     EXPECT_DOUBLE_EQ(1, v->getFieldAs<float>(Dimension::Id::X, 0));
253     EXPECT_DOUBLE_EQ(1, v->getFieldAs<float>(Dimension::Id::Y, 0));
254     EXPECT_DOUBLE_EQ(1, v->getFieldAs<float>(Dimension::Id::Z, 0));
255 
256     EXPECT_DOUBLE_EQ(2, v->getFieldAs<float>(Dimension::Id::X, 1));
257     EXPECT_DOUBLE_EQ(2, v->getFieldAs<float>(Dimension::Id::Y, 1));
258     EXPECT_DOUBLE_EQ(2, v->getFieldAs<float>(Dimension::Id::Z, 1));
259 
260     EXPECT_DOUBLE_EQ(3, v->getFieldAs<float>(Dimension::Id::X, 2));
261     EXPECT_DOUBLE_EQ(3, v->getFieldAs<float>(Dimension::Id::Y, 2));
262     EXPECT_DOUBLE_EQ(3, v->getFieldAs<float>(Dimension::Id::Z, 2));
263 }
264 
TEST(PcdWriterTest,binaryPdalTypes)265 TEST(PcdWriterTest, binaryPdalTypes)
266 {
267     using namespace Dimension;
268 
269     PointTable table;
270     table.layout()->registerDims({Id::X, Id::Y, Id::Z, Id::Intensity});
271 
272     PointViewPtr view(new PointView(table));
273     view->setField(Id::X, 0, 1);
274     view->setField(Id::Y, 0, 1);
275     view->setField(Id::Z, 0, 1);
276     view->setField(Id::Intensity, 0, 1);
277 
278     view->setField(Id::X, 1, 2.2222222222);
279     view->setField(Id::Y, 1, 2.2222222222);
280     view->setField(Id::Z, 1, 2.2222222222);
281     view->setField(Id::Intensity, 1, 2.22222222);
282 
283     view->setField(Id::X, 2, 3.33);
284     view->setField(Id::Y, 2, 3.33);
285     view->setField(Id::Z, 2, 3.33);
286     view->setField(Id::Intensity, 2, 3.33);
287 
288     BufferReader r;
289     r.addView(view);
290 
291     std::string outfile(Support::temppath("binary-test.pcd"));
292 
293     PcdWriter w;
294 
295     Options o;
296     o.add("order", "X=Float,Y=Float,Z=Float,Intensity=Unsigned32");
297     o.add("compression", "binary");
298     o.add("filename", outfile);
299 
300     w.setInput(r);
301     w.setOptions(o);
302 
303     w.prepare(table);
304     w.execute(table);
305 
306     PcdReader pr;
307     Options po;
308     po.add("filename", outfile);
309     pr.setOptions(po);
310     PointTable t;
311     pr.prepare(t);
312     PointViewSet pvs = pr.execute(t);
313 
314     PointViewPtr v = *pvs.begin();
315     EXPECT_EQ(3U, v->size());
316 
317     // Validate some point data.
318     EXPECT_DOUBLE_EQ(1, v->getFieldAs<float>(Dimension::Id::X, 0));
319     EXPECT_DOUBLE_EQ(1, v->getFieldAs<float>(Dimension::Id::Y, 0));
320     EXPECT_DOUBLE_EQ(1, v->getFieldAs<float>(Dimension::Id::Z, 0));
321     EXPECT_EQ(1, v->getFieldAs<int>(Dimension::Id::Intensity, 0));
322 
323     EXPECT_NEAR(2.2222222222, v->getFieldAs<float>(Dimension::Id::X, 1),
324         0.0001);
325     EXPECT_NEAR(2.2222222222, v->getFieldAs<float>(Dimension::Id::Y, 1),
326         0.0001);
327     EXPECT_NEAR(2.2222222222, v->getFieldAs<float>(Dimension::Id::Z, 1),
328         0.0001);
329     EXPECT_EQ(2, v->getFieldAs<int>(Dimension::Id::Intensity, 1));
330 
331     EXPECT_NEAR(3.33, v->getFieldAs<float>(Dimension::Id::X, 2), 0.0001);
332     EXPECT_NEAR(3.33, v->getFieldAs<float>(Dimension::Id::Y, 2), 0.0001);
333     EXPECT_NEAR(3.33, v->getFieldAs<float>(Dimension::Id::Z, 2), 0.0001);
334     EXPECT_EQ(3, v->getFieldAs<int>(Dimension::Id::Intensity, 2));
335 }
336