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 [ DRUCK , 2004 , 2005 , 2006 , 2007 , 2008 , 2009 ] Tinyray-PovRayCode Tinyray-GlutCCode Tinyray-VRMLCode > > Tinyray-Raytracer / Tinyray-Wallpapers > > / Java C/C++ POV-Ray LaTeX > / Künstliche Intelligenz > Schach Privates / Inhalt >
Tinyray-PovRayCode
PovRayCode erzeugt aus einem Tinyray-Programm ein POV-Ray-Programm.
POV-Ray Über POV-Ray
Zielvorstellung
Ein Tinyray-Quellprogramm soll in ein POV-Ray-Programm übersetzt werden.
Was ist denn eigentlich POV-Ray?
POV-Ray steht für „Persistence of Vision Ray Tracer”.

Im Gegensatz zu Tinyray ist POV-Ray ein besonders fortschrittlicher Raytracer, welcher unter www.povray.org heruntergeladen werden kann.
Implementierung Implementierung der PovRayCode-Klasse
Die Java-Klasse PovRayCode ist hier als Visitor realisiert.
PovRayCode.java
package tinyray.language;

import java.util.Iterator;

/**
 * Die Klasse PovRayCode implementiert einen Besucher (Visitor),
 * der aus einem Syntaxbaum, der mit Hilfe von LanguageKit erzeugt ist,
 * einen POV-Ray-Code erzeugt.
 */

public class PovRayCode implements Visitor<String, String> {

    // Zeichenkette für eine neue Zeile.
    private final static String NEWLINE = "\r\n";

    // Zeichenkette für das Einrücken vorgesehen,
    // um den Ausgabe-Code etwas lesbarer zu gestalten.
    private final static String INDENT = "\t";

    // Globale Parameter.
    private Defaults defaults;

    /**
     * Initialisiert den PovRayCode-Visitor mit der Voreinstellung der
     * globalen Parameter (Defaults).
     */

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

    /**
     * Besucht einen besuchbaren Tinyray-Knoten und generiert einen
     * entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
     * und gibt diesen Code als Zeichenkette zurück.
     * @param tinyray Der besuchbare Knoten.
     * @param indent Die Einrückung.
     * @return Der generierte POV-Ray-Code.
     */

    public String visit(Tinyray tinyray, String indent) {
        String result = "";
        // Kommentar
        result += indent;
        result += "// Automatisch generierter POV-Ray-Code (POV-Ray 3.6.1).";
        result += NEWLINE + indent;
        result += "// Herkunft: Tinyray (http://www.stefan-baur.de)";
        result += NEWLINE;
        result += NEWLINE;
        // Ambience
        result += NEWLINE;
        result += tinyray.ambience.accept(this, indent);
        result += NEWLINE;
        // Camera
        result += NEWLINE;
        result += tinyray.camera.accept(this, indent);
        result += NEWLINE;
        // Background
        result += NEWLINE;
        result += tinyray.background.accept(this, indent);
        result += NEWLINE;
        // Fog
        if (tinyray.fog.density.value > 0.0) {
            result += NEWLINE;
            result += tinyray.fog.accept(this, indent);
            result += NEWLINE;
        }
        // Suns
        Iterator<Sun> suns = tinyray.suns.iterator();
        while (suns.hasNext()) {
            result += NEWLINE;
            result += suns.next().accept(this, indent);
            result += NEWLINE;
        }
        // Geos
        Iterator<Visitable> visitables = tinyray.visitables.iterator();
        while (visitables.hasNext()) {
            result += NEWLINE;
            result += visitables.next().accept(this, indent);
            result += NEWLINE;
        }
        // Sourcecode
        result += NEWLINE + indent;
        result += "// Quelle: Tinyray-Code";
        result += NEWLINE + indent;
        result += "//";
        result += NEWLINE;
        result += tinyray.accept(new PrettyPrint(), indent + "// ");
        result += NEWLINE;
        return result;
    }

    /**
     * Besucht einen besuchbaren Camera-Knoten und generiert einen
     * entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
     * und gibt diesen Code als Zeichenkette zurück.
     * @param camera Der besuchbare Knoten.
     * @param indent Die Einrückung.
     * @return Der generierte POV-Ray-Code.
     */

    public String visit(Camera camera, String indent) {
        String result = "";
        result += indent;
        result += "camera {";
        result += NEWLINE + indent + INDENT;
        result += "perspective";
        result += NEWLINE + indent + INDENT;
        result += "location ";
        result += camera.location.accept(this, "");
        result += NEWLINE + indent + INDENT;
        result += "look_at ";
        result += camera.lookAt.accept(this, "");
        result += NEWLINE + indent + INDENT;
        result += "up -y";
        result += NEWLINE + indent + INDENT;
        result += "sky ";
        result += camera.up.accept(this, "");
        result += NEWLINE + indent + INDENT;
        result += "angle 40.0 // eigentlich 30.0, aber 40.0 passt besser!?";
        result += NEWLINE + indent;
        result += "}";
        return result;
    }

    /**
     * Besucht einen besuchbaren Background-Knoten und generiert einen
     * entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
     * und gibt diesen Code als Zeichenkette zurück.
     * @param background Der besuchbare Knoten.
     * @param indent Die Einrückung.
     * @return Der generierte POV-Ray-Code.
     */

    public String visit(Background background, String indent) {
        String result = "";
        result += indent;
        result += "background {";
        result += NEWLINE + indent + INDENT;
        result += "color rgb ";
        result += background.color.accept(this, "");
        result += NEWLINE + indent;
        result += "}";
        return result;
    }

    /**
     * Besucht einen besuchbaren Ambience-Knoten und generiert einen
     * entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
     * und gibt diesen Code als Zeichenkette zurück.
     * @param ambience Der besuchbare Knoten.
     * @param indent Die Einrückung.
     * @return Der generierte POV-Ray-Code.
     */

    public String visit(Ambience ambience, String indent) {
        String result = "";
        result += indent;
        result += "global_settings {";
        result += NEWLINE + indent + INDENT;
        result += "ambient_light rgb ";
        result += ambience.color.accept(this, "");
        result += NEWLINE + indent;
        result += "}";
        return result;
    }

    /**
     * Besucht einen besuchbaren Fog-Knoten und generiert einen
     * entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
     * und gibt diesen Code als Zeichenkette zurück.
     * @param fog Der besuchbare Knoten.
     * @param indent Die Einrückung.
     * @return Der generierte POV-Ray-Code.
     */

    public String visit(Fog fog, String indent) {
        String result = "";
        result += indent;
        result += "fog {";
        result += NEWLINE + indent + INDENT;
        result += "fog_type 1";
        result += NEWLINE + indent + INDENT;
        Real distance = new Real(1.0 / fog.density.value);
        result += "distance ";
        result += distance.accept(this, "");
        result += NEWLINE + indent + INDENT;
        result += "color rgb ";
        result += fog.color.accept(this, "");
        result += NEWLINE + indent;
        result += "}";
        return result;
    }

    /**
     * Besucht einen besuchbaren Sun-Knoten und generiert einen
     * entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
     * und gibt diesen Code als Zeichenkette zurück.
     * @param sun Der besuchbare Knoten.
     * @param indent Die Einrückung.
     * @return Der generierte POV-Ray-Code.
     */

    public String visit(Sun sun, String indent) {
        String result = "";
        result += indent;
        result += "light_source {";
        result += NEWLINE + indent + INDENT;
        Vector location = Vector.mult(10000.0, sun.direction);
        result += location.accept(this, "");
        result += ", ";
        result += sun.color.accept(this, "");
        result += NEWLINE + indent + INDENT;
        result += "parallel";
        result += NEWLINE + indent + INDENT;
        result += "point_at ";
        result += (new Vector()).accept(this, "");
        result += NEWLINE + indent;
        result += "}";
        return result;
    }

    /**
     * Besucht einen besuchbaren Bounding-Knoten und generiert einen
     * entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
     * und gibt diesen Code als Zeichenkette zurück.
     * @param bounding Der besuchbare Knoten.
     * @param indent Die Einrückung.
     * @return Der generierte POV-Ray-Code.
     */

    public String visit(Bounding bounding, String indent) {
        String result = "";
        Iterator<Visitable> visitables = bounding.visitables.iterator();
        while (visitables.hasNext()) {
            result += NEWLINE;
            result += visitables.next().accept(this, indent);
            result += NEWLINE;
        }
        return result;
    }

    /**
     * Besucht einen besuchbaren Triangle-Knoten und generiert einen
     * entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
     * und gibt diesen Code als Zeichenkette zurück.
     * @param triangle Der besuchbare Knoten.
     * @param indent Die Einrückung.
     * @return Der generierte POV-Ray-Code.
     */

    public String visit(Triangle triangle, String indent) {
        String result = "";
        result += indent;
        result += "triangle {";
        result += NEWLINE;
        result += triangle.x.accept(this, indent + INDENT);
        result += ", ";
        result += triangle.y.accept(this, "");
        result += ", ";
        result += triangle.z.accept(this, "");
        result += NEWLINE;
        result += triangle.parameters.accept(this, indent + INDENT);
        result += NEWLINE + indent;
        result += "}";
        return result;
    }

    /**
     * Besucht einen besuchbaren Sphere-Knoten und generiert einen
     * entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
     * und gibt diesen Code als Zeichenkette zurück.
     * @param sphere Der besuchbare Knoten.
     * @param indent Die Einrückung.
     * @return Der generierte POV-Ray-Code.
     */

    public String visit(Sphere sphere, String indent) {
        String result = "";
        result += indent;
        result += "sphere {";
        result += NEWLINE;
        result += sphere.center.accept(this, indent + INDENT);
        result += ", ";
        result += sphere.radius.accept(this, "");
        result += NEWLINE;
        result += sphere.parameters.accept(this, indent + INDENT);
        result += NEWLINE + indent;
        result += "}";
        return result;
    }

    /**
     * Besucht einen besuchbaren Plane-Knoten und generiert einen
     * entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
     * und gibt diesen Code als Zeichenkette zurück.
     * @param plane Der besuchbare Knoten.
     * @param indent Die Einrückung.
     * @return Der generierte POV-Ray-Code.
     */

    public String visit(Plane plane, String indent) {
        String result = "";
        result += indent;
        result += "plane {";
        result += NEWLINE;
        Vector normal0 = Vector.normal0(plane.x, plane.y, plane.z);
        result += normal0.accept(this, indent + INDENT);
        result += ", ";
        Real distance = new Real(-Vector.dot(normal0, Vector.anti(plane.x)));
        result += distance.accept(this, "");
        result += NEWLINE;
        result += plane.parameters.accept(this, indent + INDENT);
        result += NEWLINE + indent;
        result += "}";
        return result;
    }

    /**
     * Besucht einen besuchbaren Defaults-Knoten und generiert einen
     * entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
     * und gibt diesen Code als Zeichenkette zurück.
     * @param defaults Der besuchbare Knoten.
     * @param indent Die Einrückung.
     * @return Der generierte POV-Ray-Code.
     */

    public String visit(Defaults defaults, String indent) {
        String result = "";
        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 result;
    }

    /**
     * Besucht einen besuchbaren Parameters-Knoten und generiert einen
     * entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
     * und gibt diesen Code als Zeichenkette zurück.
     * @param parameters Der besuchbare Knoten.
     * @param indent Die Einrückung.
     * @return Der generierte POV-Ray-Code.
     */

    public String visit(Parameters parameters, String indent) {
        String result = "";

        int globalDefaultsSize = this.defaults.parameters.visitables.size();
        int parametersSize = parameters.visitables.size();
        // params 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);
        }
        // params 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();

        // texture einleiten
        result += indent;
        result += "texture {";
        if (0 < size) {
            result += NEWLINE + indent + INDENT;
            result += "pigment {";
            result += NEWLINE + indent + INDENT + INDENT;
            result += "color rgb ";
            result += params.visitables.get(0).accept(this, "");
            result += NEWLINE + indent + INDENT;
            result += "}";
        }
        if (1 < size) {
            // finish einleiten
            result += NEWLINE + indent + INDENT;
            result += "finish {";
            result += NEWLINE + indent + INDENT + INDENT;
            result += "ambient rgb ";
            result += params.visitables.get(1).accept(this, "");
        }
        if (2 < size) {
            result += NEWLINE + indent + INDENT + INDENT;
            result += "phong ";
            result += params.visitables.get(2).accept(this, "");
        }
        if (3 < size) {
            result += NEWLINE + indent + INDENT + INDENT;
            result += "phong_size ";
            result += params.visitables.get(3).accept(this, "");
        }

        if (4 < size) {
            result += NEWLINE + indent + INDENT + INDENT;
            result += "reflection ";
            result += params.visitables.get(4).accept(this, "");
        }
        if (1 < size) {
            // finish abschließen
            result += NEWLINE + indent + INDENT;
            result += "}"; // finish
        }
        // texture abschließen
        result += NEWLINE + indent;
        result += "}";
        return result;
    }

    /**
     * Besucht einen besuchbaren Vector-Knoten und generiert einen
     * entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
     * und gibt diesen Code als Zeichenkette zurück.
     * @param vector Der besuchbare Knoten.
     * @param indent Die Einrückung.
     * @return Der generierte POV-Ray-Code.
     */

    public String visit(Vector vector, String indent) {
        String result = "";
        result += indent;
        result += "<";
        result += vector.x.accept(this, "");
        result += ", ";
        result += vector.y.accept(this, "");
        result += ", ";
        result += vector.z.accept(this, "");
        result += ">";
        return result;
    }

    /**
     * Besucht einen besuchbaren Real-Knoten und generiert einen
     * entsprechenden POV-Ray-Code mit einer bestimmten Einrückung
     * und gibt diesen Code als Zeichenkette zurück.
     * @param real Der besuchbare Knoten.
     * @param indent Die Einrückung.
     * @return Der generierte POV-Ray-Code.
     */

    public String visit(Real real, String indent) {
        String result = "";
        result += indent;
        result += new Float(real.value).toString();
        return result;
    }
}
Anwendung Anwendung der PovRayCode-Klasse
Folgende Anwendung nutzt die Klasse PovRayCode und wandelt ein gegebenes Tinyray-Programm in ein POV-Ray-Programm um.
UsePovRayCode.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.PovRayCode;
import tinyray.language.Tinyray;
import tinyray.language.Visitable;

/**
 * Die Klasse UsePovRayCode generiert aus einem Tinyray-Code
 * einen POV-Ray-Code (siehe http://www.povray.org/).
 */

public class UsePovRayCode {

    /**
     * Das Hauptprogramm, welches aus einem Tinyray-Code einen POV-Ray-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).
                // PovRayCode ist ein Besucher, der die Wurzel des
                // Syntaxbaums besucht und dabei einen entsprechenden
                // POV-Ray-Code (povraycode) generiert.
                String povraycode = tinyray.accept(new PovRayCode(), "");

                // Ausgabe des generierten POV-Ray-Codes.
                System.out.println(povraycode);

            } 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/UsePovRayCode <TinyrayDatei>\r\n";
        result += "\r\nBeispiele:\r\n";
        result += " java tinyray/UsePovRayCode MyScene.tinyray\r\n";
        result += " java tinyray/UsePovRayCode 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 UsePovRayCode
java tinyray/UsePovRayCode <TinyrayDatei>

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

Hinweis:
 Mindestens JRE (java-1.5.0) erforderlich.