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