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 {
00092 template <class Type>
00093 class Generic
00094 {
00095 public:
00099 Generic(uint width = 0, uint height = 0) {
00100 resize(width, height);
00101 }
00102
00103 virtual ~Generic() {}
00104
00108 void resize(uint width, uint height) {
00109 _width = width;
00110 _height = height;
00111 _vector.resize(width*height);
00112 }
00113
00117 void fill(const Type &value) {
00118 for (int i=0; i<_vector.count(); i++) _vector[i] = value;
00119 }
00120
00124 uint width() const { return _width; }
00128 uint height() const { return _height; }
00132 uint size() const { return _width*_height; }
00133
00137 uint index(const Coord &c) const {
00138 return c.first + c.second*_width;
00139 }
00140
00144 Coord coord(uint index) const {
00145 return Coord(index % _width, index / _width);
00146 }
00147
00151 const Type &at(const Coord &c) const { return _vector[index(c)]; }
00155 Type &at(const Coord &c) { return _vector[index(c)]; }
00159 const Type &operator [](const Coord &c) const { return _vector[index(c)]; }
00163 Type &operator [](const Coord &c) { return _vector[index(c)]; }
00164
00168 const Type &at(uint index) const { return _vector[index]; }
00172 Type &at(uint index) { return _vector[index]; }
00176 const Type &operator [](uint index) const { return _vector[index]; }
00180 Type &operator [](uint index) { return _vector[index]; }
00181
00185 bool inside(const Coord &c) const {
00186 return ( c.first>=0 && c.first<(int)_width
00187 && c.second>=0 && c.second<(int)_height );
00188 }
00189
00193 void bound(Coord &c) const {
00194 c.first = qMax(qMin(c.first, (int)_width-1), 0);
00195 c.second = qMax(qMin(c.second, (int)_height-1), 0);
00196 }
00197
00198 protected:
00199 uint _width, _height;
00200 QVector<Type> _vector;
00201 };
00202 }
00203
00204 template <class Type>
00205 QDataStream &operator <<(QDataStream &s, const KGrid2D::Generic<Type> &m) {
00206 s << (quint32)m.width() << (quint32)m.height();
00207 for (uint i=0; i<m.size(); i++) s << m[i];
00208 return s;
00209 }
00210
00211 template <class Type>
00212 QDataStream &operator >>(QDataStream &s, KGrid2D::Generic<Type> &m) {
00213 quint32 w, h;
00214 s >> w >> h;
00215 m.resize(w, h);
00216 for (uint i=0; i<m.size(); i++) s >> m[i];
00217 return s;
00218 }
00219
00220
00221 namespace KGrid2D
00222 {
00223
00224
00231 class SquareBase
00232 {
00233 public:
00237 enum Neighbour { Left=0, Right, Up, Down, LeftUp, LeftDown,
00238 RightUp, RightDown, Nb_Neighbour };
00239
00243 static double angle(Neighbour n) {
00244 switch (n) {
00245 case Left: return M_PI;
00246 case Right: return 0;
00247 case Up: return M_PI_2;
00248 case Down: return -M_PI_2;
00249 case LeftUp: return 3.0*M_PI_4;
00250 case LeftDown: return -3.0*M_PI_4;
00251 case RightUp: return M_PI_4;
00252 case RightDown: return -M_PI_4;
00253 case Nb_Neighbour: Q_ASSERT(false);
00254 }
00255 return 0;
00256 }
00257
00261 static Neighbour opposed(Neighbour n) {
00262 switch (n) {
00263 case Left: return Right;
00264 case Right: return Left;
00265 case Up: return Down;
00266 case Down: return Up;
00267 case LeftUp: return RightDown;
00268 case LeftDown: return RightUp;
00269 case RightUp: return LeftDown;
00270 case RightDown: return LeftUp;
00271 case Nb_Neighbour: Q_ASSERT(false);
00272 }
00273 return Nb_Neighbour;
00274 }
00275
00280 static bool isDirect(Neighbour n) { return n<LeftUp; }
00281
00285 static Coord neighbour(const Coord &c, Neighbour n) {
00286 switch (n) {
00287 case Left: return c + Coord(-1, 0);
00288 case Right: return c + Coord( 1, 0);
00289 case Up: return c + Coord( 0, -1);
00290 case Down: return c + Coord( 0, 1);
00291 case LeftUp: return c + Coord(-1, -1);
00292 case LeftDown: return c + Coord(-1, 1);
00293 case RightUp: return c + Coord( 1, -1);
00294 case RightDown: return c + Coord( 1, 1);
00295 case Nb_Neighbour: Q_ASSERT(false);
00296 }
00297 return c;
00298 }
00299 };
00300
00307 template <class T>
00308 class Square : public Generic<T>, public SquareBase
00309 {
00310 public:
00314 Square(uint width = 0, uint height = 0)
00315 : Generic<T>(width, height) {}
00316
00324 CoordList neighbours(const Coord &c, bool insideOnly = true,
00325 bool directOnly = false) const {
00326 CoordList neighbours;
00327 for (int i=0; i<(directOnly ? LeftUp : Nb_Neighbour); i++) {
00328 Coord n = neighbour(c, (Neighbour)i);
00329 if ( insideOnly && !Generic<T>::inside(n) ) continue;
00330 neighbours.append(n);
00331 }
00332 return neighbours;
00333 }
00334
00341 Coord toEdge(const Coord &c, Neighbour n) const {
00342 switch (n) {
00343 case Left: return Coord(0, c.second);
00344 case Right: return Coord(Generic<T>::width()-1, c.second);
00345 case Up: return Coord(c.first, 0);
00346 case Down: return Coord(c.first, Generic<T>::height()-1);
00347 case LeftUp: return Coord(0, 0);
00348 case LeftDown: return Coord(0, Generic<T>::height()-1);
00349 case RightUp: return Coord(Generic<T>::width()-1, 0);
00350 case RightDown: return Coord(Generic<T>::width()-1, Generic<T>::height()-1);
00351 case Nb_Neighbour: Q_ASSERT(false);
00352 }
00353 return c;
00354 }
00355 };
00356
00357
00369 class HexagonalBase
00370 {
00371 public:
00375 enum Neighbour { Left = 0, Right, LeftUp, LeftDown,
00376 RightUp, RightDown, Nb_Neighbour };
00377
00381 static double angle(Neighbour n) {
00382 switch (n) {
00383 case Left: return M_PI;
00384 case Right: return 0;
00385 case LeftUp: return 2.0*M_PI/3;
00386 case LeftDown: return -2.0*M_PI/3;
00387 case RightUp: return M_PI/3;
00388 case RightDown: return -M_PI/3;
00389 case Nb_Neighbour: Q_ASSERT(false);
00390 }
00391 return 0;
00392 }
00393
00397 static Neighbour opposed(Neighbour n) {
00398 switch (n) {
00399 case Left: return Right;
00400 case Right: return Left;
00401 case LeftUp: return RightDown;
00402 case LeftDown: return RightUp;
00403 case RightUp: return LeftDown;
00404 case RightDown: return LeftUp;
00405 case Nb_Neighbour: Q_ASSERT(false);
00406 }
00407 return Nb_Neighbour;
00408 }
00409
00413 static Coord neighbour(const Coord &c, Neighbour n) {
00414 bool oddRow = c.second%2;
00415 switch (n) {
00416 case Left: return c + Coord(-1, 0);
00417 case Right: return c + Coord( 1, 0);
00418 case LeftUp: return c + (oddRow ? Coord( 0, -1) : Coord(-1, -1));
00419 case LeftDown: return c + (oddRow ? Coord( 0, 1) : Coord(-1, 1));
00420 case RightUp: return c + (oddRow ? Coord( 1, -1) : Coord( 0, -1));
00421 case RightDown: return c + (oddRow ? Coord( 1, 1) : Coord( 0, 1));
00422 case Nb_Neighbour: Q_ASSERT(false);
00423 }
00424 return c;
00425 }
00426
00430 static uint distance(const Coord &c1, const Coord &c2) {
00431 return qAbs(c1.first - c2.first) + qAbs(c1.second - c2.second)
00432 + (c1.first==c2.first || c1.second==c2.second ? 0 : -1);
00433 }
00434 };
00435
00447 template <class Type>
00448 class Hexagonal : public Generic<Type>, public HexagonalBase
00449 {
00450 public:
00454 Hexagonal(uint width = 0, uint height = 0)
00455 : Generic<Type>(width, height) {}
00456
00463 CoordList neighbours(const Coord &c, bool insideOnly = true) const {
00464 CoordList neighbours;
00465 for (uint i=0; i<Nb_Neighbour; i++) {
00466 Coord n = neighbour(c, (Neighbour)i);
00467 if ( insideOnly && !Generic<Type>::inside(n) ) continue;
00468 neighbours.append(n);
00469 }
00470 return neighbours;
00471 }
00472
00473
00482 CoordList neighbours(const Coord &c, uint distance, bool all,
00483 bool insideOnly = true) const {
00484
00485 CoordList ring;
00486 if ( distance==0 ) return ring;
00487 ring = neighbours(c, insideOnly);
00488 if ( distance==1 ) return ring;
00489 CoordList center;
00490 center.append(c);
00491 for (uint i=1; i<distance; i++) {
00492 CoordList newRing;
00493 CoordList::const_iterator it;
00494 for (it=ring.begin(); it!=ring.end(); ++it) {
00495 CoordList n = neighbours(*it, insideOnly);
00496 CoordList::const_iterator it2;
00497 for (it2=n.begin(); it2!=n.end(); ++it2)
00498 if ( center.indexOf(*it2)==-1
00499 && ring.indexOf(*it2)==-1
00500 && newRing.indexOf(*it2)==-1 )
00501 newRing.append(*it2);
00502 center.append(*it);
00503 }
00504 ring = newRing;
00505 }
00506 if ( !all ) return ring;
00507 CoordList::const_iterator it;
00508 for (it=ring.begin(); it!=ring.end(); ++it)
00509 center.append(*it);
00510 center.removeAll(c);
00511 return center;
00512 }
00513 };
00514
00515 }
00516
00517 #endif