00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef __KGRID2D_H_
00021 #define __KGRID2D_H_
00022
00023 #include <math.h>
00024
00025 #include <QtCore/QPair>
00026 #include <QtCore/QVector>
00027
00028 #include <QtCore/QTextStream>
00029
00030 #include <kglobal.h>
00031
00032
00033
00034 namespace KGrid2D
00035 {
00039 typedef QPair<int, int> Coord;
00040
00044 typedef QList<Coord> CoordList;
00045 }
00046
00047 inline KGrid2D::Coord
00048 operator +(const KGrid2D::Coord &c1, const KGrid2D::Coord &c2) {
00049 return KGrid2D::Coord(c1.first + c2.first, c1.second + c2.second);
00050 }
00051
00052 inline KGrid2D::Coord
00053 operator -(const KGrid2D::Coord &c1, const KGrid2D::Coord &c2) {
00054 return KGrid2D::Coord(c1.first - c2.first, c1.second - c2.second);
00055 }
00056
00060 inline KGrid2D::Coord
00061 maximum(const KGrid2D::Coord &c1, const KGrid2D::Coord &c2) {
00062 return KGrid2D::Coord(qMax(c1.first, c2.first), qMax(c1.second, c2.second));
00063 }
00067 inline KGrid2D::Coord
00068 minimum(const KGrid2D::Coord &c1, const KGrid2D::Coord &c2) {
00069 return KGrid2D::Coord(qMin(c1.first, c2.first), qMin(c1.second, c2.second));
00070 }
00071
00072 inline QTextStream &operator <<(QTextStream &s, const KGrid2D::Coord &c) {
00073 return s << '(' << c.second << "," << c.first << ')';
00074 }
00075
00076 inline QTextStream &operator <<(QTextStream &s, const KGrid2D::CoordList &list)
00077 {
00078 for(KGrid2D::CoordList::const_iterator i=list.begin(); i!=list.end(); ++i)
00079 s << *i;
00080 return s;
00081 }
00082
00083
00084 namespace KGrid2D
00085 {
00090 template <class Type>
00091 class Generic
00092 {
00093 public:
00097 Generic(uint width = 0, uint height = 0) {
00098 resize(width, height);
00099 }
00100
00101 virtual ~Generic() {}
00102
00106 void resize(uint width, uint height) {
00107 _width = width;
00108 _height = height;
00109 _vector.resize(width*height);
00110 }
00111
00115 void fill(const Type &value) {
00116 for (int i=0; i<_vector.count(); i++) _vector[i] = value;
00117 }
00118
00122 uint width() const { return _width; }
00126 uint height() const { return _height; }
00130 uint size() const { return _width*_height; }
00131
00135 uint index(const Coord &c) const {
00136 return c.first + c.second*_width;
00137 }
00138
00142 Coord coord(uint index) const {
00143 return Coord(index % _width, index / _width);
00144 }
00145
00149 const Type &at(const Coord &c) const { return _vector[index(c)]; }
00153 Type &at(const Coord &c) { return _vector[index(c)]; }
00157 const Type &operator [](const Coord &c) const { return _vector[index(c)]; }
00161 Type &operator [](const Coord &c) { return _vector[index(c)]; }
00162
00166 const Type &at(uint index) const { return _vector[index]; }
00170 Type &at(uint index) { return _vector[index]; }
00174 const Type &operator [](uint index) const { return _vector[index]; }
00178 Type &operator [](uint index) { return _vector[index]; }
00179
00183 bool inside(const Coord &c) const {
00184 return ( c.first>=0 && c.first<(int)_width
00185 && c.second>=0 && c.second<(int)_height );
00186 }
00187
00191 void bound(Coord &c) const {
00192 c.first = qMax(qMin(c.first, (int)_width-1), 0);
00193 c.second = qMax(qMin(c.second, (int)_height-1), 0);
00194 }
00195
00196 protected:
00197 uint _width, _height;
00198 QVector<Type> _vector;
00199 };
00200 }
00201
00202 template <class Type>
00203 QDataStream &operator <<(QDataStream &s, const KGrid2D::Generic<Type> &m) {
00204 s << (quint32)m.width() << (quint32)m.height();
00205 for (uint i=0; i<m.size(); i++) s << m[i];
00206 return s;
00207 }
00208
00209 template <class Type>
00210 QDataStream &operator >>(QDataStream &s, KGrid2D::Generic<Type> &m) {
00211 quint32 w, h;
00212 s >> w >> h;
00213 m.resize(w, h);
00214 for (uint i=0; i<m.size(); i++) s >> m[i];
00215 return s;
00216 }
00217
00218
00219 namespace KGrid2D
00220 {
00221
00222
00227 class SquareBase
00228 {
00229 public:
00233 enum Neighbour { Left=0, Right, Up, Down, LeftUp, LeftDown,
00234 RightUp, RightDown, Nb_Neighbour };
00235
00239 static double angle(Neighbour n) {
00240 switch (n) {
00241 case Left: return M_PI;
00242 case Right: return 0;
00243 case Up: return M_PI_2;
00244 case Down: return -M_PI_2;
00245 case LeftUp: return 3.0*M_PI_4;
00246 case LeftDown: return -3.0*M_PI_4;
00247 case RightUp: return M_PI_4;
00248 case RightDown: return -M_PI_4;
00249 case Nb_Neighbour: Q_ASSERT(false);
00250 }
00251 return 0;
00252 }
00253
00257 static Neighbour opposed(Neighbour n) {
00258 switch (n) {
00259 case Left: return Right;
00260 case Right: return Left;
00261 case Up: return Down;
00262 case Down: return Up;
00263 case LeftUp: return RightDown;
00264 case LeftDown: return RightUp;
00265 case RightUp: return LeftDown;
00266 case RightDown: return LeftUp;
00267 case Nb_Neighbour: Q_ASSERT(false);
00268 }
00269 return Nb_Neighbour;
00270 }
00271
00276 static bool isDirect(Neighbour n) { return n<LeftUp; }
00277
00281 static Coord neighbour(const Coord &c, Neighbour n) {
00282 switch (n) {
00283 case Left: return c + Coord(-1, 0);
00284 case Right: return c + Coord( 1, 0);
00285 case Up: return c + Coord( 0, -1);
00286 case Down: return c + Coord( 0, 1);
00287 case LeftUp: return c + Coord(-1, -1);
00288 case LeftDown: return c + Coord(-1, 1);
00289 case RightUp: return c + Coord( 1, -1);
00290 case RightDown: return c + Coord( 1, 1);
00291 case Nb_Neighbour: Q_ASSERT(false);
00292 }
00293 return c;
00294 }
00295 };
00296
00301 template <class T>
00302 class Square : public Generic<T>, public SquareBase
00303 {
00304 public:
00308 Square(uint width = 0, uint height = 0)
00309 : Generic<T>(width, height) {}
00310
00318 CoordList neighbours(const Coord &c, bool insideOnly = true,
00319 bool directOnly = false) const {
00320 CoordList neighbours;
00321 for (int i=0; i<(directOnly ? LeftUp : Nb_Neighbour); i++) {
00322 Coord n = neighbour(c, (Neighbour)i);
00323 if ( insideOnly && !Generic<T>::inside(n) ) continue;
00324 neighbours.append(n);
00325 }
00326 return neighbours;
00327 }
00328
00335 Coord toEdge(const Coord &c, Neighbour n) const {
00336 switch (n) {
00337 case Left: return Coord(0, c.second);
00338 case Right: return Coord(Generic<T>::width()-1, c.second);
00339 case Up: return Coord(c.first, 0);
00340 case Down: return Coord(c.first, Generic<T>::height()-1);
00341 case LeftUp: return Coord(0, 0);
00342 case LeftDown: return Coord(0, Generic<T>::height()-1);
00343 case RightUp: return Coord(Generic<T>::width()-1, 0);
00344 case RightDown: return Coord(Generic<T>::width()-1, Generic<T>::height()-1);
00345 case Nb_Neighbour: Q_ASSERT(false);
00346 }
00347 return c;
00348 }
00349 };
00350
00351
00361 class HexagonalBase
00362 {
00363 public:
00367 enum Neighbour { Left = 0, Right, LeftUp, LeftDown,
00368 RightUp, RightDown, Nb_Neighbour };
00369
00373 static double angle(Neighbour n) {
00374 switch (n) {
00375 case Left: return M_PI;
00376 case Right: return 0;
00377 case LeftUp: return 2.0*M_PI/3;
00378 case LeftDown: return -2.0*M_PI/3;
00379 case RightUp: return M_PI/3;
00380 case RightDown: return -M_PI/3;
00381 case Nb_Neighbour: Q_ASSERT(false);
00382 }
00383 return 0;
00384 }
00385
00389 static Neighbour opposed(Neighbour n) {
00390 switch (n) {
00391 case Left: return Right;
00392 case Right: return Left;
00393 case LeftUp: return RightDown;
00394 case LeftDown: return RightUp;
00395 case RightUp: return LeftDown;
00396 case RightDown: return LeftUp;
00397 case Nb_Neighbour: Q_ASSERT(false);
00398 }
00399 return Nb_Neighbour;
00400 }
00401
00405 static Coord neighbour(const Coord &c, Neighbour n) {
00406 bool oddRow = c.second%2;
00407 switch (n) {
00408 case Left: return c + Coord(-1, 0);
00409 case Right: return c + Coord( 1, 0);
00410 case LeftUp: return c + (oddRow ? Coord( 0, -1) : Coord(-1, -1));
00411 case LeftDown: return c + (oddRow ? Coord( 0, 1) : Coord(-1, 1));
00412 case RightUp: return c + (oddRow ? Coord( 1, -1) : Coord( 0, -1));
00413 case RightDown: return c + (oddRow ? Coord( 1, 1) : Coord( 0, 1));
00414 case Nb_Neighbour: Q_ASSERT(false);
00415 }
00416 return c;
00417 }
00418
00422 static uint distance(const Coord &c1, const Coord &c2) {
00423 return qAbs(c1.first - c2.first) + qAbs(c1.second - c2.second)
00424 + (c1.first==c2.first || c1.second==c2.second ? 0 : -1);
00425 }
00426 };
00427
00437 template <class Type>
00438 class Hexagonal : public Generic<Type>, public HexagonalBase
00439 {
00440 public:
00444 Hexagonal(uint width = 0, uint height = 0)
00445 : Generic<Type>(width, height) {}
00446
00453 CoordList neighbours(const Coord &c, bool insideOnly = true) const {
00454 CoordList neighbours;
00455 for (uint i=0; i<Nb_Neighbour; i++) {
00456 Coord n = neighbour(c, (Neighbour)i);
00457 if ( insideOnly && !Generic<Type>::inside(n) ) continue;
00458 neighbours.append(n);
00459 }
00460 return neighbours;
00461 }
00462
00463
00472 CoordList neighbours(const Coord &c, uint distance, bool all,
00473 bool insideOnly = true) const {
00474
00475 CoordList ring;
00476 if ( distance==0 ) return ring;
00477 ring = neighbours(c, insideOnly);
00478 if ( distance==1 ) return ring;
00479 CoordList center;
00480 center.append(c);
00481 for (uint i=1; i<distance; i++) {
00482 CoordList newRing;
00483 CoordList::const_iterator it;
00484 for (it=ring.begin(); it!=ring.end(); ++it) {
00485 CoordList n = neighbours(*it, insideOnly);
00486 CoordList::const_iterator it2;
00487 for (it2=n.begin(); it2!=n.end(); ++it2)
00488 if ( center.indexOf(*it2)==-1
00489 && ring.indexOf(*it2)==-1
00490 && newRing.indexOf(*it2)==-1 )
00491 newRing.append(*it2);
00492 center.append(*it);
00493 }
00494 ring = newRing;
00495 }
00496 if ( !all ) return ring;
00497 CoordList::const_iterator it;
00498 for (it=ring.begin(); it!=ring.end(); ++it)
00499 center.append(*it);
00500 center.removeAll(c);
00501 return center;
00502 }
00503 };
00504
00505 }
00506
00507 #endif