🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Processing

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

Q&A

解決済

2回答

2280閲覧

processingを使って円を描写する方法

21J

総合スコア5

Processing

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

1グッド

1クリップ

投稿2021/01/16 11:02

リンク内容
実現したいこと
processingを使用してランダムに複数個の円を描画したいです
条件としては
・円が重ならない
・指定した複数サイズの大きさの円を描画する
・円の場所が異なる多数の画像を同時に作成する
・作成した画像を保存する
です
この画像のようにしたいです
(この画像だと3種類の大きさの円がランダムに描画されているのですがどうしても重なってしまいます。)
イメージ

ソースコード
リンクのサイトを少し変えてみて下記のようにしました。

ArrayList <PVector> circles; void setup() { background(0,0,100); size(600, 600); //色相・彩度・明度で指定 colorMode(RGB, 256, 256, 256); smooth(); noLoop(); } void draw() { background(255,255,255); circles = new ArrayList <PVector>(); addCircle(); for (int i=0; i<circles.size(); i++) { PVector p = circles.get(i); noStroke(); fill( 0,0,0); ellipse(p.x, p.y, p.z, p.z); } } void addCircle() { //10は個数 while (circles.size() <30) { //大きさが10から100の間 float diameter =10; PVector c = new PVector(random(width), random(height), diameter); boolean overlapping = false; for (PVector p : circles) { /* distは2点間の距離を出す dist(x1, y1, x2, y2) この場合は、cとpの2点間の距離 > cの半径+pの半径の場合に描画される cとpの2点間の距離 < cの半径+pの半径の場合は重なってしまう */ if (dist(c.x, c.y, p.x, p.y) < (c.z + p.z)) { overlapping = true; break; } } if (!overlapping) { //配列の要素を追加 circles.add(c); save("E:/processing/a.png"); } } }

問題点
しかし、
・複数の大きさの円を描画できない(サイトではランダムに大きさを変更できているのですが大きさを2つ以上指定する方法がわかりません)
・サイトではクリックすると円の位置を変更できるがクリックせずに複数画像を同時に作りたい
・実行するとprocessing上では円の描画された画像が出てくるがエクスプローラーからフォルダ内を見てみると白いだけで円が描画されていない画像が保存されている。

どのように改善すれば良いかアドバイスお願いします。

TN8001👍を押しています

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

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

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

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

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

thkana

2021/01/16 11:27

「複数画像を同時に作りたい」はなぜ「同時」なのですか? 順次複数の画像を作成するのではいけないのですか?
21J

2021/01/17 06:35

すいません 同時というのは1つのコードを実行するだけで複数枚の画像を作りたいという意味です。
guest

回答2

0

ベストアンサー

複数の大きさの円を描画できない(サイトではランダムに大きさを変更できているのですが大きさを2つ以上指定する方法がわかりません)

どういう指定法をイメージしているのかがわかりませんが、複数個のサイズからランダムにチョイスならばこんな感じになるでしょう。

Processing

1int[] sizes = { 10, 20, 50 }; 2int index = int(random(sizes.length)); 3int diameter = sizes[index];

サイトではクリックすると円の位置を変更できるがクリックせずに複数画像を同時に作りたい

ほぼ同時?にすることもできますが、noLoop()をやめてフレームごとに描画・保存するのはどうでしょう?
frameRateを上げれば、数秒で大量に画像ができます^^;

実行するとprocessing上では円の描画された画像が出てくるがエクスプローラーからフォルダ内を見てみると白いだけで円が描画されていない画像が保存されている。

save()は現在の描画を保存します。
この時点ではまだ描画されていないため(ellipse()があるforが描画処理)、真っ白の画像になります。
つまり描画が終わってから、save()するようにします。


Processing

1ArrayList<PVector> circles; 2 3void setup() { 4 size(600, 600); 5 smooth(); 6 7 frameRate(1); // 1秒に1回に再描画(数字を増やすと早くなる) 8} 9 10void draw() { 11 background(255); 12 circles = new ArrayList<PVector>(); // 毎回circlesを作り直す 13 14 // 円のデータを準備 15 addCircle(); 16 17 // 円を全部描画 18 for (PVector p : circles) { 19 noStroke(); 20 fill(0); 21 ellipse(p.x, p.y, p.z, p.z); 22 } 23 24 // 画像の保存 a1.png a2.png ... 25 save("a" + frameCount + ".png"); 26} 27 28void addCircle() { 29 int[] sizes = { 10, 20, 50 }; // 複数のサイズ候補(円の個数やサイズが大きいと、時間がかかったり無限ループしたりするので注意) 30 while (circles.size() < 30) { 31 int index = int(random(sizes.length)); // sizesのうち、どれを使うかランダムに決定 32 int diameter = sizes[index]; // サイズを取得 33 34 // 3次元のベクトルのうちxyを2次元座標、zを円の直径として利用している 35 PVector c = new PVector(random(width), random(height), diameter); 36 boolean overlapping = false; 37 38 for (PVector p : circles) { 39 // zは直径なので理屈的には割る2 くっついて見えるのがまずい場合は、少し足すなりなんなり 40 if (dist(c.x, c.y, p.x, p.y) < (c.z + p.z) / 2) { 41 overlapping = true; 42 break; 43 } 44 } 45 46 if (!overlapping) { 47 circles.add(c); 48 } 49 } 50}

追記

Processing

1// 必要サイズ候補を羅列(大きい順のほうが少し安全? 時間がかかったり無限ループになりにくい) 2int[] sizes = { 3 30, 30, 30, 30, 30, 4 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 5 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 6}; 7ArrayList<PVector> circles; // 円のデータ 8 9void setup() { 10 size(600, 600); 11 smooth(); 12 13 frameRate(10); // 1秒に10回再描画(数字を増やすと早くなる) 14} 15 16void draw() { 17 background(255); 18 circles = new ArrayList<PVector>(); // 毎回circlesを作り直す 19 20 // 円のデータを準備 21 addCircle(); 22 23 // 円を全部描画 24 for (PVector p : circles) { 25 noStroke(); 26 fill(0); 27 ellipse(p.x, p.y, p.z, p.z); 28 } 29 30 // 画像の保存 a1.png a2.png ... 31 save("a" + frameCount + ".png"); 32 33 if (frameCount == 100) { // 100枚作ったら止める 34 noLoop(); // 止める 35 36 //launch("start " + sketchPath()); // Windows専用 エクスプローラでフォルダを開く 37 //exit(); // 終了 38 } 39} 40 41void addCircle() { 42 while (circles.size() < sizes.length) { // 円のデータの個数が、必要サイズ候補数より少ない間ループ 43 // サイズを取得(配列は0始まりなので、circles.size()が0の時は0番目、circles.size()が1の時は1番目... 44 int diameter = sizes[circles.size()]; 45 46 // 3次元のベクトルのうちxyを2次元座標、zを円の直径として利用している 47 PVector c = new PVector(random(width), random(height), diameter); 48 boolean overlapping = false; 49 50 for (PVector p : circles) { 51 // zは直径なので理屈的には割る2 くっついて見えるのがまずい場合は、少し足すなりなんなり 52 if (dist(c.x, c.y, p.x, p.y) < (c.z + p.z) / 2) { 53 overlapping = true; 54 break; 55 } 56 } 57 58 if (!overlapping) { 59 circles.add(c); 60 } 61 } 62}

投稿2021/01/16 12:21

編集2021/01/17 09:10
TN8001

総合スコア9855

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

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

21J

2021/01/17 05:50

回答ありがとうございます 円のサイズについて私の説明不足で申し訳ございません。 例えば、サイズ10 20 30の3種類の大きさの円をそれぞれ10個 10個 5個の様に個数を指定して場所だけランダムにしたいです。 flameRateについて質問させてください。 もし100枚の画像が欲しいときはflameRate(10)にして10秒後に止めるときは手動で止めるしか出来ないですか?もし自動で止まる方法があれば教えていただきたいです。
TN8001

2021/01/17 08:22

> 例えば、サイズ10 20 30の3種類の大きさの円をそれぞれ10個 10個 5個の様に個数を指定して場所だけランダムにしたいです。 なるほど。やり方はいろいろあると思います。 単純に候補を羅列して、順番に取得するのがわかりやすいかと思います。 > もし100枚の画像が欲しいときはflameRate(10)にして10秒後に止めるときは手動で止めるしか出来ないですか?もし自動で止まる方法があれば教えていただきたいです。 上限に達したら止めるコードを書けばいいのです。それがプログラミングです^^ 上記改良を回答に追記しました。
21J

2021/01/17 09:15

ありがとうございます。 自分の思っていた通り画像が作れるコードになりました。 大変助かりました。
guest

0

結論

こんな感じでいいのでしょうか?

Processing

1ArrayList <PVector> circles; 2 3void setup() { 4 background(0,0,100); 5 size(600, 600); 6 7 //色相・彩度・明度で指定 8 colorMode(RGB, 256, 256, 256); 9 smooth(); 10 noLoop(); 11} 12 13void draw() { 14 for ( int n = 1; n <= 10; ++n ) { 15 background(255,255,255); 16 circles = new ArrayList <PVector>(); 17 18 addCircle(); 19 20 for (int i=0; i<circles.size(); i++) { 21 PVector p = circles.get(i); 22 noStroke(); 23 fill( 0,0,0); 24 ellipse(p.x, p.y, p.z, p.z); 25 } 26 27 // ファイルの保存はすべての描画が終わってから 28 save(String.format(""E:/processing/a%03d.png",n)); 29 } 30} 31 32 33void addCircle() { 34 //10は個数 35 while (circles.size() <30) { 36 //大きさが10から100の間 37 float diameter =random(10,100); 38 PVector c = new PVector(random(width), random(height), diameter); 39 boolean overlapping = false; 40 41 for (PVector p : circles) { 42 43 /* 44 distは2点間の距離を出す dist(x1, y1, x2, y2) 45 この場合は、cとpの2点間の距離 > cの半径+pの半径の場合に描画される 46 cとpの2点間の距離 < cの半径+pの半径の場合は重なってしまう 47 */ 48 49 if (dist(c.x, c.y, p.x, p.y) < (c.z + p.z)) { 50 overlapping = true; 51 break; 52 } 53 } 54 55 if (!overlapping) { 56 //配列の要素を追加 57 circles.add(c); 58 } 59 } 60 61}

説明

・複数の大きさの円を描画できない(サイトではランダムに大きさを変更できているのですが大きさを2つ以上指定する方法がわかりません)

座標の生成につかわれている random メソッドで、サイズも生成させればいいのではないでしょうか?

Processing

1//大きさが10から100の間 2float diameter = random(10,100); 3PVector c = new PVector(random(width), random(height), diameter);

・実行するとprocessing上では円の描画された画像が出てくるがエクスプローラーからフォルダ内を見てみると白いだけで円が描画されていない画像が保存されている。

ご質問のコードでは、円を描画する前にファイルの書き出しを行っています。
save を draw メソッドの最後に移して、全ての描画が終わった後で、ファイルを書きだすようにすれば、ファイルの内容と画面の表示が一致するはずです。

・サイトではクリックすると円の位置を変更できるがクリックせずに複数画像を同時に作りたい

draw の描画処理全体を以下のようにループで囲ってファイル名を変えてセーブすればできると思います。

Processing

1void draw() { 2 for ( int n = 1; n < 10; ++n ) { 3~中略~ 4 // 最後に画像を保存 5 save(String.format(""E:/processing/a%03d.png",n)); 6 } 7}

コメントで追加いただいた仕様について

例えば、サイズ10 20 30の3種類の大きさの円をそれぞれ10個 10個 5個の様に個数を指定して場所だけランダムにしたいです。

こんな感じでしょうか。

Processing

1ArrayList <PVector> circles; 2 3public class CircleDefine { 4 public int size; 5 public int count; 6 7 public CircleDefine( int size, int count ) { 8 this.size = size; 9 this.count = count; 10 } 11} 12ArrayList<CircleDefine> circle_defines = new ArrayList<CircleDefine>(); 13 14void setup() { 15 background(0,0,100); 16 size(600, 600); 17 18 //色相・彩度・明度で指定 19 colorMode(RGB, 256, 256, 256); 20 21 // 円のサイズと数を指定 22 circle_defines.add(new CircleDefine(30,5)); 23 circle_defines.add(new CircleDefine(10,10)); 24 circle_defines.add(new CircleDefine(20,10)); 25 26 smooth(); 27 noLoop(); 28} 29 30void draw() { 31 for ( int n = 1; n <= 10; ++n ) { 32 background(255,255,255); 33 circles = new ArrayList <PVector>(); 34 35 addCircle(); 36 37 for (int i=0; i<circles.size(); i++) { 38 PVector p = circles.get(i); 39 noStroke(); 40 fill( 0,0,0); 41 ellipse(p.x, p.y, p.z, p.z); 42 } 43 44 // ファイルの保存はすべての描画が終わってから 45// save(String.format("E:/processing/a%03d.png",n)); 46 save(String.format("C:/tmp/a%03d.png",n)); 47 } 48} 49 50 51void addCircle() { 52 53 for ( CircleDefine circle_define : circle_defines ) { 54 int next_count = circles.size() + circle_define.count; 55 while (circles.size() < next_count ) { 56 57 PVector c = new PVector(random(width), random(height), circle_define.size); 58 boolean overlapping = false; 59 60 for (PVector p : circles) { 61 62 /* 63 distは2点間の距離を出す dist(x1, y1, x2, y2) 64 この場合は、cとpの2点間の距離 > cの半径+pの半径の場合に描画される 65 cとpの2点間の距離 < cの半径+pの半径の場合は重なってしまう 66 */ 67 68 if (dist(c.x, c.y, p.x, p.y) < (c.z + p.z)) { 69 overlapping = true; 70 break; 71 } 72 } 73 74 if (!overlapping) { 75 //配列の要素を追加 76 circles.add(c); 77 } 78 } 79 } 80 81}

基本的な考え方としては、作りたい円の定義をあらかじめ変数に入れて用意しておき、
描画時にそれを順に取り出して描画していきます。
以下の例ではクラスを新たに作っていますが、以下のように配列を二つ作ってしまったほうが早いかもしれません。

processing

1int[] size = { 10, 20, 30 }; 2int[] count = { 10, 10, 5 };

投稿2021/01/16 12:18

編集2021/01/17 08:34
kozuchi

総合スコア1193

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

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

21J

2021/01/17 05:51

回答ありがとうございます 円のサイズについて私の説明不足で申し訳ございません。 例えば、サイズ10 20 30の3種類の大きさの円をそれぞれ10個 10個 5個の様に個数を指定して場所だけランダムにしたいです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問