1 //
2 // (C) Copyright 2010 Michael P. Gerlek (mpg@flaxen.com)
3 // Distributed under the BSD License
4 // (See accompanying file LICENSE.txt or copy at
5 // http://www.opensource.org/licenses/bsd-license.php)
6 //
7 
8 #ifdef HAVE_LASZIP
9 
10 #include <liblas/liblas.hpp>
11 #include <tut/tut.hpp>
12 #include <cstdio>
13 #include <bitset>
14 #include <fstream>
15 #include <string>
16 #include "liblas_test.hpp"
17 #include "common.hpp"
18 
19 namespace tut
20 {
21     struct zipwriter_data
22     {
23         std::string file_laz;
24         std::string header_10;
25         std::string header_10_vlr;
26         std::string header_12;
27         std::string header_12_vlr;
28         std::string header_10_compressed;
29         std::string header_10_compressed_vlr;
30         std::string header_12_compressed;
31         std::string header_12_compressed_vlr;
32         std::string header_12_padded;
33         std::string header_12_too_small_pad;
34 
zipwriter_datatut::zipwriter_data35         zipwriter_data() :
36             file_laz(g_test_data_path + "//tmp.laz"),
37             header_10(g_test_data_path + "//header-1.0-test.las"),
38             header_10_vlr(g_test_data_path + "//header-1.0-vlr-test.las"),
39             header_12(g_test_data_path + "//header-1.2-test.las"),
40             header_12_vlr(g_test_data_path + "//header-1.2-vlr-test.las"),
41             header_10_compressed(g_test_data_path + "//header-1.0-compressed-test.laz"),
42             header_10_compressed_vlr(g_test_data_path + "//header-1.0-compressed-test.laz"),
43             header_12_compressed(g_test_data_path + "//header-1.2-compressed-test.laz"),
44             header_12_compressed_vlr(g_test_data_path + "//header-1.2-compressed-test.laz"),
45             header_12_padded(g_test_data_path + "//header-1.2-padded.laz"),
46             header_12_too_small_pad(g_test_data_path + "//header-1.2-too-small-pad.laz")
47         {}
48 
~zipwriter_datatut::zipwriter_data49         ~zipwriter_data()
50         {
51             cleanup(file_laz);
52             cleanup(header_10);
53             cleanup(header_10_vlr);
54             cleanup(header_12);
55             cleanup(header_12_vlr);
56             cleanup(header_10_compressed);
57             cleanup(header_10_compressed_vlr);
58             cleanup(header_12_compressed);
59             cleanup(header_12_compressed_vlr);
60             cleanup(header_12_padded);
61             cleanup(header_12_too_small_pad);
62 
63         }
64 
cleanuptut::zipwriter_data65         void cleanup(std::string const& input)
66         {
67             const int ret = std::remove(input.c_str());
68             if (0 != ret)
69             {
70                 ; // ignore, file may not exist
71             }
72         }
73 
setuptut::zipwriter_data74         void setup(  std::string const& input,
75                 liblas::Header const& header)
76         {
77 
78             std::ofstream ofs;
79             ofs.open(input.c_str(), std::ios::out | std::ios::binary);
80 
81             liblas::Writer writer(ofs, header);
82 
83             liblas::Point point(&writer.GetHeader());
84 
85             // Write 1st point
86             point.SetCoordinates(10, 20, 30);
87             point.SetIntensity(5);
88             point.SetReturnNumber(1);
89             point.SetNumberOfReturns(1);
90             point.SetScanDirection(1);
91             point.SetFlightLineEdge(1);
92             point.SetClassification(7);
93             point.SetScanAngleRank(90);
94             point.SetUserData(0);
95             point.SetPointSourceID(1);
96 
97             writer.WritePoint(point);
98 
99             // write 2nd point
100             point.SetCoordinates(40, 50, 60);
101             point.SetPointSourceID(2);
102             writer.WritePoint(point);
103 
104             // write 3rd point
105             point.SetCoordinates(70, 80, 90);
106             point.SetPointSourceID(3);
107             writer.WritePoint(point);
108 
109         }
110 
FetchHeadertut::zipwriter_data111         liblas::Header FetchHeader(std::string input)
112         {
113             std::ifstream ifs;
114             ifs.open(input.c_str(), std::ios::in | std::ios::binary);
115             ensure(ifs.is_open());
116 
117             liblas::ReaderFactory factory;
118             liblas::Reader reader = factory.CreateWithStream(ifs);
119             return reader.GetHeader();
120         }
121 
ConstructVLRtut::zipwriter_data122         liblas::VariableRecord ConstructVLR()
123         {
124             liblas::VariableRecord r;
125 
126             std::vector<boost::uint8_t> vdata;
127             vdata.resize(256);
128             for(int i=0; i < 256; i++)
129             {
130                 vdata[i] = (boost::uint8_t)i;
131             }
132             r.SetReserved(0xAABB);
133             r.SetUserId("HOBU");
134             r.SetRecordId(1234);
135             r.SetDescription("some lovely text");
136             r.SetData(vdata);
137 
138             r.SetRecordLength((boost::uint16_t)vdata.size());
139             return r;
140         }
141     };
142 
143     typedef test_group<zipwriter_data> tg;
144     typedef tg::object to;
145 
146     tg test_group_zipwriter("liblas::ZipWriter");
147 
148     // Test ability to make a compressed header
149     template<>
150     template<>
test()151     void to::test<1>()
152     {
153         // Create new LAS file using default header block
154         {
155             std::ofstream ofs;
156             ofs.open(file_laz.c_str(), std::ios::out | std::ios::binary);
157 
158             // LAS 1.2, Point Format 0
159             liblas::Header header;
160             ensure_equals(header.Compressed(), false);
161             header.SetCompressed(true);
162             ensure_equals(header.Compressed(), true);
163 
164             liblas::Writer writer(ofs, header);
165         }
166 
167         // Read previously created LAS file and check its header block, laszip VLR
168         {
169             std::ifstream ifs;
170             ifs.open(file_laz.c_str(), std::ios::in | std::ios::binary);
171             ensure(ifs.is_open());
172 
173             liblas::ReaderFactory factory;
174             liblas::Reader reader = factory.CreateWithStream(ifs);
175 
176             ensure_equals(reader.GetHeader().Compressed(), true);
177 
178             test_laszip_vlr(reader.GetHeader());
179         }
180 
181         return;
182     }
183 
184     // Test ability to write a few points, using the writer factory
185     template<>
186     template<>
test()187     void to::test<2>()
188     {
189         {
190             std::ofstream ofs;
191             ofs.open(file_laz.c_str(), std::ios::out | std::ios::binary);
192 
193             // LAS 1.1, Point Format 0
194             liblas::Header header;
195             header.SetCompressed(true);
196 
197             liblas::Writer writer(ofs, header);
198 
199             liblas::Point point(&writer.GetHeader());
200 
201             // Write 1st point
202             point.SetCoordinates(10, 20, 30);
203             point.SetIntensity(5);
204             point.SetReturnNumber(1);
205             point.SetNumberOfReturns(1);
206             point.SetScanDirection(1);
207             point.SetFlightLineEdge(1);
208             point.SetClassification(7);
209             point.SetScanAngleRank(90);
210             point.SetUserData(0);
211             point.SetPointSourceID(1);
212 
213             writer.WritePoint(point);
214 
215             // write 2nd point
216             point.SetCoordinates(40, 50, 60);
217             point.SetPointSourceID(2);
218             writer.WritePoint(point);
219 
220             // write 3rd point
221             point.SetCoordinates(70, 80, 90);
222             point.SetPointSourceID(3);
223             writer.WritePoint(point);
224         }
225 
226         // Read previously create LAS file with 3 point records
227         {
228             std::ifstream ifs;
229             ifs.open(file_laz.c_str(), std::ios::in | std::ios::binary);
230             ensure(ifs.is_open());
231 
232             liblas::ReaderFactory factory;
233             liblas::Reader reader = factory.CreateWithStream(ifs);
234 
235             ensure_equals(reader.GetHeader().Compressed(), true);
236 
237             liblas::Point point(&reader.GetHeader()); // reusable cache
238 
239             // read 1st point
240             bool ok = reader.ReadNextPoint();
241             ensure_equals(ok, true);
242             point = reader.GetPoint();
243 
244             ensure_distance(point.GetX(), 10.0, 0.1);
245             ensure_distance(point.GetY(), 20.0, 0.1);
246             ensure_distance(point.GetZ(), 30.0, 0.1);
247             ensure_equals(point.GetIntensity(), 5);
248             ensure_equals(point.GetReturnNumber(), 1);
249             ensure_equals(point.GetNumberOfReturns(), 1);
250             ensure_equals(point.GetScanDirection(), 1);
251             ensure_equals(point.GetFlightLineEdge(), 1);
252             ensure_equals(point.GetScanAngleRank(), 90);
253             ensure_equals(point.GetUserData(), 0);
254             ensure_equals(point.GetPointSourceID(), 1);
255 
256             typedef liblas::Classification::bitset_type bitset_type;
257             ensure_equals(bitset_type(point.GetClassification()), bitset_type(7));
258 
259             // read 2nd point
260             ok = reader.ReadNextPoint();
261             ensure_equals(ok, true);
262             point = reader.GetPoint();
263 
264             ensure_distance(point.GetX(), 40.0, 0.1);
265             ensure_distance(point.GetY(), 50.0, 0.1);
266             ensure_distance(point.GetZ(), 60.0, 0.1);
267             ensure_equals(point.GetIntensity(), 5);
268             ensure_equals(point.GetReturnNumber(), 1);
269             ensure_equals(point.GetNumberOfReturns(), 1);
270             ensure_equals(point.GetScanDirection(), 1);
271             ensure_equals(point.GetFlightLineEdge(), 1);
272             ensure_equals(point.GetScanAngleRank(), 90);
273             ensure_equals(point.GetUserData(), 0);
274             ensure_equals(point.GetPointSourceID(), 2);
275 
276             // read 3rd point
277             ok = reader.ReadNextPoint();
278             ensure_equals(ok, true);
279             point = reader.GetPoint();
280 
281             ensure_distance(point.GetX(), 70.0, 0.1);
282             ensure_distance(point.GetY(), 80.0, 0.1);
283             ensure_distance(point.GetZ(), 90.0, 0.1);
284             ensure_equals(point.GetIntensity(), 5);
285             ensure_equals(point.GetReturnNumber(), 1);
286             ensure_equals(point.GetNumberOfReturns(), 1);
287             ensure_equals(point.GetScanDirection(), 1);
288             ensure_equals(point.GetFlightLineEdge(), 1);
289             ensure_equals(point.GetScanAngleRank(), 90);
290             ensure_equals(point.GetUserData(), 0);
291             ensure_equals(point.GetPointSourceID(), 3);
292 
293             typedef liblas::Classification::bitset_type bitset_type;
294             ensure_equals(bitset_type(point.GetClassification()), bitset_type(7));
295 
296             return;
297         }
298     }
299 
300     // Test header integrity
301     template<>
302     template<>
test()303     void to::test<3>()
304     {
305 
306         {
307             liblas::Header header;
308 
309             header.SetVersionMinor(0);
310             header.SetHeaderPadding(0);
311             header.SetCompressed(false);
312 
313             setup(header_10, header);
314         }
315 
316         {
317             liblas::Header header = FetchHeader(header_10);
318 
319             ensure_equals("1.0 no-vlr iscompressed?", header.Compressed(), false);
320 
321             // compression is going to add the LASzip VLR
322             ensure_equals("1.0 no-vlr data offset", header.GetDataOffset(), (boost::uint32_t)229);
323             ensure_equals("1.0 no-vlr header padding", header.GetHeaderPadding(), (boost::uint32_t)2);
324 
325         }
326 
327         {
328             liblas::Header header;
329 
330             header.SetVersionMinor(0);
331             header.SetHeaderPadding(0);
332             header.SetCompressed(false);
333             liblas::VariableRecord v = ConstructVLR();
334             header.AddVLR(v);
335 
336             setup(header_10_vlr, header);
337         }
338 
339         {
340             liblas::Header header = FetchHeader(header_10_vlr);
341 
342             ensure_equals("1.0 vlr iscompressed?", header.Compressed(), false);
343 
344             // compression is going to add the LASzip VLR
345             ensure_equals("1.0 vlr data offset", header.GetDataOffset(), (boost::uint32_t)539);
346             ensure_equals("1.0 vlr header padding", header.GetHeaderPadding(), (boost::uint32_t)2);
347 
348         }
349 
350         {
351             liblas::Header header;
352 
353             header.SetVersionMinor(2);
354             header.SetHeaderPadding(0);
355             header.SetCompressed(false);
356 
357             setup(header_12, header);
358         }
359 
360         {
361             liblas::Header header = FetchHeader(header_12);
362 
363             ensure_equals("1.2 no-vlr iscompressed?", header.Compressed(), false);
364 
365             // compression is going to add the LASzip VLR
366             ensure_equals("1.2 no-vlr data offset", header.GetDataOffset(), (boost::uint32_t)227);
367             ensure_equals("1.2 no-vlr header padding", header.GetHeaderPadding(), (boost::uint32_t)0);
368 
369         }
370 
371         {
372             liblas::Header header;
373 
374             header.SetVersionMinor(2);
375             header.SetHeaderPadding(0);
376             header.SetCompressed(false);
377             liblas::VariableRecord v = ConstructVLR();
378             header.AddVLR(v);
379 
380             setup(header_12_vlr, header);
381         }
382 
383         {
384             liblas::Header header = FetchHeader(header_12_vlr);
385 
386             ensure_equals("1.2 vlr iscompressed?", header.Compressed(), false);
387 
388             // compression is going to add the LASzip VLR
389             ensure_equals("1.2 vlr data offset", header.GetDataOffset(), (boost::uint32_t)537);
390             ensure_equals("1.2 vlr header padding", header.GetHeaderPadding(), (boost::uint32_t)0);
391 
392         }
393 
394         {
395             liblas::Header header;
396 
397             header.SetVersionMinor(0);
398             header.SetHeaderPadding(0);
399             header.SetCompressed(true);
400 
401             setup(header_10_compressed, header);
402         }
403 
404         {
405             liblas::Header header = FetchHeader(header_10_compressed);
406 
407             ensure_equals("1.0 no-vlr compressed iscompressed?", header.Compressed(), true);
408 
409             // compression is going to add the LASzip VLR
410             ensure_equals("1.0 no-vlr compressed data offset", header.GetDataOffset(), (boost::uint32_t)335);
411             ensure_equals("1.0 no-vlr compressed header padding", header.GetHeaderPadding(), (boost::uint32_t)2);
412 
413         }
414 
415         {
416             liblas::Header header;
417 
418             header.SetVersionMinor(2);
419             header.SetHeaderPadding(0);
420             header.SetCompressed(true);
421 
422             setup(header_12_compressed, header);
423         }
424 
425         {
426             liblas::Header header = FetchHeader(header_12_compressed);
427 
428             ensure_equals("1.2 no-vlr compressed iscompressed?", header.Compressed(), true);
429 
430             // compression is going to add the LASzip VLR
431             ensure_equals("1.2 no-vlr compressed data offset", header.GetDataOffset(), (boost::uint32_t)333);
432             ensure_equals("1.2 no-vlr compressed header padding", header.GetHeaderPadding(), (boost::uint32_t)0);
433 
434         }
435 
436         {
437             liblas::Header header;
438 
439             header.SetVersionMinor(2);
440             header.SetHeaderPadding(0);
441             header.SetCompressed(true);
442             liblas::VariableRecord v = ConstructVLR();
443             header.AddVLR(v);
444 
445             setup(header_12_compressed_vlr, header);
446         }
447 
448         {
449             liblas::Header header = FetchHeader(header_12_compressed_vlr);
450 
451             ensure_equals("1.2 vlr compressed iscompressed?", header.Compressed(), true);
452 
453             // compression is going to add the LASzip VLR
454             ensure_equals("1.2 vlr compressed data offset", header.GetDataOffset(), (boost::uint32_t)643);
455             ensure_equals("1.2 vlr compressed header padding", header.GetHeaderPadding(), (boost::uint32_t)0);
456 
457         }
458 
459         {
460             liblas::Header header;
461 
462             header.SetVersionMinor(2);
463             header.SetHeaderPadding(0);
464             header.SetCompressed(true);
465             header.SetDataOffset(1024);
466             liblas::VariableRecord v = ConstructVLR();
467             header.AddVLR(v);
468 
469             setup(header_12_padded, header);
470         }
471 
472         {
473             liblas::Header header = FetchHeader(header_12_padded);
474 
475             ensure_equals("1.2 header_12_padded iscompressed?", header.Compressed(), true);
476 
477             // compression is going to add the LASzip VLR
478             ensure_equals("1.2 header_12_padded data offset", header.GetDataOffset(), (boost::uint32_t)1024);
479             ensure_equals("1.2 header_12_padded header padding", header.GetHeaderPadding(), (boost::uint32_t)381);
480 
481         }
482 
483         {
484             liblas::Header header;
485 
486             header.SetVersionMinor(2);
487             header.SetHeaderPadding(0);
488             header.SetCompressed(true);
489             header.SetDataOffset(440);
490             liblas::VariableRecord v = ConstructVLR();
491             header.AddVLR(v);
492 
493             setup(header_12_too_small_pad, header);
494         }
495 
496         {
497             liblas::Header header = FetchHeader(header_12_too_small_pad);
498 
499             ensure_equals("1.2 header_12_too_small_pad iscompressed?", header.Compressed(), true);
500 
501             // compression is going to add the LASzip VLR
502             ensure_equals("1.2 header_12_too_small_pad data offset", header.GetDataOffset(), (boost::uint32_t)643);
503             ensure_equals("1.2 header_12_too_small_pad header padding", header.GetHeaderPadding(), (boost::uint32_t)0);
504 
505         }
506     }
507 }
508 
509 #endif // HAVE_LASZIP
510