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();
        }
    }

}