Logo Search packages:      
Sourcecode: kdegames-kde4 version File versions  Download package

kgrid2d.h

/*
    This file is part of the KDE games library
    Copyright (C) 2001-02 Nicolas Hadacek (hadacek@kde.org)

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#ifndef __KGRID2D_H_
#define __KGRID2D_H_

#include <math.h>

#include <QtCore/QPair>
#include <QtCore/QVector>
//Added by qt3to4:
#include <QtCore/QTextStream>

#include <kglobal.h>


//-----------------------------------------------------------------------------
namespace KGrid2D
{
    /**
     * This type represents coordinates on a bidimensionnal grid.
     */
    typedef QPair<int, int> Coord;

    /**
     * This type represents a list of @ref Coord.
     */
    typedef QList<Coord> CoordList;
}

inline KGrid2D::Coord
operator +(const KGrid2D::Coord &c1, const KGrid2D::Coord &c2) {
    return KGrid2D::Coord(c1.first + c2.first, c1.second + c2.second);
}

inline KGrid2D::Coord
operator -(const KGrid2D::Coord &c1, const KGrid2D::Coord &c2) {
    return KGrid2D::Coord(c1.first - c2.first, c1.second - c2.second);
}

/**
 * @return the maximum of both coordinates.
 */
inline KGrid2D::Coord
maximum(const KGrid2D::Coord &c1, const KGrid2D::Coord &c2) {
    return KGrid2D::Coord(qMax(c1.first, c2.first), qMax(c1.second, c2.second));
}
/**
 * @return the minimum of both coordinates.
 */
inline KGrid2D::Coord
minimum(const KGrid2D::Coord &c1, const KGrid2D::Coord &c2) {
    return KGrid2D::Coord(qMin(c1.first, c2.first), qMin(c1.second, c2.second));
}

inline QTextStream &operator <<(QTextStream &s, const KGrid2D::Coord &c) {
    return s << '(' << c.second << "," << c.first << ')';
}

inline QTextStream &operator <<(QTextStream &s, const KGrid2D::CoordList &list)
{
    for(KGrid2D::CoordList::const_iterator i=list.begin(); i!=list.end(); ++i)
        s << *i;
      return s;
}

//-----------------------------------------------------------------------------
namespace KGrid2D
{
/**
 * This template class represents a generic bidimensionnal grid. Each node
 * contains an element of the template type.
 */
template <class Type>
00091 class Generic
{
 public:
    /**
     * Constructor.
     */
00097     Generic(uint width = 0, uint height = 0) {
        resize(width, height);
    }

    virtual ~Generic() {}

    /**
     * Resize the grid.
     */
00106     void resize(uint width, uint height) {
        _width = width;
        _height = height;
        _vector.resize(width*height);
    }

    /**
     * Fill the nodes with the given value.
     */
00115     void fill(const Type &value) {
        for (int i=0; i<_vector.count(); i++) _vector[i] = value;
    }

    /**
     * @return the width.
     */
00122     uint width() const  { return _width; }
    /**
     * @return the height.
     */
00126     uint height() const { return _height; }
    /**
     * @return the number of nodes (ie width*height).
     */
00130     uint size() const   { return _width*_height; }

    /**
     * @return the linear index for the given coordinate.
     */
00135     uint index(const Coord &c) const {
        return c.first + c.second*_width;
    }

    /**
     * @return the coordinate corresponding to the linear index.
     */
00142     Coord coord(uint index) const {
        return Coord(index % _width, index / _width);
    }

    /**
     * @return the value at the given coordinate.
     */
00149     const Type &at(const Coord &c) const { return _vector[index(c)]; }
    /**
     * @return the value at the given coordinate.
     */
00153     Type &at(const Coord &c)             { return _vector[index(c)]; }
    /**
     * @return the value at the given coordinate.
     */
00157     const Type &operator [](const Coord &c) const { return _vector[index(c)]; }
    /**
     * @return the value at the given coordinate.
     */
00161     Type &operator [](const Coord &c)             { return _vector[index(c)]; }

    /**
     * @return the value at the given linear index.
     */
00166     const Type &at(uint index) const          { return _vector[index]; }
    /**
     * @return the value at the given linear index.
     */
00170     Type &at(uint index)                      { return _vector[index]; }
    /**
     * @return the value at the given linear index.
     */
00174     const Type &operator [](uint index) const { return _vector[index]; }
    /**
     * @return the value at the given linear index.
     */
00178     Type &operator [](uint index)             { return _vector[index]; }

    /**
     * @return if the given coordinate is inside the grid.
     */
00183     bool inside(const Coord &c) const {
        return ( c.first>=0 && c.first<(int)_width
                 && c.second>=0 && c.second<(int)_height );
    }

    /**
     * Bound the given coordinate with the grid dimensions.
     */
00191     void bound(Coord &c) const {
        c.first = qMax(qMin(c.first, (int)_width-1), 0);
        c.second = qMax(qMin(c.second, (int)_height-1), 0);
    }

 protected:
    uint               _width, _height;
    QVector<Type> _vector;
};
}

template <class Type>
QDataStream &operator <<(QDataStream &s, const KGrid2D::Generic<Type> &m) {
    s << (quint32)m.width() << (quint32)m.height();
    for (uint i=0; i<m.size(); i++) s << m[i];
    return s;
}

template <class Type>
QDataStream &operator >>(QDataStream &s, KGrid2D::Generic<Type> &m) {
    quint32 w, h;
    s >> w >> h;
    m.resize(w, h);
    for (uint i=0; i<m.size(); i++) s >> m[i];
    return s;
}


namespace KGrid2D
{

//-----------------------------------------------------------------------------
/**
 * This class contains static methods to manipulate coordinates for a
 * square bidimensionnal grid.
 */
00227 class SquareBase
{
 public:
    /**
     * Identify the eight neighbours.
     */
00233     enum Neighbour { Left=0, Right, Up, Down, LeftUp, LeftDown,
                     RightUp, RightDown, Nb_Neighbour };

    /**
     * @return the trigonometric angle in radians for the given neighbour.
     */
00239     static double angle(Neighbour n) {
        switch (n) {
        case Left:      return M_PI;
        case Right:     return 0;
        case Up:        return M_PI_2;
        case Down:      return -M_PI_2;
        case LeftUp:    return 3.0*M_PI_4;
        case LeftDown:  return -3.0*M_PI_4;
        case RightUp:   return M_PI_4;
        case RightDown: return -M_PI_4;
        case Nb_Neighbour: Q_ASSERT(false);
        }
        return 0;
    }

    /**
     * @return the opposed neighbour.
     */
00257     static Neighbour opposed(Neighbour n) {
        switch (n) {
        case Left:      return Right;
        case Right:     return Left;
        case Up:        return Down;
        case Down:      return Up;
        case LeftUp:    return RightDown;
        case LeftDown:  return RightUp;
        case RightUp:   return LeftDown;
        case RightDown: return LeftUp;
        case Nb_Neighbour: Q_ASSERT(false);
        }
        return Nb_Neighbour;
    }

    /**
     * @return true if the neighbour is a direct one (ie is one of the four
     * nearest).
     */
00276     static bool isDirect(Neighbour n) { return n<LeftUp; }

    /**
     * @return the neighbour for the given coordinate.
     */
00281     static Coord neighbour(const Coord &c, Neighbour n) {
        switch (n) {
        case Left:      return c + Coord(-1,  0);
        case Right:     return c + Coord( 1,  0);
        case Up:        return c + Coord( 0, -1);
        case Down:      return c + Coord( 0,  1);
        case LeftUp:    return c + Coord(-1, -1);
        case LeftDown:  return c + Coord(-1,  1);
        case RightUp:   return c + Coord( 1, -1);
        case RightDown: return c + Coord( 1,  1);
        case Nb_Neighbour: Q_ASSERT(false);
        }
        return c;
    }
};

/**
 * This template is a @ref Generic implementation for a square bidimensionnal
 * grid (@ref SquareBase).
 */
template <class T>
00302 class Square : public Generic<T>, public SquareBase
{
 public:
    /**
     * Constructor.
     */
00308     Square(uint width = 0, uint height = 0)
        : Generic<T>(width, height) {}

    /**
     * @return the neighbours of coordinate @param c
     * to the given set of coordinates
     * @param c the coordinate to use as the reference point
     * @param insideOnly only add coordinates that are inside the grid.
     * @param directOnly only add the four nearest neighbours.
     */
00318     CoordList neighbours(const Coord &c, bool insideOnly = true,
                         bool directOnly = false) const {
        CoordList neighbours;
        for (int i=0; i<(directOnly ? LeftUp : Nb_Neighbour); i++) {
            Coord n = neighbour(c, (Neighbour)i);
            if ( insideOnly && !Generic<T>::inside(n) ) continue;
            neighbours.append(n);
        }
        return neighbours;
    }

    /**
     * @return the "projection" of the given coordinate on the grid edges.
     *
     * @param c the coordinate to use as the reference point
     * @param n the direction of projection.
     */
00335     Coord toEdge(const Coord &c, Neighbour n) const {
        switch (n) {
        case Left:      return Coord(0, c.second);
        case Right:     return Coord(Generic<T>::width()-1, c.second);
        case Up:        return Coord(c.first, 0);
        case Down:      return Coord(c.first, Generic<T>::height()-1);
        case LeftUp:    return Coord(0, 0);
        case LeftDown:  return Coord(0, Generic<T>::height()-1);
        case RightUp:   return Coord(Generic<T>::width()-1, 0);
        case RightDown: return Coord(Generic<T>::width()-1, Generic<T>::height()-1);
        case Nb_Neighbour: Q_ASSERT(false);
        }
        return c;
    }
};

//-----------------------------------------------------------------------------
/**
 * This class contains static methods to manipulate coordinates on an
 * hexagonal grid where hexagons form horizontal lines:
 * <pre>
 * (0,0)   (0,1)   (0,2)
 *     (1,0)   (1,1)   (1,2)
 * (2,0)   (2,1)   (2,2)
 * </pre>
 */
00361 class HexagonalBase
{
 public:
    /**
     * Identify the six neighbours.
     */
00367     enum Neighbour { Left = 0, Right, LeftUp, LeftDown,
                     RightUp, RightDown, Nb_Neighbour };

     /**
     * @return the trigonometric angle in radians for the given neighbour.
     */
00373     static double angle(Neighbour n) {
        switch (n) {
        case Left:      return M_PI;
        case Right:     return 0;
        case LeftUp:    return 2.0*M_PI/3;
        case LeftDown:  return -2.0*M_PI/3;
        case RightUp:   return M_PI/3;
        case RightDown: return -M_PI/3;
        case Nb_Neighbour: Q_ASSERT(false);
        }
        return 0;
    }

    /**
     * @return the opposed neighbour.
     */
00389     static Neighbour opposed(Neighbour n) {
        switch (n) {
        case Left:      return Right;
        case Right:     return Left;
        case LeftUp:    return RightDown;
        case LeftDown:  return RightUp;
        case RightUp:   return LeftDown;
        case RightDown: return LeftUp;
        case Nb_Neighbour: Q_ASSERT(false);
        }
        return Nb_Neighbour;
    }

    /**
     * @return the neighbour of the given coordinate.
     */
00405     static Coord neighbour(const Coord &c, Neighbour n) {
        bool oddRow = c.second%2;
        switch (n) {
        case Left:      return c + Coord(-1,  0);
        case Right:     return c + Coord( 1,  0);
        case LeftUp:    return c + (oddRow ? Coord( 0, -1) : Coord(-1, -1));
        case LeftDown:  return c + (oddRow ? Coord( 0,  1) : Coord(-1,  1));
        case RightUp:   return c + (oddRow ? Coord( 1, -1) : Coord( 0, -1));
        case RightDown: return c + (oddRow ? Coord( 1,  1) : Coord( 0,  1));
        case Nb_Neighbour: Q_ASSERT(false);
        }
        return c;
    }

    /**
    * @return the distance between the two coordinates in term of hexagons.
    */
00422     static uint distance(const Coord &c1, const Coord &c2) {
        return qAbs(c1.first - c2.first) + qAbs(c1.second - c2.second)
            + (c1.first==c2.first || c1.second==c2.second ? 0 : -1);
    }
};

/**
 * This template implements a hexagonal grid
 * where hexagons form horizontal lines:
 * <pre>
 * (0,0)   (0,1)   (0,2)
 *     (1,0)   (1,1)   (1,2)
 * (2,0)   (2,1)   (2,2)
 * </pre>
 */
template <class Type>
00438 class Hexagonal : public Generic<Type>, public HexagonalBase
{
 public:
    /**
     * Constructor.
     */
00444     Hexagonal(uint width = 0, uint height = 0)
        : Generic<Type>(width, height) {}

    /**
     * @return the neighbours of coordinate @param c
     * to the given set of coordinates
     * @param c the coordiante to use as the reference point
     * @param insideOnly only add coordinates that are inside the grid.
     */
00453     CoordList neighbours(const Coord &c, bool insideOnly = true) const {
        CoordList neighbours;
        for (uint i=0; i<Nb_Neighbour; i++) {
            Coord n = neighbour(c, (Neighbour)i);
            if ( insideOnly && !Generic<Type>::inside(n) ) continue;
            neighbours.append(n);
        }
        return neighbours;
    }


    /**
     * @return the neighbours at distance @param distance of coordinate
     * @param c the coordinate to use as the reference point
     * @param distance distance to the neighbour (1 means at contact).
     * @param insideOnly only add coordinates that are inside the grid.
     * @param all returns all neighbours at distance equal and less than
     *        @param distance (the original coordinate is not included).
     */
00472     CoordList neighbours(const Coord &c, uint distance, bool all,
                        bool insideOnly = true) const {
        // brute force algorithm -- you're welcome to make it more efficient :)
        CoordList ring;
        if ( distance==0 ) return ring;
        ring = neighbours(c, insideOnly);
        if ( distance==1 ) return ring;
        CoordList center;
        center.append(c);
        for (uint i=1; i<distance; i++) {
            CoordList newRing;
            CoordList::const_iterator it;
            for (it=ring.begin(); it!=ring.end(); ++it) {
                CoordList n = neighbours(*it, insideOnly);
                CoordList::const_iterator it2;
                for (it2=n.begin(); it2!=n.end(); ++it2)
                    if ( center.indexOf(*it2)==-1
                         && ring.indexOf(*it2)==-1
                         && newRing.indexOf(*it2)==-1 )
                        newRing.append(*it2);
                center.append(*it);
            }
            ring = newRing;
        }
        if ( !all ) return ring;
        CoordList::const_iterator it;
        for (it=ring.begin(); it!=ring.end(); ++it)
            center.append(*it);
        center.removeAll(c);
        return center;
    }
};

} // namespace

#endif

Generated by  Doxygen 1.6.0   Back to index