Skip to content

Commit

Permalink
Merge pull request #4 from poncateam/improve_demo
Browse files Browse the repository at this point in the history
Improve demo
  • Loading branch information
nmellado authored Dec 12, 2023
2 parents 375cf34 + 7ed1433 commit 86810e3
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 56 deletions.
15 changes: 10 additions & 5 deletions src/drawingPasses/poncaFitField.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,17 @@

#include <Ponca/Fitting>

struct BaseFitField : public DrawingPass{
inline explicit BaseFitField() : DrawingPass() {}
~BaseFitField() override = default;
float m_scale {20.f};
int m_iter {1};
};

template <typename _FitType>
struct FitField : public DrawingPass {
inline explicit FitField() : DrawingPass() {}
struct FitField : public BaseFitField {
inline explicit FitField() : BaseFitField() {}
~FitField() override = default;

using FitType = _FitType;
using WeightFunc = typename FitType::WeightFunction;
Expand Down Expand Up @@ -51,9 +59,6 @@ struct FitField : public DrawingPass {
}
}
}

float m_scale {20.f};
int m_iter {1};
};

using PointType = typename MyView::PointCollection::DataPoint;
Expand Down
93 changes: 55 additions & 38 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,36 +57,11 @@ class ExampleApplication : public Screen {
{ \
FitWidget = new nanogui::Widget(window); \
FitWidget->set_layout(new GroupLayout()); \
new nanogui::Label(FitWidget, name, "sans-bold"); \
new nanogui::Label(FitWidget, "Scale"); \
auto slider = new Slider(FitWidget); \
slider->set_value(fit->m_scale); \
slider->set_range({5,100}); \
slider->set_callback([&](float value) { \
fit->m_scale = value; \
std::cout<< "Set scale to " << value << std::endl; \
renderPasses(); \
}); \
/* Positive integer widget */ \
new Label(FitWidget, "MLS Iterations :", "sans-bold"); \
auto int_box = new IntBox<int>(FitWidget, fit->m_iter); \
int_box->set_editable(true); \
int_box->set_spinnable(true); \
int_box->set_min_value(1); \
int_box->set_max_value(10); \
int_box->set_value_increment(1); \
int_box->set_callback([&](int value) { \
fit->m_iter = value; \
renderPasses(); \
}); \
}



public:



ExampleApplication()
: Screen(Vector2i(1024, 768), "PoncaPlot"){

Expand Down Expand Up @@ -149,6 +124,38 @@ class ExampleApplication : public Screen {
new nanogui::Label(distanceFieldWidget, "no parameter available");
}

{
genericFitWidget = new nanogui::Widget(window);
genericFitWidget->set_layout(new GroupLayout());
new nanogui::Label(genericFitWidget, "Local Fitting", "sans-bold");
new nanogui::Label(genericFitWidget, "Scale");
auto slider = new Slider(genericFitWidget);
slider->set_value(passPlaneFit->m_scale); // init with plane, but sync with current.
slider->set_range({5,200});
slider->set_callback([&](float value) {
passPlaneFit->m_scale = value;
passSphereFit->m_scale = value;
passOrientedSphereFit->m_scale = value;
passUnorientedSphereFit->m_scale = value;
renderPasses();
});

new Label(genericFitWidget, "MLS Iterations :", "sans-bold");
auto int_box = new IntBox<int>(genericFitWidget, passPlaneFit->m_iter);
int_box->set_editable(true);
int_box->set_spinnable(true);
int_box->set_min_value(1);
int_box->set_max_value(10);
int_box->set_value_increment(1);
int_box->set_callback([&](int value) {
passPlaneFit->m_iter = value;
passSphereFit->m_iter = value;
passOrientedSphereFit->m_iter = value;
passUnorientedSphereFit->m_iter = value;
renderPasses();
});
}

CONFIG_PONCA_FIT_INTERFACE(planeFitWidget,passPlaneFit,combo->items()[1])
CONFIG_PONCA_FIT_INTERFACE(sphereFitWidget,passSphereFit,combo->items()[2])
CONFIG_PONCA_FIT_INTERFACE(orientedSphereFitWidget,passOrientedSphereFit,combo->items()[3])
Expand All @@ -171,6 +178,7 @@ class ExampleApplication : public Screen {
slider->set_range({1,20});
slider->set_callback([&](float value) {
dynamic_cast<DisplayPoint *>(m_passes[2])->m_halfSize = int(value);
image_view->setSelectionThreshold(value);
renderPasses();
});
}
Expand All @@ -180,17 +188,15 @@ class ExampleApplication : public Screen {
window->set_size(Vector2i(768,768));
window->set_layout(new GroupLayout(3));

m_textureBuffer = new uint8_t [tex_width*tex_height];
m_textureBufferPing = new uint8_t [tex_width * tex_height * 4]; // use UInt8 RGBA textures
m_textureBufferPong = new uint8_t [tex_width * tex_height * 4]; // use UInt8 RGBA textures
m_texture = new Texture(
Texture::PixelFormat::RGBA,
Texture::ComponentFormat::UInt8,
{tex_width,tex_height},
Texture::InterpolationMode::Trilinear,
Texture::InterpolationMode::Nearest,
Texture::WrapMode::ClampToEdge,
1,
Texture::TextureFlags::ShaderRead,
false); // manual mipmap update
Texture::WrapMode::ClampToEdge);

image_view = new MyView(window);
image_view->set_size(Vector2i(768,768));
Expand All @@ -199,13 +205,14 @@ class ExampleApplication : public Screen {
image_view->center();
image_view->setUpdateFunction([this](){ this->renderPasses();});

renderPasses(); // render twice to fill m_textureBufferPing and m_textureBufferPong
renderPasses();

// call perform_layout
buildPassInterface(0);
}

virtual bool keyboard_event(int key, int scancode, int action, int modifiers) {
bool keyboard_event(int key, int scancode, int action, int modifiers) override {
if (Screen::keyboard_event(key, scancode, action, modifiers))
return true;
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
Expand All @@ -215,21 +222,22 @@ class ExampleApplication : public Screen {
return false;
}

virtual void draw(NVGcontext *ctx) {
void draw(NVGcontext *ctx) override {
// if (m_needUpdate)
Screen::draw(ctx);
}

virtual void draw_contents() {
void draw_contents() override {
if (m_needUpdate){
m_texture->upload(m_textureBuffer);
m_texture->upload(m_computeInPing ? m_textureBufferPong : m_textureBufferPing);
m_needUpdate = false;
}
Screen::draw_contents();
}

void buildPassInterface(int id){
distanceFieldWidget->set_visible(false);
genericFitWidget->set_visible(false);
planeFitWidget->set_visible(false);
sphereFitWidget->set_visible(false);
orientedSphereFitWidget->set_visible(false);
Expand All @@ -239,15 +247,19 @@ class ExampleApplication : public Screen {
distanceFieldWidget->set_visible(true);
break;
case 1:
genericFitWidget->set_visible(true);
planeFitWidget->set_visible(true);
break;
case 2:
genericFitWidget->set_visible(true);
sphereFitWidget->set_visible(true);
break;
case 3:
genericFitWidget->set_visible(true);
orientedSphereFitWidget->set_visible(true);
break;
case 4:
genericFitWidget->set_visible(true);
unorientedSphereFitWidget->set_visible(true);
break;
default: throw std::runtime_error("Unknown Field type!");
Expand All @@ -259,17 +271,22 @@ class ExampleApplication : public Screen {
std::cout << "[Main] Update texture" << std::endl;
const auto& points = image_view->getPointCollection();
for (auto* p : m_passes) {
p->render(points, m_textureBuffer, tex_width, tex_height);
p->render(points, m_computeInPing ? m_textureBufferPing : m_textureBufferPong, tex_width, tex_height);
}

m_computeInPing = ! m_computeInPing;
m_needUpdate = true;
}
private:
uint8_t* m_textureBuffer {nullptr};
uint8_t* m_textureBufferPing {nullptr}, * m_textureBufferPong {nullptr};
bool m_computeInPing{true};
Texture* m_texture {nullptr};
std::array<DrawingPass*,3> m_passes;
std::array<DrawingPass*,3> m_passes{nullptr, nullptr, nullptr};
bool m_needUpdate{false};
Widget* pass1Widget, *distanceFieldWidget, *planeFitWidget, *sphereFitWidget, *orientedSphereFitWidget, *unorientedSphereFitWidget, *pass3Widget;
Widget* pass1Widget, *distanceFieldWidget,
*genericFitWidget, //< parameters applicable to all fitting techniques
*planeFitWidget, *sphereFitWidget, *orientedSphereFitWidget, *unorientedSphereFitWidget,
*pass3Widget;
DistanceFieldWithKdTree *passDFWithKdTree;
PlaneFitField *passPlaneFit;
SphereFitField *passSphereFit;
Expand Down
22 changes: 13 additions & 9 deletions src/myview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@ MyView::fitImage() {

//#define USE_KDTREE
int
MyView::findPointId(const Vector2f &lp, float epsilon) const{
MyView::findPointId(const Vector2f &lp) const{
if(! m_points.empty()) {
int i = 0;
#ifndef USE_KDTREE
for(const auto&p : m_points) {
Vector2f query(p.x(), p.y());
if (norm((lp - query)) <= epsilon)
if (norm((lp - query)) <= m_selectionThreshold)
return i;
++i;
}
Expand All @@ -67,19 +67,21 @@ bool
MyView::mouse_button_event(const Vector2i &p, int button, bool down, int modifiers)
{
auto lp = pos_to_pixel(p - m_pos);
// left click, no modifier, on press
if (modifiers==0 && down && isInsideImage(lp)) {
// std::cout << "mouse_button_event: p=[" << pos_to_pixel(p - m_pos) << "], button=[" << button
// << "], isdown: " << down << std::endl;
auto pointId = findPointId(lp);
if (pointId < 0) { // create new point
std::cout << "MyView::add new point" << std::endl;
m_points.emplace_back( lp.x(), lp.y(), M_PI/2.);
updateCollection();
return true;
if (pointId < 0) {
if(button == 0) { // create new point iif left click (button id seems to be different wrt drag event
std::cout << "MyView::add new point" << std::endl;
m_points.emplace_back(lp.x(), lp.y(), M_PI / 2.);
updateCollection();
}
} else {
m_movedPoint = pointId;
return true;
}
return true;
}
m_movedPoint = -1;
return ImageView::mouse_button_event(p, button, down, modifiers);
Expand All @@ -105,8 +107,10 @@ MyView::mouse_drag_event(const nanogui::Vector2i &p, const nanogui::Vector2i &re
break;
case 2: //right click
{
int dist = std::min(std::abs(rel.x()), 50);
if (rel.x() < 0) dist *=-1;
// if is on a point
auto relAngle = std::asin(float(rel.x()) / 40.f); // move by 40px to get 90degree angle
auto relAngle = std::asin(float(dist) / 50.1f); // move by 40px to get 90 degree angle
m_points[m_movedPoint].z() += relAngle;
// std::cout << "Change normal by " << rel << ". Gives angle " << m_points[m_movedPoint].z() << std::endl;
updateCollection();
Expand Down
11 changes: 7 additions & 4 deletions src/myview.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ class DataPoint
[[nodiscard]] inline const auto& normal() const {return m_normal;}
/// \fixme Use maps to avoid duplication
explicit inline DataPoint(const nanogui::Vector3f &pn)
: m_pos({pn.x(), pn.y()}), m_normal({std::cos(pn.z()), std::sin(pn.z())}) {
std::cout << m_normal.transpose() << std::endl;
}
: m_pos({pn.x(), pn.y()}), m_normal({std::cos(pn.z()), std::sin(pn.z())}) {}
private:
VectorType m_pos, m_normal;
};
Expand All @@ -42,7 +40,8 @@ class MyView : public nanogui::ImageView {
bool fitImage();

// Check if a point is at this coordinate. If yes, return the point id, -1 otherwise
int findPointId(const nanogui::Vector2f &lp, float epsilon = 3.f) const;
// \see m_selectionThreshold
int findPointId(const nanogui::Vector2f &lp) const;

// Widget implementation
/// Handle a mouse button event
Expand All @@ -60,6 +59,9 @@ class MyView : public nanogui::ImageView {
/// Set Update function, called after each point update
inline void setUpdateFunction(std::function<void()> &&f) { m_updateFunction = f; }

/// Set selection threshold
inline void setSelectionThreshold(float dist) { m_selectionThreshold = dist; }

private:
inline void updateCollection();

Expand All @@ -68,4 +70,5 @@ class MyView : public nanogui::ImageView {
PointCollection m_tree;
std::function<void()> m_updateFunction {[](){}};
int m_movedPoint{-1};
float m_selectionThreshold{2}; // distance in pixel used to select points
};

0 comments on commit 86810e3

Please sign in to comment.