前提・実現したいこと
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/ツールのバージョンなど)
回答1件
あなたの回答
tips
プレビュー