Click here to Skip to main content
15,886,091 members
Articles / Desktop Programming / Windows Forms

AViD

Rate me:
Please Sign up or sign in to vote.
4.81/5 (18 votes)
3 Mar 2009CPOL10 min read 53.6K   1.2K   24  
An application for visualizing common dendrimer models
#region Using Statements

using System;
using System.Xml;
using System.IO;
using System.Reflection;
using System.Collections.Generic;
using Microsoft.DirectX.Direct3D;
using System.Collections.ObjectModel;
using Microsoft.DirectX;

using AViD.Figures;

#endregion Using Statements

namespace AViD
{
  /// <summary>
  ///   The abstract <see cref="Figure"/> class is used to provide a basic
  ///   layer of functionality to simplify the rendering of the dendrimer
  ///   sub-components.
  /// </summary>
  public abstract class Figure
  {
    #region Constants

    private const string _XML_GENERATION = "Generation";
    private const string _XML_POSITION = "Position";
    private const string _XML_RENDER_FIGURE = "RenderFigure";

    #endregion Constants

    #region Static Methods

    /// <summary>
    ///   Gets the current figure and all of its children (and subsequent children)
    ///   into a single array.
    /// </summary>
    /// <param name="figure">The figure at which to start processing from.</param>
    /// <param name="blnIncludeOnlyVisible">True - Includes only visible figures. False - Includes all figures.</param>
    /// <returns>An array of the current figure and all of its children (and subsequent children).</returns>
    public static Figure[] GetAllFigures(Figure figure, bool blnIncludeOnlyVisible)
    {
      List<Figure> lstResult;

      lstResult = new List<Figure>(figure.Children.Length + 1);

      if (figure.Visible || !blnIncludeOnlyVisible)
      {
        lstResult.Add(figure);

        foreach (Figure child in figure.Children)
          lstResult.AddRange(Figure.GetAllFigures(child, blnIncludeOnlyVisible));
      }

      return lstResult.ToArray();
    }
    /// <summary>
    ///   Loads the figure from an <see cref="XmlNode"/>.
    /// </summary>
    /// <param name="device">The <see cref="Device"/> to bind the stick to.</param>
    /// <param name="xmlNode">The <see cref="XmlNode"/> containing the figure's data.</param>
    /// <exception cref="ArgumentException">In the event that the file contains a value that is invalid,
    /// an <see cref="ArgumentException"/> could be thrown.</exception>
    /// <exception cref="ArgumentNullException">In the event that the file contains a value that is invalid,
    /// an <see cref="ArgumentNullException"/> could be thrown.</exception>
    /// <exception cref="ArgumentOutOfRangeException">In the event that the file contains a value that is invalid,
    /// an <see cref="ArgumentOutOfRangeException"/> could be thrown.</exception>
    /// <returns>The resulting figure stored in the <see cref="XmlDocument"/>.</returns>
    public static Figure LoadFigure(Device device, XmlNode xmlNode)
    {
      Figure figure;
      XmlAttribute xmlAtt;
      int intGeneration;
      Vector3 vecPosition;
      bool blnRenderFigure;

      // Take the first xml node in the document and load it.
      switch (xmlNode.Name)
      {
        case Ball.XmlName:
          figure = Ball.Load(device, xmlNode);
          break;
        case SimpleLine.XmlName:
          figure = SimpleLine.Load(device, xmlNode);
          break;
        case Stick.XmlName:
          figure = Stick.Load(device, xmlNode);
          break;
        default:
          throw new NotImplementedException(string.Format("Unable to load a figure of type, {0}, from the xml.", xmlNode.Name));
      }

      // Load any base 'figure' elements.
      if (((xmlAtt = xmlNode.Attributes[Figure._XML_GENERATION]) == null) || !int.TryParse(xmlAtt.InnerText, out intGeneration))
        intGeneration = 0;
      if (((xmlAtt = xmlNode.Attributes[Figure._XML_POSITION]) == null) || !Utility.LoadVectorFromString(xmlAtt.InnerText, out vecPosition))
        vecPosition = Vector3.Empty;
      if (((xmlAtt = xmlNode.Attributes[Figure._XML_RENDER_FIGURE]) == null) || !bool.TryParse(xmlAtt.InnerText, out blnRenderFigure))
        blnRenderFigure = true;

      // Set the values into the figure.
      figure.Generation = intGeneration;
      figure.Position = vecPosition;
      figure.Visible = blnRenderFigure;

      // Load any children.
      foreach (XmlNode xmlChild in xmlNode.ChildNodes)
        figure.AddChild(Figure.LoadFigure(device, xmlChild));

      return figure;
    }

    #endregion Static Methods

    #region Constructor

    /// <summary>
    ///   Initializes the underlying components necessary for the <see cref="Figure"/>
    ///   class.
    /// </summary>
    /// <param name="intGeneration">The number indicating the generation of the figure.</param>
    /// <param name="position">The starting position of the figure.</param>
    public Figure(int intGeneration, Vector3 position)
    {
      this.Generation = intGeneration;
      this.Position = position;

      this.m_blnRenderFigure = true;
      this.m_lstChildren = new List<Figure>();
    }

    #endregion Constructor

    #region Public Properties

    /// <summary>
    ///   Gets the number indicating the generation of the figure.
    /// </summary>
    public int Generation
    {
      get
      {
        return this.m_intGeneration;
      }
      protected set
      {
        this.m_intGeneration = value;
      }
    }
    /// <summary>
    ///   Gets/sets the position of the figure.
    /// </summary>
    public virtual Vector3 Position
    {
      get
      {
        return this.m_vecPosition;
      }
      set
      {
        this.m_vecPosition = value;
      }
    }
    /// <summary>
    ///   Gets the material associated to the figure.
    /// </summary>
    public virtual Material Material
    {
      get
      {
        return this.m_Material;
      }
      set
      {
        this.m_Material = value;
      }
    }
    /// <summary>
    ///   Gets the <see cref="Figure"/> parent of the current <see cref="Figure"/>.
    /// </summary>
    public Figure Parent
    {
      get
      {
        return this.m_Parent;
      }
    }
    /// <summary>
    ///   Gets the <see cref="Figure"/> children of the current <see cref="Figure"/>.
    /// </summary>
    public Figure[] Children
    {
      get
      {
        return this.m_lstChildren.ToArray();
      }
    }
    /// <summary>
    ///   Gets/sets whether or not the parent should render the figure.
    /// </summary>
    public bool RenderFigure
    {
      get
      {
        return this.m_blnRenderFigure;
      }
      set
      {
        this.m_blnRenderFigure = value;
      }
    }
    /// <summary>
    ///   Gets/sets whether or not the current figure is visible.
    /// </summary>
    public bool Visible
    {
      get
      {
        return this.m_blnVisible;
      }
      set
      {
        this.m_blnVisible = value;
      }
    }

    #endregion Public Properties

    #region Public Methods

    /// <summary>
    ///   Adds the <see cref="Figure"/> to the current parent.
    /// </summary>
    /// <param name="figure">The figure to add to the parent.</param>
    public void AddChild(Figure figure)
    {
      figure.m_Parent = this;
      this.m_lstChildren.Add(figure);
    }
    /// <summary>
    ///   Removes the <see cref="Figure"/> from the current parent.
    /// </summary>
    /// <param name="figure">The figure to remove from the parent.</param>
    /// <returns>True - Indicating it was removed, False - indicating it was not.</returns>
    public bool RemoveChild(Figure figure)
    {
      if (this.m_lstChildren.Remove(figure))
      {
        // Clear the parent.
        figure.m_Parent = null;

        return true;
      }
      else
        return false;
    }
    /// <summary>
    ///   Attempts to find the figure that intersects with the provided ray.  The parent figure
    ///   and all of its children will be searched.
    /// </summary>
    /// <param name="vecPosition">The <see cref="Vector3"/> indicating the origin of the ray.</param>
    /// <param name="vecDirection">The <see cref="Vector3"/> indicating the direction of the ray.</param>
    /// <param name="figure">The figure that intersected the ray.</param>
    /// <returns>Indicates true if the ray intersects a face on the figure.  Otherwise, the value is false.</returns>
    public bool FindFigure(Vector3 vecPosition, Vector3 vecDirection, out Figure figure)
    {
      Figure tempFigure;
      float fltFigureDistance, fltTempFigureDistance;

      if (this.RenderFigure && this.Visible && this.Intersect(vecPosition, vecDirection))
      {
        figure = this;
        fltFigureDistance = Vector3.Subtract(vecPosition, this.Position).Length();
      }
      else
      {
        figure = null;
        fltFigureDistance = float.MaxValue;
      }

      if (this.RenderFigure)
      {
        foreach (Figure childFigure in this.Children)
        {
          if (childFigure.FindFigure(vecPosition, vecDirection, out tempFigure))
          {
            // Find the distance from the position for the figure.
            fltTempFigureDistance = Vector3.Subtract(vecPosition, tempFigure.Position).Length();

            if ((figure == null) || (fltTempFigureDistance < fltFigureDistance))
            {
              figure = tempFigure;
              fltFigureDistance = fltTempFigureDistance;
            }
          }
        }
      }

      return (figure != null);
    }
    /// <summary>
    ///   Determines whether a ray intersects with the figure.
    /// </summary>
    /// <param name="vecPosition">The <see cref="Vector3"/> indicating the origin of the ray.</param>
    /// <param name="vecDirection">The <see cref="Vector3"/> indicating the direction of the ray.</param>
    /// <returns>Indicates true if the ray intersects a face on the figure.  Otherwise, the value is false.</returns>
    public virtual bool Intersect(Vector3 vecPosition, Vector3 vecDirection)
    {
      return false;
    }
    /// <summary>
    ///   Renders the entire figure to the user.
    /// </summary>
    /// <param name="device">The device to render to.</param>
    public void Render(Device device)
    {
      if (this.RenderFigure)
      {
        // We mark which objects are rendered to help in the pin-pointing of objects
        // are interactable on the UI.
        this.m_blnVisible = true;
        this._RenderCurrentFigure(device);

        foreach (Figure childFigure in this.Children)
          childFigure.Render(device);
      }
      else
        this._ResetVisibleFlag();
    }
    /// <summary>
    ///   Renders the figure to the user.
    /// </summary>
    /// <param name="device">The device to render to.</param>
    /// <param name="intMaximumGeneration">The maximum generation to render to.</param>
    public void RenderToGeneration(Device device, int intMaximumGeneration)
    {
      if (this.Generation <= intMaximumGeneration)
      {

        if (this.RenderFigure)
        {
          // We mark which objects are rendered to help in the pin-pointing of objects
          // are interactable on the UI.
          this.m_blnVisible = true;
          this._RenderCurrentFigure(device);

          foreach (Figure childFigure in this.Children)
            childFigure.RenderToGeneration(device, intMaximumGeneration);
        }
        else
          this._ResetVisibleFlag();
      }
      else
        this._ResetVisibleFlag();
    }
    /// <summary>
    ///   Resets all RenderChildren flags on the current figure and its children to True.
    /// </summary>
    public void ResetRenderChildrenFlags()
    {
      this.RenderFigure = true;

      foreach (Figure child in this.Children)
        child.ResetRenderChildrenFlags();
    }

    /// <summary>
    ///   Saves the figure to an <see cref="XmlDocument"/>.
    /// </summary>
    /// <param name="xmlNode">The <see cref="XmlNode"/> to save the Figure to.</param>
    public void Save(XmlNode xmlNode)
    {
      // Insert into the document the current figure's data.
      xmlNode.AppendChild(this._SaveRecursive(xmlNode.OwnerDocument));
    }

    #endregion Public Methods

    #region Protected Members

    protected int m_intGeneration;
    protected Vector3 m_vecPosition;
    protected Material m_Material;
    protected bool m_blnVisible;
    protected bool m_blnRenderFigure;
    protected Figure m_Parent;
    protected List<Figure> m_lstChildren;

    #endregion Protected Members

    #region Protected Methods

    /// <summary>
    ///   Saves the current <see cref="Figure"/> and all of its children resursively.
    /// </summary>
    /// <param name="xmlDoc">The <see cref="XmlDocument"/> to save the data to.</param>
    /// <returns>The <see cref="XmlElement"/> containing the information of the current <see cref="Figure"/> and its children.</returns>
    private XmlElement _SaveRecursive(XmlDocument xmlDoc)
    {
      XmlElement xmlElement;
      XmlAttribute xmlAtt;

      // Save the current figure.
      xmlElement = this._Save(xmlDoc);

      // Add on all the base 'figure' elements.
      xmlElement.Attributes.Append(xmlAtt = xmlDoc.CreateAttribute(Figure._XML_GENERATION));
      xmlAtt.InnerText = this.Generation.ToString();

      xmlElement.Attributes.Append(xmlAtt = xmlDoc.CreateAttribute(Figure._XML_POSITION));
      xmlAtt.InnerText = Utility.SaveVectorToString(this.Position);

      xmlElement.Attributes.Append(xmlAtt = xmlDoc.CreateAttribute(Figure._XML_RENDER_FIGURE));
      xmlAtt.InnerText = this.RenderFigure.ToString();

      // Save all of its children recursively.
      foreach (Figure child in this.Children)
        xmlElement.AppendChild(child._SaveRecursive(xmlDoc));

      return xmlElement;
    }
    /// <summary>
    ///   Resets the visible flag for the current figure and its children, the
    ///   flag is used to determine whether or not the figure is visible.
    /// </summary>
    protected void _ResetVisibleFlag()
    {
      this.m_blnVisible = false;

      foreach (Figure childFigure in this.Children)
        childFigure._ResetVisibleFlag();
    }
    /// <summary>
    ///   Saves the figure to a <see cref="XmlElement"/>.
    /// </summary>
    /// <param name="xmlDocument">The <see cref="XmlDocument"/> to create the element for.</param>
    /// <returns>The XmlElement the Figure was saved to.</returns>
    protected abstract XmlElement _Save(XmlDocument xmlDocument);
    /// <summary>
    ///   Renders the current figure to the user.
    /// </summary>
    /// <param name="device">The device to render to.</param>
    protected abstract void _RenderCurrentFigure(Device device);

    #endregion Protected Methods
  }
}

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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
United States United States
Since I've begun my profession as a software developer, I've learned one important fact - change is inevitable. Requirements change, code changes, and life changes.

So..If you're not moving forward, you're moving backwards.

Comments and Discussions