aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@operamail.com>2013-11-26 03:38:18 +0100
committerMattias Andrée <maandree@operamail.com>2013-11-26 03:38:18 +0100
commit778b6554c96663eb77f7690a0f161e3985e0d59d (patch)
tree7247c49ed7355a0713b9d8e06492d6077240c365
downloadrotation3d-778b6554c96663eb77f7690a0f161e3985e0d59d.tar.gz
rotation3d-778b6554c96663eb77f7690a0f161e3985e0d59d.tar.bz2
rotation3d-778b6554c96663eb77f7690a0f161e3985e0d59d.tar.xz
first commit
Signed-off-by: Mattias Andrée <maandree@operamail.com>
Diffstat (limited to '')
-rw-r--r--.gitignore11
-rw-r--r--COPYING22
-rw-r--r--Makefile12
-rw-r--r--src/v/D3.java280
-rw-r--r--src/v/VMaths.java225
5 files changed, 550 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c243105
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,11 @@
+_/
+bin/
+obj/
+\#*\#
+*~
+*.bak
+*.swo
+*.swp
+*.class
+*.jar
+
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..c5c21e8
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,22 @@
+Copyright (c) 2013, Mattias Andrée
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..7e724d6
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,12 @@
+JAVAC = javac
+
+.PHONY: all
+all:
+ @mkdir -p bin
+ $(JAVAC) -cp src -s src -d bin src/v/D3.java
+
+
+.PHONY: clean
+clean:
+ -rm -r bin
+
diff --git a/src/v/D3.java b/src/v/D3.java
new file mode 100644
index 0000000..0ba9815
--- /dev/null
+++ b/src/v/D3.java
@@ -0,0 +1,280 @@
+/**
+ * Copyright (c) 2013, Mattias Andrée
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package v;
+
+import javax.swing.*;
+import java.awt.event.*;
+import java.awt.*;
+import java.util.*;
+
+import static v.VMaths.*;
+
+
+public class D3
+{
+ static final float DEGREES_PER_SECOND = 50f / 1000f;
+ static final float[][] UNIT = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
+
+ static float[] xs = new float[8];
+ static float[] ys = new float[8];
+ static float[] zs = new float[8];
+
+ static float[] normal_xs = {0f, 0f, 1f, -1f, 0f, 0f};
+ static float[] normal_ys = {1f, 0f, 0f, 0f, 0f, -1f};
+ static float[] normal_zs = {0f, 1f, 0f, 0f, -1f, 0f};
+
+ static float[] rotation = {1f, 0f, 0f};
+ static float rotation_speed = 0f;
+
+ static int rx = 0;
+ static int ry = 0;
+ static int rxy = 0;
+
+ public static void main(String... args) throws InterruptedException
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ xs[i] = ((i & 1) != 0 ? 1f : 0f) - 0.5f;
+ ys[i] = ((i & 2) != 0 ? 1f : 0f) - 0.5f;
+ zs[i] = ((i & 4) != 0 ? 1f : 0f) - 0.5f;
+ }
+
+ final JFrame window = new JFrame();
+ final JPanel panel;
+ window.pack();
+ window.setLayout(new BorderLayout());
+ window.add(panel = new JPanel()
+ {
+ {
+ this.setBackground(Color.BLACK);
+ }
+
+ @Override
+ public void paint(Graphics g)
+ {
+ super.paint(g);
+
+ /* */
+ int[] z = new int[6];
+ for (int i = 0; i < 6; i++)
+ {
+ int v = (int)(normal_zs[i] * 1000f);
+ z[i] = (v << 8) | i;
+ }
+
+ Arrays.sort(z);
+
+ for (int i = 0; i < 6; i++)
+ {
+ int side = z[i] & 7;
+ switch (side)
+ {
+ case 0: draw(188, 188, 188, 0, 1, 5, 4, g, normal_zs[0]); break;
+ case 1: draw(188, 0, 0, 0, 1, 3, 2, g, normal_zs[1]); break;
+ case 2: draw( 0, 188, 0, 0, 2, 6, 4, g, normal_zs[2]); break;
+ case 3: draw( 0, 0, 188, 1, 3, 7, 5, g, normal_zs[3]); break;
+ case 4: draw(188, 128, 0, 4, 5, 7, 6, g, normal_zs[4]); break;
+ case 5: draw(188, 188, 0, 2, 3, 7, 6, g, normal_zs[5]); break;
+ }
+ }
+ /* */
+
+ /* */
+ draw(new Color(255, 0, 0), 0, 1, g);
+ draw(new Color( 0, 0, 255), 0, 2, g);
+ draw(new Color(210, 0, 210), 0, 4, g);
+ draw(new Color(255, 255, 0), 1, 3, g);
+ draw(new Color(210, 128, 0), 1, 5, g);
+ draw(new Color( 0, 255, 0), 2, 3, g);
+ draw(new Color( 0, 210, 210), 2, 6, g);
+ draw(new Color(188, 210, 0), 3, 7, g);
+ draw(new Color(188, 0, 0), 4, 5, g);
+ draw(new Color( 0, 0, 188), 4, 6, g);
+ draw(new Color(188, 188, 0), 5, 7, g);
+ draw(new Color( 0, 188, 0), 6, 7, g);
+ /* */
+ }
+
+ private void draw(int R, int G, int B, int a, int b, int c, int d, Graphics g, float normal_z)
+ {
+ int A = (int)(255f * normal_z);
+ if (A > 0)
+ {
+ A = A / 2 + 128;
+
+ if (A > 255)
+ A = 255;
+ g.setColor(new Color(R, G, B, A));
+ g.fillPolygon(new int[] {Px(a), Px(b), Px(c), Px(d)},
+ new int[] {Py(a), Py(b), Py(c), Py(d)}, 4);
+ }
+ }
+
+ private void draw(Color colour, int i, int j, Graphics g)
+ {
+ g.setColor(colour);
+ g.drawLine(Px(i), Py(i), Px(j), Py(j));
+ }
+
+ static final float SCREEN_Z = 50f;
+ static final float MODEL_Z = 55f;
+ static final float VIEWER_Z = 50f;
+ static final float VIEWER_X = 0f;
+ static final float VIEWER_Y = 0f;
+ static final float CAMERA_Z = 10f;
+ static final float CAMERA_X = 0f;
+ static final float CAMERA_Y = 0f;
+
+ private int Px(int i)
+ {
+ /* Orthogonal projection */
+ //float z = SCREEN_Z / (zs[i] + MODEL_Z);
+ //return (int)(xs[i] * z * 300f + 400f);
+
+ /* Perspective projection */
+ float model_z = zs[i] + MODEL_Z;
+ float model_x = xs[i];
+ float p = VIEWER_Z / (model_z - CAMERA_Z) * (model_x - CAMERA_X) - VIEWER_X;
+ return (int)(p * 300f + 400f);
+ }
+
+ private int Py(int i)
+ {
+ /* Orthogonal projection */
+ //float z = SCREEN_Z / (zs[i] + MODEL_Z);
+ //return (int)(ys[i] * z * 300f + 300f);
+
+ /* Perspective projection */
+ float model_z = zs[i] + MODEL_Z;
+ float model_y = ys[i];
+ float p = VIEWER_Z / (model_z - CAMERA_Z) * (model_y - CAMERA_Y) - VIEWER_Y;
+ return (int)(p * 300f + 300f);
+ }
+
+ });
+ window.setBackground(Color.BLACK);
+ final Insets in = window.getInsets();
+ window.setSize(new Dimension(in.left + 800 + in.right, in.top + 600 + in.bottom));
+ window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ window.setVisible(true);
+
+ final float SPEED = (float)(Math.sqrt(25.5f / 2f)) * DEGREES_PER_SECOND;
+
+ window.addKeyListener(new KeyListener()
+ {
+ public void keyTyped(KeyEvent e) {}
+
+ public void keyReleased(KeyEvent e)
+ {
+ switch (e.getKeyCode())
+ {
+ case KeyEvent.VK_D: rx = 0; break;
+ case KeyEvent.VK_A: rx = 0; break;
+ case KeyEvent.VK_W: ry = 0; break;
+ case KeyEvent.VK_S: ry = 0; break;
+ case KeyEvent.VK_E: rxy = 0; break;
+ case KeyEvent.VK_Q: rxy = 0; break;
+ }
+ }
+
+ public void keyPressed(KeyEvent e)
+ {
+ switch (e.getKeyCode())
+ {
+ case KeyEvent.VK_D: rx = +1; break;
+ case KeyEvent.VK_A: rx = -1; break;
+ case KeyEvent.VK_W: ry = +1; break;
+ case KeyEvent.VK_S: ry = -1; break;
+ case KeyEvent.VK_E: rxy = +1; break;
+ case KeyEvent.VK_Q: rxy = -1; break;
+
+ case KeyEvent.VK_R:
+ rotation_speed = 0;
+ break;
+ }
+ }
+ });
+
+ for (;;)
+ {
+ Thread.sleep(50);
+
+ if (rx != 0)
+ {
+ float[] v = mul(rx * SPEED, createRotation("x"));
+ v = add(mul(rotation_speed, rotation), v);
+ rotation_speed = length(v);
+ rotation = normalise(v);
+ }
+
+ if (ry != 0)
+ {
+ float[] v = mul(ry * SPEED, createRotation("y"));
+ v = add(mul(rotation_speed, rotation), v);
+ rotation_speed = length(v);
+ rotation = normalise(v);
+ }
+
+ if (rxy != 0)
+ {
+ float[] v = mul(rxy * SPEED, createRotation("xy"));
+ v = add(mul(rotation_speed, rotation), v);
+ rotation_speed = length(v);
+ rotation = normalise(v);
+ }
+
+ if (rotation_speed != 0)
+ transform(createRotation(rotation, rotation_speed));
+
+ panel.repaint();
+ }
+ }
+
+
+ public static void transform(float[][] m)
+ {
+ /* This is not a transformation of the object, but
+ * rather its projection onto the screen. (This
+ * program combines the object and the projection.) */
+
+ for (int i = 0; i < 8; i++)
+ {
+ float[] v = mul(m, xs[i], ys[i], zs[i]);
+ xs[i] = v[0];
+ ys[i] = v[1];
+ zs[i] = v[2];
+ }
+
+ for (int i = 0; i < 6; i++)
+ {
+ float[] v = mul(m, normal_xs[i], normal_ys[i], normal_zs[i]);
+ normal_xs[i] = v[0];
+ normal_ys[i] = v[1];
+ normal_zs[i] = v[2];
+ }
+ }
+
+}
+
diff --git a/src/v/VMaths.java b/src/v/VMaths.java
new file mode 100644
index 0000000..9312608
--- /dev/null
+++ b/src/v/VMaths.java
@@ -0,0 +1,225 @@
+/**
+ * Copyright (c) 2013, Mattias Andrée
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package v;
+
+/**
+ * Orthonormalised vector maths
+ */
+public class VMaths
+{
+
+ public static float[] createRotation(String side)
+ {
+ switch (side.toLowerCase())
+ {
+ case "x":
+ case "xz":
+ case "zx":
+ return new float[] { 0f, -1f, 0f };
+
+ case "y":
+ case "yz":
+ case "zy":
+ return new float[] { -1f, 0f, 0f };
+
+ case "xy":
+ case "yx":
+ return new float[] { 0f, 0f, +1f };
+ }
+
+ return null;
+ }
+
+ public static float[][] createRotation(String side, float thetaDegrees)
+ {
+ switch (side.toLowerCase())
+ {
+ case "x":
+ case "xz":
+ case "zx":
+ return createRotation( 0f, -1f, 0f, thetaDegrees);
+
+ case "y":
+ case "yz":
+ case "zy":
+ return createRotation(-1f, 0f, 0f, thetaDegrees);
+
+ case "xy":
+ case "yx":
+ return createRotation( 0f, 0f, +1f, thetaDegrees);
+ }
+
+ return null;
+ }
+
+ public static float[][] createRotation(float x, float y, float z, float thetaDegrees)
+ {
+ float theta = thetaDegrees * (float)(Math.PI) / 180f;
+ float[][] m = new float[3][3];
+
+ float cos = (float)(Math.cos(theta));
+ float sin = (float)(Math.sin(theta));
+ float _cos = 1f - cos;
+
+ m[0][0] = x * x * _cos + cos;
+ m[1][0] = x * y * _cos + z * sin;
+ m[2][0] = x * z * _cos - y * sin;
+
+ m[0][1] = y * x * _cos - z * sin;
+ m[1][1] = y * y * _cos + cos;
+ m[2][1] = y * z * _cos + x * sin;
+
+ m[0][2] = z * x * _cos + y * sin;
+ m[1][2] = z * y * _cos - x * sin;
+ m[2][2] = z * z * _cos + cos;
+
+ return m;
+ }
+
+ public static float[][] createRotation(float[] v, float thetaDegrees)
+ {
+ return createRotation(v[0], v[1], v[2], thetaDegrees);
+ }
+
+ public static float[] mul(float[][] m, float[] v)
+ {
+ int n, k = v.length;
+ float[] rc = new float[n = m.length];
+
+ for (int r = 0; r < n; r++)
+ for (int i = 0; i < k; i++)
+ rc[r] += m[r][i] * v[i];
+
+ return rc;
+ }
+
+ public static float[] mul(float[][] m, float x, float y, float z)
+ {
+ int n;
+ float[] rc = new float[n = m.length];
+
+ for (int i = 0; i < n; i++)
+ rc[i] = m[i][0] * x
+ + m[i][1] * y
+ + m[i][2] * z;
+
+ return rc;
+ }
+
+ public static float[][] mul(float[][] a, float[][] b)
+ {
+ int n, m, k = b.length;
+ float[][] rc = new float[n = a.length][m = b[0].length];
+
+ for (int r = 0; r < n; r++)
+ for (int c = 0; c < m; c++)
+ for (int i = 0; i < k; i++)
+ rc[r][c] += a[i][r] * b[c][i];
+
+ return rc;
+ }
+
+ public static float[][] mul(float a, float[][] b)
+ {
+ int n, m;
+ float[][] rc = new float[n = b.length][m = b[0].length];
+
+ for (int r = 0; r < n; r++)
+ for (int c = 0; c < m; c++)
+ rc[r][c] = a * b[r][c];
+
+ return rc;
+ }
+
+ public static float[] mul(float a, float[] b)
+ {
+ int n;
+ float[] rc = new float[n = b.length];
+
+ for (int r = 0; r < n; r++)
+ rc[r] = a * b[r];
+
+ return rc;
+ }
+
+ public static float[][] add(float[][] a, float[][] b)
+ {
+ int n, m;
+ float[][] rc = new float[n = a.length][m = b[0].length];
+
+ for (int r = 0; r < n; r++)
+ for (int c = 0; c < m; c++)
+ rc[r][c] = a[r][c] + b[r][c];
+
+ return rc;
+ }
+
+ public static float[] add(float[] a, float[] b)
+ {
+ int n;
+ float[] rc = new float[n = a.length];
+
+ for (int r = 0; r < n; r++)
+ rc[r] = a[r] + b[r];
+
+ return rc;
+ }
+
+ public static float length(float[] v)
+ {
+ int n = v.length;
+ float length = 0;
+
+ for (int r = 0; r < n; r++)
+ length += v[r] * v[r];
+
+ length = (float)Math.sqrt(length);
+
+ return length;
+ }
+
+ public static float[] normalise(float[] v)
+ {
+ int n;
+ float[] rc = new float[n = v.length];
+ float length = length(v);
+
+ if (length * length == 0f)
+ {
+ for (int r = 0; r < n; r++)
+ rc[r] = 0;
+ rc[0] = 1;
+ }
+ else
+ for (int r = 0; r < n; r++)
+ rc[r] = v[r] / length;
+
+ return rc;
+ }
+
+
+
+}
+