File indexing completed on 2024-05-12 05:46:51

0001 /*
0002  *  Copyright (c) 2019 Kuntal Majumder <hellozee@disroot.org>
0003  *
0004  *  This library is free software; you can redistribute it and/or modify
0005  *  it under the terms of the GNU Lesser General Public License as published by
0006  *  the Free Software Foundation; version 2.1 of the License.
0007  *
0008  *  This library is distributed in the hope that it will be useful,
0009  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0010  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0011  *  GNU Lesser General Public License for more details.
0012  *
0013  *  You should have received a copy of the GNU Lesser General Public License
0014  *  along with this program; if not, write to the Free Software
0015  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
0016  */
0017 
0018 #ifndef KISMAGNETICGRAPH_H
0019 #define KISMAGNETICGRAPH_H
0020 
0021 #include <boost/operators.hpp>
0022 #include <boost/graph/graph_traits.hpp>
0023 #include <kis_paint_device.h>
0024 #include <kis_random_accessor_ng.h>
0025 
0026 #include <QDebug>
0027 #include <QRect>
0028 #include <QColor>
0029 
0030 struct VertexDescriptor {
0031     long x, y;
0032 
0033     enum Direction {
0034         MIN = 0,
0035         N   = MIN, S, E, W, NW, NE, SW, SE, NONE
0036     };
0037 
0038     VertexDescriptor(long _x, long _y) :
0039         x(_x), y(_y)
0040     { }
0041 
0042     VertexDescriptor(QPoint pt) :
0043         x(pt.x()), y(pt.y())
0044     { }
0045 
0046     VertexDescriptor() :
0047         x(0), y(0)
0048     { }
0049 
0050     bool operator == (VertexDescriptor const &rhs) const
0051     {
0052         return rhs.x == x && rhs.y == y;
0053     }
0054 
0055     bool operator == (QPoint const &rhs) const
0056     {
0057         return rhs.x() == x && rhs.y() == y;
0058     }
0059 
0060     bool operator != (VertexDescriptor const &rhs) const
0061     {
0062         return rhs.x != x || rhs.y != y;
0063     }
0064 
0065     bool operator < (VertexDescriptor const &rhs) const
0066     {
0067         return x < rhs.x || (x == rhs.x && y < rhs.y);
0068     }
0069 
0070     // returns one of the 8 neighboring pixel based on the direction
0071     // it gives out multiple warnings, but I am lazy, sorry
0072     VertexDescriptor neighbor(Direction direction) const
0073     {
0074         int dx = 0, dy = 0;
0075 
0076         switch (direction) {
0077             case W:
0078                 Q_FALLTHROUGH();
0079             case SW:
0080                 Q_FALLTHROUGH();
0081             case NW:
0082                 dx = -1;
0083                 break;
0084             case E:
0085                 Q_FALLTHROUGH();
0086             case SE:
0087                 Q_FALLTHROUGH();
0088             case NE:
0089                 dx = 1;
0090             default:
0091                 ;
0092         }
0093 
0094         switch (direction) {
0095             case N:
0096                 Q_FALLTHROUGH();
0097             case NW:
0098                 Q_FALLTHROUGH();
0099             case NE:
0100                 dy = -1;
0101                 break;
0102             case S:
0103                 Q_FALLTHROUGH();
0104             case SW:
0105                 Q_FALLTHROUGH();
0106             case SE:
0107                 dy = 1;
0108             default:
0109                 ;
0110         }
0111 
0112         VertexDescriptor const neighbor(x + dx, y + dy);
0113         return neighbor;
0114     } // neighbor
0115 };
0116 
0117 QDebug operator << (QDebug dbg, const VertexDescriptor &v)
0118 {
0119     dbg.nospace() << "(" << v.x << ", " << v.y << ")";
0120     return dbg.space();
0121 }
0122 
0123 struct neighbour_iterator;
0124 
0125 struct KisMagneticGraph {
0126     typedef KisMagneticGraph type;
0127 
0128     KisMagneticGraph(){ }
0129 
0130     KisMagneticGraph(KisPaintDeviceSP dev) :
0131         m_dev(dev)
0132     {
0133         m_randAccess = m_dev->createRandomAccessorNG();
0134     }
0135 
0136     KisMagneticGraph(KisPaintDeviceSP dev, QRect graphRect) :
0137         m_rect(graphRect), m_dev(dev)
0138     {
0139         m_randAccess = m_dev->createRandomAccessorNG();
0140     }
0141 
0142     typedef VertexDescriptor vertex_descriptor;
0143     typedef std::pair<vertex_descriptor, vertex_descriptor> edge_descriptor;
0144     typedef boost::undirected_tag directed_category;
0145     typedef boost::disallow_parallel_edge_tag edge_parallel_category;
0146     typedef boost::incidence_graph_tag traversal_category;
0147     typedef neighbour_iterator out_edge_iterator;
0148     typedef unsigned degree_size_type;
0149 
0150 
0151     quint8 getIntensity(VertexDescriptor pt)
0152     {
0153         m_randAccess->moveTo(pt.x, pt.y);
0154         quint8 val = *(m_randAccess->rawData());
0155         return val;
0156     }
0157 
0158     unsigned outDegree(VertexDescriptor pt)
0159     {
0160         // corners
0161         if (pt == m_rect.topLeft() || pt == m_rect.topRight() ||
0162             pt == m_rect.bottomLeft() || pt == m_rect.bottomRight())
0163         {
0164             if (m_rect.width() == 1 || m_rect.height() == 1)
0165                 return 1;
0166 
0167             return 3;
0168         }
0169 
0170         // edges
0171         if (pt.x == m_rect.topLeft().x() || pt.y == m_rect.topLeft().y() ||
0172             pt.x == m_rect.bottomRight().x() || pt.y == m_rect.bottomRight().y())
0173         {
0174             if (m_rect.width() == 1 || m_rect.height() == 1)
0175                 return 2;
0176 
0177             return 5;
0178         }
0179         return 8;
0180     }
0181 
0182     QRect               m_rect;
0183 
0184 private:
0185     KisPaintDeviceSP    m_dev;
0186     KisRandomAccessorSP m_randAccess;
0187 };
0188 
0189 struct neighbour_iterator : public boost::iterator_facade<neighbour_iterator
0190                                                           , std::pair<VertexDescriptor, VertexDescriptor>
0191                                                           , boost::forward_traversal_tag
0192                                                           , std::pair<VertexDescriptor, VertexDescriptor> > {
0193     neighbour_iterator(VertexDescriptor v, KisMagneticGraph g, VertexDescriptor::Direction d) :
0194         m_point(v), m_direction(d), m_graph(g)
0195     { }
0196 
0197     neighbour_iterator()
0198     { }
0199 
0200     std::pair<VertexDescriptor, VertexDescriptor> operator * () const
0201     {
0202         std::pair<VertexDescriptor,
0203                   VertexDescriptor> const result = std::make_pair(m_point, m_point.neighbor(m_direction));
0204         return result;
0205     }
0206 
0207     void operator ++ ()
0208     {
0209         m_direction = static_cast<VertexDescriptor::Direction>(int(m_direction) + 1);
0210         VertexDescriptor next = m_point.neighbor(m_direction);
0211         if (m_direction == VertexDescriptor::NONE) {
0212             return;
0213         }
0214         if (!m_graph.m_rect.contains(next.x, next.y)) {
0215             operator ++ ();
0216         }
0217     }
0218 
0219     bool operator == (neighbour_iterator const& that) const
0220     {
0221         return m_point == that.m_point && m_direction == that.m_direction;
0222     }
0223 
0224     bool equal(neighbour_iterator const& that) const
0225     {
0226         return operator == (that);
0227     }
0228 
0229     void increment()
0230     {
0231         operator ++ ();
0232     }
0233 
0234 private:
0235     VertexDescriptor            m_point;
0236     VertexDescriptor::Direction m_direction;
0237     KisMagneticGraph            m_graph;
0238 };
0239 
0240 // Requirements for an Incidence Graph,
0241 // https://www.boost.org/doc/libs/1_70_0/libs/graph/doc/IncidenceGraph.html
0242 
0243 namespace boost {
0244 template <>
0245 struct graph_traits<KisMagneticGraph> {
0246     typedef typename KisMagneticGraph::vertex_descriptor vertex_descriptor;
0247     typedef typename KisMagneticGraph::edge_descriptor edge_descriptor;
0248     typedef typename KisMagneticGraph::out_edge_iterator out_edge_iterator;
0249     typedef typename KisMagneticGraph::directed_category directed_category;
0250     typedef typename KisMagneticGraph::edge_parallel_category edge_parallel_category;
0251     typedef typename KisMagneticGraph::traversal_category traversal_category;
0252     typedef typename KisMagneticGraph::degree_size_type degree_size_type;
0253 
0254     typedef void in_edge_iterator;
0255     typedef void vertex_iterator;
0256     typedef void vertices_size_type;
0257     typedef void edge_iterator;
0258     typedef void edges_size_type;
0259 };
0260 }
0261 
0262 typename KisMagneticGraph::vertex_descriptor source(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
0263 {
0264     Q_UNUSED(g);
0265     return e.first;
0266 }
0267 
0268 typename KisMagneticGraph::vertex_descriptor target(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
0269 {
0270     Q_UNUSED(g);
0271     return e.second;
0272 }
0273 
0274 std::pair<KisMagneticGraph::out_edge_iterator, KisMagneticGraph::out_edge_iterator> out_edges(
0275      typename KisMagneticGraph::vertex_descriptor v, KisMagneticGraph g)
0276 {
0277     return std::make_pair(
0278         KisMagneticGraph::out_edge_iterator(v, g, VertexDescriptor::Direction::MIN),
0279         KisMagneticGraph::out_edge_iterator(v, g, VertexDescriptor::Direction::NONE)
0280         );
0281 }
0282 
0283 typename KisMagneticGraph::degree_size_type out_degree(typename KisMagneticGraph::vertex_descriptor v,
0284      KisMagneticGraph                                                                               g)
0285 {
0286     return g.outDegree(v);
0287 }
0288 
0289 #endif // ifndef KISMAGNETICGRAPH_H