プログラムで連動するがランダムなサイズの正方形のグリッドを構築する方法


8

長方形の2次元レイアウト、つまりランダムなサイズの立方体で構成されるグリッドを作成したいと思います。立方体は互いにフィットし、パディングまたはマージン(間隔)が等しい必要があります。漫画本のレイアウトのようなもの、または添付された画像のようなもの。

どうすればこれを手続き的に行うことができますか?

実際には、おそらくPythonといくつかのグラフィックソフトウェアを使用して画像をレンダリングしますが、ランダム化されたグリッドを生成するために使用する必要があるアルゴリズムの種類(またはその他)がわかりません。

ランダムキューブ


本当に、これはプログラミングの問題ではありません。あなたは思いつき、それからあなたが正方形を望む方法、別名「アルゴリズム」を決める必要があります。それを実装すると、プログラミングの問題になります。メソッドを思いつくには?空白の紙(できればたくさんの紙)から始めて、絵を描き、次に何をしているのか説明します。
AakashM 2012年

回答:


8

1x1セルのグリッドから始めます。ランダムなスポットを選択し、セルをランダムに結合するか、それがより大きな長方形と衝突するまで。

これにより、提供するイメージに似たものが得られます。

大きなセル間のパディングとして機能する小さなセルが多数必要ない場合は、大きな問題があります。たとえば漫画本では、デッドスペースの量を最小限に抑え、セル数を最大9個にしたいと考えています。いくつかの点を選択して線を引き、それらをセルと呼ぶことができます。

//Philip Haubrich, 2012, public domain
//Build instructions: gcc comicPanels.c

#include <stdio.h>  //entirely for printf()
#include <stdlib.h> //Entirely for rand()
#include <time.h> //Entirely to help srand()

#define PAINTINGSIZE_X 79
#define PAINTINGSIZE_Y 20

#define MYNUMBEROFPOINTS 4

#define MINDISTANCEBETWEENBOXES 2
//Because I suck at naming things. You should really fix this before it gets into your codebase.

#define NORTH 0
#define EAST 1
#define SOUTH 2
#define WEST 3

#define WHITE 0
#define BLACK 1

//Or, you know, a struct with .color, .r .g .b .alpha .editablebydeadpool
char g_paintingArea[PAINTINGSIZE_X][PAINTINGSIZE_Y];

void drawLineUntilBlocked(int x, int y, int direction)
{
  do
  {
    g_paintingArea[x][y] = BLACK;
    switch(direction)
    {
    case NORTH:
      y++;
      break;
    case SOUTH:
      y--;
      break;
    case EAST:
      x++;
      break;
    case WEST:
      x--;
      break;
    default:
      printf("I really need to get away from switch statements...\n");
    }
  } while(g_paintingArea[x][y] == WHITE && x > 0 && y > 0 && x < PAINTINGSIZE_X && y < PAINTINGSIZE_Y);
  //dowhile, when you are too lazy to re-arrange the code
}

//Feel free to sub in something like SDL or openGL here
void paint()
{
  int x,y;
  for(y=0; y<PAINTINGSIZE_Y; y++)
  {
    for(x=0; x<PAINTINGSIZE_X; x++)
    {
      printf("%c",g_paintingArea[x][y]);
    }
    printf("\n");
  }
}

int empty(int origx, int origy)
{
  int x,y;
  for(x=origx-MINDISTANCEBETWEENBOXES; x<origx+MINDISTANCEBETWEENBOXES; x++)
  {
    for(y=origy-MINDISTANCEBETWEENBOXES; y<origy+MINDISTANCEBETWEENBOXES; y++)
    { 
      if( x < 0 || y < 0 || x >= PAINTINGSIZE_X || y >= PAINTINGSIZE_Y)
        continue;
      if( g_paintingArea[x][y] == BLACK)
        return 0; //Not empty, there is something nearby
    }
  }
  return 1; //Empty, like my heart
}

void init()
{
  int x,y;
  //initalize to zero
  for(x=0; x<PAINTINGSIZE_X; x++)
  {
    for(y=0; y<PAINTINGSIZE_Y; y++)
    {
      g_paintingArea[x][y] = WHITE;
    }
  }
  //Border, or as I like to call it B-town
  for(x=0; x<PAINTINGSIZE_X; x++)
  {
    g_paintingArea[x][0] = BLACK;
    g_paintingArea[x][PAINTINGSIZE_Y-1] = BLACK;
  }
  for(y=0; y<PAINTINGSIZE_Y; y++)
  {
    g_paintingArea[0][y] = BLACK;
    g_paintingArea[PAINTINGSIZE_X-1][y] = BLACK;
  }

  //oh yeah, this is important
  x = abs(time(NULL));
  srand(x);
}

int main(int argc, char** argv)
{
  int x,y,i; 

  init();

  //That part you actually asked about
  for( i=0; i<MYNUMBEROFPOINTS; i++)
  {
    x = rand() % PAINTINGSIZE_X;
    y = rand() % PAINTINGSIZE_Y;

    if(!empty(x,y))
      continue;

    switch(rand()%3)
    {
    case 0: //4 way
      drawLineUntilBlocked(x,y,NORTH);
      drawLineUntilBlocked(x,y,SOUTH);
      drawLineUntilBlocked(x,y,EAST);
      drawLineUntilBlocked(x,y,WEST);
      break;
    case 1: //North/sourth
      drawLineUntilBlocked(x,y,NORTH);
      drawLineUntilBlocked(x,y,SOUTH);
      break;
    case 2: //East/West
      drawLineUntilBlocked(x,y,EAST);
      drawLineUntilBlocked(x,y,WEST);
      break;
    default:
      printf("Oh god wtf, and other useful error messages\n");
    }
  }
  //If I have to explain to you that this next bit will depend on your platform, then programming may not be for you
  paint();  
  return 0;
}

猫の皮をむく方法はもっとたくさんあります。


7
  • 画像全体を説明する正方形から始めます。
  • 正方形を空の配列に追加します。

  • 配列内の各正方形について:

    • ランダムなtrue / false値でブール値を作成します。
    • 値がtrueの場合:
      • 正方形を4つの等しいサイズのサブ正方形に分割します。
      • それらを配列の最後に追加します。
      • 現在の正方形を配列から削除します。

プロセスの最後に、ランダムなサイズの正方形の配列ができます。おそらく、最小サイズ(この時点で分割は行われません)と最大サイズ(正方形が大きい場合は、ブール値に関係なく常に分割)を定義する必要があることに注意してください。


1
これは良い解決策のようです。
Mrwolfy

(私は大学で再帰的な迷路発生器に同様のアルゴリズムを使用しました)これには、画像全体を横切る線が常にあるという副作用があります。

@MichaelT:間違いなく問題ですが、アルゴリズムのシンプルさとスピードは間違いなくそれを補います。これが問題への適切なアプローチであるかどうかは、ユースケースに本当に依存します。例の画像は、強調表示された問題があるため、このアルゴリズムで生成されたようです。
Antは

1

画像のサイズとジオメトリを決定します。これをタイリングしたい場合、基になるジオメトリはトーラスのジオメトリです。

可能なすべての形状の左上隅のリストを維持します。最初は、これはすべての可能なスポットです。

ランダムなサイズの長方形を選択します(決めた制約内で-サンプル画像では正方形で、最大サイズは4です)。この長方形をランダムな左上隅のスポットに配置します。

長方形が大きすぎる(既存の割り当てられたスポットに重なる)場合は、収まるように長方形の寸法をトリミングします。

可能な左上隅のリストから、この長方形で覆われているすべての場所を削除します。

左上隅のリストが空になるまで繰り返します。

結果の配列を好みの方法でレンダリングします。これは、マージンを導入する場所です。


特定のグラフィックライブラリに慣れていない場合は、ppm形式の使用を検討してください。主な利点は、テキストファイルを書き出し、コンバーター(ppmto___)の1つを使用して、画像を選択した形式(ppmtogif。ppmtojpegなど)に変換できることです。


ありがとう。実際、私はそれを中心点のセット(x、yグリッド上)とスケールの説明(1や.5、2など)に変換することにもっと興味があります。これらの数値を3Dアプリにフィードします。
Mrwolfy
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.