~ubuntu-branches/ubuntu/trusty/liblas/trusty-proposed

« back to all changes in this revision

Viewing changes to src/detail/writer/header.cpp

  • Committer: Package Import Robot
  • Author(s): Francesco Paolo Lovergine
  • Date: 2014-01-05 17:00:29 UTC
  • mfrom: (7.1.2 sid)
  • Revision ID: package-import@ubuntu.com-20140105170029-ddtp0j63x5jvck2u
Tags: 1.7.0+dfsg-2
Fixed missing linking of system boost component.
(closes: #733282)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************************************
 
2
 * $Id$
 
3
 *
 
4
 * Project:  libLAS - http://liblas.org - A BSD library for LAS format data.
 
5
 * Purpose:  LAS header writer implementation for C++ libLAS 
 
6
 * Author:   Howard Butler, hobu.inc@gmail.com
 
7
 *
 
8
 ******************************************************************************
 
9
 * Copyright (c) 2010, Howard Butler
 
10
 *
 
11
 * All rights reserved.
 
12
 * 
 
13
 * Redistribution and use in source and binary forms, with or without 
 
14
 * modification, are permitted provided that the following 
 
15
 * conditions are met:
 
16
 * 
 
17
 *     * Redistributions of source code must retain the above copyright 
 
18
 *       notice, this list of conditions and the following disclaimer.
 
19
 *     * Redistributions in binary form must reproduce the above copyright 
 
20
 *       notice, this list of conditions and the following disclaimer in 
 
21
 *       the documentation and/or other materials provided 
 
22
 *       with the distribution.
 
23
 *     * Neither the name of the Martin Isenburg or Iowa Department 
 
24
 *       of Natural Resources nor the names of its contributors may be 
 
25
 *       used to endorse or promote products derived from this software 
 
26
 *       without specific prior written permission.
 
27
 * 
 
28
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 
29
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 
30
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 
31
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 
32
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 
33
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 
34
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 
 
35
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
 
36
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
 
37
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
 
38
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
 
39
 * OF SUCH DAMAGE.
 
40
 ****************************************************************************/
 
41
 
 
42
#include <liblas/header.hpp>
 
43
#include <liblas/point.hpp>
 
44
#include <liblas/spatialreference.hpp>
 
45
#include <liblas/detail/writer/header.hpp>
 
46
#include <liblas/detail/private_utility.hpp>
 
47
#include <liblas/detail/zippoint.hpp>
 
48
// boost
 
49
#include <boost/cstdint.hpp>
 
50
// std
 
51
#include <cassert>
 
52
#include <cstdlib> // std::size_t
 
53
#include <algorithm>
 
54
#include <fstream>
 
55
#include <iosfwd>
 
56
#include <ostream>
 
57
#include <sstream>
 
58
#include <stdexcept>
 
59
#include <string>
 
60
#include <vector>
 
61
 
 
62
using namespace boost;
 
63
using namespace std;
 
64
 
 
65
namespace liblas { namespace detail { namespace writer {
 
66
 
 
67
Header::Header(std::ostream& ofs, boost::uint32_t& count, liblas::Header const& header)
 
68
    : m_ofs(ofs)
 
69
    , m_header(header)
 
70
    , m_pointCount(count)
 
71
{
 
72
}
 
73
 
 
74
void Header::write()
 
75
{
 
76
 
 
77
    uint8_t n1 = 0;
 
78
    uint16_t n2 = 0;
 
79
    uint32_t n4 = 0;
 
80
    
 
81
    // Figure out how many points we already have.  
 
82
    // Figure out if we're in append mode.  If we are, we can't rewrite 
 
83
    // any of the VLRs including the Schema and SpatialReference ones.
 
84
    bool bAppendMode = false;
 
85
 
 
86
    // This test should only be true if we were opened in both 
 
87
    // std::ios::in *and* std::ios::out
 
88
 
 
89
    // Seek to the beginning
 
90
    m_ofs.seekp(0, ios::beg);
 
91
    ios::pos_type begin = m_ofs.tellp();
 
92
 
 
93
    // Seek to the end
 
94
    m_ofs.seekp(0, ios::end);
 
95
    ios::pos_type end = m_ofs.tellp();
 
96
    if ((begin != end) && (end != static_cast<ios::pos_type>(0))) {
 
97
        bAppendMode = true;
 
98
    }
 
99
 
 
100
    // If we are in append mode, we are not touching *any* VLRs. 
 
101
    if (bAppendMode) 
 
102
    {
 
103
        // We're opened in append mode
 
104
        
 
105
        if (!m_header.Compressed())
 
106
        {
 
107
            ios::off_type points = end - static_cast<ios::off_type>(m_header.GetDataOffset());
 
108
            ios::off_type count = points / static_cast<ios::off_type>(m_header.GetDataRecordLength());
 
109
        
 
110
            if (points < 0) {
 
111
                std::ostringstream oss;
 
112
                oss << "The header's data offset, " << m_header.GetDataOffset() 
 
113
                    <<", is much larger than the size of the file, " << end
 
114
                    <<", and something is amiss.  Did you use the right header"
 
115
                    <<" offset value?";
 
116
                throw std::runtime_error(oss.str());
 
117
            }
 
118
            
 
119
            m_pointCount = static_cast<uint32_t>(count);
 
120
 
 
121
        } else {
 
122
            m_pointCount = m_header.GetPointRecordsCount();
 
123
        }
 
124
 
 
125
        // Position to the beginning of the file to start writing the header
 
126
        m_ofs.seekp(0, ios::beg);
 
127
 
 
128
    } 
 
129
    else 
 
130
    {
 
131
        
 
132
        // Rewrite the georeference VLR entries if they exist
 
133
        m_header.DeleteVLRs("liblas", 2112);
 
134
        m_header.SetGeoreference();
 
135
 
 
136
        // If we have a custom schema, add the VLR and write it into the 
 
137
        // file.  
 
138
        if (m_header.GetSchema().IsCustom()) {
 
139
            
 
140
            // Wipe any schema-related VLRs we might have, as this is now out of date.
 
141
            m_header.DeleteVLRs("liblas", 7);
 
142
        
 
143
            VariableRecord v = m_header.GetSchema().GetVLR();
 
144
            std::cout <<  m_header.GetSchema()<< std::endl;
 
145
            m_header.AddVLR(v);
 
146
        }
 
147
    
 
148
        // add the laszip VLR, if needed
 
149
        if (m_header.Compressed())
 
150
        {
 
151
#ifdef HAVE_LASZIP
 
152
            m_header.DeleteVLRs("laszip encoded", 22204);
 
153
            ZipPoint zpd(m_header.GetDataFormatId(), m_header.GetVLRs());
 
154
            VariableRecord v;
 
155
            zpd.ConstructVLR(v);
 
156
            m_header.AddVLR(v);
 
157
#else
 
158
            throw configuration_error("LASzip compression support not enabled in this libLAS configuration.");
 
159
#endif
 
160
        }
 
161
        else
 
162
        {
 
163
            m_header.DeleteVLRs("laszip encoded", 22204);
 
164
        }
 
165
        
 
166
        int32_t existing_padding = m_header.GetDataOffset() - 
 
167
                                  (m_header.GetVLRBlockSize() + 
 
168
                                   m_header.GetHeaderSize());
 
169
 
 
170
        if (existing_padding < 0) 
 
171
        {
 
172
            int32_t d = abs(existing_padding);
 
173
            
 
174
            // If our required VLR space is larger than we have 
 
175
            // room for, we have no padding.  AddVLRs will take care 
 
176
            // of incrementing up the space it needs.
 
177
            if (static_cast<boost::int32_t>(m_header.GetVLRBlockSize()) > d)
 
178
            {
 
179
                m_header.SetHeaderPadding(0);
 
180
            } else {
 
181
                m_header.SetHeaderPadding(d - m_header.GetVLRBlockSize());
 
182
            }
 
183
        } else {
 
184
            // cast is safe, we've already checked for < 0
 
185
            if (static_cast<uint32_t>(existing_padding) >= m_header.GetHeaderPadding())
 
186
            {
 
187
                m_header.SetHeaderPadding(existing_padding);
 
188
            }
 
189
            else {
 
190
                m_header.SetHeaderPadding(m_header.GetHeaderPadding() + existing_padding);
 
191
            }
 
192
 
 
193
        }
 
194
 
 
195
        m_header.SetDataOffset( m_header.GetHeaderSize() + 
 
196
                                m_header.GetVLRBlockSize() + 
 
197
                                m_header.GetHeaderPadding());
 
198
    }
 
199
 
 
200
    
 
201
    // 1. File Signature
 
202
    std::string const filesig(m_header.GetFileSignature());
 
203
    assert(filesig.size() == 4);
 
204
    detail::write_n(m_ofs, filesig, 4);
 
205
    
 
206
    
 
207
    // 2. File SourceId / Reserved
 
208
    if (m_header.GetVersionMinor()  ==  0) {
 
209
        n4 = m_header.GetReserved();
 
210
        detail::write_n(m_ofs, n4, sizeof(n4));         
 
211
    } else if (m_header.GetVersionMinor()  >  0) {
 
212
        n2 = m_header.GetFileSourceId();
 
213
        detail::write_n(m_ofs, n2, sizeof(n2));                
 
214
        n2 = m_header.GetReserved();
 
215
        detail::write_n(m_ofs, n2, sizeof(n2));        
 
216
    } 
 
217
 
 
218
    // 3-6. GUID data
 
219
    uint32_t d1 = 0;
 
220
    uint16_t d2 = 0;
 
221
    uint16_t d3 = 0;
 
222
    uint8_t d4[8] = { 0 };
 
223
    liblas::guid g = m_header.GetProjectId();
 
224
    g.output_data(d1, d2, d3, d4);
 
225
    detail::write_n(m_ofs, d1, sizeof(d1));
 
226
    detail::write_n(m_ofs, d2, sizeof(d2));
 
227
    detail::write_n(m_ofs, d3, sizeof(d3));
 
228
    detail::write_n(m_ofs, d4, sizeof(d4));
 
229
    
 
230
    // 7. Version major
 
231
    n1 = m_header.GetVersionMajor();
 
232
    assert(1 == n1);
 
233
    detail::write_n(m_ofs, n1, sizeof(n1));
 
234
    
 
235
    // 8. Version minor
 
236
    n1 = m_header.GetVersionMinor();
 
237
    detail::write_n(m_ofs, n1, sizeof(n1));
 
238
 
 
239
    // 9. System ID
 
240
    std::string sysid(m_header.GetSystemId(true));
 
241
    assert(sysid.size() == 32);
 
242
    detail::write_n(m_ofs, sysid, 32);
 
243
    
 
244
    // 10. Generating Software ID
 
245
    std::string softid(m_header.GetSoftwareId(true));
 
246
    assert(softid.size() == 32);
 
247
    detail::write_n(m_ofs, softid, 32);
 
248
 
 
249
    // 11. Flight Date Julian
 
250
    n2 = m_header.GetCreationDOY();
 
251
    detail::write_n(m_ofs, n2, sizeof(n2));
 
252
 
 
253
    // 12. Year
 
254
    n2 = m_header.GetCreationYear();
 
255
    detail::write_n(m_ofs, n2, sizeof(n2));
 
256
 
 
257
    // 13. Header Size
 
258
    n2 = m_header.GetHeaderSize();
 
259
    assert(227 <= n2);
 
260
    detail::write_n(m_ofs, n2, sizeof(n2));
 
261
 
 
262
    // 14. Offset to data
 
263
    n4 = m_header.GetDataOffset();
 
264
    detail::write_n(m_ofs, n4, sizeof(n4));
 
265
 
 
266
    // 15. Number of variable length records
 
267
    n4 = m_header.GetRecordsCount();
 
268
    detail::write_n(m_ofs, n4, sizeof(n4));
 
269
 
 
270
    // 16. Point Data Format ID
 
271
    n1 = static_cast<uint8_t>(m_header.GetDataFormatId());
 
272
    uint8_t n1tmp = n1;
 
273
    if (m_header.Compressed()) // high bit set indicates laszip compression
 
274
        n1tmp |= 0x80;
 
275
    detail::write_n(m_ofs, n1tmp, sizeof(n1tmp));
 
276
 
 
277
    // 17. Point Data Record Length
 
278
    n2 = m_header.GetDataRecordLength();
 
279
    detail::write_n(m_ofs, n2, sizeof(n2));
 
280
 
 
281
    // 18. Number of point records
 
282
    // This value is updated if necessary, see UpdateHeader function.
 
283
    n4 = m_header.GetPointRecordsCount();
 
284
    detail::write_n(m_ofs, n4, sizeof(n4));
 
285
 
 
286
    // 19. Number of points by return
 
287
    std::vector<uint32_t>::size_type const srbyr = 5;
 
288
    std::vector<uint32_t> const& vpbr = m_header.GetPointRecordsByReturnCount();
 
289
    // TODO: fix this for 1.3, which has srbyr = 7;  See detail/reader/header.cpp for more details
 
290
    // assert(vpbr.size() <= srbyr);
 
291
    uint32_t pbr[srbyr] = { 0 };
 
292
    std::copy(vpbr.begin(), vpbr.begin() + srbyr, pbr); // FIXME: currently, copies only 5 records, to be improved
 
293
    detail::write_n(m_ofs, pbr, sizeof(pbr));
 
294
 
 
295
    // 20-22. Scale factors
 
296
    detail::write_n(m_ofs, m_header.GetScaleX(), sizeof(double));
 
297
    detail::write_n(m_ofs, m_header.GetScaleY(), sizeof(double));
 
298
    detail::write_n(m_ofs, m_header.GetScaleZ(), sizeof(double));
 
299
 
 
300
    // 23-25. Offsets
 
301
    detail::write_n(m_ofs, m_header.GetOffsetX(), sizeof(double));
 
302
    detail::write_n(m_ofs, m_header.GetOffsetY(), sizeof(double));
 
303
    detail::write_n(m_ofs, m_header.GetOffsetZ(), sizeof(double));
 
304
 
 
305
    // 26-27. Max/Min X
 
306
    detail::write_n(m_ofs, m_header.GetMaxX(), sizeof(double));
 
307
    detail::write_n(m_ofs, m_header.GetMinX(), sizeof(double));
 
308
 
 
309
    // 28-29. Max/Min Y
 
310
    detail::write_n(m_ofs, m_header.GetMaxY(), sizeof(double));
 
311
    detail::write_n(m_ofs, m_header.GetMinY(), sizeof(double));
 
312
 
 
313
    // 30-31. Max/Min Z
 
314
    detail::write_n(m_ofs, m_header.GetMaxZ(), sizeof(double));
 
315
    detail::write_n(m_ofs, m_header.GetMinZ(), sizeof(double));
 
316
 
 
317
    if (!bAppendMode) 
 
318
    {
 
319
        WriteVLRs();
 
320
 
 
321
        // if we have padding, we should write it
 
322
        if (m_header.GetHeaderPadding() > 0) {
 
323
            m_ofs.seekp(m_header.GetHeaderSize() + m_header.GetVLRBlockSize(), std::ios::end);
 
324
            detail::write_n(m_ofs, "\0", m_header.GetHeaderPadding());
 
325
        }
 
326
 
 
327
        // Write the 1.0 pad signature if we need to.
 
328
        WriteLAS10PadSignature(); 
 
329
    }
 
330
 
 
331
    // If we already have points, we're going to put it at the end of the file.  
 
332
    // If we don't have any points,  we're going to leave it where it is.
 
333
    if (m_pointCount != 0)
 
334
    {
 
335
        m_ofs.seekp(0, std::ios::end);
 
336
    }
 
337
    else
 
338
    {
 
339
        m_ofs.seekp(m_header.GetDataOffset(), std::ios::beg);
 
340
    }
 
341
    
 
342
}
 
343
 
 
344
void Header::WriteVLRs() 
 
345
{
 
346
 
 
347
    // Seek to the end of the public header block (beginning of the VLRs)
 
348
    // to start writing
 
349
    m_ofs.seekp(m_header.GetHeaderSize(), std::ios::beg);
 
350
 
 
351
    int32_t diff = m_header.GetDataOffset() - GetRequiredHeaderSize();
 
352
    
 
353
    if (diff < 0) {
 
354
 
 
355
        m_header.SetDataOffset(GetRequiredHeaderSize());
 
356
        // Seek to the location of the data offset in the header and write a new one.
 
357
        m_ofs.seekp(96, std::ios::beg);
 
358
        detail::write_n(m_ofs, m_header.GetDataOffset(), sizeof(m_header.GetDataOffset()));
 
359
        m_ofs.seekp(m_header.GetHeaderSize(), std::ios::beg);
 
360
        
 
361
        // std::ostringstream oss;
 
362
        // oss << "Header is not large enough to contain VLRs.  Data offset is ";
 
363
        // oss << m_header.GetDataOffset() << " while the required total size ";
 
364
        // oss << "for the VLRs is " << GetRequiredHeaderSize();
 
365
        // throw std::runtime_error(oss.str());
 
366
    }
 
367
 
 
368
    for (uint32_t i = 0; i < m_header.GetRecordsCount(); ++i)
 
369
    {
 
370
        VariableRecord const &vlr = m_header.GetVLR(i);
 
371
 
 
372
        detail::write_n(m_ofs, vlr.GetReserved(), sizeof(uint16_t));
 
373
        detail::write_n(m_ofs, vlr.GetUserId(true).c_str(), 16);
 
374
        detail::write_n(m_ofs, vlr.GetRecordId(), sizeof(uint16_t));
 
375
        detail::write_n(m_ofs, vlr.GetRecordLength(), sizeof(uint16_t));
 
376
        detail::write_n(m_ofs, vlr.GetDescription(true).c_str(), 32);
 
377
        std::vector<uint8_t> const& data = vlr.GetData();
 
378
        std::streamsize const size = static_cast<std::streamsize>(data.size());
 
379
        detail::write_n(m_ofs, data.front(), size);
 
380
    }
 
381
 
 
382
 
 
383
 
 
384
}
 
385
 
 
386
boost::int32_t Header::GetRequiredHeaderSize() const
 
387
{
 
388
    return m_header.GetVLRBlockSize() + m_header.GetHeaderSize();
 
389
}
 
390
 
 
391
void Header::WriteLAS10PadSignature()
 
392
{
 
393
    // Only write pad signature bytes for LAS 1.0 files.  Any other files 
 
394
    // will not get the pad bytes and we are *not* allowing anyone to 
 
395
    // override this either - hobu
 
396
    
 
397
    if (m_header.GetVersionMinor() > 0) {
 
398
        return;
 
399
    }
 
400
 
 
401
    int32_t diff = m_header.GetDataOffset() - GetRequiredHeaderSize();
 
402
 
 
403
    if (diff < 2) {
 
404
        
 
405
        m_header.SetDataOffset(m_header.GetDataOffset() + 2);
 
406
        // Seek to the location of the data offset in the header and write a new one.
 
407
        m_ofs.seekp(96, std::ios::beg);
 
408
        detail::write_n(m_ofs, m_header.GetDataOffset(), sizeof(m_header.GetDataOffset()));
 
409
    }    
 
410
    
 
411
    
 
412
    // step back two bytes to write the pad bytes.  We should have already
 
413
    // determined by this point if a) they will fit b) they won't overwrite 
 
414
    // exiting real data 
 
415
    m_ofs.seekp(m_header.GetDataOffset() - 2, std::ios::beg);
 
416
    
 
417
    // Write the pad bytes.
 
418
    uint8_t const sgn1 = 0xCC;
 
419
    uint8_t const sgn2 = 0xDD;
 
420
    detail::write_n(m_ofs, sgn1, sizeof(uint8_t));
 
421
    detail::write_n(m_ofs, sgn2, sizeof(uint8_t));
 
422
}
 
423
 
 
424
 
 
425
}}} // namespace liblas::detail::writer