Logo Search packages:      
Sourcecode: palapeli version File versions  Download package

void Palapeli::HexagonalPattern::doSlice ( const QImage &  image  )  [protected, virtual]

Provides the slicing algorithm. This function splits a given image into pieces and defines relations between them. These pieces and relations are used to build the puzzle.

Parameters:
image the image to be sliced
See also:
addPiece, addRelation, reportPieceCount

Implements Palapeli::Pattern.

Definition at line 46 of file pattern-hexagon.cpp.

References Palapeli::Pattern::addPiece(), Palapeli::Pattern::addRelation(), Palapeli::Pattern::CreatePuzzle, Palapeli::Pattern::mode(), Palapeli::Pattern::pieceCount(), and Palapeli::Pattern::reportPieceCount().

{
      const int width = image.width(), height = image.height();
      const QSize imageSize(width, height);
      const QRect imageRect(0, 0, width, height);
      const int pieceWidth = width / m_xCount + 1, pieceHeight = height / m_yCount + 1; //the +1 is a hack to avoid pieces with width or height = 1
      const QSize pieceSize(pieceWidth, pieceHeight);
      const QRect pieceRect(0, 0, pieceWidth, pieceHeight);
      //block 1: the hexagonal mask
      //create painter path for mask - start at left, then go around clockwise
      QPainterPath path;
      path.moveTo(0, pieceHeight / 2);
      path.lineTo(pieceWidth / 4, 0);
      path.lineTo(pieceWidth * 3 / 4, 0);
      path.lineTo(pieceWidth, pieceHeight / 2);
      path.lineTo(pieceWidth * 3 / 4, pieceHeight);
      path.lineTo(pieceWidth / 4, pieceHeight);
      path.lineTo(0, pieceHeight / 2);
      //create mask
      QImage mask(pieceSize, QImage::Format_ARGB32_Premultiplied);
      mask.fill(0x00000000);
      QPainter painter;
      painter.begin(&mask);
      painter.setPen(Qt::NoPen);
      painter.setBrush(Qt::black);
      painter.drawPath(path);
      painter.end();
      //block 2: create pieces
      //Note that the pieces are ordered linearly in y direction, but not in x direction; i.e. (x,y + 1) and (x,y) have the same position in X direction, but (x + 1,y) and (x,y) do not have the same position in Y direction. That is the main characteristic of a hexagonal grid: One of the three main axes of this grid can equal a normal carthesic axis (the Y axis in this case), but the other carthesic axis may not.
      QList<QPoint> pieceIndices; //index (0,0) is at the center
      //get (approximate) coordinate range for pieces
      int maxX = 0, maxY = 0; int pieceCount = 1; //piece (0,0) is already counted
      for (int x = 0; imageRect.intersects(pieceRect.translated(pieceBasePosition(x, 0, pieceSize, imageSize))); ++x)
      {
            maxX = qMax(x, maxX);
            for (int y = 0; imageRect.intersects(pieceRect.translated(pieceBasePosition(x, y, pieceSize, imageSize))); ++y)
            {
                  maxY = qMax(y, maxY);
                  if (x + y >= 0)
                        pieceCount += 4; //because signs have not yet been taken into account, each piece has to be counted as four (except for (0,0) which was already counted once)
            }
      }
      reportPieceCount(pieceCount);
      if (mode() != CreatePuzzle)
            return;
      //iterate through possible pieces
      for (int x = -maxX; x <= maxX; ++x)
      {
            for (int y = -maxY; y <= maxY; ++y)
            {
                  //find position of this piece
                  const QPoint thisPiecePosition = pieceBasePosition(x, y, pieceSize, imageSize);
                  const QRect thisPieceFullRect = pieceRect.translated(thisPiecePosition);
                  if (!thisPieceFullRect.intersects(imageRect))
                        continue;
                  //find actual size of this piece (may be smaller than expected because of the image boundaries)
                  const QRect thisPieceRect = thisPieceFullRect.intersected(imageRect); //only the part of thisPieceFullRect that actually contains an image
                  const QRect thisMaskRect(thisPieceRect.topLeft() - thisPieceFullRect.topLeft(), thisPieceRect.size()); //only the part of the mask that belongs to the image in thisPieceRect (the full mask is for the thisPieceFullRect)
                  //crop image and mask (if necessary), pass them to Palapeli
                  addPiece(image.copy(thisPieceRect), mask.copy(thisMaskRect), thisPieceRect);
                  pieceIndices << QPoint(x, y);
            }
      }
      //block 3: add relations
      int index1, index2;
      for (int x = -maxX; x <= maxX; ++x)
      {
            for (int y = -maxY; y <= maxY; ++y)
            {
                  index1 = pieceIndices.indexOf(QPoint(x, y));
                  if (index1 == -1)
                        continue;
                  //vertical axis
                  index2 = pieceIndices.indexOf(QPoint(x, y + 1));
                  if (index2 != -1)
                        addRelation(index1, index2);
                  index2 = pieceIndices.indexOf(QPoint(x, y - 1));
                  if (index2 != -1)
                        addRelation(index1, index2);
                  //first diagonal axis
                  index2 = pieceIndices.indexOf(QPoint(x + 1, y));
                  if (index2 != -1)
                        addRelation(index1, index2);
                  index2 = pieceIndices.indexOf(QPoint(x - 1, y));
                  if (index2 != -1)
                        addRelation(index1, index2);
                  //second diagonal axis
                  const int xFactor = qAbs(x) % 2 * 2 - 1; //-1 for even and +1 for odd values of qAbs(x)
                  index2 = pieceIndices.indexOf(QPoint(x + 1, y - xFactor));
                  if (index2 != -1)
                        addRelation(index1, index2);
                  index2 = pieceIndices.indexOf(QPoint(x - 1, y - xFactor));
                  if (index2 != -1)
                        addRelation(index1, index2);
            }
      }
}


Generated by  Doxygen 1.6.0   Back to index