diff --git a/src/drawingPass.h b/src/drawingPass.h index 3d5e2f3..cc99a11 100644 --- a/src/drawingPass.h +++ b/src/drawingPass.h @@ -45,9 +45,9 @@ struct DisplayPoint : public DrawingPass { inline explicit DisplayPoint(const nanogui::Vector4i &pointColor = {0,0,0,255}) : DrawingPass(), m_pointColor(pointColor) {} void render(const MyView::PointCollection& points, uint8_t*buffer, int w, int h) override{ - for (const auto&p : points){ - int i (std::floor(p.x())); - int j (std::floor(p.y())); + for (const auto&p : points.point_data()){ + int i (std::floor(p.pos().x())); + int j (std::floor(p.pos().y())); for (int u = -1; u <= 1; ++u ){ for (int v = -1; v <= 1; ++v ){ //this is suboptimal: we check multiple time, could be done better. diff --git a/src/drawingPasses/distanceField.h b/src/drawingPasses/distanceField.h index 7e38bfa..8599a15 100644 --- a/src/drawingPasses/distanceField.h +++ b/src/drawingPasses/distanceField.h @@ -5,14 +5,16 @@ struct DistanceField : public DrawingPass { inline explicit DistanceField() : DrawingPass() {} void render(const MyView::PointCollection& points, uint8_t*buffer, int w, int h) override{ + if(points.point_data().empty()) return; + double normFactor (std::max(w,h)); for (int j = 0; j < h; ++j ) { for (int i = 0; i < w; ++i) { auto *b = buffer + (i + j * w) * 4; int minDist = normFactor; //distance should necessarily be smaller - for (const auto &p: points) { - int u(std::floor(p.x())); - int v(std::floor(p.y())); + for (const auto &p : points.point_data()) { + int u(std::floor(p.pos().x())); + int v(std::floor(p.pos().y())); auto dist = int(std::sqrt((i-u)*(i-u) + (j-v)*(j-v))); minDist = std::min(dist, minDist); } @@ -23,3 +25,25 @@ struct DistanceField : public DrawingPass { } } }; +struct DistanceFieldWithKdTree : public DrawingPass { + inline explicit DistanceFieldWithKdTree() : DrawingPass() {} + void render(const MyView::PointCollection& points, uint8_t*buffer, int w, int h) override{ + if(points.point_data().empty()) return; + + double normFactor (std::max(w,h)); + for (int j = 0; j < h; ++j ) { + for (int i = 0; i < w; ++i) { + auto *b = buffer + (i + j * w) * 4; + DataPoint::VectorType query (i, j); + auto res = points.nearest_neighbor( query ); + if(res.begin()!=res.end()) { + auto nei = points.point_data()[res.get()].pos(); + float dist = (nei-query).norm(); + auto col = uint (255. * dist / normFactor); + b[0] = b[1] = b[2] = col; + b[3] = 255; + } + } + } + } +}; diff --git a/src/main.cpp b/src/main.cpp index 537a437..8f2f876 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -89,6 +89,7 @@ class ExampleApplication : public Screen { m_passes.clear(); m_passes.push_back( new FillPass( {0,0,0,255})); m_passes.push_back( new DistanceField()); +// m_passes.push_back( new DistanceFieldWithKdTree()); // too slow m_passes.push_back( new DisplayPoint({255,0,0,255})); image_view = new MyView(window); diff --git a/src/myview.cpp b/src/myview.cpp index d2d21d2..1fce9be 100644 --- a/src/myview.cpp +++ b/src/myview.cpp @@ -23,14 +23,25 @@ MyView::isInsideImage(const Vector2f &lp) const { return true; } +//#define USE_KDTREE int MyView::findPointId(const Vector2f &lp, float epsilon) const{ - int i = 0; - for(const auto&p : m_points) - { - if(norm((lp-p)) <= epsilon) - return i; - ++i; + 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) + return i; + ++i; + } +#else + DataPoint::VectorType query(lp.x(), lp.y()); + auto res = m_tree.nearest_neighbor(query); + if (res.begin() != res.end() && + (query-m_tree.point_data()[res.get()].pos()).norm() #include +#include + #include #include #include +class DataPoint +{ +public: + enum {Dim = 2}; + using Scalar = float; + using VectorType = Eigen::Vector; + inline const auto& pos() const {return m_pos;} + inline const auto& normal() const {return m_normal;} + /// \fixme Use maps to avoid duplication + explicit inline DataPoint(const nanogui::Vector4f &pn) + : m_pos({pn.x(), pn.y()}), m_normal({pn.z(), pn.w()}) {} +private: + VectorType m_pos, m_normal; +}; + class MyView : public nanogui::ImageView { public: - using PointCollection = std::vector; + using PointCollection = Ponca::KdTree; /// Initialize the widget explicit MyView(Widget *parent); @@ -29,13 +46,17 @@ class MyView : public nanogui::ImageView { bool mouse_drag_event(const nanogui::Vector2i &p, const nanogui::Vector2i &rel, int button, int modifiers) override; /// Read access to point collection - inline const PointCollection& getPointCollection() const { return m_points; } + inline const PointCollection& getPointCollection() const { return m_tree; } /// Set Update function, called after each point update inline void setUpdateFunction(std::function &&f) { m_updateFunction = f; } private: - PointCollection m_points; + inline void updateCollection(); + + using PointContainer = std::vector; // stores x,y,nx,ny + PointContainer m_points; + PointCollection m_tree; std::function m_updateFunction {[](){}}; int m_movedPoint{-1}; };