Startseite < Informatik < Algorithmen Datenstrukturen / Software-Engineering / Programmiersprachen < Compiler Interpreter < Setty Tinyray < Tinyray-Scanner Tinyray-Parser / Tinyray-Language < Tinyray-LanguageKit Tinyray-Visitables Tinyray-Visitors < Tinyray-PrettyPrint Tinyray-DotCode Tinyray-PovRayCode Tinyray-GlutCCode [ DRUCK , 2004 , 2005 , 2006 , 2007 , 2008 , 2009 ] Tinyray-VRMLCode > > Tinyray-Raytracer / Tinyray-Wallpapers > > / Java C/C++ POV-Ray LaTeX > / Künstliche Intelligenz > Schach Privates / Inhalt >
Tinyray-VRMLCode
VRMLCode erzeugt aus einem Tinyray-Programm ein VRML97-Programm.
VRML Über VRML
Zielvorstellung
Ein Tinyray-Quellprogramm soll in ein VRML97-Programm übersetzt werden.
Implementierung Implementierung der VRMLCode-Klasse
Die Java-Klasse VRMLCode ist hier als Visitor realisiert.
VRMLCode.java
package tinyray.language;

import java.util.Iterator;

public class VRMLCode implements Visitor<String, String> {

    // Der Zeilenumbruch des zugrundeliegenden Systems.
    private final static String nl() {
        return System.getProperty("line.separator");
    }

    // Die Einrückung.
    private final static String INDENT = "\t";

    // Die globalen Parameter.
    private Defaults defaults;

    public VRMLCode() {
        // Setzt globale Parameter
        this.defaults = new Defaults();
        // color = [0.5, 0.5, 0.5]
        this.defaults.parameters.visitables.add(new Vector(0.5, 0.5, 0.5));
        // ambient = [0.1, 0.1, 0.1]
        this.defaults.parameters.visitables.add(new Vector(0.1, 0.1, 0.1));
        // specular = 0.5
        this.defaults.parameters.visitables.add(new Real(0.5));
        // shininess = 1000.0
        this.defaults.parameters.visitables.add(new Real(1000.0));
        // mirror = 0.4
        this.defaults.parameters.visitables.add(new Real(0.4));
    }

    @Override
    public String visit(Tinyray tinyray, String indent) {

        StringBuilder result = new StringBuilder();

        result.append(indent);
        result.append("#VRML V2.0 utf8");
        result.append(nl());
        result.append(nl()).append(indent);
        result.append("# Automatisch generierter VRML-Code.");
        result.append(nl()).append(indent);
        result.append("# Herkunft: Tinyray (http://www.stefan-baur.de)");
        result.append(nl());

        // Camera
        result.append(nl());
        result.append(tinyray.camera.accept(this, indent));

        // Background
        result.append(nl());
        result.append(tinyray.background.accept(this, indent));

        // Fog
        if (tinyray.fog.density.value > 0.0) {
            result.append(nl());
            result.append(tinyray.fog.accept(this, indent));
        }

        // Ambience (global)
        result.append(nl());
        result.append(tinyray.ambience.accept(this, indent));

        // Suns
        Iterator<Sun> suns = tinyray.suns.iterator();
        while (suns.hasNext()) {
            result.append(nl());
            result.append(suns.next().accept(this, indent));
        }

        // Geos
        Iterator<Visitable> visitables = tinyray.visitables.iterator();
        while (visitables.hasNext()) {
            result.append(nl());
            result.append(visitables.next().accept(this, indent));
        }

        // PrettyPrint
        result.append(nl()).append(nl()).append(indent);
        result.append("# Quelle: Tinyray-Code");
        result.append(nl()).append(indent);
        result.append('#');
        result.append(nl());
        result.append(tinyray.accept(new PrettyPrint(), indent + "# "));
        result.append(nl());

        return result.toString();
    }

    @Override
    public String visit(Camera camera, String indent) {

        StringBuilder result = new StringBuilder();

        result.append(indent);
        result.append("Viewpoint {");

        result.append(nl()).append(indent).append(INDENT);
        result.append("fieldOfView ");
        result.append(30.0 * Math.PI / 180.0);

        result.append(nl()).append(indent).append(INDENT);
        result.append("position ");
        result.append(camera.location.accept(this, ""));

        // (location, lookat, up) -> (direction, rotation) = orientation

        Vector a = Vector.norm(Vector.sub(camera.lookAt, camera.location));
        Vector b = new Vector(a.y.value, -a.x.value, 0.0);
        Vector c = new Vector(0.0, 1.0, 0.0);
        double d = 1.0;
        if (!Vector.isTiny(b)) {
            double e = 0.5 * Math.acos(Math.max(-1.0, Math.min(1.0, -a.z.value)));
            c = Vector.mult(Math.sin(e), Vector.norm(b));
            d = Math.cos(e);
        }
        Vector f = new Vector(0.0, 1.0, 0.0);
        Vector g = Vector.add(Vector.mult(d, f), Vector.cross(c, f));
        Vector h = Vector.anti(c);
        Vector i = Vector.add(Vector.mult(-Vector.dot(c, f), h),
                Vector.add(Vector.mult(d, g), Vector.cross(g, h)));
        Vector j = Vector.norm(camera.up);
        Vector k = Vector.norm(Vector.sub(j, Vector.mult(Vector.dot(j, a), a)));
        Vector l = Vector.cross(i, k);
        if (Vector.isTiny(l)) l = new Vector(0.0, -k.z.value, k.y.value);
        if (Vector.isTiny(l)) l = new Vector(k.z.value, 0.0, -k.x.value);
        double m = 0.5 * Math.acos(Math.max(-1.0, Math.min(1.0, Vector.dot(i, k))));
        Vector n = Vector.mult(Math.sin(m), Vector.norm(l));
        double o = Math.cos(m);
        Vector p = Vector.add(Vector.mult(o, c),
                Vector.add(Vector.mult(d, n), Vector.cross(n, c)));
        double q = Math.acos(* d - Vector.dot(n, c));
        double r = Math.sin(q);

        // direction, rotation
        Vector direction = (!= 0.0) ? Vector.mult(1.0 / r, p) : f;
        double rotation = 2.0 * q;

        result.append(nl()).append(indent).append(INDENT);
        result.append("orientation");
        result.append(nl()).append(indent).append(INDENT).append(INDENT);
        result.append(direction.x.accept(this, ""));
        result.append(nl()).append(indent).append(INDENT).append(INDENT);
        result.append(direction.y.accept(this, ""));
        result.append(nl()).append(indent).append(INDENT).append(INDENT);
        result.append(direction.z.accept(this, ""));
        result.append(nl()).append(indent).append(INDENT).append(INDENT);
        result.append(rotation);

        result.append(nl()).append(indent);
        result.append("}");

        return result.toString();
    }

    @Override
    public String visit(Background background, String indent) {

        StringBuilder result = new StringBuilder();

        result.append(indent);
        result.append("Background { skyColor ");
        result.append(background.color.accept(this, ""));
        result.append(" }");

        return result.toString();
    }

    @Override
    public String visit(Ambience ambience, String indent) {

        return indent + "# global ambience is ignored";
    }

    @Override
    public String visit(Fog fog, String indent) {

        StringBuilder result = new StringBuilder();

        result.append(indent);
        result.append("Fog {");

        result.append(nl()).append(indent).append(INDENT);
        result.append("color ");
        result.append(fog.color.accept(this, ""));

        result.append(nl()).append(indent).append(INDENT);
        result.append("fogType \"LINEAR\"");

        if (fog.density.value != 0.0) {
            result.append(nl()).append(indent).append(INDENT);
            result.append("visibilityRange ");
            result.append(2.0 / fog.density.value);
        }

        result.append(nl()).append(indent);
        result.append('}');

        return result.toString();
    }

    @Override
    public String visit(Sun sun, String indent) {

        StringBuilder result = new StringBuilder();

        result.append(indent);
        result.append("DirectionalLight {");

        result.append(nl()).append(indent).append(INDENT);
        result.append("color ");
        result.append(sun.color.accept(this, ""));

        result.append(nl()).append(indent).append(INDENT);
        result.append("intensity 0.75");

        result.append(nl()).append(indent).append(INDENT);
        result.append("direction ");
        result.append(Vector.anti(sun.direction).accept(this, ""));

        result.append(nl()).append(indent);
        result.append('}');

        return result.toString();
    }

    @Override
    public String visit(Bounding bounding, String indent) {

        StringBuilder result = new StringBuilder();

        Iterator<Visitable> visitables = bounding.visitables.iterator();
        while (visitables.hasNext()) {
            result.append(nl());
            result.append(visitables.next().accept(this, indent));
        }

        return result.toString();
    }

    @Override
    public String visit(Triangle triangle, String indent) {

        StringBuilder result = new StringBuilder();

        result.append(indent);
        result.append("Shape {");

        result.append(nl());
        result.append(triangle.parameters.accept(this, indent + INDENT));

        result.append(nl()).append(indent).append(INDENT);
        result.append("geometry IndexedFaceSet {");
        result.append(nl()).append(indent).append(INDENT).append(INDENT);
        result.append("solid FALSE");
        result.append(nl()).append(indent).append(INDENT).append(INDENT);
        result.append("coord Coordinate {");
        result.append(nl()).append(indent).append(INDENT).append(INDENT);
        result.append(INDENT);
        result.append("point [");
        result.append(nl()).append(indent).append(INDENT).append(INDENT);
        result.append(INDENT).append(INDENT);
        result.append(triangle.x.accept(this, ""));
        result.append(", # 0");
        result.append(nl()).append(indent).append(INDENT).append(INDENT);
        result.append(INDENT).append(INDENT);
        result.append(triangle.y.accept(this, ""));
        result.append(", # 1");
        result.append(nl()).append(indent).append(INDENT).append(INDENT);
        result.append(INDENT).append(INDENT);
        result.append(triangle.z.accept(this, ""));
        result.append(" # 2");
        result.append(nl()).append(indent).append(INDENT).append(INDENT);
        result.append(INDENT);
        result.append(']');
        result.append(nl()).append(indent).append(INDENT).append(INDENT);
        result.append('}');
        result.append(nl()).append(indent).append(INDENT).append(INDENT);
        result.append("coordIndex [ 0, 1, 2, 0, -1 ]");
        result.append(nl()).append(indent).append(INDENT);
        result.append('}');

        result.append(nl()).append(indent);
        result.append('}');

        return result.toString();
    }

    @Override
    public String visit(Sphere sphere, String indent) {

        StringBuilder result = new StringBuilder();

        result.append(indent);
        result.append("Transform {");

        result.append(nl()).append(indent).append(INDENT);
        result.append("translation ");
        result.append(sphere.center.accept(this, ""));

        result.append(nl()).append(indent).append(INDENT);
        result.append("children Shape {");

        result.append(nl());
        result.append(sphere.parameters.accept(this, indent + INDENT + INDENT));

        result.append(nl()).append(indent).append(INDENT).append(INDENT);
        result.append("geometry Sphere { radius ");
        result.append(sphere.radius.accept(this, ""));
        result.append(" }");

        result.append(nl()).append(indent).append(INDENT);
        result.append('}');

        result.append(nl()).append(indent);
        result.append('}');

        return result.toString();
    }

    @Override
    public String visit(Plane plane, String indent) {

        Vector c = Vector.mult(1.0 / 3.0,
                Vector.add(plane.x, Vector.add(plane.y, plane.z)));

        Vector rx = Vector.mult(10000.0, Vector.sub(plane.x, c));
        Vector ry = Vector.mult(10000.0, Vector.sub(plane.y, c));
        Vector rz = Vector.mult(10000.0, Vector.sub(plane.z, c));

        Triangle triangle = new Triangle();
        triangle.= Vector.add(c, rx);
        triangle.= Vector.add(c, ry);
        triangle.= Vector.add(c, rz);

        return triangle.accept(this, indent);
    }

    @Override
    public String visit(Defaults defaults, String indent) {

        int globalDefaultsSize = this.defaults.parameters.visitables.size();
        int size = defaults.parameters.visitables.size();

        for (int i = 0; i < Math.min(globalDefaultsSize, size); i++) {
            Visitable v = defaults.parameters.visitables.get(i);
            this.defaults.parameters.visitables.set(i, v);
        }

        return "";
    }

    @Override
    public String visit(Parameters parameters, String indent) {

        StringBuilder result = new StringBuilder();

        int globalDefaultsSize = this.defaults.parameters.visitables.size();
        int parametersSize = parameters.visitables.size();
        // Paramter auf Default setzen
        Parameters params = new Parameters();
        for (int i = 0; i < globalDefaultsSize; i++) {
            Visitable v = this.defaults.parameters.visitables.get(i);
            params.visitables.add(v);
        }
        // Default-Paramter mit parameters überschreiben
        for (int i = 0; i < Math.min(globalDefaultsSize, parametersSize); i++) {
            Visitable v = parameters.visitables.get(i);
            params.visitables.set(i, v);
        }
        int size = params.visitables.size();

        result.append(indent);
        result.append("appearance Appearance { ");
        result.append(nl()).append(indent).append(INDENT);
        result.append("material Material {");
        if (0 < size) {
            result.append(nl()).append(indent).append(INDENT).append(INDENT);
            result.append("diffuseColor ");
            result.append(params.visitables.get(0).accept(this, ""));
        }
        if (1 < size) {
            result.append(nl()).append(indent).append(INDENT).append(INDENT);
            result.append("emissiveColor ");
            result.append(params.visitables.get(1).accept(this, ""));
        }
        if (2 < size) {
            result.append(nl()).append(indent).append(INDENT).append(INDENT);
            result.append("specularColor ");
            result.append(params.visitables.get(2).accept(this, ""));
            result.append(params.visitables.get(2).accept(this, " "));
            result.append(params.visitables.get(2).accept(this, " "));
        }
        if (3 < size) {
            result.append(nl()).append(indent).append(INDENT).append(INDENT);
            result.append("shininess ");
            result.append(params.visitables.get(3).accept(this, ""));
        }
        if (4 < size) {
            result.append(nl()).append(indent).append(INDENT).append(INDENT);
            result.append("# mirror/reflection is not supported by VRML");
        }
        result.append(nl()).append(indent).append(INDENT);
        result.append('}');
        result.append(nl()).append(indent);
        result.append('}');

        return result.toString();
    }

    @Override
    public String visit(Vector vector, String indent) {

        StringBuilder result = new StringBuilder();

        result.append(vector.x.accept(this, indent));
        result.append(vector.y.accept(this, " "));
        result.append(vector.z.accept(this, " "));

        return result.toString();
    }

    @Override
    public String visit(Real real, String indent) {

        return indent + real.value;
    }
}
Anwendung Anwendung der VRMLCode-Klasse
Folgende Anwendung nutzt die Klasse VRMLCode und wandelt ein gegebenes Tinyray-Programm in ein VRML-Programm um.
UseVRMLCode.java
package tinyray;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

import tinyray.frontend.ParseException;
import tinyray.frontend.Parser;
import tinyray.frontend.Scanner;
import tinyray.language.LanguageKit;
import tinyray.language.Tinyray;
import tinyray.language.VRMLCode;
import tinyray.language.Visitable;

/**
 * Die Klasse UseVRMLCode generiert aus einem Tinyray-Code
 * einen entsprechenden VRML-Code
 * (siehe http://www.web3d.org/x3d/specifications/#vrml97).
 */

public class UseVRMLCode {

    /**
     * Das Hauptprogramm, welches aus einem Tinyray-Code einen entsprechenden
     * VRML-Code generiert.
     * Das Ergebnis wird auf der Konsole ausgegeben (System.out).
     * @param arguments Die Aufrufargumente.
     *        Das erste Argument gibt den Dateinamen der Tinyray-Datei an.
     *        Ist das erste Argument nicht gesetzt, erhält der Benutzer
     *        einen kurzen Hilfetext.
     */

    public static void main(String[] arguments) {

        // Mindestens ein Argument erforderlich: <Dateiname>
        if (arguments.length > 0) {

            try {
                // Der Scanner erhält den Tinyray-Code als Stream.
                Scanner scanner =
                    new Scanner(new FileInputStream(arguments[0]));

                // Der Parser erhält den Scanner und eine konkreten Fabrik
                // (hier LanguageKit).
                Parser<Visitable, Tinyray> parser =
                    new Parser<Visitable, Tinyray>(scanner, new LanguageKit());

                // Der Parse-Vorgang bringt einen Syntaxbaum hervor.
                // Die einzelnen Knoten des Syntaxbaumes werden automatisch
                // von der konkreten Fabrik "LanguageKit" erzeugt.
                Tinyray tinyray = parser.parse();

                // Der Syntaxbaum besteht aus besuchbaren Knoten (accept).
                // VRMLCode ist ein Besucher, der die Wurzel des
                // Syntaxbaums besucht und dabei einen entsprechenden
                // VRML-Code generiert.
                String vrmlcode = tinyray.accept(new VRMLCode(), "");

                // Ausgabe des generierten VRML-Codes.
                System.out.println(vrmlcode);

            } catch (ParseException e) {
                // Fehlermeldung, falls gegebener Tinyray-Code fehlerhaft.
                System.err.println(e.getMessage());
            } catch (FileNotFoundException e) {
                // Fehlermeldung, falls das erste Argument keine Datei benennt.
                System.err.println(e.getMessage());
            }

        } else {
            // Kurzhilfe, falls Aufruf ohne Argument.
            System.out.println(usage());
        }
    }

    /**
     * Erläuterung zum korrekten Aufruf (Kurzhilfe).
     * @return Die Kurzhilfe als Zeichenkette.
     */

    public static String usage() {
        String result = "";
        result += "java tinyray/UseVRMLCode <TinyrayDatei>\r\n";
        result += "\r\nBeispiele:\r\n";
        result += " java tinyray/UseVRMLCode MyScene.tinyray\r\n";
        result += " java tinyray/UseVRMLCode Test01.txt\r\n";
        result += "\r\nHinweis:\r\n";
        result += " Mindestens JRE (java-1.6.0) erforderlich.\r\n";
        return result;
    }
}
Ein Programmaufruf ohne Aufrufparameter zeigt dem Aufrufenden die Programmkurzhilfe (usage).
java UseVRMLCode
java tinyray/UseVRMLCode <TinyrayDatei>

Beispiele:
 java tinyray/UseVRMLCode MyScene.tinyray
 java tinyray/UseVRMLCode Test01.txt

Hinweis:
 Mindestens JRE (java-1.6.0) erforderlich.