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 @@
#include <QRect>
#include <QColor>
struct VertexDescriptor : public boost::equality_comparable<VertexDescriptor>{
struct VertexDescriptor {
long x,y;
......@@ -42,13 +42,21 @@ struct VertexDescriptor : public boost::equality_comparable<VertexDescriptor>{
x(0), y(0)
{ }
bool operator ==(const VertexDescriptor &rhs) const {
bool operator==(VertexDescriptor const &rhs) const {
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;
}
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;
......@@ -70,13 +78,13 @@ struct KisMagneticGraph{
typedef boost::disallow_parallel_edge_tag edge_parallel_category;
typedef boost::incidence_graph_tag traversal_category;
typedef neighbour_iterator out_edge_iterator;
typedef long degree_size_type;
typedef unsigned long degree_size_type;
degree_size_type outDegree;
QPoint topLeft, bottomRight;
double getIntensity(QPoint pt){
QColor *col;
QColor *col = new QColor;
m_dev->pixel(pt.x(),pt.y(), col);
double intensity = col->blackF();
delete col;
......@@ -93,7 +101,7 @@ struct neighbour_iterator : public boost::iterator_facade<neighbour_iterator,
std::pair<VertexDescriptor, VertexDescriptor>>
{
neighbour_iterator(VertexDescriptor v, KisMagneticGraph g):
currentPoint(v), graph(g)
graph(g), currentPoint(v)
{
nextPoint = VertexDescriptor(g.topLeft.x(), g.topLeft.y());
if(nextPoint == currentPoint){
......@@ -101,6 +109,9 @@ struct neighbour_iterator : public boost::iterator_facade<neighbour_iterator,
}
}
neighbour_iterator()
{ }
std::pair<VertexDescriptor, VertexDescriptor>
operator*() const {
std::pair<VertexDescriptor, VertexDescriptor> const result = std::make_pair(currentPoint,nextPoint);
......@@ -108,6 +119,7 @@ struct neighbour_iterator : public boost::iterator_facade<neighbour_iterator,
}
void operator++() {
// I am darn sure that Dmitry is wrong, definitely wrong
if(nextPoint == graph.bottomRight)
return; // we are done, no more points
......@@ -158,11 +170,13 @@ struct graph_traits<KisMagneticGraph> {
typename KisMagneticGraph::vertex_descriptor
source(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g) {
Q_UNUSED(g)
return e.first;
}
typename KisMagneticGraph::vertex_descriptor
target(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g) {
Q_UNUSED(g)
return e.second;
}
......@@ -176,6 +190,7 @@ out_edges(typename KisMagneticGraph::vertex_descriptor v, KisMagneticGraph g) {
typename KisMagneticGraph::degree_size_type
out_degree(typename KisMagneticGraph::vertex_descriptor v, KisMagneticGraph g) {
Q_UNUSED(v)
return g.outDegree;
}
......
......@@ -20,35 +20,77 @@
#include "kis_gaussian_kernel.h"
#include <QtCore>
#include <QPolygon>
#include <boost/graph/astar_search.hpp>
#include <boost/functional/hash.hpp>
#include <boost/unordered_map.hpp>
#include "KisMagneticGraph.h"
struct VertexHash : std::unary_function<VertexDescriptor, std::size_t> {
std::size_t operator()(VertexDescriptor const& u) const {
std::size_t seed = 0;
boost::hash_combine(seed, u.x);
boost::hash_combine(seed, u.y);
return seed;
struct DistanceMap {
typedef VertexDescriptor key_type;
typedef double data_type;
typedef std::pair<key_type, data_type> value_type;
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;
};
struct PredecessorMap{
PredecessorMap()
{ }
PredecessorMap(PredecessorMap const& that):
m_map(that.m_map)
{ }
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;
};
typedef boost::unordered_map<VertexDescriptor, VertexDescriptor, VertexHash> PredMap;
typedef boost::associative_property_map<PredMap> APredMap;
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;
}
class AstarHeuristic : public boost::astar_heuristic<KisMagneticGraph, double> {
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:
APredMap m_pmap;
PredecessorMap m_pmap;
VertexDescriptor m_goal;
double coeff_a, coeff_b;
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)
{ }
AstarHeuristic(VertexDescriptor goal, APredMap pmap):
AStarHeuristic(VertexDescriptor goal, PredecessorMap pmap):
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> {
auto prev = m_pmap[v];
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);
auto dist = [](VertexDescriptor p1, VertexDescriptor p2){
return std::sqrt(std::pow(p1.y-p2.y, 2) + std::pow(p1.x-p2.x, 2));
};
double dz = dist(prev, m_goal);
double dz = EuclideanDistance(prev, m_goal);
di = di/dz;
double dm = dist(v, m_goal);
double dm = EuclideanDistance(v, m_goal);
return coeff_a * di + coeff_b * (dm - dz);
}
};
KisMagneticWorker::KisMagneticWorker():
m_dev(0), m_rect(QRect())
{ }
struct GoalFound {};
KisMagneticWorker::KisMagneticWorker(KisPaintDeviceSP dev, const QRect &rect):
m_dev(dev), m_rect(rect)
{ }
class AStarGoalVisitor : public boost::default_astar_visitor {
public:
AStarGoalVisitor(VertexDescriptor goal) : m_goal(goal) { }
void KisMagneticWorker::run(KisPaintDeviceSP dev, const QRect &rect)
{
KisGaussianKernel::applyLoG(dev, rect, 2, -1.0, QBitArray(), 0);
void examine_vertex(VertexDescriptor u, KisMagneticGraph const &g) {
Q_UNUSED(g)
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)
{
Q_UNUSED(start)
Q_UNUSED(end)
KisGaussianKernel::applyLoG(m_dev, m_rect, 2, -1.0, QBitArray(), 0);
QVector<QPoint> KisMagneticWorker::computeEdge(KisPaintDeviceSP dev, int radius, QPoint begin, QPoint end) {
QRect rect = calculateRect(begin, end, radius);
KisGaussianKernel::applyLoG(dev, 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 @@
#include <kritaselectiontools_export.h>
class KRITASELECTIONTOOLS_EXPORT KisMagneticWorker{
public:
KisMagneticWorker();
KisMagneticWorker(KisPaintDeviceSP dev, const QRect &rect);
void run(KisPaintDeviceSP dev, const QRect& rect);
void computeEdge(QPoint start, QPoint end);
private:
KisPaintDeviceSP m_dev;
const QRect m_rect;
public:
QVector<QPoint> computeEdge(KisPaintDeviceSP dev, int radius, QPoint start, QPoint end);
private:
QRect calculateRect(QPoint p1, QPoint p2, int radius) const;
};
#endif
......@@ -44,7 +44,6 @@ void KisMagneticWorkerTest::testWorker()
const QRect rect = dev->exactBounds();
KisPaintDeviceSP grayscaleDev = KisPainter::convertToAlphaAsGray(dev);
KisMagneticWorker worker;
worker.run(grayscaleDev, rect);
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