From 8be71caeaff7d950af85c701f5b9a50f9376d3ce Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 18 Dec 2014 17:47:08 +0000 Subject: [PATCH] From Aitor Moreno, LAS plugin - depends upon boost and liblas and liblas-c git-svn-id: http://svn.openscenegraph.org/osg/OpenSceneGraph/trunk@14622 16af8721-9629-0410-8352-f15c8da7e697 --- CMakeLists.txt | 3 + CMakeModules/FindLIBLAS.cmake | 105 ++++++++++++ src/osgPlugins/CMakeLists.txt | 4 + src/osgPlugins/las/CMakeLists.txt | 9 ++ src/osgPlugins/las/ReaderWriterLAS.cpp | 215 +++++++++++++++++++++++++ 5 files changed, 336 insertions(+) create mode 100644 CMakeModules/FindLIBLAS.cmake create mode 100644 src/osgPlugins/las/CMakeLists.txt create mode 100644 src/osgPlugins/las/ReaderWriterLAS.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0db1adb18..daa45ba67 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -644,6 +644,9 @@ ELSE() ENDIF() FIND_PACKAGE(ZeroConf) + FIND_PACKAGE(Boost) # used by LIBLAS + FIND_PACKAGE(LIBLAS) + IF (NOT(OSG_USE_LOCAL_LUA_SOURCE)) FIND_PACKAGE(Lua52) IF (NOT (LUA_LIBRARIES AND LUA_INCLUDE_DIR)) diff --git a/CMakeModules/FindLIBLAS.cmake b/CMakeModules/FindLIBLAS.cmake new file mode 100644 index 000000000..ff62afd2e --- /dev/null +++ b/CMakeModules/FindLIBLAS.cmake @@ -0,0 +1,105 @@ +#--- +# File: FindLIBLAS.cmake +# +# Find the native LIBLAS includes and library +# +# LIBLAS_INCLUDE_DIRS - where to find liblas's includes. +# LIBLAS_LIBRARIES - List of libraries when using liblas. +# LIBLAS_FOUND - True if liblas found. +#--- + + +# Set the include dir: +find_path(LIBLAS_INCLUDE_DIR liblas/liblas.hpp) + +# Macro for setting libraries: +macro(FIND_LIBLAS_LIBRARY MYLIBRARY MYLIBRARYNAME) + + find_library( + "${MYLIBRARY}_DEBUG" + NAMES "${MYLIBRARYNAME}${CMAKE_DEBUG_POSTFIX}" + PATHS + ${LIBLAS_DIR}/lib/Debug + ${LIBLAS_DIR}/lib64/Debug + ${LIBLAS_DIR}/lib + ${LIBLAS_DIR}/lib64 + $ENV{LIBLAS_DIR}/lib/debug + $ENV{LIBLAS_DIR}/lib64/debug + NO_DEFAULT_PATH + ) + + find_library( + "${MYLIBRARY}_DEBUG" + NAMES "${MYLIBRARYNAME}${CMAKE_DEBUG_POSTFIX}" + PATHS + ~/Library/Frameworks + /Library/Frameworks + /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 + /sw/lib + /opt/local/lib + /opt/csw/lib + /opt/lib + [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ +Manager\\Environment;LIBLAS_ROOT]/lib + /usr/freeware/lib64 + ) + + find_library( + ${MYLIBRARY} + NAMES "${MYLIBRARYNAME}${CMAKE_RELEASE_POSTFIX}" + PATHS + ${LIBLAS_DIR}/lib/Release + ${LIBLAS_DIR}/lib64/Release + ${LIBLAS_DIR}/lib + ${LIBLAS_DIR}/lib64 + $ENV{LIBLAS_DIR}/lib/Release + $ENV{LIBLAS_DIR}/lib64/Release + $ENV{LIBLAS_DIR}/lib + $ENV{LIBLAS_DIR}/lib64 + $ENV{LIBLAS_DIR} + $ENV{LIBLASDIR}/lib + $ENV{LIBLASDIR}/lib64 + $ENV{LIBLASDIR} + $ENV{LIBLAS_ROOT}/lib + $ENV{LIBLAS_ROOT}/lib64 + NO_DEFAULT_PATH + ) + + find_library( + ${MYLIBRARY} + NAMES "${MYLIBRARYNAME}${CMAKE_RELEASE_POSTFIX}" + PATHS + ~/Library/Frameworks + /Library/Frameworks + /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 + /sw/lib + /opt/local/lib + /opt/csw/lib + /opt/lib + [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ +Manager\\Environment;LIBLAS_ROOT]/lib + /usr/freeware/lib64 + ) + + if( NOT ${MYLIBRARY}_DEBUG ) + if( MYLIBRARY ) + set( ${MYLIBRARY}_DEBUG ${MYLIBRARY} ) + endif(MYLIBRARY) + endif( NOT ${MYLIBRARY}_DEBUG ) + +endmacro(FIND_LIBLAS_LIBRARY LIBRARY LIBRARYNAME) + +FIND_LIBLAS_LIBRARY(LIBLAS_LIBRARY las) +FIND_LIBLAS_LIBRARY(LIBLASC_LIBRARY las_c) + +set(LIBLAS_FOUND "NO") +if(LIBLAS_LIBRARY AND LIBLASC_LIBRARY AND LIBLAS_INCLUDE_DIR) + set(LIBLAS_LIBRARIES ${LIBLAS_LIBRARY} ${LIBLASC_LIBRARY} ) + set(LIBLAS_FOUND "YES") +endif(LIBLAS_LIBRARY AND LIBLASC_LIBRARY LIBLAS_INCLUDE_DIR) \ No newline at end of file diff --git a/src/osgPlugins/CMakeLists.txt b/src/osgPlugins/CMakeLists.txt index c6db5a5e9..782da5fb2 100644 --- a/src/osgPlugins/CMakeLists.txt +++ b/src/osgPlugins/CMakeLists.txt @@ -263,6 +263,10 @@ ADD_SUBDIRECTORY(osc) ADD_SUBDIRECTORY(trk) ADD_SUBDIRECTORY(tf) +IF(Boost_INCLUDE_DIR AND LIBLAS_FOUND) + ADD_SUBDIRECTORY(las) +ENDIF() + #################################################### # diff --git a/src/osgPlugins/las/CMakeLists.txt b/src/osgPlugins/las/CMakeLists.txt new file mode 100644 index 000000000..c6feef0a8 --- /dev/null +++ b/src/osgPlugins/las/CMakeLists.txt @@ -0,0 +1,9 @@ +INCLUDE_DIRECTORIES(${LIBLAS_INCLUDE_DIRS}) +INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR}) + +SET(TARGET_SRC ReaderWriterLAS.cpp ) + +SET(TARGET_LIBRARIES_VARS LIBLAS_LIBRARIES) + +#### end var setup ### +SETUP_PLUGIN(las) diff --git a/src/osgPlugins/las/ReaderWriterLAS.cpp b/src/osgPlugins/las/ReaderWriterLAS.cpp new file mode 100644 index 000000000..2ca732e3c --- /dev/null +++ b/src/osgPlugins/las/ReaderWriterLAS.cpp @@ -0,0 +1,215 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +class ReaderWriterLAS : public osgDB::ReaderWriter +{ + public: + + ReaderWriterLAS() + { + supportsExtension("las","LAS point cloud format"); + supportsOption("v","Verbose output"); + } + + virtual const char* className() const { return "LAS point cloud reader"; } + + virtual ReadResult readNode(const std::string& file, const osgDB::ReaderWriter::Options* options) const + { + std::string ext = osgDB::getLowerCaseFileExtension(file); + if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; + + std::string fileName = osgDB::findDataFile( file, options ); + if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; + + OSG_INFO << "Reading file "<getOptionString()); + std::string opt; + while (iss >> opt) + { + if(opt=="v") + { + verbose = true; + } + } + } + + /// HEADER /// + + std::ifstream ifs; + if (!liblas::Open(ifs, file)) + { + return ReadResult::ERROR_IN_READING_FILE; + } + liblas::Reader reader(ifs); + liblas::Header const& h = reader.GetHeader(); + + if (verbose) { + std::cout << "File name: " << file << '\n'; + //std::cout << "Version : " << reader.GetVersion() << '\n'; + std::cout << "Signature: " << h.GetFileSignature() << '\n'; + std::cout << "Format : " << h.GetDataFormatId() << '\n'; + std::cout << "Project : " << h.GetProjectId() << '\n'; + std::cout << "Points count: " << h.GetPointRecordsCount() << '\n'; + std::cout << "VLRecords count: " << h.GetRecordsCount() << '\n'; + std::cout << "Points by return: "; + std::copy(h.GetPointRecordsByReturnCount().begin(), + h.GetPointRecordsByReturnCount().end(), + std::ostream_iterator(std::cout, " ")); + std::cout << std::endl; + } + + + // POINTS //// + + unsigned int targetNumVertices = 10000; + + osg::Geode* geode = new osg::Geode; + + osg::Geometry* geometry = new osg::Geometry; + + osg::Vec3Array* vertices = new osg::Vec3Array; + osg::Vec4ubArray* colours = new osg::Vec4ubArray; + + vertices->reserve(targetNumVertices); + colours->reserve(targetNumVertices); + + liblas::detail::Timer t; + t.start(); + + // This is legacy from libLas Read example. + // The limits are not used in the OSG actual code + // It is left for visual "verification" using the cout output + typedef std::pair minmax_t; + minmax_t mx (DBL_MAX, -DBL_MAX); + minmax_t my (DBL_MAX, -DBL_MAX); + minmax_t mz (DBL_MAX, -DBL_MAX); + + while (reader.ReadNextPoint()) + { + liblas::Point const& p = reader.GetPoint(); + + mx.first = std::min(mx.first, p[0]); + mx.second = std::max(mx.second, p[0]); + my.first = std::min(my.first, p[1]); + my.second = std::max(my.second, p[1]); + mz.first = std::min(mz.first, p[2]); + mz.second = std::max(mz.second, p[2]); + } + + double const d1 = t.stop(); + t.start(); + + if (verbose) { + std::cout << "Min Max calculation. Elapsed Time: " << d1 << "\n" + << std::fixed << std::setprecision(6) + << "\nX: (" << mx.first << ", " << mx.second << ")" + << "\nY: (" << my.first << ", " << my.second << ")" + << "\nZ: (" << mz.first << ", " << mz.second << ")" + << std::endl; + } + + // calculate the mid point of the point cloud + double mid_x = 0.5*(mx.second - mx.first); + double mid_y = 0.5*(my.second - my.first); + double mid_z = 0.5*(mz.second - mz.first); + + // now we do a second pass substracting the mid point to each point + reader.Reset(); + uint32_t i = 0; + while (reader.ReadNextPoint()) + { + liblas::Point const& p = reader.GetPoint(); + + // Extract color components from LAS point + liblas::Color c = p.GetColor(); + uint32_t r = c.GetRed(); + uint32_t g = c.GetGreen(); + uint32_t b = c.GetBlue(); + uint32_t a = 255; // default value, since LAS point has no alpha information + + if (vertices->size()>=targetNumVertices) + { + // finishing setting up the current geometry and add it to the geode. + geometry->setUseDisplayList(true); + geometry->setUseVertexBufferObjects(true); + geometry->setVertexArray(vertices); + geometry->setColorArray(colours, osg::Array::BIND_PER_VERTEX); + geometry->addPrimitiveSet(new osg::DrawArrays(GL_POINTS,0,vertices->size())); + + geode->addDrawable(geometry); + + // allocate a new geometry + geometry = new osg::Geometry; + + vertices = new osg::Vec3Array; + colours = new osg::Vec4ubArray; + + vertices->reserve(targetNumVertices); + colours->reserve(targetNumVertices); + } + + vertices->push_back(osg::Vec3d (p[0] - mid_x, p[1] - mid_y, p[2] - mid_z) ); + colours->push_back(osg::Vec4ub(r,g,b,a)); + + // Warning: Printing zillion of points may take looong time + //std::cout << i << ". " << p << '\n'; + i++; + } + double const d2 = t.stop(); + + if (reader.GetHeader().GetPointRecordsCount() != i) + { + return ReadResult::ERROR_IN_READING_FILE; + } + + + if (verbose) { + std::cout << "Read points: " << i << " Elapsed Time: " << d2 + << std::endl << std::endl; + } + + geometry->setUseDisplayList(true); + geometry->setUseVertexBufferObjects(true); + geometry->setVertexArray(vertices); + geometry->setColorArray(colours, osg::Array::BIND_PER_VERTEX); + geometry->addPrimitiveSet(new osg::DrawArrays(GL_POINTS,0,vertices->size())); + + geode->addDrawable(geometry); + + + // MatrixTransform with the mid-point translation + + osg::MatrixTransform *mt = new osg::MatrixTransform; + mt->setMatrix ( osg::Matrix::translate ( osg::Vec3d(mid_x, mid_y, mid_z)) ); + mt->addChild (geode); + + return mt; + } +}; + +// now register with Registry to instantiate the above +// reader/writer. +REGISTER_OSGPLUGIN(las, ReaderWriterLAS)