553 lines
19 KiB
C++
Executable File
553 lines
19 KiB
C++
Executable File
// Copyright (c) 2017 Geometry Factory
|
|
// All rights reserved.
|
|
//
|
|
// This file is part of CGAL (www.cgal.org).
|
|
// You can redistribute it and/or modify it under the terms of the GNU
|
|
// General Public License as published by the Free Software Foundation,
|
|
// either version 3 of the License, or (at your option) any later version.
|
|
//
|
|
// Licensees holding a valid commercial license may use this file in
|
|
// accordance with the commercial license agreement provided with the software.
|
|
//
|
|
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
|
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// $URL$
|
|
// $Id$
|
|
// SPDX-License-Identifier: GPL-3.0+
|
|
//
|
|
// Author(s) : Simon Giraudot
|
|
|
|
#ifndef CGAL_READ_LAS_POINTS_H
|
|
#define CGAL_READ_LAS_POINTS_H
|
|
|
|
#include <CGAL/license/Point_set_processing_3.h>
|
|
|
|
#include <CGAL/config.h>
|
|
#if defined(CGAL_CFG_NO_CPP0X_RVALUE_REFERENCE) || defined(CGAL_CFG_NO_CPP0X_VARIADIC_TEMPLATES)
|
|
#error CGAL LAS reader requires a C++11 compiler
|
|
#endif
|
|
|
|
#include <tuple>
|
|
|
|
#include <CGAL/property_map.h>
|
|
#include <CGAL/value_type_traits.h>
|
|
#include <CGAL/point_set_processing_assertions.h>
|
|
#include <CGAL/Kernel_traits.h>
|
|
|
|
#include <CGAL/boost/graph/named_function_params.h>
|
|
#include <CGAL/boost/graph/named_params_helper.h>
|
|
|
|
#include <boost/version.hpp>
|
|
#include <boost/cstdint.hpp>
|
|
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
#ifdef BOOST_MSVC
|
|
# pragma warning(push)
|
|
# pragma warning(disable:4251) // DLL warning from LASlib
|
|
#endif
|
|
|
|
#ifdef __GNUC__
|
|
# pragma GCC diagnostic push
|
|
# pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
|
#endif
|
|
|
|
#define USE_AS_DLL
|
|
#include <lasreader_las.hpp>
|
|
#undef USE_AS_DLL
|
|
|
|
#ifdef __GNUC__
|
|
# pragma GCC diagnostic pop
|
|
#endif
|
|
|
|
#ifdef BOOST_MSVC
|
|
# pragma warning(pop)
|
|
#endif
|
|
|
|
|
|
namespace CGAL {
|
|
|
|
|
|
/// \cond SKIP_IN_MANUAL
|
|
namespace LAS_property
|
|
{
|
|
namespace Id
|
|
{
|
|
enum Id
|
|
{
|
|
X,
|
|
Y,
|
|
Z,
|
|
Intensity,
|
|
Return_number,
|
|
Number_of_returns,
|
|
Scan_direction_flag,
|
|
Edge_of_flight_line,
|
|
Classification,
|
|
Synthetic_flag,
|
|
Keypoint_flag,
|
|
Withheld_flag,
|
|
Scan_angle,
|
|
User_data,
|
|
Point_source_ID,
|
|
Deleted_flag,
|
|
GPS_time,
|
|
R,
|
|
G,
|
|
B,
|
|
I
|
|
};
|
|
}
|
|
|
|
template <typename T, Id::Id id>
|
|
struct Base
|
|
{
|
|
typedef T type;
|
|
};
|
|
|
|
typedef Base<double, Id::X> X;
|
|
typedef Base<double, Id::Y> Y;
|
|
typedef Base<double, Id::Z> Z;
|
|
typedef Base<unsigned short, Id::Intensity> Intensity;
|
|
typedef Base<unsigned char, Id::Return_number> Return_number;
|
|
typedef Base<unsigned char, Id::Number_of_returns> Number_of_returns;
|
|
typedef Base<unsigned char, Id::Scan_direction_flag> Scan_direction_flag;
|
|
typedef Base<unsigned char, Id::Edge_of_flight_line> Edge_of_flight_line;
|
|
typedef Base<unsigned char, Id::Classification> Classification;
|
|
typedef Base<unsigned char, Id::Synthetic_flag> Synthetic_flag;
|
|
typedef Base<unsigned char, Id::Keypoint_flag> Keypoint_flag;
|
|
typedef Base<unsigned char, Id::Withheld_flag> Withheld_flag;
|
|
typedef Base<float, Id::Scan_angle> Scan_angle;
|
|
typedef Base<unsigned char, Id::User_data> User_data;
|
|
typedef Base<unsigned short, Id::Point_source_ID> Point_source_ID;
|
|
typedef Base<unsigned int, Id::Deleted_flag> Deleted_flag;
|
|
typedef Base<double, Id::GPS_time> GPS_time;
|
|
typedef Base<unsigned short, Id::R> R;
|
|
typedef Base<unsigned short, Id::G> G;
|
|
typedef Base<unsigned short, Id::B> B;
|
|
typedef Base<unsigned short, Id::I> I;
|
|
}
|
|
/// \endcond
|
|
|
|
|
|
/**
|
|
\ingroup PkgPointSetProcessingIOLas
|
|
|
|
Generates a %LAS property handler to read 3D points. Points are
|
|
constructed from the input the using 3 %LAS properties
|
|
`LAS_property::X`, `LAS_property::Y` and `LAS_property::Z`.
|
|
|
|
\sa `read_las_points_with_properties()`
|
|
|
|
\tparam PointMap the property map used to store points.
|
|
*/
|
|
template <typename PointMap>
|
|
std::tuple<PointMap,
|
|
typename Kernel_traits<typename PointMap::value_type>::Kernel::Construct_point_3,
|
|
LAS_property::X, LAS_property::Y, LAS_property::Z >
|
|
make_las_point_reader(PointMap point_map)
|
|
{
|
|
return std::make_tuple (point_map, typename Kernel_traits<typename PointMap::value_type>::Kernel::Construct_point_3(),
|
|
LAS_property::X(), LAS_property::Y(), LAS_property::Z());
|
|
}
|
|
|
|
/// \cond SKIP_IN_MANUAL
|
|
|
|
namespace internal {
|
|
|
|
namespace LAS {
|
|
|
|
void get_value(const LASpoint& r, double& v, LAS_property::X&)
|
|
{ v = r.get_x(); }
|
|
void get_value(const LASpoint& r, double& v, LAS_property::Y&)
|
|
{ v = r.get_y(); }
|
|
void get_value(const LASpoint& r, double& v, LAS_property::Z&)
|
|
{ v = r.get_z(); }
|
|
void get_value(const LASpoint& r, unsigned short& v, LAS_property::Intensity&)
|
|
{ v = r.get_intensity(); }
|
|
void get_value(const LASpoint& r, unsigned char& v, LAS_property::Return_number&)
|
|
{ v = r.get_return_number(); }
|
|
void get_value(const LASpoint& r, unsigned char& v, LAS_property::Number_of_returns&)
|
|
{ v = r.get_number_of_returns(); }
|
|
void get_value(const LASpoint& r, unsigned char& v, LAS_property::Scan_direction_flag&)
|
|
{ v = r.get_scan_direction_flag(); }
|
|
void get_value(const LASpoint& r, unsigned char& v, LAS_property::Edge_of_flight_line&)
|
|
{ v = r.get_edge_of_flight_line(); }
|
|
void get_value(const LASpoint& r, unsigned char& v, LAS_property::Classification&)
|
|
{ v = r.get_classification(); }
|
|
void get_value(const LASpoint& r, unsigned char& v, LAS_property::Synthetic_flag&)
|
|
{ v = r.get_synthetic_flag(); }
|
|
void get_value(const LASpoint& r, unsigned char& v, LAS_property::Keypoint_flag&)
|
|
{ v = r.get_keypoint_flag(); }
|
|
void get_value(const LASpoint& r, unsigned char& v, LAS_property::Withheld_flag&)
|
|
{ v = r.get_withheld_flag(); }
|
|
void get_value(const LASpoint& r, float& v, LAS_property::Scan_angle&)
|
|
{ v = r.get_scan_angle(); }
|
|
void get_value(const LASpoint& r, unsigned char& v, LAS_property::User_data&)
|
|
{ v = r.get_user_data(); }
|
|
void get_value(const LASpoint& r, unsigned short& v, LAS_property::Point_source_ID&)
|
|
{ v = r.get_point_source_ID(); }
|
|
void get_value(const LASpoint& r, unsigned int& v, LAS_property::Deleted_flag&)
|
|
{ v = r.get_deleted_flag(); }
|
|
void get_value(const LASpoint& r, double& v, LAS_property::GPS_time&)
|
|
{ v = r.get_gps_time(); }
|
|
void get_value(const LASpoint& r, unsigned short& v, LAS_property::R&)
|
|
{ v = r.get_R(); }
|
|
void get_value(const LASpoint& r, unsigned short& v, LAS_property::G&)
|
|
{ v = r.get_G(); }
|
|
void get_value(const LASpoint& r, unsigned short& v, LAS_property::B&)
|
|
{ v = r.get_B(); }
|
|
void get_value(const LASpoint& r, unsigned short& v, LAS_property::I&)
|
|
{ v = r.get_I(); }
|
|
|
|
|
|
template <std::size_t N>
|
|
struct Filler
|
|
{
|
|
template <class Value_tuple, class LAS_property_tuple>
|
|
static void fill(const LASpoint& r, Value_tuple& values, LAS_property_tuple wrappers)
|
|
{
|
|
get_value(r, std::get<N>(values), std::get<N+2>(wrappers));
|
|
Filler<N-1>::fill(r, values, wrappers);
|
|
}
|
|
};
|
|
|
|
template<int ...>
|
|
struct seq { };
|
|
|
|
template<int N, int ...S>
|
|
struct gens : gens<N-1, N-1, S...> { };
|
|
|
|
template<int ...S>
|
|
struct gens<0, S...> {
|
|
typedef seq<S...> type;
|
|
};
|
|
|
|
template<class ValueType, class Functor, class Tuple, int ...S>
|
|
ValueType call_functor(Functor f, Tuple t, seq<S...>) {
|
|
return f(std::get<S>(t) ...);
|
|
}
|
|
|
|
template <class ValueType, class Functor, typename ... T>
|
|
ValueType call_functor(Functor f, std::tuple<T...>& t)
|
|
{
|
|
return call_functor<ValueType>(f, t, typename gens<sizeof...(T)>::type());
|
|
}
|
|
|
|
template<>
|
|
struct Filler<0>
|
|
{
|
|
template <class Value_tuple, class LAS_property_tuple>
|
|
static void fill(const LASpoint& r, Value_tuple& values, LAS_property_tuple wrappers)
|
|
{
|
|
get_value(r, std::get<0>(values), std::get<2>(wrappers));
|
|
}
|
|
};
|
|
|
|
template <typename OutputValueType, typename PropertyMap, typename T, LAS_property::Id::Id id>
|
|
void process_properties (const LASpoint& reader, OutputValueType& new_element,
|
|
std::pair<PropertyMap, LAS_property::Base<T,id> >&& current);
|
|
|
|
template <typename OutputValueType, typename PropertyMap, typename T, LAS_property::Id::Id id,
|
|
typename NextPropertyBinder, typename ... PropertyMapBinders>
|
|
void process_properties (const LASpoint& reader, OutputValueType& new_element,
|
|
std::pair<PropertyMap, LAS_property::Base<T,id> >&& current,
|
|
NextPropertyBinder&& next,
|
|
PropertyMapBinders&& ... properties);
|
|
|
|
template <typename OutputValueType,
|
|
typename PropertyMap,
|
|
typename Constructor,
|
|
typename ... T,
|
|
LAS_property::Id::Id ... id>
|
|
void process_properties (const LASpoint& reader, OutputValueType& new_element,
|
|
std::tuple<PropertyMap, Constructor, LAS_property::Base<T,id>...>&& current)
|
|
{
|
|
typedef typename PropertyMap::value_type PmapValueType;
|
|
std::tuple<T...> values;
|
|
Filler<sizeof...(T)-1>::fill(reader, values, current);
|
|
PmapValueType new_value = call_functor<PmapValueType>(std::get<1>(current), values);
|
|
put (std::get<0>(current), new_element, new_value);
|
|
}
|
|
|
|
template <typename OutputValueType,
|
|
typename PropertyMap,
|
|
typename Constructor,
|
|
typename ... T,
|
|
LAS_property::Id::Id ... id,
|
|
typename NextPropertyBinder,
|
|
typename ... PropertyMapBinders>
|
|
void process_properties (const LASpoint& reader, OutputValueType& new_element,
|
|
std::tuple<PropertyMap, Constructor, LAS_property::Base<T,id>...>&& current,
|
|
NextPropertyBinder&& next,
|
|
PropertyMapBinders&& ... properties)
|
|
{
|
|
typedef typename PropertyMap::value_type PmapValueType;
|
|
std::tuple<T...> values;
|
|
Filler<sizeof...(T)-1>::fill(reader, values, current);
|
|
PmapValueType new_value = call_functor<PmapValueType>(std::get<1>(current), values);
|
|
put (std::get<0>(current), new_element, new_value);
|
|
|
|
process_properties (reader, new_element, std::forward<NextPropertyBinder>(next),
|
|
std::forward<PropertyMapBinders>(properties)...);
|
|
}
|
|
|
|
|
|
template <typename OutputValueType, typename PropertyMap, typename T, LAS_property::Id::Id id>
|
|
void process_properties (const LASpoint& reader, OutputValueType& new_element,
|
|
std::pair<PropertyMap, LAS_property::Base<T,id> >&& current)
|
|
{
|
|
T new_value = T();
|
|
get_value (reader, new_value, current.second);
|
|
put (current.first, new_element, new_value);
|
|
}
|
|
|
|
template <typename OutputValueType, typename PropertyMap, typename T, LAS_property::Id::Id id,
|
|
typename NextPropertyBinder, typename ... PropertyMapBinders>
|
|
void process_properties (const LASpoint& reader, OutputValueType& new_element,
|
|
std::pair<PropertyMap, LAS_property::Base<T,id> >&& current,
|
|
NextPropertyBinder&& next,
|
|
PropertyMapBinders&& ... properties)
|
|
{
|
|
T new_value = T();
|
|
get_value (reader, new_value, current.second);
|
|
put (current.first, new_element, new_value);
|
|
process_properties (reader, new_element, std::forward<NextPropertyBinder>(next),
|
|
std::forward<PropertyMapBinders>(properties)...);
|
|
}
|
|
|
|
} // namespace LAS
|
|
|
|
} // namespace internal
|
|
|
|
|
|
/// \endcond
|
|
|
|
|
|
/**
|
|
\ingroup PkgPointSetProcessingIOLas
|
|
|
|
Reads user-selected points properties from a .las or .laz stream.
|
|
Potential additional properties are ignored.
|
|
|
|
Properties are handled through a variadic list of property
|
|
handlers. A `PropertyHandler` can either be:
|
|
|
|
- A `std::pair<PropertyMap, LAS_property::Tag >` if the user wants to
|
|
read a %LAS property as a scalar value `LAS_property::Tag::type` (for
|
|
example, storing an `int` %LAS property into an `int` variable).
|
|
|
|
- A `std::tuple<PropertyMap, Constructor,
|
|
LAS_property::Tag...>` if the user wants to use one or several
|
|
%LAS properties to construct a complex object (for example,
|
|
storing 4 `unsigned short` %LAS properties into a %Color object
|
|
that can for example be a `CGAL::cpp11::array<unsigned short,
|
|
4>`). In that case, the second element of the tuple should be a
|
|
functor that constructs the value type of `PropertyMap` from N
|
|
objects of of type `LAS_property::Tag::type`.
|
|
|
|
The %LAS standard defines a fixed set of properties accessible
|
|
through the following tag classes:
|
|
|
|
- `LAS_property::X` with type `double`
|
|
- `LAS_property::Y` with type `double`
|
|
- `LAS_property::Z` with type `double`
|
|
- `LAS_property::Intensity` with type `unsigned short`
|
|
- `LAS_property::Return_number` with type `unsigned char`
|
|
- `LAS_property::Number_of_returns` with type `unsigned char`
|
|
- `LAS_property::Scan_direction_flag` with type `unsigned char`
|
|
- `LAS_property::Edge_of_flight_line` with type `unsigned char`
|
|
- `LAS_property::Classification` with type `unsigned char`
|
|
- `LAS_property::Synthetic_flag` with type `unsigned char`
|
|
- `LAS_property::Keypoint_flag` with type `unsigned char`
|
|
- `LAS_property::Withheld_flag` with type `unsigned char`
|
|
- `LAS_property::Scan_angle` with type `double`
|
|
- `LAS_property::User_data` with type `unsigned char`
|
|
- `LAS_property::Point_source_ID` with type `unsigned short`
|
|
- `LAS_property::Deleted_flag` with type `unsigned int`
|
|
- `LAS_property::GPS_time` with type `double`
|
|
- `LAS_property::R` with type `unsigned short`
|
|
- `LAS_property::G` with type `unsigned short`
|
|
- `LAS_property::B` with type `unsigned short`
|
|
- `LAS_property::I` with type `unsigned short`
|
|
|
|
\cgalRequiresCPP11
|
|
|
|
\sa `make_las_point_reader()`
|
|
|
|
\tparam OutputIteratorValueType type of objects that can be put in `OutputIterator`.
|
|
It is default to `value_type_traits<OutputIterator>::%type` and can be omitted when the default is fine.
|
|
\tparam OutputIterator iterator over output points.
|
|
\tparam PropertyHandler handlers to recover properties.
|
|
|
|
\return `true` on success.
|
|
*/
|
|
template <typename OutputIteratorValueType,
|
|
typename OutputIterator,
|
|
typename ... PropertyHandler>
|
|
bool read_las_points_with_properties (std::istream& stream,
|
|
OutputIterator output,
|
|
PropertyHandler&& ... properties)
|
|
{
|
|
typedef OutputIteratorValueType Enriched_point;
|
|
|
|
LASreaderLAS lasreader;
|
|
lasreader.open(stream);
|
|
|
|
while (lasreader.read_point())
|
|
{
|
|
const LASpoint& laspoint = lasreader.point;
|
|
Enriched_point new_point;
|
|
|
|
internal::LAS::process_properties (laspoint, new_point, std::forward<PropertyHandler>(properties)...);
|
|
|
|
*(output ++) = new_point;
|
|
}
|
|
|
|
lasreader.close();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
/// \cond SKIP_IN_MANUAL
|
|
template <typename OutputIterator,
|
|
typename ... PropertyHandler>
|
|
bool read_las_points_with_properties (std::istream& stream,
|
|
OutputIterator output,
|
|
PropertyHandler&& ... properties)
|
|
{
|
|
typedef typename value_type_traits<OutputIterator>::type OutputValueType;
|
|
|
|
return read_las_points_with_properties<OutputValueType>
|
|
(stream, output, std::forward<PropertyHandler>(properties)...);
|
|
}
|
|
/// \endcond
|
|
|
|
/**
|
|
\ingroup PkgPointSetProcessingIOLas
|
|
Reads points (position only) from a .las or .laz stream.
|
|
Potential additional properties are ignored.
|
|
|
|
\tparam OutputIteratorValueType type of objects that can be put in `OutputIterator`.
|
|
It is default to `value_type_traits<OutputIterator>::%type` and can be omitted when the default is fine.
|
|
\tparam OutputIterator iterator over output points.
|
|
|
|
\param stream input stream.
|
|
\param output output iterator over points.
|
|
|
|
\param np optional sequence of \ref psp_namedparameters "Named Parameters" among the ones listed below.
|
|
|
|
\cgalNamedParamsBegin
|
|
\cgalParamBegin{point_map} a model of `WritablePropertyMap` with value type `geom_traits::Point_3`.
|
|
If this parameter is omitted, `CGAL::Identity_property_map<geom_traits::Point_3>` is used.\cgalParamEnd
|
|
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
|
|
\cgalNamedParamsEnd
|
|
|
|
\return true on success.
|
|
|
|
\cgalRequiresCPP11
|
|
*/
|
|
template < typename OutputIteratorValueType,
|
|
typename OutputIterator,
|
|
#ifdef DOXYGEN_RUNNING
|
|
typename NamedParameters
|
|
#else
|
|
typename CGAL_BGL_NP_TEMPLATE_PARAMETERS
|
|
#endif
|
|
>
|
|
bool read_las_points(std::istream& stream,
|
|
OutputIterator output,
|
|
#ifdef DOXYGEN_RUNNING
|
|
const NamedParameters& np)
|
|
#else
|
|
const CGAL_BGL_NP_CLASS& np)
|
|
#endif
|
|
{
|
|
using boost::choose_param;
|
|
|
|
typedef Point_set_processing_3::Fake_point_range<OutputIteratorValueType> PointRange;
|
|
|
|
typedef typename Point_set_processing_3::GetPointMap<PointRange, CGAL_BGL_NP_CLASS>::type PointMap;
|
|
PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap());
|
|
|
|
return read_las_points_with_properties (stream, output,
|
|
make_las_point_reader (point_map));
|
|
}
|
|
|
|
/// \cond SKIP_IN_MANUAL
|
|
// variant with default NP
|
|
template <typename OutputIteratorValueType,
|
|
typename OutputIterator>
|
|
bool
|
|
read_las_points(
|
|
std::istream& stream, ///< input stream.
|
|
OutputIterator output) ///< output iterator over points.
|
|
{
|
|
return read_las_points<OutputIteratorValueType>
|
|
(stream, output, CGAL::parameters::all_default());
|
|
}
|
|
|
|
// variant with default output iterator value type
|
|
template <typename OutputIterator,
|
|
typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
|
bool
|
|
read_las_points(
|
|
std::istream& stream, ///< input stream.
|
|
OutputIterator output,
|
|
const CGAL_BGL_NP_CLASS& np)
|
|
{
|
|
return read_las_points<typename value_type_traits<OutputIterator>::type>
|
|
(stream, output, np);
|
|
}
|
|
|
|
// variant with default NP and output iterator value type
|
|
template <typename OutputIterator>
|
|
bool
|
|
read_las_points(
|
|
std::istream& stream, ///< input stream.
|
|
OutputIterator output)
|
|
{
|
|
return read_las_points<typename value_type_traits<OutputIterator>::type>
|
|
(stream, output, CGAL::parameters::all_default());
|
|
}
|
|
|
|
#ifndef CGAL_NO_DEPRECATED_CODE
|
|
// deprecated API
|
|
template < typename OutputIteratorValueType,
|
|
typename OutputIterator,
|
|
typename PointMap >
|
|
CGAL_DEPRECATED_MSG("you are using the deprecated V1 API of CGAL::read_las_points(), please update your code")
|
|
bool read_las_points(std::istream& stream, ///< input stream.
|
|
OutputIterator output, ///< output iterator over points.
|
|
PointMap point_map) ///< property map: value_type of OutputIterator -> Point_3.
|
|
{
|
|
return read_las_points<OutputIteratorValueType>
|
|
(stream, output,
|
|
CGAL::parameters::point_map (point_map));
|
|
}
|
|
|
|
// deprecated API
|
|
template < typename OutputIterator,
|
|
typename PointMap >
|
|
CGAL_DEPRECATED_MSG("you are using the deprecated V1 API of CGAL::read_las_points(), please update your code")
|
|
bool read_las_points(std::istream& stream, ///< input stream.
|
|
OutputIterator output, ///< output iterator over points.
|
|
PointMap point_map) ///< property map: value_type of OutputIterator -> Point_3.
|
|
{
|
|
return read_las_points<typename value_type_traits<OutputIterator>::type>
|
|
(stream, output,
|
|
CGAL::parameters::point_map (point_map));
|
|
}
|
|
#endif // CGAL_NO_DEPRECATED_CODE
|
|
/// \endcond
|
|
|
|
|
|
} //namespace CGAL
|
|
|
|
#endif // CGAL_READ_LAS_POINTS_H
|