// File: LindenmayerMain.cs
// Created by: Beau Skinner
// Creation date: Nov 19, 2003
using System;
using System.Collections;
using System.IO;
namespace Lindenmayer
{
///
/// Main class for Lindenmayer application, which generates PostScript files
/// of iterations of a collection of Lindenmayer fractals.
///
class LindenmayerMain
{
///
/// Writes a page containing a single given command to the slideshow output file.
///
/// The command to output.
private static void WritePage(string command) {
// Each new page consists of:
// - a %%Page: line
// - a gsave command
// - the given command
// - a grestore command
// - a showpage command
m_output.WriteLine("%%Page: {0} {0}", m_page++);
m_output.WriteLine("gsave {0} grestore showpage", command);
}
///
/// Calculates the duration in seconds between the current time and a given timestamp.
///
/// The timestamp to subtract from the current time.
/// Duration in seconds between the current time and the given timestamp.
private static string Duration(DateTime start) {
TimeSpan duration = DateTime.Now.Subtract(start);
return duration.TotalSeconds.ToString();
}
///
/// Outputs PostScript files for a given numbe of iterations of a fractal described by
/// a given Lindenmayer object.
///
/// The name of the fractal (used in titling the slideshow).
/// The Lindenmayer object for the fractal.
/// The number of iterations to output.
private static void Run(string name, Lindenmayer l, int maxItns) {
// Add a title page to the slideshow with the name of the fractal.
WritePage("(" + name + ") title");
// Output the first iteration, and if a file was generated, add it to the slideshow.
// A file will not be generated if the first iteration is blank.
l.Output();
if (File.Exists(l.Name + "1.ps")) {
Console.WriteLine("{0} 1...", name);
WritePage("(" + l.Name + "1.ps) run");
}
// Continue for the given number of iterations.
for (int i = 2; i <= Math.Min(maxItns, m_itns); i++) {
DateTime start = DateTime.Now;
Console.Write("{0} {1}... ", name, i);
l.Iterate();
l.Output();
Console.WriteLine("{0} seconds", Duration(start));
WritePage("(" + l.Name + i + ".ps) run");
}
Console.WriteLine();
m_output.WriteLine();
}
///
/// Opens the temporary file for output. If a file of the same name exists, it is erased.
///
private static void OpenTempOutput() {
m_output = new StreamWriter(m_tempFile);
}
///
/// Closes the currently open output file.
///
private static void CloseOutput() {
m_output.Close();
}
///
/// Creates the slideshow file with initial lines of code, and copies the contents of the
/// temporary file to the end of the slideshow file. The temporary file is then deleted.
///
private static void CopyOutput() {
// The slideshow file has a title procedure at the start, for making the title pages.
m_output = new StreamWriter(m_file);
m_output.WriteLine("%!PS-Adobe-2.0");
m_output.WriteLine("%%Pages: {0}", --m_page);
m_output.WriteLine();
m_output.WriteLine("/title {");
m_output.WriteLine(" /text exch def");
m_output.WriteLine(" /Helvetica-Bold findfont");
m_output.WriteLine(" 72 dup scale");
m_output.WriteLine(" 1 3 div scalefont");
m_output.WriteLine(" setfont");
m_output.WriteLine(" 2 9 moveto");
m_output.WriteLine(" text show");
m_output.WriteLine("} def");
m_output.WriteLine();
m_input = new StreamReader(m_tempFile);
string line;
while ((line = m_input.ReadLine()) != null) {
m_output.WriteLine(line);
}
m_input.Close();
m_output.Close();
File.Delete(m_tempFile);
}
///
/// The main entry point for the application.
///
[STAThread]
static void Main(string[] args)
{
DateTime start = DateTime.Now;
// This is the maximum number of iterations to perform.
m_itns = 15;
// This keeps track of the number of pages that the slideshow will have.
m_page = 1;
Rules rules;
Lindenmayer l;
OpenTempOutput();
// Hilbert
rules = new Rules();
rules.Add("X", "-YF+XFX+FY-");
rules.Add("Y", "+XF-YFY-FX+");
l = new Lindenmayer("hilbert", "X", 0, -90, rules);
Run("Hilbert", l, 9);
// Koch-Island
rules = new Rules();
rules.Add("F", "F+F-F-FF+F+F-F");
l = new Lindenmayer("kochisland", "F+F+F+F", 45, -90, rules);
Run("Koch-Island", l, 5);
// Koch-Snowflake
rules = new Rules();
rules.Add("F", "F-F++F-F");
l = new Lindenmayer("kochsnowflake", "F++F++F", 0, 60, rules);
Run("Koch-Snowflake", l, 7);
// Y-tree
rules = new Rules();
rules.Add("+++", "-F+++f-F+++f-");
rules.Add("F", "FF");
rules.Add("f", "ff");
l = new Lindenmayer("ytree", "F+++f", 90, -60, rules);
Run("Y-tree", l, 11);
// Bracket
rules = new Rules();
rules.Add("F", "F[-F]F[+F][F]");
l = new Lindenmayer("bracket", "F", 90, -30, rules);
Run("Bracket", l, 7);
// Willow
rules = new Rules();
rules.Add("LFFF", "TFFF[+LFFF]RFFF");
rules.Add("RFFF", "TFFF[-LFFF]LFFF");
rules.Add("TF", "TFF");
l = new Lindenmayer("willow", "LFFF", 80, -30, rules);
Run("Willow", l, 13);
// O-Tile
rules = new Rules();
rules.Add("X", "[F+F+F+F[---X-Y]+++++F++++++++F-F-F-F]");
rules.Add("Y", "[F+F+F+F[---Y]+++++F++++++++F-F-F-F]");
l = new Lindenmayer("otile", "X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+", 90, -15, rules);
Run("O-Tile", l, 12);
// Sierpinski-Gasket
rules = new Rules();
rules.Add("G", "F+G+F");
rules.Add("F", "G-F-G");
l = new Lindenmayer("sierpgasket", "F", 0, 60, rules);
Run("Sierpinski-Gasket", l, 10);
// Sierpinski-Carpet
rules = new Rules();
rules.Add("F", "F+F-F-F-f+F+F+F-F");
rules.Add("f", "fff");
l = new Lindenmayer("sierpcarpet", "F", 45, 90, rules);
Run("Sierpinski-Carpet", l, 6);
// Cantor's-Dust
rules = new Rules();
rules.Add("F", "FfF");
rules.Add("f", "fff");
l = new Lindenmayer("cantordust", "F", 0, 0, rules);
Run("Cantor's-Dust", l, 8);
// Other examples:
rules = new Rules();
rules.Add("F", "FF-F-F-F-F-F+F");
l = new Lindenmayer("rings", "F-F-F-F", 0, 90, rules);
Run("Rings", l, 6);
rules = new Rules();
rules.Add("F", "FF-F-F-F-FF");
l = new Lindenmayer("boxes", "F-F-F-F", 0, 90, rules);
Run("Boxes", l, 6);
rules = new Rules();
rules.Add("F", "FF-F+F-F-FF");
l = new Lindenmayer("rectangles", "F-F-F-F", 0, 90, rules);
Run("Rectangles", l, 6);
rules = new Rules();
rules.Add("F", "F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF");
rules.Add("f", "ffff");
l = new Lindenmayer("diningroom", "F-F-F-F", 0, 90, rules);
Run("Dining-Room", l, 4);
rules = new Rules();
rules.Add("F", "F[-F]F[+F]F");
l = new Lindenmayer("tree1", "F", 90, 27.5, rules);
Run("Tree1", l, 6);
rules = new Rules();
rules.Add("X", "F[+X]F[-X]+X");
rules.Add("F", "FF");
l = new Lindenmayer("tree2", "X", 90, 20, rules);
Run("Tree2", l, 9);
// Close temporary output and create the slideshow file.
CloseOutput();
CopyOutput();
Console.WriteLine("*** OPERATION COMPLETE *** Total time taken: {0} seconds", Duration(start));
}
private static int m_itns, m_page;
private static StreamWriter m_output;
private static StreamReader m_input;
private static string m_tempFile = "showall.tmp", m_file = "_showall.ps";
}
}