矩形分割
提供:kuhalaboWiki
(版間での差分)
(→長方形の分割) |
(→リンク) |
||
| 439行: | 439行: | ||
== リンク == | == リンク == | ||
| + | [https://youtu.be/F69mzVTf_KU AI Composition, Y.Kuhara, The Faculty of Arts Festival 2022] | ||
[[フィボナッチ数列]] | [[フィボナッチ数列]] | ||
2022年11月2日 (水) 04:36時点における最新版
- 現代アート作家 モンドリアンの代表作品、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(){}