2008年の年賀状
2008年の年賀状を紹介.
メビウスの帯です. Javaで座標データを計算して,Blenderでレンダリング, Gimpでネズミの画像を追加しました.
プログラム
OBJファイルを生成するJavaプログラム.まったく汎用ではない...
package nenga2008; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; /** * */ public class Nenga2008 { // 出力 static PrintWriter out; static double pi = Math.PI; static double sqrt2 = Math.sqrt(2); static double scale = 1.0; /** * 頂点を表すクラス */ public class Vertex { public double x; public double y; public double z; public Vertex(double x, double y, double z) { this.x = x; this.y = y; this.z = z; } public void output() { double a1 = scale * y; double b1 = scale * z; double c1 = -scale * x; out.println("v " + a1 + " " + b1 + " " + c1); } } /** * 帯の端の線を表すクラス */ public class Edge { // 中心点 public Vertex v; // y軸方向の回転角 public double t = 0.0; // 幅 public double w = 1.0; public Edge(Vertex v) { this.v = v; } public Edge(Vertex v, double t) { this.v = v; this.t = t; } public Edge(Vertex v, double t, double w) { this.v = v; this.t = t; this.w = w; } public void output() { double c = w / 2 * Math.cos(t); double s = w / 2 * Math.sin(t); Vertex v1 = new Vertex(v.x - c, v.y - s, v.z); v1.output(); Vertex v2 = new Vertex(v.x + c, v.y + s, v.z); v2.output(); } } public class Ribbon { public ArrayList<Edge> edges = new ArrayList<Edge>(); public boolean isLoop = false; public void addLine(Vertex v1, Vertex v2, double t1, double t2, int n) { double dx = (v2.x - v1.x) / n; double dy = (v2.y - v1.y) / n; double dz = (v2.z - v1.z) / n; double dt = (t2 - t1) / n; edges.add(new Edge(v1, t1)); for (int i = 1; i < n; i++) { double x = v1.x + i * dx; double y = v1.y + i * dy; double z = v1.z + i * dz; double t = t1 + i * dt; edges.add(new Edge(new Vertex(x, y, z), t)); } edges.add(new Edge(v2, t2)); } public void addArcYZ(Vertex v0, double r, double a1, double a2, double t1, double t2, int n) { addArcYZ(v0, r, a1, a2, t1, t2, 0, 0, n); } public void addArcYZ(Vertex v0, double r, double a1, double a2, double t1, double t2, double dx1, double dx2, int n) { double da = (a2 - a1) / n; double dt = (t2 - t1) / n; double dx = (dx2 - dx1) / n; for (int i = 0; i <= n; i++) { double a = a1 + i * da; double t = t1 + i * dt; double x = v0.x + dx1 + i * dx; double y = v0.y + r * Math.cos(a); double z = v0.z + r * Math.sin(a); edges.add(new Edge(new Vertex(x, y, z), t)); } } public void twist(double t1, double t2) { int n = edges.size(); double dt = (t2 - t1) / (n - 1); for (int i = 0; i < n; i++) { double t = t1 + i * dt; edges.get(i).t = t; } } public Edge lastEdge() { return edges.get(edges.size() - 1); } public void removeFirst() { edges.remove(0); } public void removeLast() { edges.remove(edges.size() - 1); } public void addAll(Ribbon ribbon) { edges.addAll(ribbon.edges); } public void output() { int n = edges.size(); for (int i = 0; i < n; i++) { edges.get(i).output(); } for (int i = 0; i < n - 1; i++) { int j = 2 * (i - n); out.println("f " + j + " " + (j + 1) + " " + (j + 3) + " " + (j + 2)); } if (isLoop) { int j = -2 * n; out.println("f -1 -2 " + (j + 1) + " " + j); } } } public class Char3D extends Ribbon { public double r = 1.0; public int n = 8; public Vertex[][] v = new Vertex[3][5]; public Char3D(double x0, double y0, double z0) { for (int i = 0; i < v.length; i++) { for (int j = 0; j < v[i].length; j++) { v[i][j] = new Vertex(x0, y0 + i * r, z0 + j * r); } } } } // 2 の文字 public class Char2 extends Char3D { public Char2(double x0, double y0, double z0) { super(x0, y0, z0); addArcYZ(v[1][3], r, pi, -pi / 2, 0, 3 * pi / 4, 3 * n); addArcYZ(v[1][1], r, pi / 2, pi, 3 * pi / 4, pi, n); addLine(v[0][1], v[0][0], pi, pi, n); addLine(v[0][0], v[2][0], pi, pi, n); } } // 0 の文字 public class Char0 extends Char3D { public Char0(double x0, double y0, double z0) { super(x0, y0, z0); isLoop = true; addLine(v[0][2], v[0][3], 0, 0, n); addArcYZ(v[1][3], r, pi, 0, 0, pi / 2, 2 * n); addLine(v[2][3], v[2][2], pi / 2, pi / 2, n); addLine(v[2][2], v[2][1], pi / 2, pi / 2, n); addArcYZ(v[1][1], r, 0, -pi, pi / 2, pi, 2 * n); addLine(v[0][1], v[0][2], pi, pi, n); } } // 8 の文字 public class Char8 extends Char3D { public Char8(double x0, double y0, double z0) { super(x0, y0, z0); isLoop = true; double r1 = 0.6 * r; if (false) { addArcYZ(v[1][3], r, -pi / 2, -pi, 0, 0, n); addArcYZ(v[1][3], r, pi, 0, 0, pi / 2, 0, -r1, 2 * n); Vertex v1 = new Vertex(v[2][3].x - r1, v[2][3].y, v[2][3].z); Vertex v2 = new Vertex(v[0][1].x - r1, v[0][1].y, v[0][1].z); addLine(v1, v2, pi / 2, pi / 2, 2 * n); addArcYZ(v[1][1], r, -pi, 0, pi / 2, pi, -r1, 0, 3 * n); addArcYZ(v[1][1], r, 0, pi / 2, pi, pi, n); } else { double r2 = r / sqrt2; addArcYZ(v[1][3], r, -pi / 2, -pi, 0, 0, n); addArcYZ(v[1][3], r, pi, -pi / 4, 0, pi / 2, 0, -r1, 2 * n); Vertex v1 = new Vertex(v[1][3].x - r1, v[1][3].y + r2, v[1][3].z - r2); Vertex v2 = new Vertex(v[1][1].x - r1, v[1][1].y - r2, v[1][1].z + r2); addLine(v1, v2, pi / 2, pi / 2, 2 * n); addArcYZ(v[1][1], r, -5 * pi / 4, 0, pi / 2, pi, -r1, 0, 3 * n); addArcYZ(v[1][1], r, 0, pi / 2, pi, pi, n); } } } public void output() { (new Char2(0, -8, 1)).output(); (new Char0(0, -4, 1)).output(); (new Char0(0, 0, 1)).output(); (new Char8(0, 4, 1)).output(); } public static void main(String[] args) { String outFileName = "nenga2008.obj"; try { out = new PrintWriter(new FileWriter(outFileName)); Nenga2008 nenga = new Nenga2008(); nenga.output(); out.close(); } catch (IOException e) { e.printStackTrace(); } } }