// 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"; } }