From 08185e1b02b58f02d3311c37b8179927ebd11ca7 Mon Sep 17 00:00:00 2001 From: Nicolas Mellado Date: Fri, 22 Dec 2023 12:51:26 +0100 Subject: [PATCH 01/11] Add submodule argparse --- .gitmodules | 3 +++ CMakeLists.txt | 9 +++++++++ external/argparse | 1 + 3 files changed, 13 insertions(+) create mode 160000 external/argparse diff --git a/.gitmodules b/.gitmodules index 6e700fa..01cfbf3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "external/ponca"] path = external/ponca url = https://github.com/poncateam/ponca.git +[submodule "external/argparse"] + path = external/argparse + url = https://github.com/p-ranav/argparse.git diff --git a/CMakeLists.txt b/CMakeLists.txt index d3ca3c3..76ba4a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,13 @@ set( NANOGUI_BUILD_PYTHON CACHE BOOL OFF) message("\n\n == CMAKE recursively building NanoGUI\n") add_subdirectory("external/nanogui") +# Add argparse +set(ARGPARSE_INSTALL OFF) +set(ARGPARSE_BUILD_TESTS OFF) +set(ARGPARSE_BUILD_SAMPLES OFF) +message("\n\n == CMAKE recursively building argparse\n") +add_subdirectory("external/argparse") + # Find OpenMP find_package(OpenMP) set(OpenMP_link_libraries ) @@ -57,6 +64,8 @@ add_executable( poncaplot src/myview.cpp src/application.h src/application.cpp + src/cli.h + src/cli.cpp src/poncaTypes.h src/drawingPass.h src/drawingPasses/distanceField.h diff --git a/external/argparse b/external/argparse new file mode 160000 index 0000000..af442b4 --- /dev/null +++ b/external/argparse @@ -0,0 +1 @@ +Subproject commit af442b4da0cd7a07b56fa709bd16571889dc7fda From c150d5cfffcdd4dc5d5f84a19aabe029974b93be Mon Sep 17 00:00:00 2001 From: Nicolas Mellado Date: Fri, 22 Dec 2023 12:51:57 +0100 Subject: [PATCH 02/11] Add base class and logic to switch from CLI to Graphics app --- src/application.cpp | 4 ++-- src/application.h | 2 +- src/cli.cpp | 17 ++++++++++++++ src/cli.h | 15 +++++++++++++ src/main.cpp | 54 +++++++++++++++++++++++++++++++-------------- 5 files changed, 72 insertions(+), 20 deletions(-) create mode 100644 src/cli.cpp create mode 100644 src/cli.h diff --git a/src/application.cpp b/src/application.cpp index febf97c..6c7c7ed 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -27,8 +27,8 @@ using namespace nanogui; const int tex_width = 500; const int tex_height = 500; -PoncaPlotApplication::PoncaPlotApplication() : -Screen(Vector2i(1200, 1024), "PoncaPlot"), m_dataMgr(new DataManager()){ +PoncaPlotApplication::PoncaPlotApplication(DataManager* mgr) : +Screen(Vector2i(1200, 1024), "PoncaPlot"), m_dataMgr(mgr){ m_dataMgr->setKdTreePostUpdateFunction([this]() { this->renderPasses(); }); diff --git a/src/application.h b/src/application.h index c95c87c..dcc99bb 100644 --- a/src/application.h +++ b/src/application.h @@ -20,7 +20,7 @@ namespace nanogui{ class PoncaPlotApplication : public nanogui::Screen { public: - PoncaPlotApplication(); + PoncaPlotApplication(DataManager* mgr); bool keyboard_event(int key, int scancode, int action, int modifiers) override; diff --git a/src/cli.cpp b/src/cli.cpp new file mode 100644 index 0000000..7df7a24 --- /dev/null +++ b/src/cli.cpp @@ -0,0 +1,17 @@ +#include "cli.h" + +#include "myview.h" +#include "dataManager.h" +#include "drawingPass.h" +#include "drawingPasses/distanceField.h" + + + +PoncaPlotCLI::PoncaPlotCLI(DataManager* mgr) : m_dataMgr(mgr){ + +} + +bool +PoncaPlotCLI::run(int argc, char **argv) { + return false; +} diff --git a/src/cli.h b/src/cli.h new file mode 100644 index 0000000..96c9520 --- /dev/null +++ b/src/cli.h @@ -0,0 +1,15 @@ +#pragma once + +// forward declarations +class DataManager; + +class PoncaPlotCLI { + +public: + PoncaPlotCLI(DataManager* mgr); + bool run(int argc, char**argv); + +private: + float* m_texture {nullptr}; + DataManager *m_dataMgr{nullptr}; +}; diff --git a/src/main.cpp b/src/main.cpp index 547ce4c..77312c5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,28 +13,48 @@ #include +#include "dataManager.h" #include "application.h" +#include "cli.h" -int main(int /* argc */, char ** /* argv */) { - try { - nanogui::init(); +DataManager *mgr {nullptr}; - /* scoped variables */ { - nanogui::ref app = new PoncaPlotApplication(); - app->dec_ref(); - app->draw_all(); - app->set_visible(true); - nanogui::mainloop(1 / 10.f * 1000); - } +void clean(){ + if (mgr){ + delete mgr; + mgr = nullptr; + } +} - nanogui::shutdown(); - } catch (const std::exception &e) { - std::string error_msg = std::string("Caught a fatal error: ") + std::string(e.what()); - std::cerr << error_msg << std::endl; - return -1; - } catch (...) { - std::cerr << "Caught an unknown error!" << std::endl; +int main(int argc , char ** argv) { + mgr = new DataManager(); + + PoncaPlotCLI cli(mgr); + + if (! cli.run(argc, argv)) { + std::cout << "CLI does not want to run: launching graphic app" << std::endl; + try { + nanogui::init(); + + /* scoped variables */ { + nanogui::ref app = new PoncaPlotApplication(mgr); + app->dec_ref(); + app->draw_all(); + app->set_visible(true); + nanogui::mainloop(1 / 10.f * 1000); + } + + nanogui::shutdown(); + } catch (const std::exception &e) { + std::string error_msg = std::string("Caught a fatal error: ") + std::string(e.what()); + std::cerr << error_msg << std::endl; + clean(); + return -1; + } catch (...) { + std::cerr << "Caught an unknown error!" << std::endl; + } } + clean(); return 0; } From 9446b8752673ef3a0a91913b256cfae3efc02c29 Mon Sep 17 00:00:00 2001 From: Nicolas Mellado Date: Fri, 22 Dec 2023 13:08:16 +0100 Subject: [PATCH 03/11] [cmake] Fix missing include directive to argparse --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 76ba4a1..543b967 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,6 +77,7 @@ add_executable( poncaplot target_include_directories(poncaplot PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/external/nanogui/include" "${CMAKE_CURRENT_SOURCE_DIR}/external/ponca/" + "${CMAKE_CURRENT_SOURCE_DIR}/external/argparse/include" "${CMAKE_CURRENT_SOURCE_DIR}/src/") # Link settings From 8c82fd0b1e62f7b3c811b109a0d09cd5c62eadc6 Mon Sep 17 00:00:00 2001 From: Nicolas Mellado Date: Fri, 22 Dec 2023 14:56:20 +0100 Subject: [PATCH 04/11] Move KdTree definition to poncaTypes.h --- src/dataManager.h | 33 -------------------------- src/drawingPass.h | 14 +++++------ src/drawingPasses/distanceField.h | 4 ++-- src/drawingPasses/poncaFitField.h | 2 +- src/poncaTypes.h | 39 ++++++++++++++++++++++++++++++- 5 files changed, 48 insertions(+), 44 deletions(-) diff --git a/src/dataManager.h b/src/dataManager.h index 7a8e80a..7bc75f9 100644 --- a/src/dataManager.h +++ b/src/dataManager.h @@ -19,39 +19,6 @@ #endif #define DEFAULT_POINT_ANGLE M_PI / 2. -template > -struct MyKdTreeInnerNode : public Ponca::KdTreeDefaultInnerNode { - using AabbType = _AabbType; - AabbType m_aabb{}; -}; -// -//template -//using MyKdTreeNode = Ponca::KdTreeCustomizableNode >; - -template -struct MyKdTreeNode : Ponca::KdTreeCustomizableNode> { - - using Base = Ponca::KdTreeCustomizableNode>; - using AabbType = typename Base::AabbType; - - void configure_range(Index start, Index size, const AabbType &aabb) - { - Base::configure_range(start, size, aabb); - if (! Base::is_leaf() ) - { - Base::getAsInner().m_aabb = aabb; - } - } - [[nodiscard]] inline std::optional getAabb() const { - if (! Base::is_leaf()) - return Base::getAsInner().m_aabb; - else - return std::optional(); - } -}; /// Structure holding shared data struct DataManager { diff --git a/src/drawingPass.h b/src/drawingPass.h index 2366043..0e4f66b 100644 --- a/src/drawingPass.h +++ b/src/drawingPass.h @@ -3,19 +3,19 @@ #include #include -#include "dataManager.h" +#include "poncaTypes.h" /// Base class to rendering processes struct DrawingPass { - virtual void render(const DataManager::KdTree& points, float*buffer, int w, int h) = 0; + virtual void render(const KdTree& points, float*buffer, int w, int h) = 0; virtual ~DrawingPass() = default; }; struct FillPass : public DrawingPass { inline explicit FillPass(const nanogui::Vector4f &fillColor = {1,1,1,1}) : m_fillColor(fillColor) {} - void render(const DataManager::KdTree& /*points*/, float*buffer, int w, int h) override{ + void render(const KdTree& /*points*/, float*buffer, int w, int h) override{ #pragma omp parallel for default(none) shared(buffer, w, h) for(auto j = 0; j; using SphereFit = Ponca::Basket; using OrientedSphereFit= Ponca::Basket; -using UnorientedSphereFit = Ponca::Basket; \ No newline at end of file +using UnorientedSphereFit = Ponca::Basket; + + + + +#include + +template > +struct MyKdTreeInnerNode : public Ponca::KdTreeDefaultInnerNode { + using AabbType = _AabbType; + AabbType m_aabb{}; +}; + +template +struct MyKdTreeNode : Ponca::KdTreeCustomizableNode> { + + using Base = Ponca::KdTreeCustomizableNode>; + using AabbType = typename Base::AabbType; + + void configure_range(Index start, Index size, const AabbType &aabb) + { + Base::configure_range(start, size, aabb); + if (! Base::is_leaf() ) + { + Base::getAsInner().m_aabb = aabb; + } + } + [[nodiscard]] inline std::optional getAabb() const { + if (! Base::is_leaf()) + return Base::getAsInner().m_aabb; + else + return std::optional(); + } +}; + +using KdTree = Ponca::KdTreeBase>; From 20f44941c93a1cf152010144107bf80a5049e3ad Mon Sep 17 00:00:00 2001 From: Nicolas Mellado Date: Fri, 22 Dec 2023 14:57:19 +0100 Subject: [PATCH 05/11] Centralise DrawingPasses storage and creation in DataManager --- src/application.cpp | 37 +++++++++++++++----------------- src/application.h | 8 +++---- src/dataManager.cpp | 42 +++++++++++++++++++++++++++++++++++++ src/dataManager.h | 51 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 25 deletions(-) diff --git a/src/application.cpp b/src/application.cpp index 6c7c7ed..61cf7d9 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -32,14 +32,12 @@ Screen(Vector2i(1200, 1024), "PoncaPlot"), m_dataMgr(mgr){ m_dataMgr->setKdTreePostUpdateFunction([this]() { this->renderPasses(); }); - passDFWithKdTree = new DistanceFieldWithKdTree(); - passPlaneFit = new PlaneFitField(); - passSphereFit = new SphereFitField(); - passOrientedSphereFit = new OrientedSphereFitField(); - passUnorientedSphereFit = new UnorientedSphereFitField(); + // force creation of all supported DrawingPasses + for(int i=0;i!=m_dataMgr->nbSupportedDrawingPasses;++i) + m_dataMgr->getDrawingPass(i); m_passes[0] = new FillPass( {1,1,1,1}); - m_passes[1] = passOrientedSphereFit; + m_passes[1] = m_dataMgr->getDrawingPass("Oriented Sphere"); m_passes[2] = new ColorMap({1,1,1,1}); m_passes[3] = new DisplayPoint({0,0,0,1}); @@ -98,22 +96,16 @@ Screen(Vector2i(1200, 1024), "PoncaPlot"), m_dataMgr(mgr){ new nanogui::Label(window, "Select Fit Type", "sans-bold"); - auto combo =new nanogui::ComboBox(window, - { "Distance Field", - "Plane", - "Sphere", - "Oriented Sphere", - "Unoriented Sphere"}); + + std::vector names; + names.resize(m_dataMgr->nbSupportedDrawingPasses); + for (const auto& p : m_dataMgr->supportedDrawingPasses) + names[p.second] = p.first; + + auto combo =new nanogui::ComboBox(window, names); combo->set_selected_index(3); combo->set_callback([this](int id){ - switch (id) { - case 0: m_passes[1] = passDFWithKdTree; break; - case 1: m_passes[1] = passPlaneFit; break; - case 2: m_passes[1] = passSphereFit; break; - case 3: m_passes[1] = passOrientedSphereFit; break; - case 4: m_passes[1] = passUnorientedSphereFit; break; - default: throw std::runtime_error("Unknown Field type!"); - } + m_passes[1] = m_dataMgr->getDrawingPass(id); buildPassInterface(id); renderPasses(); }); @@ -141,6 +133,11 @@ Screen(Vector2i(1200, 1024), "PoncaPlot"), m_dataMgr(mgr){ new nanogui::Label(distanceFieldWidget, "no parameter available"); } + passPlaneFit = dynamic_cast(m_dataMgr->getDrawingPass("Plane")); + passSphereFit = dynamic_cast(m_dataMgr->getDrawingPass("Sphere")); + passOrientedSphereFit = dynamic_cast(m_dataMgr->getDrawingPass("Oriented Sphere")); + passUnorientedSphereFit = dynamic_cast(m_dataMgr->getDrawingPass("Unoriented Sphere")); + { genericFitWidget = new nanogui::Widget(window); genericFitWidget->set_layout(new GroupLayout()); diff --git a/src/application.h b/src/application.h index dcc99bb..70dca45 100644 --- a/src/application.h +++ b/src/application.h @@ -46,9 +46,7 @@ class PoncaPlotApplication : public nanogui::Screen { *genericFitWidget, //< parameters applicable to all fitting techniques *planeFitWidget, *sphereFitWidget, *orientedSphereFitWidget, *unorientedSphereFitWidget, *pass3Widget,*pass4Widget; - DistanceFieldWithKdTree *passDFWithKdTree; - PlaneFitField *passPlaneFit; - SphereFitField *passSphereFit; - OrientedSphereFitField *passOrientedSphereFit; - UnorientedSphereFitField *passUnorientedSphereFit; + + + BaseFitField* passPlaneFit, *passSphereFit, *passOrientedSphereFit, *passUnorientedSphereFit; }; diff --git a/src/dataManager.cpp b/src/dataManager.cpp index ecec428..8b86917 100644 --- a/src/dataManager.cpp +++ b/src/dataManager.cpp @@ -3,6 +3,15 @@ #include #include +DataManager::DataManager() { + m_drawingPasses.fill(nullptr); +} + +DataManager::~DataManager() { + for (auto* p : m_drawingPasses) + delete p; +} + bool DataManager::savePointCloud(const std::string& path) const{ if( path.empty() ) return false; @@ -106,3 +115,36 @@ DataManager::fitPointCloudToRange(const std::pair& rangesEnd, const } } +DrawingPass* +DataManager::getDrawingPass(const std::string& name){ + return getDrawingPass(supportedDrawingPasses.at(name)); +} + +DrawingPass* +DataManager::getDrawingPass(size_t index){ + if (index >= nbSupportedDrawingPasses) return nullptr; + + DrawingPass** p = &(m_drawingPasses[index]); + if((*p) == nullptr) { + switch (index) { + case 0: //Distance Field + *p = new DistanceFieldWithKdTree(); + break; + case 1: // Plane + *p = new PlaneFitField(); + break; + case 2: // Sphere + *p = new SphereFitField(); + break; + case 3: // Oriented Sphere + *p = new OrientedSphereFitField(); + break; + case 4: // Unoriented Sphere + *p = new UnorientedSphereFitField(); + break; + default: + break; + } + } + return *p; +} diff --git a/src/dataManager.h b/src/dataManager.h index 7bc75f9..be74f5a 100644 --- a/src/dataManager.h +++ b/src/dataManager.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include //pair #include @@ -11,6 +12,8 @@ #include #include "poncaTypes.h" +#include "drawingPasses/distanceField.h" +#include "drawingPasses/poncaFitField.h" #ifndef M_PI @@ -20,6 +23,8 @@ #define DEFAULT_POINT_ANGLE M_PI / 2. +struct DrawingPass; + /// Structure holding shared data struct DataManager { public: @@ -28,6 +33,9 @@ struct DataManager { using PointContainer = std::vector; // stores x,y,normal angle in radians using VectorType = typename KdTree::VectorType; + DataManager(); + ~DataManager(); + /// Read access to point collection inline const KdTree& getKdTree() const { return m_tree; } @@ -62,9 +70,52 @@ struct DataManager { /// \param Number of neighbors (3 means current point and 2 closest points: left and right) void computeNormals(int k = 3); + /// Names of the supported drawing passes + static constexpr size_t nbSupportedDrawingPasses = 5; + const std::map supportedDrawingPasses { + {"Distance Field", 0}, + {"Plane", 1}, + {"Sphere", 2}, + {"Oriented Sphere", 3}, + {"Unoriented Sphere", 4} + }; + + DrawingPass* getDrawingPass(const std::string& name); + + /// Build a a drawing pass + /// \param index of the pass name in supportedDrawingPasses + DrawingPass* getDrawingPass(size_t index); + + template + bool processPass(int index, Functor f) { + switch (index) { + case 0: //Distance Field + f(dynamic_cast(getDrawingPass(0))); + break; + case 1: // Plane + f(dynamic_cast(getDrawingPass(1))); + break; + case 2: // Sphere + f(dynamic_cast(getDrawingPass(2))); + break; + case 3: // Oriented Sphere + f(dynamic_cast(getDrawingPass(3))); + break; + case 4: // Unoriented Sphere + f(dynamic_cast(getDrawingPass(4))); + break; + default: + return false; + } + return true; + } + + private: PointContainer m_points; KdTree m_tree; std::function m_updateFunction {[](){}}; + + std::array m_drawingPasses; }; From e73b6500955463a65e4e08e30fe010a00dc74247 Mon Sep 17 00:00:00 2001 From: Nicolas Mellado Date: Fri, 22 Dec 2023 14:57:50 +0100 Subject: [PATCH 06/11] Start adding attributes for CLI parsing --- src/cli.cpp | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/cli.cpp b/src/cli.cpp index 7df7a24..ae26812 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -5,6 +5,8 @@ #include "drawingPass.h" #include "drawingPasses/distanceField.h" +#include "argparse/argparse.hpp" + PoncaPlotCLI::PoncaPlotCLI(DataManager* mgr) : m_dataMgr(mgr){ @@ -13,5 +15,41 @@ PoncaPlotCLI::PoncaPlotCLI(DataManager* mgr) : m_dataMgr(mgr){ bool PoncaPlotCLI::run(int argc, char **argv) { - return false; + + std::vector names; + names.resize(m_dataMgr->nbSupportedDrawingPasses); + for (const auto& p : m_dataMgr->supportedDrawingPasses) + names[p.second] = p.first; + std::string namesStr; + for (const auto& n : names) + namesStr.append("\"" + n + "\" "); + + + + argparse::ArgumentParser program("poncaplot-cli"); + + program.add_argument("scale") + .help("scale size (in pixels)") + .scan<'g', float>() + .default_value(10); + program.add_argument("-i", "--input") + .required() + .help("input file (.pts or .txt)"); + program.add_argument("-o", "--output") + .required() + .help("output file (image)"); + program.add_argument("-f", "--fitType") + .help("fit type: [" + namesStr + "]"); + + try { + program.parse_args(argc, argv); + } + catch (const std::exception& err) { + std::cout << err.what() << std::endl; + std::cout << program; + return false; + } + + // do processing + return true; } From d596293594b81050f364c73982a946ef574c7109 Mon Sep 17 00:00:00 2001 From: Nicolas Mellado Date: Mon, 8 Jan 2024 17:08:46 +0100 Subject: [PATCH 07/11] Add file loading: GUI is started if output file is not set --- src/cli.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/cli.cpp b/src/cli.cpp index ae26812..4b66b76 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -36,13 +36,19 @@ PoncaPlotCLI::run(int argc, char **argv) { .required() .help("input file (.pts or .txt)"); program.add_argument("-o", "--output") - .required() .help("output file (image)"); program.add_argument("-f", "--fitType") .help("fit type: [" + namesStr + "]"); try { program.parse_args(argc, argv); + auto inputPath = program.get("-i"); + if (! inputPath.empty()) + { + m_dataMgr->loadPointCloud(inputPath); + // load other properties + if( ! program.is_used("-o")) return false; // be sure that GUI is started. + } } catch (const std::exception& err) { std::cout << err.what() << std::endl; From 1f3e72bf382016f7febe9b98da1e0d1949852347 Mon Sep 17 00:00:00 2001 From: Nicolas Mellado Date: Tue, 9 Jan 2024 12:12:43 +0100 Subject: [PATCH 08/11] Add missing include directive (optional) --- src/poncaTypes.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/poncaTypes.h b/src/poncaTypes.h index d518982..11b90fe 100644 --- a/src/poncaTypes.h +++ b/src/poncaTypes.h @@ -2,6 +2,7 @@ #include +#include class DataPoint { From 5af8c01d7dc092f526018f1af3a42da04ff831ab Mon Sep 17 00:00:00 2001 From: Nicolas Mellado Date: Wed, 10 Jan 2024 16:53:33 +0100 Subject: [PATCH 09/11] Add controllers + render image Image is fine in debug mode, but looks faded in release. Need to investigate --- .gitmodules | 3 ++ CMakeLists.txt | 1 + external/stb | 1 + src/cli.cpp | 136 ++++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 122 insertions(+), 19 deletions(-) create mode 160000 external/stb diff --git a/.gitmodules b/.gitmodules index 01cfbf3..6d1cff1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "external/argparse"] path = external/argparse url = https://github.com/p-ranav/argparse.git +[submodule "external/stb"] + path = external/stb + url = https://github.com/nothings/stb.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 543b967..2ab381e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,7 @@ target_include_directories(poncaplot PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/external/nanogui/include" "${CMAKE_CURRENT_SOURCE_DIR}/external/ponca/" "${CMAKE_CURRENT_SOURCE_DIR}/external/argparse/include" + "${CMAKE_CURRENT_SOURCE_DIR}/external/stb/" "${CMAKE_CURRENT_SOURCE_DIR}/src/") # Link settings diff --git a/external/stb b/external/stb new file mode 160000 index 0000000..f4a71b1 --- /dev/null +++ b/external/stb @@ -0,0 +1 @@ +Subproject commit f4a71b13373436a2866c5d68f8f80ac6f0bc1ffe diff --git a/src/cli.cpp b/src/cli.cpp index 4b66b76..ef27c02 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -1,13 +1,23 @@ #include "cli.h" -#include "myview.h" #include "dataManager.h" #include "drawingPass.h" -#include "drawingPasses/distanceField.h" +//#include "drawingPasses/distanceField.h" #include "argparse/argparse.hpp" +#define STB_IMAGE_STATIC +#define STB_IMAGE_IMPLEMENTATION +#define STB_IMAGE_WRITE_IMPLEMENTATION +#if defined(_MSC_VER) +# pragma warning (disable: 4505) // don't warn about dead code in stb_image.h +#elif defined(__GNUC__) +# pragma GCC diagnostic ignored "-Wunused-function" +#endif +#include "stb_image.h" +#include "stb_image_write.h" +#include // floor PoncaPlotCLI::PoncaPlotCLI(DataManager* mgr) : m_dataMgr(mgr){ @@ -16,6 +26,19 @@ PoncaPlotCLI::PoncaPlotCLI(DataManager* mgr) : m_dataMgr(mgr){ bool PoncaPlotCLI::run(int argc, char **argv) { + struct { + std::string inputPath {}; + struct { + std::string name {"Oriented Sphere"}; + float scale {40}; + } fitting; + struct { + std::string path {}; + size_t width {500}; + size_t height {500}; + } output; + } params; + std::vector names; names.resize(m_dataMgr->nbSupportedDrawingPasses); for (const auto& p : m_dataMgr->supportedDrawingPasses) @@ -27,35 +50,110 @@ PoncaPlotCLI::run(int argc, char **argv) { argparse::ArgumentParser program("poncaplot-cli"); - - program.add_argument("scale") - .help("scale size (in pixels)") - .scan<'g', float>() - .default_value(10); program.add_argument("-i", "--input") .required() .help("input file (.pts or .txt)"); - program.add_argument("-o", "--output") - .help("output file (image)"); - program.add_argument("-f", "--fitType") - .help("fit type: [" + namesStr + "]"); + // output controls + { + program.add_argument("-o", "--output") + .help("output file (image)"); + program.add_argument("-w", "--width") + .help("output image width (in pixels)") + .default_value(params.output.width); + program.add_argument("-h", "--height") + .help("output image height (in pixels)") + .default_value(params.output.height); + } + + // fitting controls + { + auto ft = program.add_argument("-f", "--fitType") + .default_value(params.fitting.name) + .help("fit type: [" + namesStr + "]"); + for (const auto& type : m_dataMgr->supportedDrawingPasses) + ft.add_choice(type.first); + + program.add_argument("-s") + .help("scale size (in pixels)") + .scan<'g', float>() + .default_value(params.fitting.scale); + } + + // return value of the method: do we skip the GUI ? + bool skipGUI = true; + + bool loaded = false; try { program.parse_args(argc, argv); - auto inputPath = program.get("-i"); - if (! inputPath.empty()) + params.inputPath = program.get("-i"); + if (! params.inputPath.empty()) { - m_dataMgr->loadPointCloud(inputPath); - // load other properties - if( ! program.is_used("-o")) return false; // be sure that GUI is started. + loaded = m_dataMgr->loadPointCloud(params.inputPath);; + + // load fit properties + if (program.is_used("-f")) params.fitting.name = program.get("-f"); + if (program.is_used("-s")) params.fitting.scale = program.get("-s"); + + // load output properties + auto output = program.present("-o"); + if( output ) { + params.output.path = output.value(); + if (program.is_used("-w")) params.output.width = program.get("-w"); + if (program.is_used("-h")) params.output.height = program.get("-h"); + } else + skipGUI = false; // no output is set: display GUI with parameters set } } catch (const std::exception& err) { std::cout << err.what() << std::endl; std::cout << program; - return false; + skipGUI = false; + } + + // configure and do rendering + if (loaded && skipGUI){ + auto texture = new float [params.output.width * params.output.height * 4]; + + // configure fitting + std::cout << "Configure fitting" << std::endl; + auto pass = m_dataMgr->getDrawingPass(params.fitting.name); + + if( auto fit = dynamic_cast(pass) ) { + fit->m_scale = params.fitting.scale; + } + + // configure renderer + std::cout << "Configure renderer" << std::endl; + std::array renderPasses{ + new FillPass( {1,1,1,1}) + , pass + , new ColorMap({1,1,1,1}) +// , new DisplayPoint({0,0,0,1}) + }; + + // render + std::cout << "Render" << std::endl; + const auto& points = m_dataMgr->getKdTree(); + for (auto* p : renderPasses) { + p->render(points, texture, int(params.output.width), int(params.output.height)); + } + + std::cout << "Save image" << std::endl; + { + auto buffer = new char [params.output.width * params.output.height * 4]; + std::transform(texture, texture + params.output.width * params.output.height * 4, + buffer, + [](float in) -> char{ + return char(std::floor(in*255.f)); + }); + stbi_write_png(params.output.path.c_str(), params.output.width, params.output.height, + 4, buffer, params.output.width * 4); + stbi_image_free(buffer); + } + + delete[] texture; } - // do processing - return true; + return skipGUI; } From 880e5dde3bcb820bf472da30f350d7dae7d1b2e9 Mon Sep 17 00:00:00 2001 From: Nicolas Mellado Date: Fri, 26 Jan 2024 13:04:12 +0100 Subject: [PATCH 10/11] remove -h and -w short options (conflict with help) --- src/cli.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cli.cpp b/src/cli.cpp index ef27c02..b3c3116 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -58,10 +58,10 @@ PoncaPlotCLI::run(int argc, char **argv) { { program.add_argument("-o", "--output") .help("output file (image)"); - program.add_argument("-w", "--width") + program.add_argument("--width") .help("output image width (in pixels)") .default_value(params.output.width); - program.add_argument("-h", "--height") + program.add_argument("--height") .help("output image height (in pixels)") .default_value(params.output.height); } From f42e6ee8bf60c09173f114338f2ab1f1f697af5f Mon Sep 17 00:00:00 2001 From: Leo Date: Fri, 2 Feb 2024 10:00:40 +0100 Subject: [PATCH 11/11] Fix save image CLI --- src/cli.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cli.cpp b/src/cli.cpp index b3c3116..fa1012f 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -58,11 +58,13 @@ PoncaPlotCLI::run(int argc, char **argv) { { program.add_argument("-o", "--output") .help("output file (image)"); - program.add_argument("--width") + program.add_argument("-W", "--width") .help("output image width (in pixels)") + .scan<'i', size_t>() .default_value(params.output.width); - program.add_argument("--height") + program.add_argument("-H", "--height") .help("output image height (in pixels)") + .scan<'i', size_t>() .default_value(params.output.height); } @@ -99,8 +101,8 @@ PoncaPlotCLI::run(int argc, char **argv) { auto output = program.present("-o"); if( output ) { params.output.path = output.value(); - if (program.is_used("-w")) params.output.width = program.get("-w"); - if (program.is_used("-h")) params.output.height = program.get("-h"); + if (program.is_used("-W")) params.output.width = program.get("-W"); + if (program.is_used("-H")) params.output.height = program.get("-H"); } else skipGUI = false; // no output is set: display GUI with parameters set }