JPanelに正六面体ワイヤーフレームを投影変換して描画し、マウスドラッグして空間内で回転する
Total: 1183
, Today: 2
, Yesterday: 1
Posted by aterai at
Last-modified:
概要
JPanel
に正六面体ワイヤーフレームを投影変換で描画し、マウスドラッグして各頂点を変換して空間内で回転します。
Screenshot
Advertisement
サンプルコード
class Vertex {
private double dx;
private double dy;
private double dz;
public double vx;
public double vy;
protected Vertex(double dx, double dy, double dz) {
this.dx = dx;
this.dy = dy;
this.dz = dz;
projectionTransformation();
}
private void projectionTransformation() {
double screenDistance = 500d;
double depth = 1000d;
double gz = dz + depth;
this.vx = screenDistance * dx / gz;
this.vy = screenDistance * dy / gz;
}
public void rotateTransformation(double kx, double ky, double kz) {
double x0 = dx * Math.cos(ky) - dz * Math.sin(ky);
double y0 = dy;
double z0 = dx * Math.sin(ky) + dz * Math.cos(ky);
double y1 = y0 * Math.cos(kx) - z0 * Math.sin(kx);
double z1 = y0 * Math.sin(kx) + z0 * Math.cos(kx);
this.dx = x0 * Math.cos(kz) - y1 * Math.sin(kz);
this.dy = x0 * Math.sin(kz) + y1 * Math.cos(kz);
this.dz = z1;
projectionTransformation();
}
}
View in GitHub: Java, Kotlin解説
- 頂点を表す
Vertex
クラスを8
個使用して辺の長さが100
の正六面体ワイヤーフレームを作成List<Vertex> cube = new ArrayList<>(8); double sideLength = 100; cube.add(new Vertex(sideLength, sideLength, sideLength)); cube.add(new Vertex(sideLength, sideLength, -sideLength)); cube.add(new Vertex(-sideLength, sideLength, -sideLength)); cube.add(new Vertex(-sideLength, sideLength, sideLength)); cube.add(new Vertex(sideLength, -sideLength, sideLength)); cube.add(new Vertex(sideLength, -sideLength, -sideLength)); cube.add(new Vertex(-sideLength, -sideLength, -sideLength)); cube.add(new Vertex(-sideLength, -sideLength, sideLength));
- 視点を原点、スクリーンまでの距離を
500
、z
軸座標値をスクリーンの奥へ1000
移動して正六面体の各頂点を投影変換 - 変換した頂点座標を
Path2D
で繋いでワイヤーフレームをJPanel
の中央に描画@Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g.create(); g2.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); Path2D path = new Path2D.Double(); path.moveTo(cube.get(0).vx, cube.get(0).vy); path.lineTo(cube.get(1).vx, cube.get(1).vy); path.lineTo(cube.get(2).vx, cube.get(2).vy); path.lineTo(cube.get(3).vx, cube.get(3).vy); path.lineTo(cube.get(0).vx, cube.get(0).vy); path.lineTo(cube.get(4).vx, cube.get(4).vy); path.lineTo(cube.get(5).vx, cube.get(5).vy); path.lineTo(cube.get(6).vx, cube.get(6).vy); path.lineTo(cube.get(7).vx, cube.get(7).vy); path.lineTo(cube.get(4).vx, cube.get(4).vy); path.moveTo(cube.get(1).vx, cube.get(1).vy); path.lineTo(cube.get(5).vx, cube.get(5).vy); path.moveTo(cube.get(2).vx, cube.get(2).vy); path.lineTo(cube.get(6).vx, cube.get(6).vy); path.moveTo(cube.get(3).vx, cube.get(3).vy); path.lineTo(cube.get(7).vx, cube.get(7).vy); Rectangle r = SwingUtilities.calculateInnerArea(this, null); g2.setPaint(Color.WHITE); g2.fill(r); g2.translate(r.getCenterX(), r.getCenterY()); g2.setPaint(Color.BLACK); g2.draw(path); g2.dispose(); }
- 正六面体を投影変換して描画する
JPanel
に以下のようなMouseAdapter
を追加して各頂点を空間内で回転private class DragRotateHandler extends MouseAdapter { private final Cursor defCursor = Cursor.getDefaultCursor(); private final Cursor hndCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); private final Point pp = new Point(); @Override public void mouseDragged(MouseEvent e) { Point pt = e.getPoint(); double rotY = (pt.x - pp.x) * .03; double rotX = (pt.y - pp.y) * .03; double rotZ = 0d; for (Vertex v : cube) { v.rotateTransformation(rotX, rotY, rotZ); } pp.setLocation(pt); e.getComponent().repaint(); } @Override public void mousePressed(MouseEvent e) { e.getComponent().setCursor(hndCursor); pp.setLocation(e.getPoint()); } @Override public void mouseReleased(MouseEvent e) { e.getComponent().setCursor(defCursor); } }
参考リンク
- Designing Math. 数学とデザインをむすぶプログラミング入門 | 古堅 真彦 | 工学 | Kindleストア | Amazon
- APCS wiki - Perspective
jdk-8-windows-x64-demos.zip\jdk1.8.0_341\demo\jfc\Java2D\src.zip\java2d\demos\Colors\Rotator3D.java
Java 2D
デモのColors
タブのdemos.Colors.Rotator3D
に色付き正六面体が回転移動するアニメーションデモがある- Java2Dデモを最新JDKで動かす - きしだのHatena