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 [ DRUCK , 2004 , 2005 , 2006 , 2007 , 2008 , 2009 ] Tinyray-DotCode Tinyray-PovRayCode Tinyray-GlutCCode Tinyray-VRMLCode > > Tinyray-Raytracer / Tinyray-Wallpapers > > / Java C/C++ POV-Ray LaTeX > / Künstliche Intelligenz > Schach Privates / Inhalt >
Tinyray-DotCode
DotCode erzeugt aus einem Tinyray-Programm ein Dot-Programm von graphviz.
Dot Über Dot
Zielvorstellung
Ein Tinyray-Quellprogramm soll in ein Dot-Programm übersetzt werden.
Was ist denn eigentlich Dot?
Dot ist eine Anwendung zur Visualisierung von Grafen. Diese Dot-Anwendung können Sie unter www.graphviz.org herunterladen.
Implementierung Implementierung der DotCode-Klasse
Die Java-Klasse DotCode ist hier als Visitor realisiert.
DotCode.java
package tinyray.language;

import java.util.Iterator;

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

public class DotCode implements Visitor<String, String> {

    private final static String NEWLINE = "\r\n";
    private final static String INDENT = "\t";
    private final static String BREAK = NEWLINE + INDENT;
    private final static String ARROW = " -> ";
    private final static String TERMINATOR = ";";
    private final static String NODE = "node";
    private final static String EDGE = "edge";

    private boolean compact;
    private int indexer;
    private boolean color;

    private String label(String string) {
        return "[label=\"" + string + "\"]";
    }

    public DotCode() {
        this(false);
    }

    public DotCode(boolean compact) {
        this.compact = compact;
        this.indexer = 0;

        this.color = false;
    }

    public String visit(Tinyray tinyray, String parent) {
        String node = NODE + indexer++;
        String result = "";
        // Header
        result += "// Automatisch generierter Dot-Code";
        result += NEWLINE;
        result += "// $ dot -Tpng mein.dot -o mein.png";
        result += NEWLINE;
        result += "// Herkunft: Tinyray (http://www.stefan-baur.de)";
        result += NEWLINE;
        result += NEWLINE;
        // Dot-Graph
        result += "digraph TinyrayGraph {";
        // Dot-Parameter
        result += NEWLINE;
        result += BREAK + "graph[rankdir=LR]" + TERMINATOR;
        result += BREAK + "graph[ranksep=0.3]" + TERMINATOR;
        result += BREAK + "edge[fontname=\"Arial\"]" + TERMINATOR;
        result += BREAK + "edge[fontsize=11]" + TERMINATOR;
        result += BREAK + "edge[fontcolor=\"#333333\"]" + TERMINATOR;
        result += BREAK + "edge[color=\"#333333\"]" + TERMINATOR;
        result += BREAK + "node[height=0.08]" + TERMINATOR;
        result += BREAK + "node[fontname=\"Arial\"]" + TERMINATOR;
        result += BREAK + "node[fontsize=10]" + TERMINATOR;
        result += BREAK + "node[fontcolor=\"#333333\"]" + TERMINATOR;
        result += BREAK + "node[color=\"#333333\"]" + TERMINATOR;
        result += NEWLINE;
        // Tinyray-Knoten Dot-Code
        result += BREAK + node + this.label("Tinyray") + TERMINATOR;
        result += BREAK + node + TERMINATOR;
        // Besuche camera
        result += NEWLINE;
        result += BREAK + EDGE + this.label("") + TERMINATOR;
        result += tinyray.camera.accept(this, node);
        // Besuche ambience
        result += NEWLINE;
        result += BREAK + EDGE + this.label("") + TERMINATOR;
        result += tinyray.ambience.accept(this, node);
        // Besuche background
        result += NEWLINE;
        result += BREAK + EDGE + this.label("") + TERMINATOR;
        result += tinyray.background.accept(this, node);
        // Besuche fog
        result += NEWLINE;
        result += BREAK + EDGE + this.label("") + TERMINATOR;
        result += tinyray.fog.accept(this, node);
        // Besuche suns
        Iterator<Sun> suns = tinyray.suns.iterator();
        while (suns.hasNext()) {
            result += NEWLINE;
            result += BREAK + EDGE + this.label("") + TERMINATOR;
            result += suns.next().accept(this, node);
        }
        // Besuche Defaults und Geoobjekte
        Iterator<Visitable> visitables = tinyray.visitables.iterator();
        while (visitables.hasNext()) {
            result += NEWLINE;
            result += BREAK + EDGE + this.label("") + TERMINATOR;
            result += visitables.next().accept(this, node);
        }
        result += NEWLINE;
        result += "}";
        // Sourcecode
        result += NEWLINE;
        result += NEWLINE;
        result += "// Quelle: Tinyray-Code";
        result += NEWLINE;
        result += "//";
        result += NEWLINE;
        result += tinyray.accept(new PrettyPrint(), "// ");
        result += NEWLINE;
        return result;
    }

    public String visit(Camera camera, String parent) {
        String node = NODE + indexer++;
        String result = "";
        // Camera-Knoten Dot-Code
        result += BREAK + node + this.label("Camera") + TERMINATOR;
        result += BREAK + parent + ARROW + node + TERMINATOR;
        // Besuche location
        result += NEWLINE;
        result += BREAK + EDGE + this.label("location") + TERMINATOR;
        result += camera.location.accept(this, node);
        // Besuche lookAt
        result += NEWLINE;
        result += BREAK + EDGE + this.label("look at") + TERMINATOR;
        result += camera.lookAt.accept(this, node);
        // Besuche up
        result += NEWLINE;
        result += BREAK + EDGE + this.label("up") + TERMINATOR;
        result += camera.up.accept(this, node);
        return result;
    }

    public String visit(Background background, String parent) {
        String node = NODE + indexer++;
        String result = "";
        // Background-Knoten Dot-Code
        result += BREAK + node + this.label("Background") + TERMINATOR;
        result += BREAK + parent + ARROW + node + TERMINATOR;
        // Besuche color
        result += NEWLINE;
        result += BREAK + EDGE + this.label("color") + TERMINATOR;
        this.color = true;
        result += background.color.accept(this, node);
        return result;
    }

    public String visit(Ambience ambience, String parent) {
        String node = NODE + indexer++;
        String result = "";
        // Ambience-Knoten Dot-Code
        result += BREAK + node + this.label("Ambience") + TERMINATOR;
        result += BREAK + parent + ARROW + node + TERMINATOR;
        // Besuche color
        result += NEWLINE;
        result += BREAK + EDGE + this.label("color") + TERMINATOR;
        this.color = true;
        result += ambience.color.accept(this, node);
        return result;
    }

    public String visit(Fog fog, String parent) {
        String node = NODE + indexer++;
        String result = "";
        // Fog-Knoten Dot-Code
        result += BREAK + node + this.label("Fog") + TERMINATOR;
        result += BREAK + parent + ARROW + node + TERMINATOR;
        // Besuche color
        result += NEWLINE;
        result += BREAK + EDGE + this.label("color") + TERMINATOR;
        this.color = true;
        result += fog.color.accept(this, node);
        // Besuche density
        result += NEWLINE;
        result += BREAK + EDGE + this.label("density") + TERMINATOR;
        result += fog.density.accept(this, node);
        return result;
    }

    public String visit(Defaults defaults, String parent) {
        String node = NODE + indexer++;
        String result = "";
        // Defaults-Knoten Dot-Code
        result += BREAK + node + this.label("Defaults") + TERMINATOR;
        result += BREAK + parent + ARROW + node + TERMINATOR;
        // Besuche parameters
        result += NEWLINE;
        result += BREAK + EDGE + this.label("") + TERMINATOR;
        result += defaults.parameters.accept(this, node);
        return result;
    }

    public String visit(Sun sun, String parent) {
        String node = NODE + indexer++;
        String result = "";
        // Sun-Knoten Dot-Code
        result += BREAK + node + this.label("Sun") + TERMINATOR;
        result += BREAK + parent + ARROW + node + TERMINATOR;
        // Besuche direction
        result += NEWLINE;
        result += BREAK + EDGE + this.label("direction") + TERMINATOR;
        result += sun.direction.accept(this, node);
        // Besuche color
        result += NEWLINE;
        result += BREAK + EDGE + this.label("color") + TERMINATOR;
        this.color = true;
        result += sun.color.accept(this, node);
        return result;
    }

    public String visit(Bounding bounding, String parent) {
        String node = NODE + indexer++;
        String result = "";
        // Bounding-Knoten Dot-Code
        result += BREAK + node + this.label("Bounding") + TERMINATOR;
        result += BREAK + parent + ARROW + node + TERMINATOR;
        // Besuche alle besuchbaren Objekte von bounding
        Iterator<Visitable> visitables = bounding.visitables.iterator();
        while (visitables.hasNext()) {
            result += NEWLINE;
            result += BREAK + EDGE + this.label("") + TERMINATOR;
            result += visitables.next().accept(this, node);
        }
        return result;
    }

    public String visit(Triangle triangle, String parent) {
        String node = NODE + indexer++;
        String result = "";
        // Triangle-Knoten Dot-Code
        result += BREAK + node + this.label("Triangle") + TERMINATOR;
        result += BREAK + parent + ARROW + node + TERMINATOR;
        // Besuche x
        result += NEWLINE;
        result += BREAK + EDGE + this.label("x") + TERMINATOR;
        result += triangle.x.accept(this, node);
        // Besuche y
        result += NEWLINE;
        result += BREAK + EDGE + this.label("y") + TERMINATOR;
        result += triangle.y.accept(this, node);
        // Besuche z
        result += NEWLINE;
        result += BREAK + EDGE + this.label("z") + TERMINATOR;
        result += triangle.z.accept(this, node);
        // Besuche parameters
        if (triangle.parameters.visitables.size() > 0) {
            result += NEWLINE;
            result += BREAK + EDGE + this.label("") + TERMINATOR;
            result += triangle.parameters.accept(this, node);
        }
        return result;
    }

    public String visit(Sphere sphere, String parent) {
        String node = NODE + indexer++;
        String result = "";
        // Sphere-Knoten Dot-Code
        result += BREAK + node + this.label("Sphere") + TERMINATOR;
        result += BREAK + parent + ARROW + node + TERMINATOR;
        // Besuche center
        result += NEWLINE;
        result += BREAK + EDGE + this.label("center") + TERMINATOR;
        result += sphere.center.accept(this, node);
        // Besuche radius
        result += NEWLINE;
        result += BREAK + EDGE + this.label("radius") + TERMINATOR;
        result += sphere.radius.accept(this, node);
        // Besuche parameters
        if (sphere.parameters.visitables.size() > 0) {
            result += NEWLINE;
            result += BREAK + EDGE + this.label("") + TERMINATOR;
            result += sphere.parameters.accept(this, node);
        }
        return result;
    }

    public String visit(Plane plane, String parent) {
        String node = NODE + indexer++;
        String result = "";
        // Plane-Knoten Dot-Code
        result += BREAK + node + this.label("Plane") + TERMINATOR;
        result += BREAK + parent + ARROW + node + TERMINATOR;
        // Besuche x
        result += NEWLINE;
        result += BREAK + EDGE + this.label("x") + TERMINATOR;
        result += plane.x.accept(this, node);
        // Besuche y
        result += NEWLINE;
        result += BREAK + EDGE + this.label("y") + TERMINATOR;
        result += plane.y.accept(this, node);
        // Besuche z
        result += NEWLINE;
        result += BREAK + EDGE + this.label("z") + TERMINATOR;
        result += plane.z.accept(this, node);
        // Besuche parameters
        if (plane.parameters.visitables.size() > 0) {
            result += NEWLINE;
            result += BREAK + EDGE + this.label("") + TERMINATOR;
            result += plane.parameters.accept(this, node);
        }
        return result;
    }

    public String visit(Parameters parameters, String parent) {
        String node = NODE + indexer++;
        String result = "";
        // Parameters-Knoten Dot-Code
        result += BREAK + node + this.label("Parameters") + TERMINATOR;
        result += BREAK + parent + ARROW + node + TERMINATOR;
        // Besuche 1. Parameter, falls vorhanden
        if (parameters.visitables.size() > 0) {
            result += NEWLINE;
            result += BREAK + EDGE + this.label("diffuse") + TERMINATOR;
            this.color = true;
            result += parameters.visitables.get(0).accept(this, node);
        }
        // Besuche 2. Parameter, falls vorhanden
        if (parameters.visitables.size() > 1) {
            result += NEWLINE;
            result += BREAK + EDGE + this.label("ambient") + TERMINATOR;
            this.color = true;
            result += parameters.visitables.get(1).accept(this, node);
        }
        // Besuche 3. Parameter, falls vorhanden
        if (parameters.visitables.size() > 2) {
            result += NEWLINE;
            result += BREAK + EDGE + this.label("specular") + TERMINATOR;
            result += parameters.visitables.get(2).accept(this, node);
        }
        // Besuche 4. Parameter, falls vorhanden
        if (parameters.visitables.size() > 3) {
            result += NEWLINE;
            result += BREAK + EDGE + this.label("shininess") + TERMINATOR;
            result += parameters.visitables.get(3).accept(this, node);
        }
        // Besuche 5. Parameter, falls vorhanden
        if (parameters.visitables.size() > 4) {
            result += NEWLINE;
            result += BREAK + EDGE + this.label("mirror") + TERMINATOR;
            result += parameters.visitables.get(4).accept(this, node);
        }
        return result;
    }

    public String visit(Vector vector, String parent) {
        String node = NODE + indexer++;
        String result = "";

        if (this.color) {
            // Hintergrundfarbe des Vector-Knotens ermitteln und setzen.
            int r = Math.min(Math.max((int)(vector.x.value * 255.0), 0), 255);
            int g = Math.min(Math.max((int)(vector.y.value * 255.0), 0), 255);
            int b = Math.min(Math.max((int)(vector.z.value * 255.0), 0), 255);
            String hexR = ((<= 0xF) ? "0" : "") + Integer.toHexString(r);
            String hexG = ((<= 0xF) ? "0" : "") + Integer.toHexString(g);
            String hexB = ((<= 0xF) ? "0" : "") + Integer.toHexString(b);
            String hexRGB = hexR + hexG + hexB;
            result += BREAK + node + "[style=filled]" + TERMINATOR;
            result += BREAK + node + "[fillcolor=\"#";
            result += hexRGB + "\"]" + TERMINATOR;
            // Vordergrundfarbe des Vector-Knotens setzen.
            if (+ g + b > 255) {
                result += BREAK + node + "[color=\"#333333\"]" + TERMINATOR;
                result += BREAK + node + "[fontcolor=\"#333333\"]" + TERMINATOR;
            } else {
                result += BREAK + node + "[color=\"#cccccc\"]" + TERMINATOR;
                result += BREAK + node + "[fontcolor=\"#cccccc\"]" + TERMINATOR;
            }
            // Farbe konsumiert.
            this.color = false;
        }
        // Vector-Knoten Dot-Code
        if (this.compact) {
            // Kurzfassung
            result += BREAK + node + "[shape=record]" + TERMINATOR;
            result += BREAK + node + "[label=\"{ Vector | { ";
            result += vector.x.value + " | ";
            result += vector.y.value + " | ";
            result += vector.z.value + " } }\"]" + TERMINATOR;
            result += BREAK + parent + ARROW + node + TERMINATOR;
        } else {
            // Langfassung
            result += BREAK + node + this.label("Vector") + TERMINATOR;
            result += BREAK + parent + ARROW + node + TERMINATOR;
            // Besuche x
            result += NEWLINE;
            result += BREAK + EDGE + this.label("x") + TERMINATOR;
            result += vector.x.accept(this, node);
            // Besuche y
            result += NEWLINE;
            result += BREAK + EDGE + this.label("y") + TERMINATOR;
            result += vector.y.accept(this, node);
            // Besuche z
            result += NEWLINE;
            result += BREAK + EDGE + this.label("z") + TERMINATOR;
            result += vector.z.accept(this, node);
        }
        return result;
    }

    public String visit(Real real, String parent) {
        String node = NODE + indexer++;
        String result = "";
        // Real-Knoten Dot-Code
        result += BREAK + node + "[shape=record]" + TERMINATOR;
        result += BREAK + node + "[label=\"{ Real | ";
        result += real.value + " }\"]" + TERMINATOR;
        result += BREAK + parent + ARROW + node + TERMINATOR;
        return result;
    }
}
Anwendung Anwendung der DotCode-Klasse
Folgende Anwendung nutzt die Klasse DotCode und wandelt ein gegebenes Tinyray-Programm in ein Dot-Programm um.
UseDotCode.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.DotCode;
import tinyray.language.Tinyray;
import tinyray.language.Visitable;

/**
 * Die Klasse UseDotCode generiert aus einem Tinyray-Code
 * einen Dot-Code (siehe http://www.graphviz.org/).
 */

public class UseDotCode {

    /**
     * Das Hauptprogramm, welches aus einem Tinyray-Code einen Dot-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).

                boolean compact = false;

                if (arguments.length > 1) {
                    compact = "compact".equalsIgnoreCase(arguments[1]);
                }

                String dotcode = tinyray.accept(new DotCode(compact), "");

                // Ausgabe des DotCode
                System.out.println(dotcode);

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

    public static String usage() {
        String result = "";
        result += "java tinyray/UseDotCode <TinyrayDatei> [compact]\r\n";
        result += "\r\nBeispiele:\r\n";
        result += " java tinyray/UseDotCode MyScene.tinyray\r\n";
        result += " java tinyray/UseDotCode Test01.txt compact\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 UseDotCode
java tinyray/UseDotCode <TinyrayDatei> [compact]

Beispiele:
 java tinyray/UseDotCode MyScene.tinyray
 java tinyray/UseDotCode Test01.txt compact

Hinweis:
 Mindestens JRE (java-1.6.0) erforderlich.