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 = ((r <= 0xF) ? "0" : "") + Integer.toHexString(r);
String hexG = ((g <= 0xF) ? "0" : "") + Integer.toHexString(g);
String hexB = ((b <= 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 (r + 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;
}
}