Verified Commit 09c77df3 authored by Kuntal  Majumder's avatar Kuntal Majumder 😟

Implemented boost::astar_search using the KisMagneticGraph wrapper

Ref T10894
parent a900a5fc
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include <QRect> #include <QRect>
#include <QColor> #include <QColor>
struct VertexDescriptor : public boost::equality_comparable<VertexDescriptor>{ struct VertexDescriptor {
long x,y; long x,y;
...@@ -42,13 +42,21 @@ struct VertexDescriptor : public boost::equality_comparable<VertexDescriptor>{ ...@@ -42,13 +42,21 @@ struct VertexDescriptor : public boost::equality_comparable<VertexDescriptor>{
x(0), y(0) x(0), y(0)
{ } { }
bool operator ==(const VertexDescriptor &rhs) const { bool operator==(VertexDescriptor const &rhs) const {
return rhs.x == x && rhs.y == y; return rhs.x == x && rhs.y == y;
} }
bool operator ==(const QPoint &rhs) const { bool operator==(QPoint const &rhs) const {
return rhs.x() == x && rhs.y() == y; return rhs.x() == x && rhs.y() == y;
} }
bool operator !=(VertexDescriptor const &rhs) const {
return rhs.x != x || rhs.y != y;
}
bool operator<(VertexDescriptor const &rhs) const {
return x < rhs.x || (x == rhs.x && y < rhs.y);
}
}; };
struct neighbour_iterator; struct neighbour_iterator;
...@@ -70,13 +78,13 @@ struct KisMagneticGraph{ ...@@ -70,13 +78,13 @@ struct KisMagneticGraph{
typedef boost::disallow_parallel_edge_tag edge_parallel_category; typedef boost::disallow_parallel_edge_tag edge_parallel_category;
typedef boost::incidence_graph_tag traversal_category; typedef boost::incidence_graph_tag traversal_category;
typedef neighbour_iterator out_edge_iterator; typedef neighbour_iterator out_edge_iterator;
typedef long degree_size_type; typedef unsigned long degree_size_type;
degree_size_type outDegree; degree_size_type outDegree;
QPoint topLeft, bottomRight; QPoint topLeft, bottomRight;
double getIntensity(QPoint pt){ double getIntensity(QPoint pt){
QColor *col; QColor *col = new QColor;
m_dev->pixel(pt.x(),pt.y(), col); m_dev->pixel(pt.x(),pt.y(), col);
double intensity = col->blackF(); double intensity = col->blackF();
delete col; delete col;
...@@ -93,7 +101,7 @@ struct neighbour_iterator : public boost::iterator_facade<neighbour_iterator, ...@@ -93,7 +101,7 @@ struct neighbour_iterator : public boost::iterator_facade<neighbour_iterator,
std::pair<VertexDescriptor, VertexDescriptor>> std::pair<VertexDescriptor, VertexDescriptor>>
{ {
neighbour_iterator(VertexDescriptor v, KisMagneticGraph g): neighbour_iterator(VertexDescriptor v, KisMagneticGraph g):
currentPoint(v), graph(g) graph(g), currentPoint(v)
{ {
nextPoint = VertexDescriptor(g.topLeft.x(), g.topLeft.y()); nextPoint = VertexDescriptor(g.topLeft.x(), g.topLeft.y());
if(nextPoint == currentPoint){ if(nextPoint == currentPoint){
...@@ -101,6 +109,9 @@ struct neighbour_iterator : public boost::iterator_facade<neighbour_iterator, ...@@ -101,6 +109,9 @@ struct neighbour_iterator : public boost::iterator_facade<neighbour_iterator,
} }
} }
neighbour_iterator()
{ }
std::pair<VertexDescriptor, VertexDescriptor> std::pair<VertexDescriptor, VertexDescriptor>
operator*() const { operator*() const {
std::pair<VertexDescriptor, VertexDescriptor> const result = std::make_pair(currentPoint,nextPoint); std::pair<VertexDescriptor, VertexDescriptor> const result = std::make_pair(currentPoint,nextPoint);
...@@ -108,6 +119,7 @@ struct neighbour_iterator : public boost::iterator_facade<neighbour_iterator, ...@@ -108,6 +119,7 @@ struct neighbour_iterator : public boost::iterator_facade<neighbour_iterator,
} }
void operator++() { void operator++() {
// I am darn sure that Dmitry is wrong, definitely wrong
if(nextPoint == graph.bottomRight) if(nextPoint == graph.bottomRight)
return; // we are done, no more points return; // we are done, no more points
...@@ -158,11 +170,13 @@ struct graph_traits<KisMagneticGraph> { ...@@ -158,11 +170,13 @@ struct graph_traits<KisMagneticGraph> {
typename KisMagneticGraph::vertex_descriptor typename KisMagneticGraph::vertex_descriptor
source(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g) { source(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g) {
Q_UNUSED(g)
return e.first; return e.first;
} }
typename KisMagneticGraph::vertex_descriptor typename KisMagneticGraph::vertex_descriptor
target(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g) { target(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g) {
Q_UNUSED(g)
return e.second; return e.second;
} }
...@@ -176,6 +190,7 @@ out_edges(typename KisMagneticGraph::vertex_descriptor v, KisMagneticGraph g) { ...@@ -176,6 +190,7 @@ out_edges(typename KisMagneticGraph::vertex_descriptor v, KisMagneticGraph g) {
typename KisMagneticGraph::degree_size_type typename KisMagneticGraph::degree_size_type
out_degree(typename KisMagneticGraph::vertex_descriptor v, KisMagneticGraph g) { out_degree(typename KisMagneticGraph::vertex_descriptor v, KisMagneticGraph g) {
Q_UNUSED(v)
return g.outDegree; return g.outDegree;
} }
......
...@@ -20,35 +20,77 @@ ...@@ -20,35 +20,77 @@
#include "kis_gaussian_kernel.h" #include "kis_gaussian_kernel.h"
#include <QtCore> #include <QtCore>
#include <QPolygon>
#include <boost/graph/astar_search.hpp> #include <boost/graph/astar_search.hpp>
#include <boost/functional/hash.hpp>
#include <boost/unordered_map.hpp>
#include "KisMagneticGraph.h" #include "KisMagneticGraph.h"
struct VertexHash : std::unary_function<VertexDescriptor, std::size_t> { struct DistanceMap {
std::size_t operator()(VertexDescriptor const& u) const { typedef VertexDescriptor key_type;
std::size_t seed = 0; typedef double data_type;
boost::hash_combine(seed, u.x); typedef std::pair<key_type, data_type> value_type;
boost::hash_combine(seed, u.y);
return seed; DistanceMap(double const& dval)
} : m_default(dval)
{ }
data_type &operator[](key_type const& k) {
if (m.find(k) == m.end())
m[k] = m_default;
return m[k];
}
private:
std::map<key_type, data_type> m;
data_type const m_default;
}; };
typedef boost::unordered_map<VertexDescriptor, VertexDescriptor, VertexHash> PredMap; struct PredecessorMap{
typedef boost::associative_property_map<PredMap> APredMap; PredecessorMap()
{ }
PredecessorMap(PredecessorMap const& that):
m_map(that.m_map)
{ }
class AstarHeuristic : public boost::astar_heuristic<KisMagneticGraph, double> { typedef VertexDescriptor key_type;
typedef VertexDescriptor value_type;
typedef VertexDescriptor & reference_type;
typedef boost::read_write_property_map_tag category;
VertexDescriptor &operator[](VertexDescriptor v){
return m_map[v];
}
std::map<VertexDescriptor, VertexDescriptor> m_map;
};
VertexDescriptor get(PredecessorMap const &m, VertexDescriptor v){
typename std::map<VertexDescriptor, VertexDescriptor>::const_iterator found = m.m_map.find(v);
return found != m.m_map.end() ? found->second : v;
}
void put(PredecessorMap &m, VertexDescriptor key, VertexDescriptor value){
m.m_map[key] = value;
}
double EuclideanDistance(VertexDescriptor p1, VertexDescriptor p2){
return std::sqrt(std::pow(p1.y-p2.y, 2) + std::pow(p1.x-p2.x, 2));
}
class AStarHeuristic : public boost::astar_heuristic<KisMagneticGraph, double> {
private: private:
APredMap m_pmap; PredecessorMap m_pmap;
VertexDescriptor m_goal; VertexDescriptor m_goal;
double coeff_a, coeff_b; double coeff_a, coeff_b;
public: public:
AstarHeuristic(VertexDescriptor goal, APredMap pmap, double a, double b): AStarHeuristic(VertexDescriptor goal, PredecessorMap pmap, double a, double b):
m_pmap(pmap), m_goal(goal), coeff_a(a), coeff_b(b) m_pmap(pmap), m_goal(goal), coeff_a(a), coeff_b(b)
{ } { }
AstarHeuristic(VertexDescriptor goal, APredMap pmap): AStarHeuristic(VertexDescriptor goal, PredecessorMap pmap):
m_pmap(pmap), m_goal(goal), coeff_a(0.5), coeff_b(0.5) m_pmap(pmap), m_goal(goal), coeff_a(0.5), coeff_b(0.5)
{ } { }
...@@ -56,32 +98,117 @@ class AstarHeuristic : public boost::astar_heuristic<KisMagneticGraph, double> { ...@@ -56,32 +98,117 @@ class AstarHeuristic : public boost::astar_heuristic<KisMagneticGraph, double> {
auto prev = m_pmap[v]; auto prev = m_pmap[v];
double di = (m_goal.y - prev.y) * v.x + (m_goal.x - prev.x) * v.y; double di = (m_goal.y - prev.y) * v.x + (m_goal.x - prev.x) * v.y;
di = std::abs(di + prev.x * m_goal.y + prev.y * m_goal.x); di = std::abs(di + prev.x * m_goal.y + prev.y * m_goal.x);
auto dist = [](VertexDescriptor p1, VertexDescriptor p2){ double dz = EuclideanDistance(prev, m_goal);
return std::sqrt(std::pow(p1.y-p2.y, 2) + std::pow(p1.x-p2.x, 2));
};
double dz = dist(prev, m_goal);
di = di/dz; di = di/dz;
double dm = dist(v, m_goal); double dm = EuclideanDistance(v, m_goal);
return coeff_a * di + coeff_b * (dm - dz); return coeff_a * di + coeff_b * (dm - dz);
} }
}; };
KisMagneticWorker::KisMagneticWorker(): struct GoalFound {};
m_dev(0), m_rect(QRect())
{ }
KisMagneticWorker::KisMagneticWorker(KisPaintDeviceSP dev, const QRect &rect): class AStarGoalVisitor : public boost::default_astar_visitor {
m_dev(dev), m_rect(rect) public:
{ } AStarGoalVisitor(VertexDescriptor goal) : m_goal(goal) { }
void KisMagneticWorker::run(KisPaintDeviceSP dev, const QRect &rect) void examine_vertex(VertexDescriptor u, KisMagneticGraph const &g) {
{ Q_UNUSED(g)
KisGaussianKernel::applyLoG(dev, rect, 2, -1.0, QBitArray(), 0); if(u == m_goal){
throw GoalFound();
}
}
private:
VertexDescriptor m_goal;
};
struct WeightMap{
typedef std::pair<VertexDescriptor, VertexDescriptor> key_type;
typedef double data_type;
typedef std::pair<key_type, data_type> value_type;
WeightMap() { }
data_type& operator[](key_type const& k) {
if (m_map.find(k) == m_map.end()) {
m_map[k] = EuclideanDistance(k.first, k.second);
}
return m_map[k];
}
private:
std::map<key_type, data_type> m_map;
};
QRect KisMagneticWorker::calculateRect(QPoint p1, QPoint p2, int radius) const {
// I am sure there is a simpler version of it which exists but well
double slope = (p2.y() - p1.y())/(p2.x() - p1.x());
QPoint a,b,c,d;
if(slope != 0){
slope = -1/slope;
double denom = 2 * std::sqrt(slope*slope+1);
double numer = radius/denom;
double fac1 = numer/denom;
denom = 2 * denom;
numer = 3 * slope * numer;
double fac2 = numer/denom;
a = QPoint(p1.x() - fac1, p1.y() - fac2);
b = QPoint(p1.x() + fac1, p1.y() + fac2);
c = QPoint(p2.x() - fac1, p2.y() - fac2);
d = QPoint(p2.x() + fac1, p2.y() + fac2);
}else{
double fac = radius/2;
a = QPoint(p1.x() - fac, p1.y() - fac);
b = QPoint(p1.x() + fac, p1.y() + fac);
c = QPoint(p2.x() - fac, p2.y() - fac);
d = QPoint(p2.x() + fac, p2.y() + fac);
}
QPolygon p(QVector<QPoint>{a,b,c,d});
return p.boundingRect();
} }
void KisMagneticWorker::computeEdge(QPoint start, QPoint end) QVector<QPoint> KisMagneticWorker::computeEdge(KisPaintDeviceSP dev, int radius, QPoint begin, QPoint end) {
{
Q_UNUSED(start) QRect rect = calculateRect(begin, end, radius);
Q_UNUSED(end) KisGaussianKernel::applyLoG(dev, rect, 2, -1.0, QBitArray(), 0);
KisGaussianKernel::applyLoG(m_dev, m_rect, 2, -1.0, QBitArray(), 0);
VertexDescriptor goal(end);
VertexDescriptor start(begin);
KisMagneticGraph g(dev, rect);
// How many maps does it require?
PredecessorMap pmap;
DistanceMap dmap(std::numeric_limits<double>::max());
dmap[start] = 0;
std::map<VertexDescriptor, unsigned> rmap;
std::map<VertexDescriptor, boost::default_color_type> cmap;
std::map<VertexDescriptor, unsigned> imap;
WeightMap wmap;
AStarHeuristic heuristic(goal,pmap);
QVector<QPoint> result;
try{
boost::astar_search_no_init(
g, start, heuristic
,boost::visitor(AStarGoalVisitor(goal))
.distance_map(boost::associative_property_map<DistanceMap>(dmap))
.predecessor_map(boost::ref(pmap))
.weight_map(boost::associative_property_map<WeightMap>(wmap))
.vertex_index_map(boost::associative_property_map<std::map<VertexDescriptor,unsigned>>(imap))
.rank_map(boost::associative_property_map<std::map<VertexDescriptor, unsigned>>(rmap))
.color_map(boost::associative_property_map<std::map<VertexDescriptor, boost::default_color_type>>(cmap))
.distance_combine(std::plus<double>())
.distance_compare(std::less<double>())
);
}catch(GoalFound const&){
for(VertexDescriptor u=goal; u!=start; u = pmap[u]){
result.push_back(QPoint(u.x,u.y));
}
}
return result;
} }
...@@ -22,15 +22,10 @@ ...@@ -22,15 +22,10 @@
#include <kritaselectiontools_export.h> #include <kritaselectiontools_export.h>
class KRITASELECTIONTOOLS_EXPORT KisMagneticWorker{ class KRITASELECTIONTOOLS_EXPORT KisMagneticWorker{
public: public:
KisMagneticWorker(); QVector<QPoint> computeEdge(KisPaintDeviceSP dev, int radius, QPoint start, QPoint end);
KisMagneticWorker(KisPaintDeviceSP dev, const QRect &rect); private:
void run(KisPaintDeviceSP dev, const QRect& rect); QRect calculateRect(QPoint p1, QPoint p2, int radius) const;
void computeEdge(QPoint start, QPoint end);
private:
KisPaintDeviceSP m_dev;
const QRect m_rect;
}; };
#endif #endif
...@@ -44,7 +44,6 @@ void KisMagneticWorkerTest::testWorker() ...@@ -44,7 +44,6 @@ void KisMagneticWorkerTest::testWorker()
const QRect rect = dev->exactBounds(); const QRect rect = dev->exactBounds();
KisPaintDeviceSP grayscaleDev = KisPainter::convertToAlphaAsGray(dev); KisPaintDeviceSP grayscaleDev = KisPainter::convertToAlphaAsGray(dev);
KisMagneticWorker worker; KisMagneticWorker worker;
worker.run(grayscaleDev, rect);
KIS_DUMP_DEVICE_2(grayscaleDev, rect, "main", "dd"); KIS_DUMP_DEVICE_2(grayscaleDev, rect, "main", "dd");
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment