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