File indexing completed on 2024-05-12 04:06:20

0001 /*
0002     SPDX-FileCopyrightText: 2010 Johannes Loehnert <loehnert.kde@gmx.de>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "grid.h"
0008 
0009 #include <cmath>
0010 #include <QPainterPath>
0011 #include <QDebug>
0012 #include "utilities.h"
0013 
0014 void RectMode::generateGrid(GoldbergEngine *e, int piece_count) const {
0015     // number of tries to resolve collision
0016     int collision_tries = 10 * e->m_plug_size * e->m_plug_size;
0017     if (collision_tries < 5) collision_tries = 5;
0018     const qreal collision_shrink_factor = 0.95;
0019 
0020 
0021     // calculate piece counts
0022     const int width = e->get_image_width(), height = e->get_image_height();
0023 
0024     int xCount;
0025     int yCount;
0026     getBestFit(xCount, yCount, 1.0 * width / height, piece_count);
0027 
0028     const int pieceWidth = width / xCount, pieceHeight = height / yCount;
0029     e->m_length_base = (pieceWidth + pieceHeight) * 0.5 * e->m_plug_size;
0030 
0031     GBClassicPlugParams** horizontalPlugParams = new GBClassicPlugParams*[xCount+1];
0032     GBClassicPlugParams** verticalPlugParams = new GBClassicPlugParams*[xCount+1];
0033 
0034     for (int x = 0; x < xCount+1; ++x) {
0035         horizontalPlugParams[x] = new GBClassicPlugParams[yCount+1];
0036         verticalPlugParams[x] = new GBClassicPlugParams[yCount+1];
0037         for (int y = 0; y < yCount+1; ++y) {
0038             bool odd_tile = (x+y) % 2;
0039             //borders along X axis
0040             if (y==0 || y==yCount) {
0041                 horizontalPlugParams[x][y] = e->initEdge(true);
0042             }
0043             else {
0044                 horizontalPlugParams[x][y] = e->initEdge(false);
0045             }
0046             horizontalPlugParams[x][y].flipped ^= odd_tile ^ e->m_alternate_flip;
0047             horizontalPlugParams[x][y].unit_x = QLineF(x*pieceWidth, y*pieceHeight, (x+1)*pieceWidth, y*pieceHeight);
0048             if (x>0 && x < xCount) e->smooth_join(horizontalPlugParams[x][y], horizontalPlugParams[x-1][y]);
0049             
0050             //borders along Y axis
0051             if (x==0 || x==xCount) {
0052                 verticalPlugParams[x][y] = e->initEdge(true);
0053             }
0054             else {
0055                 verticalPlugParams[x][y] = e->initEdge(false);
0056             }
0057             verticalPlugParams[x][y].flipped ^= odd_tile;
0058             verticalPlugParams[x][y].unit_x = QLineF(x*pieceWidth, y*pieceHeight, x*pieceWidth, (y+1)*pieceHeight);
0059             if (y>0 && y < yCount) e->smooth_join(verticalPlugParams[x][y], verticalPlugParams[x][y-1]);
0060 
0061             // collision checking
0062             if (x > 0 && x < xCount) {
0063                 bool v_intersects = true;
0064                 QList<GBClassicPlugParams*> offenders;
0065                 for (int i=0; i<collision_tries && v_intersects; i++) {
0066                     offenders.clear();
0067                     if (i>0 && v_intersects) {
0068                         //qDebug() << "collision: vertical edge, x=" << x << ", y=" << y;
0069                         verticalPlugParams[x][y].size_correction *= collision_shrink_factor;
0070                         e->reRandomizeEdge(verticalPlugParams[x][y], true);
0071                     }
0072                     v_intersects = e->plugsIntersect(verticalPlugParams[x][y], horizontalPlugParams[x-1][y], &offenders);
0073                     if (y<yCount) v_intersects |= e->plugsIntersect(verticalPlugParams[x][y], horizontalPlugParams[x-1][y+1], &offenders);
0074                 }
0075                 if (v_intersects) {
0076                     e->makePlugless(verticalPlugParams[x][y]);
0077                     for (int i=0; i<offenders.size(); i++) e->makePlugless(*(offenders.at(i)));
0078                 }
0079             }
0080             if (y>0 && y < yCount) {
0081                 bool h_intersects = true;
0082                 QList<GBClassicPlugParams*> offenders;
0083                 for (int i=0; i<collision_tries && h_intersects; i++) {
0084                     offenders.clear();
0085                     if (i>0 && h_intersects) {
0086                         //qDebug() << "collision: horizontal edge, x=" << x << " y=" << y;
0087                         horizontalPlugParams[x][y].size_correction *= collision_shrink_factor;
0088                         e->reRandomizeEdge(horizontalPlugParams[x][y], true);
0089                     }
0090                     h_intersects = e->plugsIntersect(horizontalPlugParams[x][y], verticalPlugParams[x][y-1], &offenders);
0091                     if (x<xCount) h_intersects |= e->plugsIntersect(horizontalPlugParams[x][y], verticalPlugParams[x][y], &offenders);
0092                 }
0093                 if (h_intersects) {
0094                     e->makePlugless(horizontalPlugParams[x][y]);
0095                     for (int i=0; i<offenders.size(); i++) e->makePlugless(*(offenders.at(i)));
0096                 }
0097             }
0098         }
0099     }
0100 
0101     //create pieces
0102     for (int x = 0; x < xCount; ++x) {
0103         for (int y = 0; y < yCount; ++y) {
0104             //create the mask path
0105             QPainterPath path;
0106             path.moveTo(horizontalPlugParams[x][y].unit_x.p1());
0107 
0108             // top, right, bottom, left plug
0109             e->addPlugToPath(path, false, horizontalPlugParams[x][y]);
0110             e->addPlugToPath(path, false, verticalPlugParams[x+1][y]);
0111             e->addPlugToPath(path, true, horizontalPlugParams[x][y+1]);
0112             e->addPlugToPath(path, true, verticalPlugParams[x][y]);
0113 
0114             e->makePieceFromPath(x + y * xCount, path);
0115         }
0116     }
0117 
0118     //create relations
0119     for (int x = 0; x < xCount; ++x) {
0120         for (int y = 0; y < yCount; ++y) {
0121             if (x != 0) e->addRelation(x + y * xCount, (x - 1) + y * xCount);
0122             if (y != 0) e->addRelation(x + y * xCount, x + (y - 1) * xCount);
0123         }
0124     }
0125 
0126     //cleanup
0127     for (int x = 0; x < xCount + 1; ++x) {
0128         delete[] horizontalPlugParams[x];
0129         delete[] verticalPlugParams[x];
0130     }
0131     delete[] horizontalPlugParams;
0132     delete[] verticalPlugParams;
0133 }
0134