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

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

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

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Swing

SwingはJavaに標準で付属するグラフィック関連のクラスライブラリを指します。

Q&A

解決済

1回答

2003閲覧

こちらのプログラムを3次元平面上で動かしたいのですが分かりません

kouya_tdu

総合スコア13

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Swing

SwingはJavaに標準で付属するグラフィック関連のクラスライブラリを指します。

0グッド

0クリップ

投稿2019/01/03 06:48

編集2019/01/03 13:27

前提・実現したいこと

Java(swing)で粒子法による剛体のシミュレーションをやりたいです。
3つの粒子で表現したL字型の剛体に力を加えた時の簡単な運動はできました。
2次元平面上では出来たのですがこれを3次元平面上に変換するやり方が分かりません。
どのようにコードを書けば良いか躓いています、ご教授お願いします。

該当のソースコード

Java

1import java.awt.geom.Point2D; 2import java.util.Arrays; 3import javax.swing.JFrame; 4 5class Main { 6 public static void main(String args[]) { 7 JFrame frame = new JFrame(); 8 frame.setSize(500, 500); 9 frame.getContentPane().add(new MyJPanel()); 10 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 11 frame.setVisible(true); 12 } 13 14} 15 16class MyJPanel extends javax.swing.JPanel { 17 18 /** 粒子の座標 */ 19 final private Point2D.Double[] m; 20 /** 重心の座標 */ 21 final private Point2D.Double g; 22 /** 角速度 */ 23 final double omega; 24 /** 並進速度 */ 25 Point2D.Double v; 26 27 28 /** 29 * コンストラクタ 30 * <p>各粒子位置、重心、速度の初期化。および座標更新タイマの設定</p> 31 */ 32 public MyJPanel() { 33 34 // 粒子の座標を決める 35 m = new Point2D.Double[] { 36 new Point2D.Double(50, 50), // m1 37 new Point2D.Double(50, 70), // m2 38 new Point2D.Double(70, 70), // m3 39 }; 40 41 // 重心を計算(粒子の重さが全て等しい場合、座標平均が重心となる) 42 g = new Point2D.Double( 43 Arrays.stream(m).mapToDouble(p -> p.x).average().getAsDouble(), 44 Arrays.stream(m).mapToDouble(p -> p.y).average().getAsDouble()); 45 46 double m1x = 50, m1y = 50, m2x = 50, m2y = 70, m3x = 70, m3y = 70; 47 double derutat = 0.01; 48 double mg =1; 49 50 double [][] a = new double[3][3]; 51 a[0][0] = mg * (m1y - g.y) * (m1y - g.y) + mg * (m2y - g.y) * (m2y - g.y) + mg * (m3y - g.y) * (m3y - g.y); 52 a[0][1] = -1 * mg * (m1x - g.x) * (m1y - g.y) - mg * (m2x - g.x) * (m2y - g.y) - mg * (m3x - g.x) * (m3y - g.y); 53 a[0][2] = 0; 54 a[1][0] = -1 * mg * (m1x - g.x) * (m1y - g.y) - mg * (m2x - g.x) * (m2y - g.y) - mg * (m3x - g.x) * (m3y - g.y); 55 a[1][1] = mg * (m1x - g.x) * (m1x - g.x) + mg * (m2x - g.x) * (m2x - g.x) + mg * (m3x - g.x) * (m3x - g.x); 56 a[1][2] = 0; 57 a[2][0] = 0; 58 a[2][1] = 0; 59 a[2][2] = mg * (m1x - g.x) * (m1x - g.x) + (m1y - g.y) * (m1y - g.y) + mg * (m2x - g.x) * (m2x - g.x) + (m2y - g.y) * (m2y - g.y) + mg * (m3x - g.x) * (m3x - g.x) + (m3y - g.y) * (m3y - g.y); 60 61 double [][] b = new double[3][3]; 62 b[0][0] = a[1][1] * a[2][2] / (a[0][0] * a[1][1] * a[2][2] - a[0][1] * a[1][0] * a[2][2]); 63 b[0][1] = -1 * a[0][1] * a[2][2] / (a[0][0] * a[1][1] * a[2][2] - a[0][1] * a[1][0] * a[2][2]); 64 b[0][2] = 0; 65 b[1][0] = -1 * a[1][0] * a[2][2] / (a[0][0] * a[1][1] * a[2][2] - a[0][1] * a[1][0] * a[2][2]); 66 b[1][1] = (a[0][0] * a[2][2] - a[0][2] * a[2][0]) / (a[0][0] * a[1][1] * a[2][2] - a[0][1] * a[1][0] * a[2][2]); 67 b[1][2] = 0; 68 b[2][0] = 0; 69 b[2][1] = 0; 70 b[2][2] = (a[0][0] * a[1][1] - a[0][1] * a[1][0]) / (a[0][0] * a[1][1] * a[2][2] - a[0][1] * a[1][0] * a[2][2]); 71 72 double [] r = new double[3]; 73 r[0] = m1x - g.x; 74 r[1] = m1y - g.y; 75 r[2] = 0; 76 77 double [] f = new double[3]; 78 f[0] = 500; 79 f[1] = 200; 80 f[2] = 0; 81 82 double [] gaiseki = new double[3]; 83 gaiseki[0] = (r[1] * f[2] - r[2] * f[1]) * derutat; 84 gaiseki[1] = (r[2] * f[0] - r[0] * f[2]) * derutat; 85 gaiseki[2] = (r[0] * f[1] - r[1] * f[0]) * derutat; 86 87 double [] kakusokudo = new double[3]; 88 kakusokudo[0] = b[0][0] * gaiseki[0] + b[0][1] * gaiseki[1] + b[0][2] * gaiseki[2]; 89 kakusokudo[1] = b[1][0] * gaiseki[0] + b[1][1] * gaiseki[1] + b[1][2] * gaiseki[2]; 90 kakusokudo[2] = b[2][0] * gaiseki[0] + b[2][1] * gaiseki[1] + b[2][2] * gaiseki[2]; 91 92 93 94 // 角速度 95 omega = kakusokudo[2]; 96 97 // 並進速度 98 v = new Point2D.Double(f[0] * derutat / (3 * mg), f[1] * derutat / (3 * mg)); 99 100 // 30ミリ秒おきに位置座標を更新して、描画更新要求 101 new javax.swing.Timer(30, e -> { 102 103 // 並進運動による位置更新 104 g.x += v.x; 105 g.y += v.y; 106 107 // 各粒子の位置更新 108 for (Point2D.Double p : m) { 109 double x = p.x + v.x, y = p.y + v.y; 110 p.x = (x - g.x) * Math.cos(omega) - (y - g.y) * Math.sin(omega) + g.x; 111 p.y = (x - g.x) * Math.sin(omega) + (y - g.y) * Math.cos(omega) + g.y; 112 } 113 114 // 描画更新要求 115 repaint(); 116 }).start(); 117 } 118 119 public void paintComponent(java.awt.Graphics g) { 120 super.paintComponent(g); 121 // 粒子の描画 122 for(Point2D.Double p : m) { 123 // とりえあえず、直径を20にしてる 124 g.drawOval((int)p.x, (int)p.y, 20, 20); 125 } 126 127 } 128}

試したこと

2Dの箇所を3Dに変えてZ軸に数値を入れたのですがうまく動きませんでした。
class Point3Dを作り追加しました。

Java

1import java.awt.geom.Point2D; 2import java.util.Arrays; 3import javax.swing.JFrame; 4 5class Main { 6 public static void main(String args[]) { 7 JFrame frame = new JFrame(); 8 frame.setSize(500, 500); 9 frame.getContentPane().add(new MyJPanel()); 10 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 11 frame.setVisible(true); 12 } 13 14} 15 16class Point3D { 17 public double x, y, z; 18 19 Point3D(double x, double y, double z) { 20 this.x = x; this.y = y; this.z = z; 21 } 22} 23 24 25class MyJPanel extends javax.swing.JPanel { 26 27 /** 粒子の座標 */ 28 final private Point3D[] m; 29 /** 重心の座標 */ 30 final private Point3D g; 31 /** 角速度 */ 32 final double omega; 33 /** 並進速度 */ 34 Point3D v; 35 36 37 /** 38 * コンストラクタ 39 * <p>各粒子位置、重心、速度の初期化。および座標更新タイマの設定</p> 40 */ 41 public MyJPanel() { 42 43 // 粒子の座標を決める 44 m = new Point3D[] { 45 new Point3D(50, 50, 0), // m1 46 new Point3D(50, 70, 0), // m2 47 new Point3D(70, 70, 0), // m3 48 }; 49 50 // 重心を計算(粒子の重さが全て等しい場合、座標平均が重心となる) 51 g = new Point3D( 52 Arrays.stream(m).mapToDouble(p -> p.x).average().getAsDouble(), 53 Arrays.stream(m).mapToDouble(p -> p.y).average().getAsDouble(), 54 Arrays.stream(m).mapToDouble(p -> p.z).average().getAsDouble()); 55 56 double m1x = 50, m1y = 50, m2x = 50, m2y = 70, m3x = 70, m3y = 70; 57 double derutat = 0.01; 58 double mg =1; 59 60 double [][] a = new double[3][3]; 61 a[0][0] = mg * (m1y - g.y) * (m1y - g.y) + mg * (m2y - g.y) * (m2y - g.y) + mg * (m3y - g.y) * (m3y - g.y); 62 a[0][1] = -1 * mg * (m1x - g.x) * (m1y - g.y) - mg * (m2x - g.x) * (m2y - g.y) - mg * (m3x - g.x) * (m3y - g.y); 63 a[0][2] = 0; 64 a[1][0] = -1 * mg * (m1x - g.x) * (m1y - g.y) - mg * (m2x - g.x) * (m2y - g.y) - mg * (m3x - g.x) * (m3y - g.y); 65 a[1][1] = mg * (m1x - g.x) * (m1x - g.x) + mg * (m2x - g.x) * (m2x - g.x) + mg * (m3x - g.x) * (m3x - g.x); 66 a[1][2] = 0; 67 a[2][0] = 0; 68 a[2][1] = 0; 69 a[2][2] = mg * (m1x - g.x) * (m1x - g.x) + (m1y - g.y) * (m1y - g.y) + mg * (m2x - g.x) * (m2x - g.x) + (m2y - g.y) * (m2y - g.y) + mg * (m3x - g.x) * (m3x - g.x) + (m3y - g.y) * (m3y - g.y); 70 71 double [][] b = new double[3][3]; 72 b[0][0] = a[1][1] * a[2][2] / (a[0][0] * a[1][1] * a[2][2] - a[0][1] * a[1][0] * a[2][2]); 73 b[0][1] = -1 * a[0][1] * a[2][2] / (a[0][0] * a[1][1] * a[2][2] - a[0][1] * a[1][0] * a[2][2]); 74 b[0][2] = 0; 75 b[1][0] = -1 * a[1][0] * a[2][2] / (a[0][0] * a[1][1] * a[2][2] - a[0][1] * a[1][0] * a[2][2]); 76 b[1][1] = (a[0][0] * a[2][2] - a[0][2] * a[2][0]) / (a[0][0] * a[1][1] * a[2][2] - a[0][1] * a[1][0] * a[2][2]); 77 b[1][2] = 0; 78 b[2][0] = 0; 79 b[2][1] = 0; 80 b[2][2] = (a[0][0] * a[1][1] - a[0][1] * a[1][0]) / (a[0][0] * a[1][1] * a[2][2] - a[0][1] * a[1][0] * a[2][2]); 81 82 double [] r = new double[3]; 83 r[0] = m1x - g.x; 84 r[1] = m1y - g.y; 85 r[2] = 0; 86 87 double [] f = new double[3]; 88 f[0] = 500; 89 f[1] = 200; 90 f[2] = 0; 91 92 double [] gaiseki = new double[3]; 93 gaiseki[0] = (r[1] * f[2] - r[2] * f[1]) * derutat; 94 gaiseki[1] = (r[2] * f[0] - r[0] * f[2]) * derutat; 95 gaiseki[2] = (r[0] * f[1] - r[1] * f[0]) * derutat; 96 97 double [] kakusokudo = new double[3]; 98 kakusokudo[0] = b[0][0] * gaiseki[0] + b[0][1] * gaiseki[1] + b[0][2] * gaiseki[2]; 99 kakusokudo[1] = b[1][0] * gaiseki[0] + b[1][1] * gaiseki[1] + b[1][2] * gaiseki[2]; 100 kakusokudo[2] = b[2][0] * gaiseki[0] + b[2][1] * gaiseki[1] + b[2][2] * gaiseki[2]; 101 102 103 104 // 角速度 105 omega = kakusokudo[2]; 106 107 // 並進速度 108 v = new Point3D(f[0] * derutat / (3 * mg), f[1] * derutat / (3 * mg), f[2] * derutat / (3 * mg) ); 109 110 // 30ミリ秒おきに位置座標を更新して、描画更新要求 111 new javax.swing.Timer(30, e -> { 112 113 // 並進運動による位置更新 114 g.x += v.x; 115 g.y += v.y; 116 g.z += v.z; 117 118 // 各粒子の位置更新 119 for (Point3D p : m) { 120 double x = p.x + v.x, y = p.y + v.y, z = p.z + v.z; 121 p.x = (x - g.x) * Math.cos(omega) - (y - g.y) * Math.sin(omega) + g.x; 122 p.y = (x - g.x) * Math.sin(omega) + (y - g.y) * Math.cos(omega) + g.y; 123 } 124 125 // 描画更新要求 126 repaint(); 127 }).start(); 128 } 129 130 public void paintComponent(java.awt.Graphics g) { 131 super.paintComponent(g); 132 // 粒子の描画 133 for(Point3D p : m) { 134 // とりえあえず、直径を20にしてる 135 g.drawOval((int)p.x, (int)p.y, (int)p.z, 20, 20, 20); 136 } 137 138 } 139} 140

補足情報(FW/ツールのバージョンなど)

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

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

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

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

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

KSwordOfHaste

2019/01/03 07:41

本サイトではコードをそのまま質問文に張り付けても字下げされません。 https://teratail.com/help#about-markdown の「コードを入力」の項に書き方があります。それを参考に質問文を編集ください。質問文の投稿・編集のページ右側にプレビューが表示されていると思いますのでそれで適切な表示になっていることを確認できると思います。
kouya_tdu

2019/01/03 08:30

親切にありがとうございます、編集しました。
KSwordOfHaste

2019/01/03 09:02 編集

> 2Dの箇所を3Dに変えて の部分はPoint2Dではないクラスで座標を表現したといういうことだと思いますが具体的にどういうクラスを使われましたか?標準ライブラリー内にはjavafx.geometry.Point3Dぐらいしかない気がしますがご自分で独自の3D座標クラスを定義したのでしょうか?
kouya_tdu

2019/01/03 09:34

説明が下手ですみません。 javafx.geometry.Point3Dも試してみました。 Point2Dで3次元の座標を表現できるのであれば、Point2Dで表現したいのですが上手く行きませんでした。 (x, y, z)から(x2d, y2d)の簡単な正射影変換の以下の式を用いようと考えています。 x2d=px+x*cosβ+z*sinβ y2d=py-(y*cosα-zt*sinα)
KSwordOfHaste

2019/01/03 09:48

大分質問者さんの状況が見えてきました。「うまくいかない」は (A)どうコードを書けばよいか躓いている (B)コードは書いてみたがコンパイルエラー (C)実行したが実行時例外が起きたり、結果が期待外 のいずれなのかを具体的に質問文に書きましょう(ここのコメント欄ではなく質問そのものを編集願います)。いずれにしてもうまくいかないといっておられるコードそのものを張り付けないとアドバイスが難しいです。仮に(A)なら途中まででよいので書いたところまで提示しましょう。
kouya_tdu

2019/01/03 10:29

丁寧にありがとうございます。 どうコードを書けば良いか躓いてますので、試したことを更新しました。
guest

回答1

0

ベストアンサー

swingの2D座標を表すクラスjava.awt.geom.Point2DとJavaFXの3D座標を表すクラスは異なるクラス設計がなされています。swingでは座標をfloatで表現するかdoubleで表現するかの2種類を想定しているため、

Point2D.Float
Point2D.Double

という2種類のクラスが用意されていました。一方JavaFXでは座標をfloatで表すという考え方はなくなっており

javafx.geometry.Point3D

という1種類のクラスしかありません。(なお質問者さんが書いておられるのはswing前提のプログラムなので座標を表現するクラスだけJavaFXを使っても特にめだった効果はありません。このクラスは単に座標を保持する箱でしかないからです。しかしそのこと自体は問題ではないと思います。便利なクラスがあるなら使ってよいと思います。)

さて質問者さんの本当の課題はリファレンスをよく調べていない点にあると思います。Point3Dを使うなら最低限リファレンスを参照してこのクラスの使い方を把握してください。

Point2D.Doubleに保持されているx座標の参照はp.xのように書けますがそれはこのクラスのフィールドxがpublicだからです。一方Point3Dで同じことをするにはp.getX()と記述しなければなりません。これらはどちらもリファレンスに明記されています。

またリファレンスをきちんと見ておくとPoint3Dにどんな機能があるかについて気づきを得られることもあります。例えばPoint2Dクラスは二次元空間のベクトルを表すものとして捉えることができますが、ベクトル同士の加算などの演算機能は持ってません。一方Point3Dクラスの方にはいくらか備わっています。
そこに気づければ

java

1g = new Point3D( 2 Arrays.stream(m).mapToDouble(p -> p.x).average().getAsDouble(), 3 Arrays.stream(m).mapToDouble(p -> p.y).average().getAsDouble(), 4 Arrays.stream(m).mapToDouble(p -> p.z).average().getAsDouble()); 5 6// => 7 8g = Arrays.stream(m).reduce(Point3D.ZERO, Point3D::add).multiply(1.0 / m.length);

のようにより単純な実装が可能だということに気づけたりします。

というわけで新しいクラスを使う場合はリファレンスを一通りチェックすることをお勧めします。


ちなみに座標の取り出し方が気に入らない(p.getX()じゃなくてp.xと書きたい)なんて感じたらこのくらい単純なクラスなら自前で作ってしまってもよい気がします。もともとあまり機能がないクラスですので...

java

1class Point3D { 2 public double x, y, z; 3 4 Point3D(double x, double y, double z) { 5 this.x = x; this.y = y; this.z = z; 6 } 7}

投稿2019/01/03 11:09

編集2019/01/03 11:09
KSwordOfHaste

総合スコア18392

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

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

kouya_tdu

2019/01/03 11:34 編集

回答ありがとうございます。 3次元空間の点を表すオブジェクトのクラスを作るとしたら class Point3D { 〜 } をどこに書けば動くようになりますでしょうか? 具体的に教えていただけると助かります。
KSwordOfHaste

2019/01/03 12:02

自分がclassにpublicをつけなかったのは暗黙裡に「同じソースコードに書く」ことを想定していました。 一つのファイルにプログラムの全ソースを書いているなら他のクラスと同列の場所に書いておけばよいです。もちろんimport javafx.geometry.Point3D;を残したままだと名前の衝突がおきますからこのimport文は消すなりコメントアウトするのをお忘れなく。
kouya_tdu

2019/01/03 12:45 編集

import文を消してclass Point3Dを書いたのですが大量にエラーが出てしまい動きません。 どこが間違っているでしょうか? 試したことの欄に書いたコードを編集しました。
KSwordOfHaste

2019/01/03 13:12 編集

うーん・・・自分は元のコードを拝見した上で「質問者さんがJavaの言語仕様をある程度のところまでは把握している」と想定して回答したのですが、どうもそうではなさそうです。 リファレンスを見ましょうと回答したのですがどうもこのアドバイスは外れでした。リファレンス云々の前に質問者さんはJavaの文法など言語仕様についてまだ曖昧な点が多いと思います。まずJavaの基本を先に学習しましょう。文法がわからない状態でこうした応用プログラムを書こうとするのは厳しいですよ?せめてコンパイルエラーを自分で解決できるようになってからこうしたプログラムに挑戦することをお勧めします。 ・・・というコメントでは気の毒なので1点だけ訂正しましょう。最初の回答にかいた「自分で定義したクラス」はPoint3D.DoubleというクラスではなくPoint3Dというクラスとして定義した例です。 Point3D.Doubleと書いてはいけません。 Point3Dと書いてください。
kouya_tdu

2019/01/03 14:10

アドバイスありがとうございます、基本的な事も分かっていないんですが、どうしても形だけでもいいんでこのプログラムを完成させなければなりません。 (x, y, z)から(x2d, y2d)の変換を以下式 x2d=px+x*cosβ+z*sinβ y2d=py-(y*cosα-zt*sinα) を使ってマウスで視点を移動させて運動を観察できるようにしたいです。 ご教授お願いできないでしょうか?
KSwordOfHaste

2019/01/03 14:53

宿題の類だと思いますが、学ぶ時間が最早ないという厳しい状況らしいのは同情します。 しかし冷たいようですが、自分は基本的に質問者さんが書いたコード、あるいはもう少しで書けそうなコードならアドバイスするつもりですが、書けそうもないコードを自分から提示するのは気が進みません。 (A)気の毒だから一つ助けてあげようと考える人もいるでしょうし (B)自分で学んで書くべきだという人もいるでしょう。 このサイトの公式な態度は(B)の方だと思います。自分でかけそうもないものを「教えて」は丸投げと呼ばれ敬遠されるのです。ご自分で調べたり考えたりしてコードを書いてみてください。それを提示していただければ時間が許す限りアドバイスすることはやぶさかではありません。
kouya_tdu

2019/01/05 07:25

本当に丁寧にありがとうございました。 調べながら考えようと思います。
退会済みユーザー

退会済みユーザー

2019/01/05 10:07

注意をもらったから解決済みにして新しい質問立てる人は回答を得られなくなりますけどね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問