1
/******************************************************************************
4
* Project: libLAS - http://liblas.org - A BSD library for LAS format data.
5
* Purpose: LAS 1.1 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/writer11.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 v11 {
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) {
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
n2 = header.GetFileSourceId();
105
detail::write_n(m_ofs, n2, sizeof(n2));
108
n2 = header.GetReserved();
109
detail::write_n(m_ofs, n2, sizeof(n2));
115
uint8_t d4[8] = { 0 };
116
liblas::guid g = header.GetProjectId();
117
g.output_data(d1, d2, d3, d4);
118
detail::write_n(m_ofs, d1, sizeof(d1));
119
detail::write_n(m_ofs, d2, sizeof(d2));
120
detail::write_n(m_ofs, d3, sizeof(d3));
121
detail::write_n(m_ofs, d4, sizeof(d4));
124
n1 = header.GetVersionMajor();
126
detail::write_n(m_ofs, n1, sizeof(n1));
129
n1 = header.GetVersionMinor();
131
detail::write_n(m_ofs, n1, sizeof(n1));
134
std::string const sysid(header.GetSystemId(true));
135
assert(sysid.size() == 32);
136
detail::write_n(m_ofs, sysid, 32);
138
// 11. Generating Software ID
139
std::string const softid(header.GetSoftwareId(true));
140
assert(softid.size() == 32);
141
detail::write_n(m_ofs, softid, 32);
143
// 12. File Creation Day of Year
144
n2 = header.GetCreationDOY();
145
detail::write_n(m_ofs, n2, sizeof(n2));
147
// 13. File Creation Year
148
n2 = header.GetCreationYear();
149
detail::write_n(m_ofs, n2, sizeof(n2));
152
n2 = header.GetHeaderSize();
154
detail::write_n(m_ofs, n2, sizeof(n2));
156
// 15. Offset to data
157
// At this point, no variable length records are written,
158
// so data offset is equal to header size (227)
159
// TODO: This value must be updated after new variable length record is added.
160
n4 = header.GetDataOffset();
161
detail::write_n(m_ofs, n4, sizeof(n4));
163
// 16. Number of variable length records
164
// TODO: This value must be updated after new variable length record is added.
165
n4 = header.GetRecordsCount();
166
detail::write_n(m_ofs, n4, sizeof(n4));
168
// 17. Point Data Format ID
169
n1 = static_cast<uint8_t>(header.GetDataFormatId());
170
detail::write_n(m_ofs, n1, sizeof(n1));
172
// 18. Point Data Record Length
173
n2 = header.GetDataRecordLength();
174
detail::write_n(m_ofs, n2, sizeof(n2));
176
// 19. Number of point records
177
// This value is updated if necessary, see UpdateHeader function.
178
n4 = header.GetPointRecordsCount();
179
detail::write_n(m_ofs, n4, sizeof(n4));
181
// 20. Number of points by return
182
std::vector<uint32_t>::size_type const srbyr = 5;
183
std::vector<uint32_t> const& vpbr = header.GetPointRecordsByReturnCount();
184
assert(vpbr.size() <= srbyr);
185
uint32_t pbr[srbyr] = { 0 };
186
std::copy(vpbr.begin(), vpbr.end(), pbr);
187
detail::write_n(m_ofs, pbr, sizeof(pbr));
189
// 21-23. Scale factors
190
detail::write_n(m_ofs, header.GetScaleX(), sizeof(double));
191
detail::write_n(m_ofs, header.GetScaleY(), sizeof(double));
192
detail::write_n(m_ofs, header.GetScaleZ(), sizeof(double));
195
detail::write_n(m_ofs, header.GetOffsetX(), sizeof(double));
196
detail::write_n(m_ofs, header.GetOffsetY(), sizeof(double));
197
detail::write_n(m_ofs, header.GetOffsetZ(), sizeof(double));
200
detail::write_n(m_ofs, header.GetMaxX(), sizeof(double));
201
detail::write_n(m_ofs, header.GetMinX(), sizeof(double));
204
detail::write_n(m_ofs, header.GetMaxY(), sizeof(double));
205
detail::write_n(m_ofs, header.GetMinY(), sizeof(double));
208
detail::write_n(m_ofs, header.GetMaxZ(), sizeof(double));
209
detail::write_n(m_ofs, header.GetMinZ(), sizeof(double));
211
// If WriteVLR returns a value, it is because the header's
212
// offset is not large enough to contain the VLRs. The value
213
// it returns is the number of bytes we must increase the header
214
// by in order for it to contain the VLRs.
215
int32_t difference = WriteVLR(header);
216
if (difference < 0) {
217
header.SetDataOffset(header.GetDataOffset() + abs(difference) );
220
// Make sure to rewrite the dataoffset in the header portion now that
222
std::streamsize const current_pos = m_ofs.tellp();
223
std::streamsize const offset_pos = 96;
224
m_ofs.seekp(offset_pos, std::ios::beg);
225
detail::write_n(m_ofs, header.GetDataOffset() , sizeof(header.GetDataOffset()));
226
m_ofs.seekp(current_pos, std::ios::beg);
229
// If we already have points, we're going to put it at the end of the file.
230
// If we don't have any points, we're going to leave it where it is.
231
if (m_pointCount != 0)
232
m_ofs.seekp(0, std::ios::end);
235
void WriterImpl::UpdateHeader(LASHeader const& header)
237
if (m_pointCount != header.GetPointRecordsCount())
239
// Skip to first byte of number of point records data member
240
std::streamsize const dataPos = 107;
241
m_ofs.seekp(dataPos, std::ios::beg);
243
detail::write_n(m_ofs, m_pointCount , sizeof(m_pointCount));
247
void WriterImpl::WritePointRecord(LASPoint const& point, const LASHeader& header)
249
// TODO: Static assert would be better
252
assert(LASHeader::ePointSize0 == sizeof(m_record));
253
Writer::FillPointRecord(m_record, point, header);
254
detail::write_n(m_ofs, m_record, sizeof(m_record));
256
if (header.GetDataFormatId() == LASHeader::ePointFormat1) {
258
detail::write_n(m_ofs, t, sizeof(double));
263
}}} // namespace liblas::detail::v11