1
/******************************************************************************
4
* Project: libLAS - http://liblas.org - A BSD library for LAS format data.
5
* Purpose: LAS 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/writer.hpp>
43
#include <liblas/detail/writer10.hpp>
44
#include <liblas/detail/writer11.hpp>
45
#include <liblas/detail/writer12.hpp>
46
#include <liblas/lasheader.hpp>
47
#include <liblas/laspoint.hpp>
48
#include <liblas/lasspatialreference.hpp>
51
#include <ogr_srs_api.h>
58
#include <cstdlib> // std::size_t
61
namespace liblas { namespace detail {
63
Writer::Writer(std::ostream& ofs) : m_ofs(ofs), m_transform(0), m_in_ref(0), m_out_ref(0)
71
OCTDestroyCoordinateTransformation(m_transform);
74
OSRDestroySpatialReference(m_in_ref);
77
OSRDestroySpatialReference(m_out_ref);
82
std::ostream& Writer::GetStream() const
88
void Writer::FillPointRecord(PointRecord& record, const LASPoint& point, const LASHeader& header)
91
// let's just copy the point for now.
92
LASPoint p = LASPoint(point);
94
record.x = static_cast<int32_t>((p.GetX() - header.GetOffsetX()) / header.GetScaleX());
95
record.y = static_cast<int32_t>((p.GetY() - header.GetOffsetY()) / header.GetScaleY());
96
record.z = static_cast<int32_t>((p.GetZ() - header.GetOffsetZ()) / header.GetScaleZ());
98
record.x = static_cast<int32_t>((point.GetX() - header.GetOffsetX()) / header.GetScaleX());
99
record.y = static_cast<int32_t>((point.GetY() - header.GetOffsetY()) / header.GetScaleY());
100
record.z = static_cast<int32_t>((point.GetZ() - header.GetOffsetZ()) / header.GetScaleZ());
103
record.intensity = point.GetIntensity();
104
record.flags = point.GetScanFlags();
105
record.classification = point.GetClassification();
106
record.scan_angle_rank = point.GetScanAngleRank();
107
record.user_data = point.GetUserData();
108
record.point_source_id = point.GetPointSourceID();
111
uint32_t Writer::WriteVLR(LASHeader const& header)
113
// If this function returns a value, it is the size that the header's
114
// data offset must be increased by in order for the VLRs to fit in
116
m_ofs.seekp(header.GetHeaderSize(), std::ios::beg);
118
// if the VLRs won't fit because the data offset is too
119
// small, we need to throw an error.
120
uint32_t vlr_total_size = 0;
122
// Calculate a new data offset size
123
for (uint32_t i = 0; i < header.GetRecordsCount(); ++i)
125
LASVariableRecord vlr = header.GetVLR(i);
126
vlr_total_size += vlr.GetTotalSize();
129
int32_t difference = header.GetDataOffset() - (vlr_total_size + header.GetHeaderSize());
136
for (uint32_t i = 0; i < header.GetRecordsCount(); ++i)
138
LASVariableRecord vlr = header.GetVLR(i);
140
detail::write_n(m_ofs, vlr.GetReserved(), sizeof(uint16_t));
141
detail::write_n(m_ofs, vlr.GetUserId(true).c_str(), 16);
142
detail::write_n(m_ofs, vlr.GetRecordId(), sizeof(uint16_t));
143
detail::write_n(m_ofs, vlr.GetRecordLength(), sizeof(uint16_t));
144
detail::write_n(m_ofs, vlr.GetDescription(true).c_str(), 32);
145
std::vector<uint8_t> const& data = vlr.GetData();
146
std::streamsize const size = static_cast<std::streamsize>(data.size());
147
detail::write_n(m_ofs, data.front(), size);
150
// if we had more room than we need for the VLRs, we need to pad that with
151
// 0's. We must also not forget to add the 1.0 pad bytes to the end of this
152
// but the impl should be the one doing that, not us.
153
if (difference > 0) {
154
detail::write_n(m_ofs, "\0", difference);
160
void Writer::SetSRS(const LASSpatialReference& srs )
164
m_in_ref = OSRNewSpatialReference(0);
165
m_out_ref = OSRNewSpatialReference(0);
167
int result = OSRSetFromUserInput(m_in_ref, m_in_srs.GetWKT().c_str());
168
if (result != OGRERR_NONE)
170
std::ostringstream msg;
171
msg << "Could not import input spatial reference for Writer::" << CPLGetLastErrorMsg() << result;
172
std::string message(msg.str());
173
throw std::runtime_error(message);
176
result = OSRSetFromUserInput(m_out_ref, m_out_srs.GetWKT().c_str());
177
if (result != OGRERR_NONE)
179
std::ostringstream msg;
180
msg << "Could not import output spatial reference for Writer::" << CPLGetLastErrorMsg() << result;
181
std::string message(msg.str());
182
throw std::runtime_error(message);
185
m_transform = OCTNewCoordinateTransformation( m_in_ref, m_out_ref);
190
void Writer::Project(LASPoint& p)
199
ret = OCTTransform(m_transform, 1, &x, &y, &z);
202
std::ostringstream msg;
203
msg << "Could not project point for Writer::" << CPLGetLastErrorMsg() << ret;
204
std::string message(msg.str());
205
throw std::runtime_error(message);
212
UNREFERENCED_PARAMETER(p);
215
Writer* WriterFactory::Create(std::ostream& ofs, LASHeader const& header)
219
throw std::runtime_error("output stream state is invalid");
222
// Select writer implementation based on requested LAS version.
223
uint8_t major = header.GetVersionMajor();
224
uint8_t minor = header.GetVersionMinor();
226
if (1 == major && 0 == minor)
228
return new v10::WriterImpl(ofs);
230
if (1 == major && 1 == minor)
232
return new v11::WriterImpl(ofs);
234
if (1 == major && 2 == minor)
236
return new v12::WriterImpl(ofs);
238
else if (2 == major && 0 == minor)
240
// TODO: LAS 2.0 read/write support
241
throw std::runtime_error("LAS 2.0 file detected but unsupported");
244
throw std::runtime_error("LAS file of unknown version");
247
void WriterFactory::Destroy(Writer* p)
253
}} // namespace liblas::detail