3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

#学生LTAdvent Calendar 2017

Day 10

水彩ボロノイ図

Last updated at Posted at 2017-12-09

#概要
こちらは水彩画のようなボロノイ図を作成する記事です。
ここではそのようなボロノイ図を便宜上、"水彩ボロノイ図"と呼ぶことにします。
何か不備がありましたら指摘していただければ幸いです。

#コード
0.5秒おきに水彩ボロノイ図が自動生成されるプログラムです。

Main.cpp
/*水彩ボロノイ図を生成*/

#include "DxLib.h"

//横画面サイズ
#define MAP_X 512

//縦画面サイズ
#define MAP_Y 512

//原点サイズ
#define PX_SIZE 16

//各位置のID
#define LU VoronoiMap[im][jm]
#define U VoronoiMap[i][jm]
#define RU VoronoiMap[ip][jm]
#define L VoronoiMap[im][j]
#define C VoronoiMap[i][j]
#define R VoronoiMap[ip][j]
#define LD VoronoiMap[im][jp]
#define D VoronoiMap[i][jp]
#define RD VoronoiMap[ip][jp]

//各位置のX座標
#define LU_X WorldX[im][jm]
#define U_X WorldX[i][jm]
#define RU_X WorldX[ip][jm]
#define L_X WorldX[im][j]
#define C_X WorldX[i][j]
#define R_X WorldX[ip][j]
#define LD_X WorldX[im][jp]
#define D_X WorldX[i][jp]
#define RD_X WorldX[ip][jp]

//各位置のY座標
#define LU_Y WorldY[im][jm]
#define U_Y WorldY[i][jm]
#define RU_Y WorldY[ip][jm]
#define L_Y WorldY[im][j]
#define C_Y WorldY[i][j]
#define R_Y WorldY[ip][j]
#define LD_Y WorldY[im][jp]
#define D_Y WorldY[i][jp]
#define RD_Y WorldY[ip][jp]


/*原点を生成する*/
void DrawPX(int x, int y, int l, int id, unsigned char VoronoiMap[][MAP_Y], unsigned short WorldX[][MAP_Y], unsigned short WorldY[][MAP_Y]) {
	for (int i = x; i < x + l; i++) {
		for (int j = y; j < y + l; j++) {
			VoronoiMap[i][j] = id;
			WorldX[i][j] = i;
			WorldY[i][j] = j;
		}
	}
	return;
}


/*ボロノイ図を生成する*/
void DrawVoronoi(unsigned char VoronoiMap[][MAP_Y]) {

	//マップを初期化
	for (unsigned int i = 0; i < MAP_X; i++) {
		for (unsigned int j = 0; j < MAP_Y; j++) {
			C = 0;
		}
	}

	//マップの座標を格納する
	unsigned short WorldX[MAP_X][MAP_Y] = { 0 };
	unsigned short WorldY[MAP_X][MAP_Y] = { 0 };

	//生成する原点の個数を決める
	int mapCount = 1 + GetRand(12);

	//原点を生成
	for (int i = 1; i <= mapCount; i++) {
		DrawPX(GetRand(MAP_X - PX_SIZE), GetRand(MAP_Y - PX_SIZE), PX_SIZE, i, VoronoiMap, WorldX, WorldY);
	}

	//上下左右の座標
	unsigned int im;
	unsigned int ip;
	unsigned int jm;
	unsigned int jp;

	//原点からの距離の2乗
	unsigned int sizeXY;


	for (unsigned int k = MAP_X; k > 0; k >>= 1) {

		for (unsigned int i = 0; i < MAP_X; i++) {

			im = (MAP_X + i - k) & (MAP_X - 1);
			ip = (i + k) & (MAP_X - 1);

			for (unsigned int j = 0; j < MAP_Y; j++) {

				jm = (MAP_Y + j - k) & (MAP_Y - 1);
				jp = (j + k) & (MAP_Y - 1);

				//原点と中心点の距離の2乗を代入
				sizeXY = (C_X - i)*(C_X - i) + (C_Y - j)*(C_Y - j);

				//上と下を比較
				if (U && U == D && (!C || sizeXY >(D_X - i)*(D_X - i) + (D_Y - j)*(D_Y - j))) {
					C = D;
					C_X = D_X;
					C_Y = D_Y;
				}

				//左と右を比較
				if (L && L == R && (!C || sizeXY > (R_X - i)*(R_X - i) + (R_Y - j)*(R_Y - j))) {
					C = R;
					C_X = R_X;
					C_Y = R_Y;
				}

				//左上と右下を比較
				if (LU && LU == RD && (!C || sizeXY > (RD_X - i)*(RD_X - i) + (RD_Y - j)*(RD_Y - j))) {
					C = RD;
					C_X = RD_X;
					C_Y = RD_Y;
				}

				//右上と左下を比較
				if (RU && RU == LD && (!C || sizeXY > (LD_X - i)*(LD_X - i) + (LD_Y - j)*(LD_Y - j))) {
					C = LD;
					C_X = LD_X;
					C_Y = LD_Y;
				}

				//色を分けて線画
				switch (VoronoiMap[i][j])
				{
				case 0:DrawPixel(i, j, GetColor(255, 255, 255)); break;
				case 1:DrawPixel(i, j, GetColor(255, 0, 0)); break;
				case 2:DrawPixel(i, j, GetColor(0, 255, 0)); break;
				case 3:DrawPixel(i, j, GetColor(0, 0, 255)); break;
				case 4:DrawPixel(i, j, GetColor(255, 255, 0)); break;
				case 5:DrawPixel(i, j, GetColor(255, 0, 255)); break;
				case 6:DrawPixel(i, j, GetColor(0, 255, 255)); break;
				case 7:DrawPixel(i, j, GetColor(127, 127, 127)); break;
				case 8:DrawPixel(i, j, GetColor(127, 0, 0)); break;
				case 9:DrawPixel(i, j, GetColor(0, 127, 0)); break;
				case 10:DrawPixel(i, j, GetColor(0, 0, 127)); break;
				case 11:DrawPixel(i, j, GetColor(127, 127, 0)); break;
				case 12:DrawPixel(i, j, GetColor(127, 0, 127)); break;
				case 13:DrawPixel(i, j, GetColor(0, 127, 127)); break;
				}

			}

		}
	}

}

/*メイン関数*/
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {

	//log出力停止・ウィンドウモード変更・初期化・裏画面設定
	SetOutApplicationLogValidFlag(FALSE), ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen(DX_SCREEN_BACK);

	//画面サイズの決定
	SetGraphMode(MAP_X, MAP_Y, 32);

	//画面サイズが偶数ではない場合
	if (MAP_X & 1 || MAP_Y & 1) {
		//DXライブラリの終了処理
		DxLib_End();
		return -1;
	}

	//マップ
	unsigned char VoronoiMap[MAP_X + 1][MAP_Y] = { 0 };

	//時間
	int time = 0;

	//ボロノイ図を生成
	DrawVoronoi(VoronoiMap);

	while (ScreenFlip() == 0 && ProcessMessage() == 0) {
		//0.5秒おきにボロノイ図を生成
		if (time == 30) {
			DrawVoronoi(VoronoiMap);
			time = 0;
		}

		//ESCキーで終了
		if (CheckHitKey(KEY_INPUT_ESCAPE)) break;

		//時間を増やす
		time++;
	}

	//DXライブラリの終了処理
	DxLib_End();
	return 0;
}

#結果
###実行してみたらこんな感じ
suivoro.png

アニメーションしてみたらこんな感じ

circleanimationmuvie

ボロノイ図と違う点は、境界線が凸凹している点ですね。
この性質を利用して例えば、自然地形を線画すると自然な出来になります。

##ソースコードのライセンス

These codes are licensed under CC0.
CC0

ソースコードは自由に使用してください。

#参考
DXライブラリ 関数リファレンスページ
新・C言語 ~ゲームプログラミングの館
ボロノイ図
ボロノイ図を作る
ボロノイ図とその3つの性質
ボロノイ分割とは?
GPUでボロノイ図を描画する
ボロノイ図の描画アルゴリズムについて

3
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?