水彩ボロノイ図

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

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

```cpp: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](https://qiita-image-store.s3.amazonaws.com/0/213065/5e43358d-8b65-18bd-f877-c91aaf0638cc.png)


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

![circleanimationmuvie](https://i.imgur.com/RapqAw9.gif)

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

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

These codes are licensed under CC0.
[![CC0](https://mirrors.creativecommons.org/presskit/buttons/88x31/svg/cc-zero.svg "CC0")](http://creativecommons.org/publicdomain/zero/1.0/deed.ja)

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


#参考
[ＤＸライブラリ　関数リファレンスページ](http://dxlib.o.oo7.jp/dxfunc.html)
[新・C言語 ～ゲームプログラミングの館](http://dixq.net/g/)
[ボロノイ図](https://ja.wikipedia.org/wiki/%E3%83%9C%E3%83%AD%E3%83%8E%E3%82%A4%E5%9B%B3)
[ボロノイ図を作る](https://qiita.com/yellow_73/items/abfca17297124785fe28)
[ボロノイ図とその３つの性質](https://mathtrain.jp/voronoi)
[ボロノイ分割とは？](http://www.pasco.co.jp/recommend/word/word048/)
[GPUでボロノイ図を描画する](http://postd.cc/voronoi-diagrams/)
[ボロノイ図の描画アルゴリズムについて](http://p-mathedu.org/docs/15th/15-01-maegawa.pdf)