~ubuntu-branches/ubuntu/wily/liblas/wily

« back to all changes in this revision

Viewing changes to src/detail/writer10.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Francesco Paolo Lovergine
  • Date: 2009-10-02 12:36:21 UTC
  • Revision ID: james.westby@ubuntu.com-20091002123621-xrf0hhzxbwloga43
Tags: upstream-1.2.1
ImportĀ upstreamĀ versionĀ 1.2.1

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 1.0 writer implementation for C++ libLAS 
 
6
 * Author:   Mateusz Loskot, mateusz@loskot.net
 
7
 *
 
8
 ******************************************************************************
 
9
 * Copyright (c) 2008, Mateusz Loskot
 
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/detail/writer10.hpp>
 
43
#include <liblas/detail/utility.hpp>
 
44
#include <liblas/lasheader.hpp>
 
45
#include <liblas/laspoint.hpp>
 
46
#include <liblas/liblas.hpp>
 
47
// std
 
48
#include <vector>
 
49
#include <fstream>
 
50
#include <stdexcept>
 
51
#include <cstdlib> // std::size_t
 
52
#include <cassert>
 
53
 
 
54
namespace liblas { namespace detail { namespace v10 {
 
55
 
 
56
WriterImpl::WriterImpl(std::ostream& ofs) :
 
57
    Base(ofs), m_pointCount(0)
 
58
{
 
59
}
 
60
 
 
61
std::size_t WriterImpl::GetVersion() const
 
62
{
 
63
    return eLASVersion10;
 
64
}
 
65
 
 
66
void WriterImpl::WriteHeader(LASHeader& header)
 
67
{
 
68
    uint8_t n1 = 0;
 
69
    uint16_t n2 = 0;
 
70
    uint32_t n4 = 0;
 
71
 
 
72
    // Rewrite the georeference VLR entries if they exist
 
73
    header.SetGeoreference();
 
74
    
 
75
    // Seek to the beginning
 
76
    m_ofs.seekp(0, std::ios::beg);
 
77
    std::ios::pos_type beginning = m_ofs.tellp();
 
78
 
 
79
    // Seek to the end
 
80
    m_ofs.seekp(0, std::ios::end);
 
81
    std::ios::pos_type end = m_ofs.tellp();
 
82
    
 
83
    // Figure out how many points we already have.  Each point record 
 
84
    // should be 20 bytes long, and header.GetDataOffset tells
 
85
    // us the location to start counting points from.  
 
86
    
 
87
    // This test should only be true if we were opened in both 
 
88
    // std::ios::in *and* std::ios::out, otherwise it should return false 
 
89
    // and we won't adjust the point count.
 
90
    
 
91
    if ((beginning != end) && ((uint32_t)end != 0)) {
 
92
        m_pointCount = ((uint32_t) end - header.GetDataOffset())/header.GetDataRecordLength();
 
93
 
 
94
        // Position to the beginning of the file to start writing the header
 
95
        m_ofs.seekp(0, std::ios::beg);
 
96
    }
 
97
 
 
98
    // 1. File Signature
 
99
    std::string const filesig(header.GetFileSignature());
 
100
    assert(filesig.size() == 4);
 
101
    detail::write_n(m_ofs, filesig, 4);
 
102
    
 
103
    // 2. Reserved
 
104
    n4 = header.GetReserved();
 
105
    detail::write_n(m_ofs, n4, sizeof(n4));
 
106
 
 
107
    // 3-6. GUID data
 
108
    uint32_t d1 = 0;
 
109
    uint16_t d2 = 0;
 
110
    uint16_t d3 = 0;
 
111
    uint8_t d4[8] = { 0 };
 
112
    liblas::guid g = header.GetProjectId();
 
113
    g.output_data(d1, d2, d3, d4);
 
114
    detail::write_n(m_ofs, d1, sizeof(d1));
 
115
    detail::write_n(m_ofs, d2, sizeof(d2));
 
116
    detail::write_n(m_ofs, d3, sizeof(d3));
 
117
    detail::write_n(m_ofs, d4, sizeof(d4));
 
118
    
 
119
    // 7. Version major
 
120
    n1 = header.GetVersionMajor();
 
121
    assert(1 == n1);
 
122
    detail::write_n(m_ofs, n1, sizeof(n1));
 
123
    
 
124
    // 8. Version minor
 
125
    n1 = header.GetVersionMinor();
 
126
    assert(0 == n1);
 
127
    detail::write_n(m_ofs, n1, sizeof(n1));
 
128
 
 
129
    // 9. System ID
 
130
    std::string sysid(header.GetSystemId(true));
 
131
    assert(sysid.size() == 32);
 
132
    detail::write_n(m_ofs, sysid, 32);
 
133
    
 
134
    // 10. Generating Software ID
 
135
    std::string softid(header.GetSoftwareId(true));
 
136
    assert(softid.size() == 32);
 
137
    detail::write_n(m_ofs, softid, 32);
 
138
 
 
139
    // 11. Flight Date Julian
 
140
    n2 = header.GetCreationDOY();
 
141
    detail::write_n(m_ofs, n2, sizeof(n2));
 
142
 
 
143
    // 12. Year
 
144
    n2 = header.GetCreationYear();
 
145
    detail::write_n(m_ofs, n2, sizeof(n2));
 
146
 
 
147
    // 13. Header Size
 
148
    n2 = header.GetHeaderSize();
 
149
    assert(227 <= n2);
 
150
    detail::write_n(m_ofs, n2, sizeof(n2));
 
151
 
 
152
    // 14. Offset to data
 
153
    // Because we are 1.0, we must also add pad bytes to the end of the 
 
154
    // header.  This means resetting the dataoffset +=2, but we 
 
155
    // don't want to change the header's actual offset until after we 
 
156
    // write the VLRs or else we'll be off by 2 when we write the pad
 
157
    // bytes
 
158
    n4 = header.GetDataOffset() + 2;
 
159
    detail::write_n(m_ofs, n4, sizeof(n4));
 
160
 
 
161
    // 15. Number of variable length records
 
162
    // TODO: This value must be updated after new variable length record is added.
 
163
    n4 = header.GetRecordsCount();
 
164
    detail::write_n(m_ofs, n4, sizeof(n4));
 
165
 
 
166
    // 16. Point Data Format ID
 
167
    n1 = static_cast<uint8_t>(header.GetDataFormatId());
 
168
    detail::write_n(m_ofs, n1, sizeof(n1));
 
169
 
 
170
    // 17. Point Data Record Length
 
171
    n2 = header.GetDataRecordLength();
 
172
    detail::write_n(m_ofs, n2, sizeof(n2));
 
173
 
 
174
    // 18. Number of point records
 
175
    // This value is updated if necessary, see UpdateHeader function.
 
176
    n4 = header.GetPointRecordsCount();
 
177
    detail::write_n(m_ofs, n4, sizeof(n4));
 
178
 
 
179
    // 19. Number of points by return
 
180
    std::vector<uint32_t>::size_type const srbyr = 5;
 
181
    std::vector<uint32_t> const& vpbr = header.GetPointRecordsByReturnCount();
 
182
    assert(vpbr.size() <= srbyr);
 
183
    uint32_t pbr[srbyr] = { 0 };
 
184
    std::copy(vpbr.begin(), vpbr.end(), pbr);
 
185
    detail::write_n(m_ofs, pbr, sizeof(pbr));
 
186
 
 
187
    // 20-22. Scale factors
 
188
    detail::write_n(m_ofs, header.GetScaleX(), sizeof(double));
 
189
    detail::write_n(m_ofs, header.GetScaleY(), sizeof(double));
 
190
    detail::write_n(m_ofs, header.GetScaleZ(), sizeof(double));
 
191
 
 
192
    // 23-25. Offsets
 
193
    detail::write_n(m_ofs, header.GetOffsetX(), sizeof(double));
 
194
    detail::write_n(m_ofs, header.GetOffsetY(), sizeof(double));
 
195
    detail::write_n(m_ofs, header.GetOffsetZ(), sizeof(double));
 
196
 
 
197
    // 26-27. Max/Min X
 
198
    detail::write_n(m_ofs, header.GetMaxX(), sizeof(double));
 
199
    detail::write_n(m_ofs, header.GetMinX(), sizeof(double));
 
200
 
 
201
    // 28-29. Max/Min Y
 
202
    detail::write_n(m_ofs, header.GetMaxY(), sizeof(double));
 
203
    detail::write_n(m_ofs, header.GetMinY(), sizeof(double));
 
204
 
 
205
    // 30-31. Max/Min Z
 
206
    detail::write_n(m_ofs, header.GetMaxZ(), sizeof(double));
 
207
    detail::write_n(m_ofs, header.GetMinZ(), sizeof(double));
 
208
 
 
209
    // If WriteVLR returns a value, it is because the header's 
 
210
    // offset is not large enough to contain the VLRs.  The value 
 
211
    // it returns is the number of bytes we must increase the header
 
212
    // by in order for it to contain the VLRs.
 
213
    
 
214
    int32_t difference = WriteVLR(header);
 
215
    if (difference < 0) {
 
216
        header.SetDataOffset(header.GetDataOffset() + abs(difference) );
 
217
        WriteVLR(header);
 
218
    }
 
219
    
 
220
    // Write the pad bytes.
 
221
    uint8_t const sgn1 = 0xCC;
 
222
    uint8_t const sgn2 = 0xDD;
 
223
    detail::write_n(m_ofs, sgn1, sizeof(uint8_t));
 
224
    detail::write_n(m_ofs, sgn2, sizeof(uint8_t));
 
225
 
 
226
    // We can now reset the header's offset to +=2.  If we monkeypatched
 
227
    // the offset because we were too small to write the VLRs, this will 
 
228
    // end up being header.GetDataOffset() + difference + 2 (see above).
 
229
    header.SetDataOffset(header.GetDataOffset() + 2);
 
230
 
 
231
    // Make sure to rewrite the dataoffset in the header portion now that
 
232
    // we've changed it.
 
233
    std::streamsize const current_pos = m_ofs.tellp();
 
234
    std::streamsize const offset_pos = 96; 
 
235
    m_ofs.seekp(offset_pos, std::ios::beg);
 
236
    detail::write_n(m_ofs, header.GetDataOffset() , sizeof(header.GetDataOffset()));
 
237
    m_ofs.seekp(current_pos, std::ios::beg);        
 
238
    
 
239
    // If we already have points, we're going to put it at the end of the file.  
 
240
    // If we don't have any points,  we're going to leave it where it is.
 
241
    if (m_pointCount != 0)
 
242
        m_ofs.seekp(0, std::ios::end);
 
243
}
 
244
 
 
245
void WriterImpl::UpdateHeader(LASHeader const& header)
 
246
{
 
247
    if (m_pointCount != header.GetPointRecordsCount())
 
248
    {
 
249
        // Skip to first byte of number of point records data member
 
250
        std::streamsize const dataPos = 107; 
 
251
        m_ofs.seekp(dataPos, std::ios::beg);
 
252
 
 
253
        detail::write_n(m_ofs, m_pointCount , sizeof(m_pointCount));
 
254
    }
 
255
}
 
256
 
 
257
void WriterImpl::WritePointRecord(LASPoint const& point, const LASHeader& header)
 
258
{
 
259
    // TODO: Static assert would be better
 
260
    
 
261
    double t = 0;
 
262
    assert(LASHeader::ePointSize0 == sizeof(m_record));
 
263
    Writer::FillPointRecord(m_record, point, header);
 
264
    detail::write_n(m_ofs, m_record, sizeof(m_record));
 
265
 
 
266
    if (header.GetDataFormatId() == LASHeader::ePointFormat1) {
 
267
        t = point.GetTime();
 
268
        detail::write_n(m_ofs, t, sizeof(double));
 
269
    }
 
270
    ++m_pointCount;
 
271
}
 
272
 
 
273
}}} // namespace liblas::detail::v10