diff --git a/CMake/External_FFmpeg.cmake b/CMake/External_FFmpeg.cmake index 7b55751fd..bc850f693 100644 --- a/CMake/External_FFmpeg.cmake +++ b/CMake/External_FFmpeg.cmake @@ -127,6 +127,10 @@ if(APPLE) list(APPEND FFMPEG_CONFIGURE_COMMAND --sysroot=${CMAKE_OSX_SYSROOT} --disable-doc) endif() +if(fletch_BUILD_CXX17) + list(APPEND FFMPEG_CONFIGURE_COMMAND --extra-cxxflags="-std=c++17") +endif() + ExternalProject_Add(FFmpeg URL ${FFmpeg_file} DEPENDS ${ffmpeg_DEPENDS} diff --git a/CMake/External_OpenCV.cmake b/CMake/External_OpenCV.cmake index 79bf1f579..ec82b43d5 100644 --- a/CMake/External_OpenCV.cmake +++ b/CMake/External_OpenCV.cmake @@ -312,7 +312,7 @@ if (CMAKE_COMPILER_IS_GNUCC AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5) endif() # OpenCV 3.3.0 has an option to enable C++ 11 -if (fletch_BUILD_CXX11) +if (fletch_BUILD_CXX17) list(APPEND OpenCV_EXTRA_BUILD_FLAGS -DENABLE_CXX11:BOOL=ON) endif() diff --git a/CMake/External_VXL.cmake b/CMake/External_VXL.cmake index ea4e097c6..b1a54df1f 100644 --- a/CMake/External_VXL.cmake +++ b/CMake/External_VXL.cmake @@ -96,6 +96,7 @@ if (EXISTS ${VXL_patch}) set(VXL_PATCH_COMMAND ${CMAKE_COMMAND} -DVXL_PATCH_DIR:PATH=${VXL_patch} -DVXL_SOURCE_DIR:PATH=${fletch_BUILD_PREFIX}/src/VXL + -Dfletch_BUILD_CXX17:BOOL=${fletch_BUILD_CXX17} -P ${VXL_patch}/Patch.cmake ) endif() diff --git a/CMake/External_libkml.cmake b/CMake/External_libkml.cmake index f9edc0291..b70bec828 100644 --- a/CMake/External_libkml.cmake +++ b/CMake/External_libkml.cmake @@ -33,6 +33,7 @@ ExternalProject_Add(libkml PATCH_COMMAND ${CMAKE_COMMAND} -Dlibkml_patch:PATH=${fletch_SOURCE_DIR}/Patches/libkml -Dlibkml_source:PATH=${fletch_BUILD_PREFIX}/src/libkml + -Dfletch_BUILD_CXX17:BOOL=${fletch_BUILD_CXX17} -P ${fletch_SOURCE_DIR}/Patches/libkml/Patch.cmake CMAKE_ARGS ${COMMON_CMAKE_ARGS} diff --git a/CMake/External_pybind11.cmake b/CMake/External_pybind11.cmake index fd37ef907..2ca123b46 100644 --- a/CMake/External_pybind11.cmake +++ b/CMake/External_pybind11.cmake @@ -1,5 +1,5 @@ -if (NOT fletch_BUILD_CXX11) - message(FATAL_ERROR "CXX11 must be enabled to use pybind11") +if (NOT fletch_BUILD_CXX17) + message(FATAL_ERROR "CXX17 must be enabled to use pybind11") endif() if (fletch_ENABLE_CPython) diff --git a/CMakeLists.txt b/CMakeLists.txt index a55fdc445..5ba6b1ba5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,9 +77,9 @@ add_custom_target(fletch-build-install) # Include CXX11 support set(fletch_CXX_STANDARD_VERSION "98") -option(fletch_BUILD_CXX11 "" TRUE) -if (fletch_BUILD_CXX11) - set(fletch_CXX_STANDARD_VERSION "11") +option(fletch_BUILD_CXX17 "" TRUE) +if (fletch_BUILD_CXX17) + set(fletch_CXX_STANDARD_VERSION "17") endif() # diff --git a/Patches/VXL/Patch.cmake b/Patches/VXL/Patch.cmake index cc5ba0396..fe6c6c2b7 100644 --- a/Patches/VXL/Patch.cmake +++ b/Patches/VXL/Patch.cmake @@ -11,3 +11,10 @@ file(COPY ${VXL_PATCH_DIR}/core/vbl/vbl_array_2d.h file(COPY ${VXL_PATCH_DIR}/v3p/openjpeg2/opj_includes.h DESTINATION ${VXL_SOURCE_DIR}/v3p/openjpeg2/ ) + +# Fix C++17 compatibility: replace deprecated std::bind2nd with lambda +if(fletch_BUILD_CXX17) + file(COPY ${VXL_PATCH_DIR}/core/vil/algo/vil_gauss_filter.cxx + DESTINATION ${VXL_SOURCE_DIR}/core/vil/algo/ + ) +endif() diff --git a/Patches/VXL/core/vil/algo/vil_gauss_filter.cxx b/Patches/VXL/core/vil/algo/vil_gauss_filter.cxx new file mode 100644 index 000000000..357a47d46 --- /dev/null +++ b/Patches/VXL/core/vil/algo/vil_gauss_filter.cxx @@ -0,0 +1,130 @@ +// This is core/vil/algo/vil_gauss_filter.cxx +#include +#include +#include +#include "vil_gauss_filter.h" +//: +// \file +// \brief Functions to smooth an image +// \author Ian Scott + +#ifdef _MSC_VER +# include +#endif +#include +#include +#include +#include + +vil_gauss_filter_5tap_params::vil_gauss_filter_5tap_params(double val_sigma) +{ + sigma_ = val_sigma; + const double z = 1/(std::sqrt(2.0)*val_sigma); + filt0_ = vnl_erf(0.5 * z) - vnl_erf(-0.5 * z); + filt1_ = vnl_erf(1.5 * z) - vnl_erf(0.5 * z); + filt2_ = vnl_erf(2.5 * z) - vnl_erf(1.5 * z); + + double five_tap_total = 2*(filt2_ + filt1_) + filt0_; +// double four_tap_total = filt2_ + 2*(filt1_) + filt0_; +// double three_tap_total = filt2_ + filt1_ + filt0_; + +// Calculate 3 tap half Gaussian filter assuming constant edge extension + filt_edge0_ = (filt0_ + filt1_ + filt2_) / five_tap_total; + filt_edge1_ = filt1_ / five_tap_total; + filt_edge2_ = filt2_ / five_tap_total; +#if 0 + filt_edge0_ = 1.0; + filt_edge1_ = 0.0; + filt_edge2_ = 0.0; +#endif +// Calculate 4 tap skewed Gaussian filter assuming constant edge extension + filt_pen_edge_n1_ = (filt1_+filt2_) / five_tap_total; + filt_pen_edge0_ = filt0_ / five_tap_total; + filt_pen_edge1_ = filt1_ / five_tap_total; + filt_pen_edge2_ = filt2_ / five_tap_total; + +// Calculate 5 tap Gaussian filter + filt0_ = filt0_ / five_tap_total; + filt1_ = filt1_ / five_tap_total; + filt2_ = filt2_ / five_tap_total; + + assert(filt_edge0_ >= filt_edge1_); + assert(filt_edge1_ >= filt_edge2_); +} + + +//: Generate an n-tap FIR filter from a Gaussian function. +// The filter uses the equation $k D^d \exp -\frac{x^2}{2\sigma^2} $, +// where D is the differential operator, and k is a normalising constant. +// \param diff The number of differential operators to apply to the filter. +// If you want just a normal gaussian, set diff to 0. +// \param sd The width of the gaussian. +// +// The taps will be calculated using the integral of the above equation over +// the pixel width. However, aliasing will reduce the meaningfulness of +// your filter when sd << (diff+1). In most applications you will +// want filter.size() ~= sd*7, which will avoid significant truncation, +// without wasting the outer taps on near-zero values. +void vil_gauss_filter_gen_ntap(double sd, unsigned diff, + std::vector &filter) +{ + std::size_t centre = filter.size()/2; // or just past centre if even length + double sum=0.0; // area under sampled curve. + double tap; // workspace + + if (diff==0) + { + const double z = 1/(std::sqrt(2.0)*sd); + if (filter.size() % 2 == 0) // even length filter - off-centre + { + for (unsigned i=0 ; i= 0.0); + double norm = 1.0 / sum; + // Use lambda instead of deprecated std::bind2nd for C++17 compatibility + std::transform(filter.begin(), filter.end(), filter.begin(), + [norm](double x) { return x * norm; }); +} diff --git a/Patches/libkml/Patch.cmake b/Patches/libkml/Patch.cmake index dd1e748dd..acad9894e 100644 --- a/Patches/libkml/Patch.cmake +++ b/Patches/libkml/Patch.cmake @@ -16,3 +16,11 @@ file(COPY ${libkml_patch}/unzip.c DESTINATION ${libkml_source}/third_party/zlib-1.2.3/contrib/minizip ) + +# Fix C++17 compatibility: remove deprecated std::binary_function +if(fletch_BUILD_CXX17) + file(COPY + ${libkml_patch}/convenience/feature_list.cc + DESTINATION ${libkml_source}/src/kml/convenience/ + ) +endif() diff --git a/Patches/libkml/convenience/feature_list.cc b/Patches/libkml/convenience/feature_list.cc new file mode 100644 index 000000000..1bac45447 --- /dev/null +++ b/Patches/libkml/convenience/feature_list.cc @@ -0,0 +1,158 @@ +// Copyright 2008, Google Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// 3. Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file contains the implementation of the FeatureList class. +// While STL list is not directly exposed the name FeatureList is as such +// to suggest list-like performance. + +#include "kml/convenience/feature_list.h" +#include +#include +#include +#include +#include +#include "kml/dom.h" +#include "kml/convenience/convenience.h" +#include "kml/engine.h" + +using kmldom::ContainerPtr; +using kmldom::DataPtr; +using kmldom::ExtendedDataPtr; +using kmldom::FeaturePtr; +using kmldom::LatLonAltBoxPtr; +using kmldom::KmlFactory; +using kmldom::RegionPtr; +using kmlengine::Bbox; + +namespace kmlconvenience { + +static const char* kFeatureScoreName = "kml.FeatureScore"; + +int GetFeatureScore(FeaturePtr feature) { + string score; + if (GetExtendedDataValue(feature, kFeatureScoreName, &score)) { + return atoi(score.c_str()); + } + return 0; +} + +void SetFeatureScore(const string& score, FeaturePtr feature) { + SetExtendedDataValue(kFeatureScoreName, score, feature); +} + +void FeatureList::PushBack(const FeaturePtr& feature) { + if (feature) { + feature_list_.push_back(feature); + } +} + +size_t FeatureList::Save(ContainerPtr container) const { + size_t count = 0; + feature_list_t::const_iterator iter; + for (iter = feature_list_.begin(); iter != feature_list_.end(); ++iter) { + ++count; + container->add_feature(*iter); + } + return count; +} + +size_t FeatureList::BboxSplit(const Bbox& bbox, size_t max, + FeatureList* output) { + if (max == 0) { // "0" has the special meaning of "all". + max = feature_list_.size(); + } + size_t count = 0; + // See Effective STL, by Scott Meyers, Item 9, page 46. A while loop is used + // instead of for to make explicit the advancement of iter within the loop. + // If the item is erased then list.erase() returns the advanced iter, + // else we advance it oursevles. + feature_list_t::iterator iter = feature_list_.begin(); + while (iter != feature_list_.end()) { + double lat, lon; + if (kmlengine::GetFeatureLatLon(*iter, &lat, &lon) && + bbox.Contains(lat,lon)) { + if (output) { + output->PushBack(*iter); + } + iter = feature_list_.erase(iter); // list.erase() advances to next. + ++count; + if (--max == 0) { // max guaranteed to be > 0. + break; + } + } else { + ++iter; // Not erasing so we advance to next explicitely. + } + } + return count; +} + +size_t FeatureList::RegionSplit(const RegionPtr& region, size_t max, + FeatureList* output) { + if (region && region->has_latlonaltbox()) { + LatLonAltBoxPtr llab = region->get_latlonaltbox(); + Bbox bbox(llab->get_north(), llab->get_south(), + llab->get_east(), llab->get_west()); + return BboxSplit(bbox, max, output); + } + return 0; +} + +// This function object is used by STL sort() to order Features +// by score. Results in sort of highest score first. +// Note: std::binary_function was removed in C++17, but it was only used +// for type definitions that are not required for the functor to work. +struct CompareFeatures { + bool operator()(const kmldom::FeaturePtr& a, + const kmldom::FeaturePtr& b) const { + return GetFeatureScore(a) > GetFeatureScore(b); + } +}; + +// Sort the internal list of features based on score. +void FeatureList::Sort() { + // See Effective STL, by Scott Meyers, Item 44, page 192. + feature_list_.sort(CompareFeatures()); +} + +// Return the number of features held in the internal list. +size_t FeatureList::Size() const { + return feature_list_.size(); +} + +// Expand the bounds of the given bbox based on the features in the list. +void FeatureList::ComputeBoundingBox(Bbox* bbox) const { + if (!bbox) { + return; + } + feature_list_t::const_iterator iter; + for (iter = feature_list_.begin(); iter != feature_list_.end(); ++iter) { + double lat, lon; + if (kmlengine::GetFeatureLatLon(*iter, &lat, &lon)) { + bbox->ExpandLatLon(lat, lon); + } + } +} + +} // end namespace kmlconvenience diff --git a/README.rst b/README.rst index a446cf701..4801fa8f5 100644 --- a/README.rst +++ b/README.rst @@ -141,7 +141,7 @@ want the C++ libraries built. ``fletch_ENABLE_ALL_PACKAGES`` Turn all packages on (you can turn some back off later) ``fletch_BUILD_WITH_PYTHON`` Build all the packages with Python support -``fletch_BUILD_CXX11`` Build using C++11 compiler options. +``fletch_BUILD_CXX17`` Build using C++17 compiler options. This is required for KWIVER. ``fletch_DOWNLOAD_DIR`` This is where Fletch will cache downloaded source source code tarballs (default is ``src/Downloads``)