Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cli #12

Merged
merged 11 commits into from
Feb 2, 2024
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,9 @@
[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
[submodule "external/stb"]
path = external/stb
url = https://github.com/nothings/stb.git
11 changes: 11 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 )
Expand All @@ -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
Expand All @@ -68,6 +77,8 @@ 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}/external/stb/"
"${CMAKE_CURRENT_SOURCE_DIR}/src/")

# Link settings
Expand Down
1 change: 1 addition & 0 deletions external/argparse
Submodule argparse added at af442b
1 change: 1 addition & 0 deletions external/stb
Submodule stb added at f4a71b
41 changes: 19 additions & 22 deletions src/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,17 @@ 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(); });

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});

Expand Down Expand Up @@ -98,22 +96,16 @@ Screen(Vector2i(1200, 1024), "PoncaPlot"), m_dataMgr(new DataManager()){


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<std::string> 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();
});
Expand Down Expand Up @@ -141,6 +133,11 @@ Screen(Vector2i(1200, 1024), "PoncaPlot"), m_dataMgr(new DataManager()){
new nanogui::Label(distanceFieldWidget, "no parameter available");
}

passPlaneFit = dynamic_cast<BaseFitField*>(m_dataMgr->getDrawingPass("Plane"));
passSphereFit = dynamic_cast<BaseFitField*>(m_dataMgr->getDrawingPass("Sphere"));
passOrientedSphereFit = dynamic_cast<BaseFitField*>(m_dataMgr->getDrawingPass("Oriented Sphere"));
passUnorientedSphereFit = dynamic_cast<BaseFitField*>(m_dataMgr->getDrawingPass("Unoriented Sphere"));

{
genericFitWidget = new nanogui::Widget(window);
genericFitWidget->set_layout(new GroupLayout());
Expand Down
10 changes: 4 additions & 6 deletions src/application.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
};
161 changes: 161 additions & 0 deletions src/cli.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
#include "cli.h"

#include "dataManager.h"
#include "drawingPass.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 <cmath> // floor

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<std::string> 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("-i", "--input")
.required()
.help("input file (.pts or .txt)");

// output controls
{
program.add_argument("-o", "--output")
.help("output file (image)");
program.add_argument("-W", "--width")
.help("output image width (in pixels)")
.scan<'i', size_t>()
.default_value(params.output.width);
program.add_argument("-H", "--height")
.help("output image height (in pixels)")
.scan<'i', size_t>()
.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);
params.inputPath = program.get("-i");
if (! params.inputPath.empty())
{
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<float>("-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<size_t>("-W");
if (program.is_used("-H")) params.output.height = program.get<size_t>("-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;
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<BaseFitField*>(pass) ) {
fit->m_scale = params.fitting.scale;
}

// configure renderer
std::cout << "Configure renderer" << std::endl;
std::array<DrawingPass*,3> 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;
}

return skipGUI;
}
15 changes: 15 additions & 0 deletions src/cli.h
Original file line number Diff line number Diff line change
@@ -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};
};
42 changes: 42 additions & 0 deletions src/dataManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@
#include <iostream>
#include <fstream>

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;
Expand Down Expand Up @@ -106,3 +115,36 @@ DataManager::fitPointCloudToRange(const std::pair<float,float>& 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;
}
Loading
Loading