1
/******************************************************************************
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
8
******************************************************************************
9
* Copyright (c) 2008, Mateusz Loskot
11
* All rights reserved.
13
* Redistribution and use in source and binary forms, with or without
14
* modification, are permitted provided that the following
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.
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
40
****************************************************************************/
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>
51
#include <cstdlib> // std::size_t
54
namespace liblas { namespace detail { namespace v10 {
56
WriterImpl::WriterImpl(std::ostream& ofs) :
57
Base(ofs), m_pointCount(0)
61
std::size_t WriterImpl::GetVersion() const
66
void WriterImpl::WriteHeader(LASHeader& header)
72
// Rewrite the georeference VLR entries if they exist
73
header.SetGeoreference();
75
// Seek to the beginning
76
m_ofs.seekp(0, std::ios::beg);
77
std::ios::pos_type beginning = m_ofs.tellp();
80
m_ofs.seekp(0, std::ios::end);
81
std::ios::pos_type end = m_ofs.tellp();
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.
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.
91
if ((beginning != end) && ((uint32_t)end != 0)) {
92
m_pointCount = ((uint32_t) end - header.GetDataOffset())/header.GetDataRecordLength();
94
// Position to the beginning of the file to start writing the header
95
m_ofs.seekp(0, std::ios::beg);
99
std::string const filesig(header.GetFileSignature());
100
assert(filesig.size() == 4);
101
detail::write_n(m_ofs, filesig, 4);
104
n4 = header.GetReserved();
105
detail::write_n(m_ofs, n4, sizeof(n4));
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));
120
n1 = header.GetVersionMajor();
122
detail::write_n(m_ofs, n1, sizeof(n1));
125
n1 = header.GetVersionMinor();
127
detail::write_n(m_ofs, n1, sizeof(n1));
130
std::string sysid(header.GetSystemId(true));
131
assert(sysid.size() == 32);
132
detail::write_n(m_ofs, sysid, 32);
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);
139
// 11. Flight Date Julian
140
n2 = header.GetCreationDOY();
141
detail::write_n(m_ofs, n2, sizeof(n2));
144
n2 = header.GetCreationYear();
145
detail::write_n(m_ofs, n2, sizeof(n2));
148
n2 = header.GetHeaderSize();
150
detail::write_n(m_ofs, n2, sizeof(n2));
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
158
n4 = header.GetDataOffset() + 2;
159
detail::write_n(m_ofs, n4, sizeof(n4));
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));
166
// 16. Point Data Format ID
167
n1 = static_cast<uint8_t>(header.GetDataFormatId());
168
detail::write_n(m_ofs, n1, sizeof(n1));
170
// 17. Point Data Record Length
171
n2 = header.GetDataRecordLength();
172
detail::write_n(m_ofs, n2, sizeof(n2));
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));
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));
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));
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));
198
detail::write_n(m_ofs, header.GetMaxX(), sizeof(double));
199
detail::write_n(m_ofs, header.GetMinX(), sizeof(double));
202
detail::write_n(m_ofs, header.GetMaxY(), sizeof(double));
203
detail::write_n(m_ofs, header.GetMinY(), sizeof(double));
206
detail::write_n(m_ofs, header.GetMaxZ(), sizeof(double));
207
detail::write_n(m_ofs, header.GetMinZ(), sizeof(double));
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.
214
int32_t difference = WriteVLR(header);
215
if (difference < 0) {
216
header.SetDataOffset(header.GetDataOffset() + abs(difference) );
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));
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);
231
// Make sure to rewrite the dataoffset in the header portion now that
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);
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);
245
void WriterImpl::UpdateHeader(LASHeader const& header)
247
if (m_pointCount != header.GetPointRecordsCount())
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);
253
detail::write_n(m_ofs, m_pointCount , sizeof(m_pointCount));
257
void WriterImpl::WritePointRecord(LASPoint const& point, const LASHeader& header)
259
// TODO: Static assert would be better
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));
266
if (header.GetDataFormatId() == LASHeader::ePointFormat1) {
268
detail::write_n(m_ofs, t, sizeof(double));
273
}}} // namespace liblas::detail::v10