Click here to Skip to main content
15,886,362 members
Articles / Programming Languages / XML

Create a Fractal Christmas Tree

Rate me:
Please Sign up or sign in to vote.
4.94/5 (33 votes)
22 Dec 20023 min read 245.2K   4.2K   60  
This program explores how trees are made using a simple fractal algorithm.
using System;
using System.Collections;
using System.Diagnostics;
using System.Windows.Forms;

namespace KA
{
	/// <summary>
	/// Defines a custom type that represents a shorthand key to look up the
	/// problem/reasons dictionary element associated with this key.
	/// </summary>
	public class DbgKey
	{
		private string key;
		
		/// <summary>
		/// Gets or sets the name of the key.
		/// </summary>
		/// <value>
		/// The name of the key.
		/// </value>
		public string Name
		{
			get {return key;}
			set {key=value;}
		}
		
		/// <summary>
		/// Constructor.
		/// </summary>
		/// <param name="key"></param>
		public DbgKey(string key)
		{
			this.key=key;
		}
	}
	
	/// <summary>
	/// Container for a problem and an array describing possible reasons
	/// associated with the problem.
	/// </summary>
	public class ProblemReason
	{
		string problem;
		string[] reasons;

		/// <summary>
		/// Constructor.
		/// </summary>
		/// <param name="problem">A description of the problem.</param>
		/// <param name="reasonArray">An array of possible reasons for the problem.</param>
		public ProblemReason(string problem, string[] reasonArray)
		{
			this.problem=problem;
			reasons=reasonArray;
		}

		/// <summary>
		/// Get the description of the problem.
		/// </summary>
		/// <returns>Description of the problem.</returns>
		public string GetProblem()
		{
			return problem;
		}

		/// <summary>
		/// Get the array of reasons associated with the problem.
		/// </summary>
		/// <returns>Gets the reasons.</returns>
		public string[] GetReasons()
		{
			return reasons;
		}
	}

	/// <summary>
	/// A class representing the collection of problem/reason descriptions.
	/// </summary>
	public class DbgProblemCollection
	{
		private SortedList probs;
		
		/// <summary>
		/// Constructor.
		/// </summary>
		public DbgProblemCollection()
		{
			probs=new SortedList();
		}
		
		/// <summary>
		/// Associates a problem description with a shorthand "key".
		/// </summary>
		/// <param name="key">The shorthand key.</param>
		/// <param name="problem">The full description of the problem.</param>
		/// <param name="reasonList">A string array representing possible reasons for the problem.</param>
		public void Add(DbgKey key, string problem, string[] reasonList)
		{
//			Dbg.Assert(!probs.Contains(key), new DbgKey("DbgMgrMultipleKeys"));
			probs.Add(key.Name, new ProblemReason(problem, reasonList));
		}
		
		/// <summary>
		/// Test if the problem collection contains the specified key.
		/// </summary>
		/// <param name="key"></param>
		/// <returns>True if the key exists in the problem collection, false otherwise.</returns>
		public bool Contains(DbgKey key)
		{
			return probs.Contains(key.Name);
		}
		
		/// <summary>
		/// Gets the number of problems in the collection.
		/// </summary>
		public int Count
		{
			get
			{
				return probs.Count;
			}
		}
		
		/// <summary>
		/// Given the index (the key), returns a ProblemReason object.  The key is the indexer to the problem DbgProblemCollection.
		/// </summary>
		public ProblemReason this[DbgKey key]
		{
			get
			{
				return (ProblemReason)probs[key.Name];
			}
		}
	}
	
	/// <summary>
	/// Combines the functionality of the Trace and Debug classes into a single class coordinated by the TRACE and DEBUG attributes.
	/// This class extends the built in .NET functionality by adding an unhandled exception handler and a dictionary of problems
	/// and reasons, which provides useful information to the end user when an exception is thrown or an assertion occurs.
	/// <br></br>
	/// <br></br>
	/// This class also provides Warn and Fail methods that can be used in conjunction with handled exceptions, either to warn
	/// the end-user of a system problem or to terminate the application with a meaningful message.  Both the Warn and Fail methods
	/// use the problem/reason dictionary to provide meaningful information to the user.
	/// <br></br>
	/// <br></br>
	/// Using this class, all Writexxx methods are available in debug mode.  In release mode, only Assert functions are enabled.
	/// This ensures that output traces are only available in debug mode and not in released projects, which can compromise
	/// your application or system security.
	/// </summary>
	public class Dbg
	{
		// The debug extensions:
		private static DbgProblemCollection problems=new DbgProblemCollection();
	
		/// <summary>
		/// Gets the problem collection.
		/// </summary>
		/// <value>
		/// The problem collection.
		/// </value>
		public static DbgProblemCollection Problems
		{
			get {return problems;}
		}

		/// <summary>
		/// Initializes the Dbg object.  This consists of adding an unhandled exception handler and a internal key
		/// named "_NEVER_FAIL_" which is used by the Verify method.
		/// </summary>
		public static void Initialize()
		{
			AppDomain.CurrentDomain.UnhandledException+=new UnhandledExceptionEventHandler(DbgExceptionHandler);

			problems.Add(
				new DbgKey("_NEVER_FAIL_"),
				"An unexpected failure has occurred where it should not have.",
				new string[] {
					"Disk space is getting low.",
					"System memory is getting low.",
					"Required resources are unavailable.",
					"A virus is affecting system resources."});

			problems.Add(
				new DbgKey("DbgMgrMultipleKeys"),
				"Duplicate problem/reason key.",
				new string[] {
					"The same key cannot be used for different entries in the problem/reason dictionary.",
					"An object is instantiated more than once that should only be instantiated once."});
					
		}

		// ************** ALWAYS AVAILABLE FUNCTIONS **********************
		
		/// <summary>
		/// The private handler for exceptions that are not handled in catch-try blocks.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="args"></param>
		private static void DbgExceptionHandler(object sender, UnhandledExceptionEventArgs args)
		{
			Exception e=(Exception) args.ExceptionObject;
			Trace.WriteLine("Exception: "+e.Message+"\n"+e.GetType()+"\nStack Trace:\n"+e.StackTrace);
			MessageBox.Show(
				"A fatal problem has occurred.\n"+e.Message+"\nin: "+e.GetType(),
				"Program Stopped",
				MessageBoxButtons.OK,
				MessageBoxIcon.Stop,
				MessageBoxDefaultButton.Button1);
			Trace.Close();
			Process.GetCurrentProcess().Kill();
		}

		/// <summary>
		/// Displays a message indicating a fatal problem has occurred, then terminates
		/// the program.  It is suitable for displaying informative messages resulting from trapped
		/// exceptions that cannot be recovered.
		/// </summary>
		/// <param name="b">The result of a boolean test.</param>
		/// <param name="key">The problem/reason key.</param>
		/// <param name="error">The error text, usually the error text associated with an exception.</param>
		public static void Fail(bool b, DbgKey key, string error)
		{
			if (!b)
			{
				Trace.WriteLine("Fail: "+key.Name+"\n"+"\tInfo: "+error);
				if (problems.Contains(key))
				{
					string explanation=GetExplanation(key);
					MessageBox.Show(
						error+"\n\n"+explanation,
						"Program Stopped",
						MessageBoxButtons.OK,
						MessageBoxIcon.Stop,
						MessageBoxDefaultButton.Button1);
				}
				else
				{
					MessageBox.Show(
						error+"\n\n"+"A fatal problem has occurred.\n\nReference: "+key.Name,
						"Program Stopped",
						MessageBoxButtons.OK,
						MessageBoxIcon.Stop,
						MessageBoxDefaultButton.Button1);
				}
				Trace.Close();
				Process.GetCurrentProcess().Kill();
			}
		}

		/// <summary>
		/// Displays a message indicating a recoverable problem has occurred.  This is suitable
		/// for displaying informative messages resulting from a recoverable exception.
		/// </summary>
		/// <param name="b">The result of a boolean test.</param>
		/// <param name="key">The problem/reason key.</param>
		/// <param name="error">The error text, usually the error text associated with an exception.</param>
		public static void Warn(bool b, DbgKey key, string error)
		{
			if (!b)
			{
				Trace.WriteLine("Warning: "+key.Name+"\n"+"\tInfo: "+error);
				if (problems.Contains(key))
				{
					string explanation=GetExplanation(key);
					MessageBox.Show(
						error+"\n\n"+explanation,
						"Warning",
						MessageBoxButtons.OK,
						MessageBoxIcon.Warning,
						MessageBoxDefaultButton.Button1);
				}
				else
				{
					MessageBox.Show(
						error+"\n\n"+"A problem has occurred that should be corrected.\n\nReference: "+key.Name,
						"Warning",
						MessageBoxButtons.OK,
						MessageBoxIcon.Warning,
						MessageBoxDefaultButton.Button1);
				}
			}
		}

		/// <summary>
		/// This method similar to the VERIFY macro in C++, which can be used
		/// for testing things that should never fail.
		/// <br></br>
		/// <br></br>
		/// This function asserts in DEBUG and TRACE modes and does nothing if 
		/// both DEBUG and TRACE flags are turned off.  This is the best we can
		/// achieve because the [Conditional] attribute doesn't let us use boolean
		/// logic to say DEBUG AND NOT TRACE, and I don't want to introduce a third
		/// attribute!
		/// <br></br><br></br>
		/// A good use of this function is when the programmer needs to verify
		/// his/her understanding of the return values of an API function.
		/// </summary>
		/// <param name="b">The result of a boolean test.</param>
		public static void Verify(bool b)
		{
			Assert(b, new DbgKey("_NEVER_FAIL_"));
		}

		/// <summary>
		/// Flag the debugger to break at the next instruction.
		/// </summary>
		public static void Break()
		{
			Debugger.Break();
		}

		/// <summary>
		/// Put together the list of possible reasons for the particular problem.
		/// </summary>
		/// <param name="key">The problem/reason key.</param>
		/// <returns>A string enumerating all the reasons associated with the problem.</returns>
		private static string GetExplanation(DbgKey key)
		{
			ProblemReason ps=problems[key];
			string explanation=ps.GetProblem()+"\n\nPossible reasons:\n\n";
			int n=1;
			foreach (string sol in ps.GetReasons())
			{
				explanation+="  "+n.ToString()+". "+sol+"\n";
				++n;
			}
			return explanation;
		}

		// ************** TRACE FLAG ON (DEFAULT RELEASE MODE) **********************

		/// <summary>
		/// If the test fails, this function provides a meaningful message and then terminates
		/// the application.
		/// </summary>
		/// <param name="b">The result of a boolean test.</param>
		/// <param name="key">The key that is associated with the problem/reason description.</param>
		[Conditional("TRACE")]
		public static void Assert(bool b, DbgKey key)
		{
			if (!b)
			{
				Trace.WriteLine("Assert: "+key.Name);
				if (problems.Contains(key))
				{
					string explanation=GetExplanation(key);
					MessageBox.Show(
						explanation,
						"Program Stopped",
						MessageBoxButtons.OK,
						MessageBoxIcon.Stop,
						MessageBoxDefaultButton.Button1);
				}
				else
				{
					MessageBox.Show(
						"A fatal problem has occurred.\n\nReference: "+key.Name,
						"Program Stopped",
						MessageBoxButtons.OK,
						MessageBoxIcon.Stop,
						MessageBoxDefaultButton.Button1);
				}
				Trace.Close();
				Process.GetCurrentProcess().Kill();
			}
		}

		/// <summary>
		/// Passes through to the System.Diagnostics.Trace.Assert method
		/// </summary>
		[Conditional("TRACE")]
		public static void Assert(bool b)
		{
			Trace.Assert(b);
		}
		
		/// <summary>
		/// Passes through to the System.Diagnostics.Trace.Assert method
		/// </summary>
		[Conditional("TRACE")]
		public static void Assert(bool b, string s)
		{
			Trace.Assert(b, s);
		}
		
		/// <summary>
		/// Passes through to the System.Diagnostics.Trace.Assert method
		/// </summary>
		[Conditional("TRACE")]
		public static void Assert(bool b, string s1, string s2)
		{
			Trace.Assert(b, s1, s2);
		}

		/// <summary>
		/// Passes through to the System.Diagnostics.Trace.Fail method
		/// </summary>
		[Conditional("TRACE")]
		public static void Fail(string s)
		{
			Trace.Fail(s);
		}
		
		/// <summary>
		/// Passes through to the System.Diagnostics.Trace.Fail method
		/// </summary>
		[Conditional("TRACE")]
		public static void Fail(string s1, string s2)
		{
			Trace.Fail(s1, s2);
		}
		
		// ************** DEBUG FLAG ON (DEFAULT DEBUG MODE) **********************

		/// <summary>
		/// Passes through to the System.Diagnostics.Debug.LogOutput method
		/// </summary>
		[Conditional("DEBUG")]
		public static void LogOutput(string fn)
		{
			Debug.Listeners.Add(new TextWriterTraceListener(fn));
			DateTime dt=DateTime.Now;
			Debug.WriteLine("\n\nDebug Logging Initialized: "+dt.ToString());
		}

		/// <summary>
		/// Passes through to the System.Diagnostics.Debug.Close method
		/// </summary>
		[Conditional("DEBUG")]		
		public static void Close()
		{
			Trace.Close();
		}
		
		/// <summary>
		/// Passes through to the System.Diagnostics.Debug.Flush method
		/// </summary>
		[Conditional("DEBUG")]		
		public static void Flush()
		{
			Debug.Flush();
		}
		
		/// <summary>
		/// Passes through to the System.Diagnostics.Debug.Indent method
		/// </summary>
		[Conditional("DEBUG")]		
		public static void Indent()
		{
			Debug.Indent();
		}
		
		/// <summary>
		/// Passes through to the System.Diagnostics.Debug.Unindent method
		/// </summary>
		[Conditional("DEBUG")]		
		public static void Unindent()
		{
			Debug.Unindent();
		}
		
		// Write
		
		/// <summary>
		/// Passes through to the System.Diagnostics.Debug.Write method
		/// </summary>
		[Conditional("DEBUG")]
		public static void Write(object obj)
		{
			Debug.Write(obj);
		}
		
		/// <summary>
		/// Passes through to the System.Diagnostics.Debug.Write method
		/// </summary>
		[Conditional("DEBUG")]		
		public static void Write(string s)
		{
			Debug.Write(s);
		}
		
		/// <summary>
		/// Passes through to the System.Diagnostics.Debug.Write method
		/// </summary>
		[Conditional("DEBUG")]		
		public static void Write(object obj, string s)
		{
			Debug.Write(obj, s);
		}
		
		/// <summary>
		/// Passes through to the System.Diagnostics.Debug.Write method
		/// </summary>
		[Conditional("DEBUG")]		
		public static void Write(string s1, string s2)
		{
			Debug.Write(s1, s2);
		}
		
		// WriteIf
		
		/// <summary>
		/// Passes through to the System.Diagnostics.Debug.WriteIf method
		/// </summary>
		[Conditional("DEBUG")]		
		public static void WriteIf(bool b, object obj)
		{
			Debug.WriteIf(b, obj);
		}
		
		/// <summary>
		/// Passes through to the System.Diagnostics.Debug.WriteIf method
		/// </summary>
		[Conditional("DEBUG")]		
		public static void WriteIf(bool b, string s)
		{
			Debug.WriteIf(b, s);
		}
		
		/// <summary>
		/// Passes through to the System.Diagnostics.Debug.WriteIf method
		/// </summary>
		[Conditional("DEBUG")]		
		public static void WriteIf(bool b, object obj, string s)
		{
			Debug.WriteIf(b, obj, s);
		}
		
		/// <summary>
		/// Passes through to the System.Diagnostics.Debug.WriteIf method
		/// </summary>
		[Conditional("DEBUG")]		
		public static void WriteIf(bool b, string s1, string s2)
		{
			Debug.WriteIf(b, s1, s2);
		}
		
		// WriteLine
		
		/// <summary>
		/// Passes through to the System.Diagnostics.Debug.WriteLine method
		/// </summary>
		[Conditional("DEBUG")]		
		public static void WriteLine(object obj)
		{
			Debug.WriteLine(obj);
		}
		
		/// <summary>
		/// Passes through to the System.Diagnostics.Debug.WriteLine method
		/// </summary>
		[Conditional("DEBUG")]		
		public static void WriteLine(string s)
		{
			Debug.WriteLine(s);
		}
		
		/// <summary>
		/// Passes through to the System.Diagnostics.Debug.WriteLine method
		/// </summary>
		[Conditional("DEBUG")]		
		public static void WriteLine(object obj, string s)
		{
			Debug.WriteLine(obj, s);
		}
		
		/// <summary>
		/// Passes through to the System.Diagnostics.Debug.WriteLine method
		/// </summary>
		[Conditional("DEBUG")]		
		public static void WriteLine(string s1, string s2)
		{
			Debug.WriteLine(s1, s2);
		}
		
		// WriteLineIf
		
		/// <summary>
		/// Passes through to the System.Diagnostics.Debug.WriteLineIf method
		/// </summary>
		[Conditional("DEBUG")]		
		public static void WriteLineIf(bool b, object obj)
		{
			Debug.WriteLineIf(b, obj);
		}
		
		/// <summary>
		/// Passes through to the System.Diagnostics.Debug.WriteLineIf method
		/// </summary>
		[Conditional("DEBUG")]		
		public static void WriteLineIf(bool b, string s)
		{
			Debug.WriteLineIf(b, s);
		}
		
		/// <summary>
		/// Passes through to the System.Diagnostics.Debug.WriteLineIf method
		/// </summary>
		[Conditional("DEBUG")]		
		public static void WriteLineIf(bool b, object obj, string s)
		{
			Debug.WriteLineIf(b, obj, s);
		}
		
		/// <summary>
		/// Passes through to the System.Diagnostics.Debug.WriteLineIf method
		/// </summary>
		[Conditional("DEBUG")]		
		public static void WriteLineIf(bool b, string s1, string s2)
		{
			Debug.WriteLineIf(b, s1, s2);
		}

		// getters and setters
		
		/// <summary>
		/// Gets and sets the current value in the System.Diagnostics.Debug.AutoFlush parameter.
		/// </summary>
		public static bool AutoFlush
		{
			get {return Debug.AutoFlush;}
			set {Debug.AutoFlush=value;}
		}
		
		/// <summary>
		/// Gets and sets the current value in the System.Diagnostics.Debug.IndentLevel parameter.
		/// </summary>
		public static int IndentLevel
		{
			get {return Debug.IndentLevel;}
			set {Debug.IndentLevel=value;}
		}
		
		/// <summary>
		/// Gets and sets the current value in the System.Diagnostics.Debug.IndentSize parameter.
		/// </summary>
		public static int IndentSize
		{
			get {return Debug.IndentSize;}
			set {Debug.IndentSize=value;}
		}
		
		/// <summary>
		/// Gets current collection of trace listeners in the System.Diagnostics.Trace object.
		/// </summary>
		public static TraceListenerCollection Listeners
		{
			get {return Trace.Listeners;}
		}
		
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.


Written By
Architect Interacx
United States United States
Blog: https://marcclifton.wordpress.com/
Home Page: http://www.marcclifton.com
Research: http://www.higherorderprogramming.com/
GitHub: https://github.com/cliftonm

All my life I have been passionate about architecture / software design, as this is the cornerstone to a maintainable and extensible application. As such, I have enjoyed exploring some crazy ideas and discovering that they are not so crazy after all. I also love writing about my ideas and seeing the community response. As a consultant, I've enjoyed working in a wide range of industries such as aerospace, boatyard management, remote sensing, emergency services / data management, and casino operations. I've done a variety of pro-bono work non-profit organizations related to nature conservancy, drug recovery and women's health.

Comments and Discussions