矩形分割
提供:kuhalaboWiki
(版間での差分)
(→リンク) |
(→長方形の分割) |
||
46行: | 46行: | ||
* 自然数x0,x1を2辺とする長方形を正方形で分割する。 | * 自然数x0,x1を2辺とする長方形を正方形で分割する。 | ||
** 最も小さい正方形の1辺が最大公約数 | ** 最も小さい正方形の1辺が最大公約数 | ||
− | * [ | + | * [https://yasushinoguchi.org/classes_j/shape/ 復習:点、線、図形の描画] |
;DivRect | ;DivRect | ||
<pre> | <pre> |
2022年7月4日 (月) 00:35時点における版
- 現代アート作家 モンドリアンの代表作品、Composition
- https://www.youtube.com/watch?v=dJmY4QhplBE (モンドリアンの作品全般の紹介、Compositionは6:01あたりから)
- https://www.youtube.com/watch?v=q21SA9NHSds(モンドリアンのComposition)
- https://www.youtube.com/watch?v=FqoZiUetwLs&t=1s (Compositionを題材にした動画)
目次 |
最大公約数
- 例
- 4と6の最大公約数は2
- 12と18の最大公約数は6
- 24と36の最大公約数は12
- 123と456の最大公約数は…3
- 912と1368の最大公約数は???…456
- ユークリッドの互除法
- 自然数x0,x1の最大公約数の求め方(x0 > x1)
- x0をx1で割り、余りをx2とする。
- x1をx2で割り、余りをx3とする。
- 割り切れるまで、この操作を繰り返す。
- xNで割り切れたら、xNが最大公約数である。
//aとbに対してユークリッド互除法を行う int a = 10; int b = 6; int c; //商のための変数 int d = b; //余りのための変数 int itr = 0; //繰り返しの回数 //繰り返し処理 while (d > 0){ //余りが0以上のとき以下の処理を実行 itr++; //繰り返し回数を1増やす c = a / b; //cに商を代入 d = a % b ; //dに余りを代入 println(itr, ":", a, "/", b, "=", c, "...", d); //計算結果を表示 a = b; //aにbを代入 b = d; //bに余りを代入 } println("GCD is", a); //最大公約数を表示
長方形の分割
- ユークリッドの互除法を可視化してみる。
- 自然数x0,x1を2辺とする長方形を正方形で分割する。
- 最も小さい正方形の1辺が最大公約数
- 復習:点、線、図形の描画
- DivRect
//横縦比がnumA:numBの長方形を正方形によって分割 int numA = 10; int numB = 6; int scalar = 50; //長方形の拡大倍率 numA *= scalar; //数値の大きさを拡大 numB *= scalar; //プログラム実行中に動く変数 int wd = numB; //分割に使う正方形の幅の大きさ(初期値numB) int xPos = 0; //正方形のx位置(初期値0) int yPos = 0; //正方形のy位置(初期値0) int itr = 0; //分割の繰り返し回数(初期値0) //描画 size(500, 500); //描画ウィンドウサイズ //繰り返し処理 while (wd > 0){ //幅が0になるまで以下を実行 itr++; //繰り返し回数を1増やす if (itr % 2 == 1){ //繰り返し回数が奇数のとき,x軸方向へ正方形を増やす while (xPos + wd <= numA){ //幅を足したとき,長方形を超えなければ以下を実行 rect(xPos, yPos, wd, wd); //(xPos,yPos)を左上の頂点とする1辺wdの正方形を描画 xPos += wd; //x位置を更新 } wd = numA - xPos; //幅を更新 } else { //繰り返し回数が偶数のとき,y軸方向へ正方形を加える while (yPos + wd <= numB){ //幅を足したとき,長方形を超えなければ以下を実行 rect(xPos, yPos, wd, wd); //(xPos,yPos)を左上の頂点とする1辺wdの正方形を描画 yPos += wd; //y位置を更新 } wd = numB - yPos; //幅を更新 } }
- 正方形に色を付けてみる
int numA = 10; int numB = 6; int scalar = 50; numA *= scalar; numB *= scalar; int wd = numB; int xPos = 0; int yPos = 0; int itr = 0; //描画 size(500, 500); color col; //色のための変数 colorMode(HSB, 1); //01区間をパラメータとするHSB色形式を使用 //ループ while (wd > 0) { itr++; if (itr % 2 ==1) { while (xPos + wd <= numA) { col = color(random(1), 1, 1); //色相のみを01区間でランダムに変える fill(col); rect(xPos, yPos, wd, wd); xPos += wd; } wd = numA - xPos; } else { while (yPos + wd <= numB) { col = color(random(1), 1, 1); fill(col); rect(xPos, yPos, wd, wd); yPos += wd; } wd = numB - yPos; } }
正方形の分割
自然数x0とx1の縦横比x0:x1を使って、長方形を正方形に変形すると、正方形を長方形に分割することになる。
- x0×x1の横長の長方形を x1/x0 に横方向に圧縮して正方形にする。
- DivSquare
//縦横比がnumA:numBの長方形によって正方形の描画ウィンドウを分割 int numA = 10; int numB = 6; float ratio = (float) numB / numA; //比率 float xPos = 0; float yPos = 0; int itr = 0; //描画 size(500, 500); colorMode(HSB, 1); float wd = width; //描画ウィンドウの横幅サイズを初期値とする //繰り返し処理 while (wd > 0.1){ //幅が許容誤差より大きければ以下を実行 itr++; if (itr % 2 == 1){ //縦幅がwdの長方形をx軸方向へ加える while (xPos + wd * ratio < width + 0.1){ //幅を足したとき,横幅がウィンドウを超えなければ以下の処理を実行 fill(color(random(1), 1, 1)); rect(xPos, yPos, wd * ratio, wd); //縦幅wd,縦横比がnumA:numBの長方形を描画 xPos += wd * ratio; //x位置を更新 } wd = width - xPos; } else { //横幅がwdの長方形をy軸方向へ加える while (yPos + wd / ratio < width + 0.1){ //幅を足したとき,縦幅がウィンドウを超えなければ以下の処理を実行 fill(color(random(1), 1, 1)); //ランダムに色を指定 rect(xPos, yPos, wd, wd / ratio); //横幅wd,縦横比がnumA:numBの長方形を描画 yPos += wd / ratio; //y位置を更新 } wd = width - yPos; } }
矩形の再帰的分割
長方形を正方形に分割し、その正方形を長方形に分割する。
//縦横比がnumB:numAの長方形を逆の比の長方形によって分割 int numA = 10; int numB = 6; float ratio = (float) numB / numA; void setup(){ //最初に1度だけ実行する関数 size(500, 500); colorMode(HSB, 1); //この関数内だけのローカル変数 int itr = 0; float xPos = 0; float yPos = 0; float wd = width * ratio; while (wd > 0.1){ itr++; if (itr % 2 == 1){ while (xPos + wd < width + 0.1){ divSquare(xPos, yPos, wd); //正方形を分割する関数の呼び出し xPos += wd; } wd = width - xPos; } else { while (yPos + wd < width * ratio + 0.1){ divSquare(xPos, yPos, wd); //正方形を分割する関数の呼び出し yPos += wd; } wd = width * ratio - yPos; } } }
正方形を長方形に分割する関数
//位置(xPos,yPos)にある1辺がwdの正方形を縦横比がnumA:numBの長方形で分割する void divSquare(float xPos, float yPos, float wd){ //この関数内だけのローカル変数 int itr = 0; float xEndPos = wd + xPos; //正方形の右下の頂点のx座標 float yEndPos = wd + yPos; //正方形の右下の頂点のy座標 //繰り返し処理 while (wd > 0.1){ itr++; if (itr % 2 == 1){ while (xPos + wd * ratio < xEndPos + 0.1){ //ratioはグローバル変数 fill(color(random(1), 1, 1)); rect(xPos, yPos, wd * ratio, wd); xPos += wd * ratio; } wd = xEndPos - xPos; } else { while (yPos + wd / ratio < yEndPos + 0.1){ fill(color(random(1), 1, 1)); rect(xPos, yPos, wd, wd / ratio); yPos += wd / ratio; } wd = yEndPos - yPos; } } }
再帰的呼び出しの使用
- 正方形を長方形に分割し、その長方形を正方形に分割し、その正方形を長方形に分割し、・・・
- 再帰的に関数を呼び出す。再帰的呼び出し(Recursive Call)
- 再帰呼び出しを止めるしきい値(Threshold)を設定する。
int numA = 10; int numB = 6; float ratio = (float) numB / numA; float thr = 160; //しきい値 void setup(){ size(500, 500); colorMode(HSB, 1); divSquare(0, 0, width); //正方形の分割 }
divSquare
//位置(xPos,yPos)にある1辺がwdの正方形を縦横比がnumA:numBの長方形で分割する void divSquare(float xPos, float yPos, float wd){ int itr = 0; float xEndPos = wd + xPos; float yEndPos = wd + yPos; fill(color(random(1), 1, 1)); rect(xPos, yPos, wd, wd); while (wd > thr){ //wdがしきい値以上の場合に処理を行う itr++; if (itr % 2 == 1){ while (xPos + wd * ratio < xEndPos + 0.1){ divRect(xPos, yPos, wd * ratio); //長方形を分割する関数の呼び出し xPos += wd * ratio; } wd = xEndPos - xPos; } else { while (yPos + wd / ratio < yEndPos + 0.1){ divRect(xPos, yPos, wd); //長方形を分割する関数の呼び出し yPos += wd / ratio; } wd = yEndPos - yPos; } } }
divRect
//位置(xPos,yPos)にある横幅wdで縦横比がnumA:numBの長方形を正方形によって分割する void divRect(float xPos, float yPos, float wd){ int itr = 0; float xEndPos = xPos + wd; float yEndPos = yPos + wd / ratio; fill(color(random(1), 1, 1)); rect(xPos, yPos, wd, wd / ratio); while (wd > thr){ //長方形の幅がしきい値以上の場合に処理を行う itr++; if (itr % 2 == 0){ while (xPos + wd < xEndPos + 0.1){ divSquare(xPos, yPos, wd); //正方形を分割する関数の呼び出し xPos += wd; } wd = xEndPos - xPos; } else { while (yPos + wd < yEndPos + 0.1){ divSquare(xPos, yPos, wd); //正方形を分割する関数の呼び出し yPos += wd; } wd = yEndPos - yPos; } } }
マウスクリックでx0,x1,thresholdをランダムに設定して描画する。
void mouseClicked(){ numA = int(random(1, 20)); //1以上20以下のランダムな整数を代入 numB = int(random(1, 20)); while (numA == numB){ //numAとnumBが異なるようにする numB = int(random(1, 20)); } thr = int(random(10,300)); println("numA =", numA, "numB =", numB,"thr =", thr); //numA,numB,thrの値を表示 ratio = (float) numA / numB; background(0, 0, 1); //背景を白で消去 divSquare(0, 0, width); } void draw(){} //プログラムを実行している間,繰り返し実行する関数
無理数比の矩形分割
- モンドリアンの再現
//float ratio = sqrt(2); //白銀比 float ratio = (sqrt(5) + 1) / 2; //黄金比 //float ratio = (3 + sqrt(13) ) / 2; //青銅比 float thr = 40; //分割する大きさに関するしきい値 float thr2 = 0.5; //確率を決定するしきい値 void setup(){ size(500, 500); colorMode(HSB, 1); colorRect(0, 0, width, width); divSquare(0, 0, width); }
モンドリアン風に配色を決める
void colorRect(float xPos, float yPos, float wd, float ht){ color col; float val = random(1); if (val < 0.15){ //15%の確率 col = color(0, 1, 1); //赤 }else if (val < 0.3){ //15%の確率 col = color(2.0 / 3, 1, 1); //青 }else if (val < 0.45){ //15%の確率 col = color(1.0 / 6, 1, 1); //黄 }else if (val < 0.5){ //5%の確率 col = color(0, 1, 0); //黒 } else if (val < 0.7){ //20%の確率 col = color(0, 0, 0.9); //灰 } else { //30%の確率 col = color(0, 0, 1); //白 } fill(col); strokeWeight(5); //長方形の枠線の太さ rect(xPos, yPos, wd, ht); }
矩形分割
void divRect(float xPos, float yPos, float wd){ //長方形を分割する関数 int itr = 0; float xEndPos = xPos + wd; //長方形の横の長さ float yEndPos = yPos + wd / ratio; //長方形の縦の長さ while (wd > thr){ //wdがしきい値以上の場合に処理を行う itr++; if (itr % 2 == 0){ while (xPos + wd < xEndPos + 0.1){ colorRect(xPos, yPos, wd, wd); //正方形を描く if (random(1) < thr2){ divSquare(xPos, yPos, wd); //正方形を分割する関数の呼び出し } xPos += wd; } wd = xEndPos - xPos; } else { while (yPos + wd < yEndPos + 0.1){ colorRect(xPos, yPos, wd, wd); //正方形を描く if (random(1) < thr2){ divSquare(xPos, yPos, wd); //正方形を分割する関数の呼び出し } yPos += wd; } wd = yEndPos - yPos; } } } void divSquare(float xPos, float yPos, float wd){ //正方形を分割する関数 int itr = 0; float xEndPos = wd + xPos; //正方形の横の長さ float yEndPos = wd + yPos; //正方形の縦の長さ while (wd > thr){ //正方形の幅がしきい値以上の場合に実行 itr++; if (itr % 2 ==1){ while (xPos + wd * ratio < xEndPos + 0.1){ colorRect(xPos, yPos, wd * ratio, wd); //長方形を描く if (random(1) < thr2){ //thr2の確率で再分割 divRect(xPos, yPos, wd * ratio); //長方形を分割する関数の呼び出し } xPos += wd * ratio; } wd = xEndPos - xPos; } else { while (yPos + wd / ratio < yEndPos + 0.1){ colorRect(xPos, yPos, wd, wd / ratio); //長方形を描く if (random(1) < thr2){ //thr2の確率で再分割 divRect(xPos, yPos, wd); //長方形を分割する関数の呼び出し } yPos += wd / ratio; } wd = yEndPos - yPos; } } }
マウスクリックでランダムに再構成
void mouseClicked(){ thr = int(random(10, 50)); thr2 = random(0,1); println("thr =", thr, "thr2 =", thr2); colorRect(0, 0, width, width); divSquare(0, 0, width); } void draw(){}