質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Processing

Processingは、オープンソースプロジェクトによるCGのためのプログラミング言語です。Javaをベースにしており、グラフィック機能に特化しています。イメージの生成やアニメーションなど、視覚的なフィードバックを簡単に得ることが可能です。

Q&A

解決済

2回答

2001閲覧

Processingで作成した四角形を回転させるには

21J

総合スコア5

Processing

Processingは、オープンソースプロジェクトによるCGのためのプログラミング言語です。Javaをベースにしており、グラフィック機能に特化しています。イメージの生成やアニメーションなど、視覚的なフィードバックを簡単に得ることが可能です。

0グッド

0クリップ

投稿2021/09/11 08:33

現状
現在processingで3種類の大きさの四角形を合計100個、画像内にランダムに配置できるようにコードを作成しました。

processing

1 2 3ArrayList<PVector> rect; // 正方形のデータ 4 5void setup() { 6 size(512, 512); 7 smooth(); 8 9 frameRate(20); // 1秒当たり描画数 10 11} 12 13void draw() { 14 15 background(255); 16 rect = new ArrayList<PVector>(); // 17 18 //データ 19 20 int a =int(random(0,100)); 21 int b =int(random(0,100-a)); 22 int d = 100-a-b; 23 24 int[] sizes ={ 25 26 27 }; 28for(int i = 0; i < a; i++){ 29 sizes = (int[])append(sizes,int(random(10,20))); 30} 31 32for(int i = 0; i < b; i++){ 33 sizes = (int[])append(sizes,int(random(1,10))); 34} 35 36for(int i = 0; i < d; i++){ 37 sizes = (int[])append(sizes,int(random(20,39))); 38} 39 40 while (rect.size() < sizes.length) { 41 int diameter = sizes[rect.size()]; 42 43 44 PVector c = new PVector(random(20,492), random(20,492), diameter); 45 boolean overlapping = false; 46 47 for (PVector p : rect) { 48 49 if (dist(c.x, c.y, p.x, p.y) < (c.z + p.z)*1.41/ 2) { 50 overlapping = true; 51 break; 52 } 53 } 54 55 if (!overlapping) { 56 rect.add(c); 57 58 } 59 } 60 61 62 // 正方形の描画 63 for ( 64 65 int i = 0; i < rect.size(); i++) { 66 PVector p = rect.get(i); 67 noStroke(); 68 fill(0); 69 rectMode(CENTER); 70 rect(p.x, p.y, p.z, p.z); 71 72 } 73 74 75 // 画像の保存 76 77 78 79 save("C:/gazou/" + frameCount + "s" + b + "m" + a + "l" + d +".png"); 80 81 if (frameCount == 50) { // n枚作ったら止める 82 noLoop(); // 止める 83 84 //launch("start " + sketchPath()); // Windows専用 エクスプローラでフォルダを開く 85 //exit(); // 終了 86 } 87}

問題点
このコードでは正方形の傾きは無いため、ランダムに正方形を回転できるようなコードを書きたいと考えました。
そこで、正方形の描画のところを変更し

for ( int i = 0; i < rect.size(); i++) { PVector p = rect.get(i); noStroke(); fill(0); translate(p.x, p.y); rotate (random(0,89)) ; rectMode(CENTER); rect(p.x, p.y, p.z, p.z); }

としたのですが、正方形が数個しか画像に映らず、うまく描画できませんでした。
translateの値を変更したり、文を追加したりしたのですが改良できませんでした。

// 正方形の描画 for ( int i = 0; i < rect.size(); i++) { PVector p = rect.get(i); noStroke(); fill(0); translate(256, 256); rotate (random(0,89)) ; rectMode(CENTER); rect(p.x, p.y, p.z, p.z); }
// 正方形の描画 for ( int i = 0; i < rect.size(); i++) { PVector p = rect.get(i); noStroke(); fill(0);   pushMatrix () ; translate(p.x, p.y); rotate (random(0,89)) ; rectMode(CENTER); rect(p.x, p.y, p.z, p.z);   popMatrix () ; }

うまく正方形を回転させ、100個すべての正方形を画像内に描画するにはどうしたらいいでしょうか?
アドバイスお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

まず、多くのプログラム言語では(そしてProcessingでも)角度は弧度法で表されます。180度が円周率π(3.1415...)ということになります。90度回したいなら3.1415/2, 45度回したいなら3.1415/4ですが、ProcessingではPI, HALF_PI, QUARTER_PIという定数が定義されていますのでこれを使ったほうがベターかと思います。
もう一つ、random(a1,a2)関数はa1以上a2未満の値を返します。なので、90度未満の回転を得たいのなら、rotate(random(0,HALF_PI));とするのがよいでしょう。

つぎに。translate()やrotate(),scale()関数の効果はdraw()関数を抜けるまでは蓄積され、draw()関数を抜けるとリセットされます。

size(300,300); noFill(); rectMode(CENTER); square(80,220.7,20); line(0,0,100,100); translate(100,100); //(0,0)はもとの座標の(100,100)になる square(0,0,20); rotate(QUARTER_PI); //45度時計方向に座標軸を回す stroke(0,255,0); square(0,0,20); stroke(0); line(0,0,0,100); translate(0,100); //45度回った座標軸で(0,100)原点を移動する。結果、原点は元の座標で(30,170.7)になる square(0,0,20); rotate(-QUARTER_PI); //反時計方向に45度座標軸を回す。結果、座標軸は元の状態に戻る stroke(0,255,0); square(0,0,20); stroke(0); line(0,0,50,50); circle(50,50,20); //描かれた円の中心座標は元の座標系では(80,220.7)

resetMatrix()関数でリセットされ、また'pushMatrix()'で現時点の座標系を保存し、pushMatrix()で保存している座標系を復帰します。(この辺はできたみたいですが)

size(300,300); rectMode(CENTER); noFill(); translate(100,100); circle(0,0,20); pushMatrix();//原点が(100,100)に移動している状態を保存します...(1) translate(100,0); circle(0,0,20); pushMatrix();//原点が(200,100)に移動している状態を保存します...(2) translate(0,100); circle(0,0,20); resetMatrix();//原点が(0,0)にある状態になります square(0,0,20); popMatrix(); //原点が(200,100)に移動している状態に復帰します...(2) square(0,0,20); translate(50,0); circle(0,0,20); pushMatrix(); //原点が(250,100)に移動している状態を保存します...(3) translate(0,50); circle(0,0,20); popMatrix(); //原点が(250,100)に移動している状態に復帰します...(3) square(0,0,20); popMatrix(); //原点が(100,100)に移動している状態に復帰します...(1) square(0,0,20);

なお、pushMatrix()とpopMatrix()は「バランス良く」使わなければいけません。pushMatrix()した回数以上にpopMatrix()してはいけませんし、popMatrix()と対にならないpushMatrix()を多く繰り返すとプログラムが異常動作を起こすかもしれません。まぁ一桁に押さえておくのが普通の使い方かと思います。

さて。translate()やrotate()を用いて図形を描く場合、考え方としては
・単体の図形は0,0を中心に描く
・図形を描く位置をtranslate()で、向きをrotate()で調整する
と考えやすくなるかと思います。というか、そう考えられるようにtranslateやrotate()がある、と言ってもいいんじゃないでしょうか。

もし、元の座標系の(100,100)に四角形を描きたいなら

size(300,300); rectMode(CENTER); translate(100,100); square(0,0,50);

とするわけです。rotate()は0,0を中心に座標系を回しますから、0,0を中心に図形を描けば素直に「回って」くれるわけです。

void setup() { size(300, 300); rectMode(CENTER); } float angle=0.01; void draw() { translate(100, 100); rotate(angle); square(0, 0, 50); angle+=0.05; }

ついでに付け加えるなら、rectMode()とかelipseMode()、fill()やstroke()などの命令は(translate()やrotate()と違って)最後に実行された効果が関数を出ても残りますから、あまり無意味に繰り返さないほうがスッキリすることが多いです(途中で変更されている可能性があるのなら仕方ないですが)。

ということで全部を適用するとこんなことになるでしょうか。

noStroke(); //ループの外にくくりだす。状況によってはsetup()に移動してもよいかも fill(0); rectMode(CENTER); for ( int i = 0; i < rect.size(); i++) { PVector p = rect.get(i); resetMatrix () ; //最初に戻すことを明確にするならresetMatrix()の方がよいのでは translate(p.x, p.y); rotate (random(0,HALF_PI)) ; square(0, 0, p.z); }

投稿2021/09/11 11:39

編集2021/09/11 11:42
thkana

総合スコア7639

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

21J

2021/09/12 05:05

詳細な解説ありがとうございました。なぜダメだったのか理由まで分かり、問題を解決できました。 ありがとうございます
guest

0

まず前回の質問でthkanaさんがわざわざ図入りで説明くださったのですが、結局当たり判定は正方形に外接する円として考えてよいわけですね?(そうでないと回転するとめんどくさいですが^^;
Processing - processingを使用して多くの正方形を描画|teratail

としたのですが、正方形が数個しか画像に映らず、うまく描画できませんでした。
translateの値を変更したり、文を追加したりしたのですが改良できませんでした。

translate(p.x, p.y)したのですから、rect(0, 0, p.z, p.z)としないとずれることになります。
それからtranslaterotateは持続しますから、どんどん移動や回転が重なっていってしまいます。
ループごとにリセットしなくてはいけません。
pushMatrix() - Reference / Processing.org
popMatrix() - Reference / Processing.org


appendなんて便利関数があるんですね。知りませんでした^^;
しかしここまでくると配列にする意味もないですね。リストのほうがすっきりすると思います。
append() - Reference / Processing.org
IntList - Reference / Processing.org

Processing

1void setup() { 2 size(512, 512); 3 smooth(); 4 noStroke(); 5 fill(0); 6 rectMode(CENTER); 7 frameRate(20); 8} 9 10void draw() { 11 background(255); 12 13 int a = int(random(0, 100)); 14 int b = int(random(0, 100 - a)); 15 int d = 100 - a - b; 16 17 IntList sizes = new IntList(); 18 for (int i = 0; i < a; i++) { 19 sizes.append(int(random(10, 20))); 20 } 21 for (int i = 0; i < b; i++) { 22 sizes.append(int(random(1, 10))); 23 } 24 for (int i = 0; i < d; i++) { 25 sizes.append(int(random(20, 39))); 26 } 27 28 ArrayList<PVector> rects = new ArrayList<PVector>(); 29 while (rects.size() < sizes.size()) { 30 int size = sizes.get(rects.size()); 31 PVector c = new PVector(random(20, 492), random(20, 492), size); 32 boolean overlapping = false; 33 34 for (PVector p : rects) { 35 if (dist(c.x, c.y, p.x, p.y) < (c.z + p.z) * 1.41 / 2) { 36 overlapping = true; 37 break; 38 } 39 } 40 41 if (!overlapping) { 42 rects.add(c); 43 } 44 } 45 46 for (PVector p : rects) { 47 pushMatrix(); 48 49 translate(p.x, p.y); 50 rotate(random(0, 89)); 51 rect(0, 0, p.z, p.z); 52 53 popMatrix(); 54 } 55 56 save("C:/gazou/" + frameCount + "s" + b + "m" + a + "l" + d +".png"); 57 58 if (frameCount == 50) { 59 noLoop(); 60 } 61}

投稿2021/09/11 09:53

編集2021/09/11 10:03
TN8001

総合スコア9326

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

21J

2021/09/12 05:08

回答ありがとうございました。 回転することによる重なり判定についても更に自分で考えてみようと思います。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問