#概要
こちらは水彩画のようなボロノイ図を作成する記事です。
ここではそのようなボロノイ図を便宜上、"水彩ボロノイ図"と呼ぶことにします。
何か不備がありましたら指摘していただければ幸いです。
#コード
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;
}
アニメーションしてみたらこんな感じ
ボロノイ図と違う点は、境界線が凸凹している点ですね。
この性質を利用して例えば、自然地形を線画すると自然な出来になります。
##ソースコードのライセンス
These codes are licensed under CC0.
ソースコードは自由に使用してください。
#参考
DXライブラリ 関数リファレンスページ
新・C言語 ~ゲームプログラミングの館
ボロノイ図
ボロノイ図を作る
ボロノイ図とその3つの性質
ボロノイ分割とは?
GPUでボロノイ図を描画する
ボロノイ図の描画アルゴリズムについて