using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Xml.Serialization;

namespace VisiMath
{
    /// <summary>
    /// Vector2 with float components
    /// </summary>
    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public struct Vector2 : IEquatable<Vector2>, IXmlSerializable
    {
        #region Fields
        /// <summary>
        /// X value of the vector
        /// </summary>
        public float X;
        /// <summary>
        /// Y value of the vector
        /// </summary>
        public float Y;
        #endregion

        #region Constants

        /// <summary>
        /// Defines a unit-length Vector2 that points towards the X-axis.
        /// </summary>
        public static readonly Vector2 UnitX = new Vector2(1, 0);

        /// <summary>
        /// Defines a unit-length Vector2 that points towards the Y-axis.
        /// </summary>
        public static readonly Vector2 UnitY = new Vector2(0, 1);

        /// <summary>
        /// Defines a zero-length Vector2.
        /// </summary>
        public static readonly Vector2 Zero = new Vector2(0, 0);

        /// <summary>
        /// Defines an instance with all components set to 1.
        /// </summary>
        public static readonly Vector2 One = new Vector2(1, 1);

        /// <summary>
        /// Invalid vector
        /// </summary>
        public static readonly Vector2 Invalid = new Vector2(float.NaN);

        /// <summary>
        /// Defines the size of the Vector2 struct in bytes.
        /// </summary>
        public static readonly int SizeInBytes = Marshal.SizeOf(new Vector2());

        #endregion

        #region Constructors

        /// <summary>
        /// Basic constructor, constructs Vector2 with specified value for all fields
        /// </summary>
        public Vector2(float val)
        {
            X = val; Y = val;
        }

        /// <summary>
        /// Constructs Vector2 from specified coordinates
        /// </summary>
        /// <param name="x">X coordinate</param>
        /// <param name="y">Y coordinate</param>
        /// <param name="z">Z coordinate</param>
        public Vector2(float x, float y)
        {
            X = x; Y = y;
        }

        /// <summary>
        /// Copy constructor
        /// </summary>
        /// <param name="vec">Source value</param>
        public Vector2(Vector2 vec)
        {
            X = vec.X; Y = vec.Y;
        }

        /// <summary>
        /// Fast copy constructor
        /// </summary>
        /// <param name="vec">Source value</param>
        public Vector2(ref Vector2 vec)
        {
            X = vec.X; Y = vec.Y;
        }


        /// <summary>
        /// Constructs Vector2 from float array
        /// </summary>
        /// <exception cref="System.ArgumentException">
        /// Thrown if argument doesn't have at least 3 components
        /// </exception>
        /// <param name="field">float array with values, must have at least 3 elements</param>
        public Vector2(float[] field)
        {
            if (field.Length < 2)
                throw new System.ArgumentException("Attempt to initialize Vector2 with float field with less then 2 elements");
            X = field[0];
            Y = field[1];
        }

        /// <summary>
        /// XML reader constructor
        /// </summary>
        /// <param name="reader">XML reader</param>
        public Vector2(System.Xml.XmlReader reader)
        {
            X = Y = 0;
            ReadXml(reader);
        }


        #endregion


        #region Assigning and modifications

        /// <summary>
        /// constructs Vector2 with specified value for all fields
        /// </summary>
        /// <param name="val">value for all fields</param>
        public void Assing(float val)
        {
            X = val;
            Y = val;
        }


        /// <summary>
        /// Sets vector to specified values
        /// </summary>
        /// <param name="x">X value</param>
        /// <param name="y">Y value</param>
        /// <param name="z">Z value</param>
        public void Assign(float x, float y)
        {
            X = x; Y = y;
        }


        /// <summary>
        /// Sets vector as copy of source vector
        /// </summary>
        /// <param name="vec">source vector</param>
        public void Assign(ref Vector2 vec)
        {
            X = vec.X; Y = vec.Y;
        }

        /// <summary>
        /// Sets vector to values from float field
        /// </summary>
        /// <exception cref="System.ArgumentException">
        /// Thrown if argument doesn't have at least 2 components
        /// </exception>
        /// <param name="field">Source values, must have at least 2 elements</param>
        public void Assign(float[] field)
        {
            if (field.Length < 2)
                throw new System.ArgumentException("Attempt to initialize Vector2 with float field with less then 2 elements");
            X = field[0];
            Y = field[1];
        }

        /// <summary>
        /// Makes Vector invalid by setting X component to float.NotANumber
        /// </summary>
        public void MakeInvalid()
        {
            X = float.NaN;
        }

        /// <summary>
        /// Inverts vector
        /// </summary>
        public void Invert()
        {
            X = -X;
            Y = -Y;
        }

        /// <summary>
        /// Adds specified vector to this vector - using ref for faster computing
        /// </summary>
        /// <param name="vec">operand</param>
        public void Add(ref Vector2 vec)
        {
            X += vec.X;
            Y += vec.Y;
        }

        /// <summary>
        /// Adds specified vector to this vector - using ref for faster computing
        /// </summary>
        /// <param name="vec">operand</param>
        /// <remarks>Use ref overloaded version where possible, it's faster</remarks>
        public void Add(Vector2 vec)
        {
            X += vec.X;
            Y += vec.Y;
        }

        /// <summary>
        /// Adds values to this vector
        /// </summary>
        public void Add(float x, float y)
        {
            X += x;
            Y += y;
        }

        /// <summary>
        /// Substracts values from the vector
        /// </summary>
        public void Substract(float x, float y)
        {
            X -= x;
            Y -= y;
        }

        /// <summary>
        /// Substracts specified vector from this vector - using ref for faster computing
        /// </summary>
        /// <param name="vec">operand</param>
        public void Substract(ref Vector2 vec)
        {
            X -= vec.X;
            Y -= vec.Y;
        }

        /// <summary>
        /// Substracts specified vector from this vector - using ref for faster computing
        /// </summary>
        /// <param name="vec">operand</param>
        /// <remarks>Use ref overloaded version where possible, it's faster</remarks>
        public void Substract(Vector2 vec)
        {
            X -= vec.X;
            Y -= vec.Y;
        }

        /// <summary>
        /// Multiplies vector by scalar value
        /// </summary>
        /// <param name="newscale">Scalar value</param>
        public void Mul(float newscale)
        {
            X *= newscale;
            Y *= newscale;
        }

        /// <summary>
        /// Divides vector by the scalar value
        /// </summary>
        /// <param name="div">scalar value</param>
        public void Divide(float div)
        {
            X /= div;
            Y /= div;
        }

        /// <summary>
        /// Normalizes vector. If length of the vector is zero, doesn't do anything.
        /// </summary>
        public void Normalize()
        {
            float l = Length;
            if (l != 0.0f)
            {
                Mul(1.0f / Length);
            }
        }

        /// <summary>
        /// Fast normalization (less precission, usable for some operations
        /// </summary>
        public void NormalizeFast()
        {
            float newscale = MathTools.InverseSqrFast(X * X + Y * Y);
            Mul(newscale);
        }


        /// <summary>
        /// Transforms vector by rotational matrix
        /// </summary>
        /// <param name="mat">Rotational matrix</param>
        public void Transform(ref Matrix2 mat)
        {
            mat.Transform(ref this);
        }

        /// <summary>
        /// Transforms vector by homogenous matrix 3x3
        /// </summary>
        /// <param name="mat">Matrix</param>
        public void Transform(ref Matrix3 mat)
        {
            mat.Transform(ref this);
        }


        /// <summary>
        /// Clamps values of the vector 
        /// </summary>
        /// <param name="min">Minimal possible value</param>
        /// <param name="max">Maximal possible value</param>
        public void Clamp(ref Vector2 min, ref Vector2 max)
        {
            X = X < min.X ? min.X : X > max.X ? max.X : X;
            Y = Y < min.Y ? min.Y : Y > max.Y ? max.Y : Y;
        }

        /// <summary>
        /// Clamps values of the vector to minimal possible value
        /// </summary>
        /// <param name="min"></param>
        public void ClampMin(ref Vector2 min)
        {
            if (X < min.X) X = min.X;
            if (Y < min.Y) Y = min.Y;
        }

        /// <summary>
        /// Clamps values of the vector to maximal possible value
        /// </summary>
        /// <param name="max"></param>
        public void ClampMax(ref Vector2 max)
        {
            if (X > max.X) X = max.X;
            if (Y > max.Y) Y = max.Y;
        }


        /// <summary>
        /// Lineary interpolates vector to target vector
        /// </summary>
        /// <param name="target">Target vector</param>
        /// <param name="inter">Interpolation value, assumes (0-1)</param>
        public void Interpolate(ref Vector2 target, float inter)
        {
            X += inter * (target.X - X);
            Y += inter * (target.Y - Y);
        }


        #endregion

        #region Methods

        /// <summary>
        /// Property for the vector as an float array
        /// </summary>
        /// <exception cref="System.ArgumentException">
        /// Thrown if argument doesnt have at least two components</exception>
        [XmlIgnore]
        public float[] Array
        {
            get { return new float[] { X, Y}; }
            set
            {
                if (value.Length >= 2)
                {
                    Assign(value);
                }
                else
                {
                    throw new ArgumentException("Vector2: Float array must contain at least 2 elements");
                }
            }
        }

        /// <summary>
        /// An index accessor 
        /// Maps index [0] -> X, [1] -> Y
        /// </summary>
        /// <param name="index">The array index referring to a component within the vector (i.e. x, y)</param>
        /// <exception cref="System.ArgumentException">
        /// Thrown if the array argument isn't between 0 and 1
        /// </exception>
        public float this[int index]
        {
            get
            {
                switch (index)
                {
                    case 0: { return X; }
                    case 1: { return Y; }
                    default: throw new ArgumentException("Indexing out of the vector", "index");
                }
            }
            set
            {
                switch (index)
                {
                    case 0: { X = value; break; }
                    case 1: { Y = value; break; }
                    default: throw new ArgumentException("Indexing out of the vector", "index");
                }
            }
        }

        /// <summary>
        /// Checks validity of the vector
        /// </summary>
        /// <returns>True if vector.X is not notanumber</returns>
        public bool IsValid()
        {
            if (float.IsNaN(X))
                return false;
            return true;
        }

        /// <summary>
        /// Returns true if vector is normalized
        /// </summary>
        /// <returns></returns>
        public bool IsNormalized()
        {
            if (LengthSquared == 1)
                return true;
            return false;
        }

        /// <summary>
        /// Vector length
        /// </summary>
        /// <exception cref="System.ArgumentOutOfRangeException">
        /// Thrown if new desired length is below zero
        /// </exception>
        /// <exception cref="System.ArgumentException">
        /// Thrown if vector is zero vector.
        /// </exception>
        [XmlIgnore]
        public float Length
        {
            get
            {
                return (float)System.Math.Sqrt(LengthSquared);
            }

            set
            {
                if (value < 0)
                    throw new ArgumentOutOfRangeException("value", value, "Cannot set negative lenght to Vector2");
                if (this.Equals(Vector2.Zero))
                {
                    throw new ArgumentException("Cannot set length to zero vector");
                }
                Mul(value / Length);
            }
        }

        /// <summary>
        /// Fast but imprecisse vector length
        /// </summary>
        [XmlIgnore]
        public float LengthFast
        {
            get
            {
                return 1.0f / MathTools.InverseSqrFast(X * X + Y * Y);
            }
        }

        /// <summary>
        /// Squared lenght for fast distance comparison
        /// </summary>
        [XmlIgnore]
        public float LengthSquared
        {
            get
            {
                return (X * X + Y * Y);
            }
        }


        /// <summary>
        /// Returns distance to other vector
        /// </summary>
        /// <param name="vec2">Vector to measure the distance</param>
        /// <returns>Distance between this and vec2</returns>
        public float Distance(ref Vector2 vec2)
        {
            float retval = (X - vec2.X) * (X - vec2.X)
                         + (Y - vec2.Y) * (Y - vec2.Y);
            return (float)Math.Sqrt(retval);
        }

        /// <summary>
        /// Returns distance to other vector, fast but unacurrate version (good enough for distance checking)
        /// </summary>
        /// <param name="vec2">Vector to measure the distance</param>
        /// <returns>Distance between this and vec2</returns>
        public float DistanceFast(ref Vector2 vec2)
        {
            float retval = (X - vec2.X) * (X - vec2.X)
                         + (Y - vec2.Y) * (Y - vec2.Y);
            return 1.0f / MathTools.InverseSqrFast(retval);
        }

        /// <summary>
        /// Returns squared distance to other vector, fast, for distance comparison
        /// </summary>
        /// <param name="vec2">Vector to measure the distance</param>
        /// <returns>Distance between this and vec2</returns>
        public float DistanceSquared(ref Vector2 vec2)
        {
            return (X - vec2.X) * (X - vec2.X)
                         + (Y - vec2.Y) * (Y - vec2.Y);
        }


        /// <summary>
        /// Dot product with another vector
        /// </summary>
        /// <param name="vec2">Second vector</param>
        /// <returns>Dot product</returns>
        public float Dot(ref Vector2 vec2)
        {
            return this.X * vec2.X + this.Y * vec2.Y;
        }

        /// <summary>
        /// Returns normalized copy of this vector
        /// </summary>
        /// <returns>Normalized copy</returns>
        public Vector2 NormalizedCopy()
        {
            Vector2 rval = new Vector2(this);
            rval.Normalize();
            return rval;
        }

        /// <summary>
        /// Computes angle between vectors
        /// </summary>
        /// <param name="v2">second operand</param>
        /// <returns>Angle between this and v2 in radians</returns>
        public float Angle(Vector2 v2)
        {
            Vector2 v1 = NormalizedCopy();
            v2.Normalize();
            return (float)Math.Acos(v1.Dot(ref v2));
        }

        /// <summary>
        /// Computes angle between vectors, expects both vectors to be normalized!
        /// </summary>
        /// <param name="v2">second operand</param>
        /// <returns>Angle between this and v2 (both must be normalized vectors) in radians</returns>
        public float AngleNorm(ref Vector2 v2)
        {
            return (float)Math.Acos(this.Dot(ref v2));
        }


        #endregion

        #region operators

        public static Vector2 operator +(Vector2 left, Vector2 right)
        {
            left.Add(ref right);
            return left;
        }

        public static Vector2 operator -(Vector2 left, Vector2 right)
        {
            left.Substract(ref right);
            return left;
        }

        public static Vector2 operator -(Vector2 vec)
        {
            vec.Invert();
            return vec;
        }

        public static Vector2 operator *(Vector2 vec, float scale)
        {
            vec.Mul(scale);
            return vec;
        }

        public static Vector2 operator *(float scale, Vector2 vec)
        {
            vec.Mul(scale);
            return vec;
        }

        public static Vector2 operator /(Vector2 vec, float scale)
        {
            vec.Divide(scale);
            return vec;
        }

        public static bool operator ==(Vector2 left, Vector2 right)
        {
            return left.Equals(right);
        }

        public static bool operator !=(Vector2 left, Vector2 right)
        {
            return !left.Equals(right);
        }

        /// <summary>
        /// Compares magnitude of the vectors
        /// </summary>
        /// <param name="left">left operand</param>
        /// <param name="right">right operand</param>
        /// <returns>True if left operand's lenght is smaller than right</returns>
        public static bool operator <(Vector2 left, Vector2 right)
        {
            return left.LengthSquared < right.LengthSquared;
        }

        /// <summary>
        /// Compares magnitude of the vectors
        /// </summary>
        /// <param name="left">left operand</param>
        /// <param name="right">right operand</param>
        /// <returns>True if left operand's lenght is bigger than right</returns>
        public static bool operator >(Vector2 left, Vector2 right)
        {
            return left.LengthSquared > right.LengthSquared;
        }

        /// <summary>
        /// Compares magnitude of the vectors
        /// </summary>
        /// <param name="left">left operand</param>
        /// <param name="right">right operand</param>
        /// <returns>True if left operand's lenght is equal or smaller than right</returns>
        public static bool operator <=(Vector2 left, Vector2 right)
        {
            return left.LengthSquared <= right.LengthSquared;
        }

        /// <summary>
        /// Compares magnitude of the vectors
        /// </summary>
        /// <param name="left">left operand</param>
        /// <param name="right">right operand</param>
        /// <returns>True if left operand's lenght is equal or bigger than right</returns>
        public static bool operator >=(Vector2 left, Vector2 right)
        {
            return left.LengthSquared >= right.LengthSquared;
        }


        #endregion

        #region Static functions


        #region Products

        /// <summary>
        /// Dot product of two vectors
        /// </summary>
        /// <param name="v1">first operand</param>
        /// <param name="v2">second operand</param>
        /// <returns>Dot product of the vectors</returns>
        public static float Dot(ref Vector2 v1, ref Vector2 v2)
        {
            return v1.Dot(ref v2);
        }

        #endregion

        /// <summary>
        /// Returns normalized copy of the vector
        /// </summary>
        /// <param name="v">operand</param>
        /// <returns>Normalized copy of v</returns>
        public static Vector2 Normalize(ref Vector2 v)
        {
            return v.NormalizedCopy();
        }


        #region math operations

        /// <summary>
        /// Adds two vectors and sets res with result
        /// </summary>
        /// <param name="v1">first operand</param>
        /// <param name="v2">second operand</param>
        /// <param name="res">vector to save the result</param>
        public static void Add(ref Vector2 v1, ref Vector2 v2, out Vector2 res)
        {
            res.X = v1.X + v2.X;
            res.Y = v1.Y + v2.Y;            
        }

        /// <summary>
        /// Adds two vectors and returns result
        /// </summary>
        /// <param name="v1">first operand</param>
        /// <param name="v2">second operand</param>
        /// <returns>v1+v2</returns>
        public static Vector2 Add(ref Vector2 v1, ref Vector2 v2)
        {
            return new Vector2(v1.X + v2.X, v1.Y + v2.Y);
        }

        /// <summary>
        /// Substracts two vectors and sets res with result
        /// </summary>
        /// <param name="v1">first operand</param>
        /// <param name="v2">second operand</param>
        /// <param name="res">vector to save the result</param>
        public static void Substract(ref Vector2 v1, ref Vector2 v2, out Vector2 res)
        {
            res.X = v1.X - v2.X;
            res.Y = v1.Y - v2.Y;
        }

        /// <summary>
        /// Substracts two vectors and returns result
        /// </summary>
        /// <param name="v1">first operand</param>
        /// <param name="v2">second operand</param>
        /// <param name="res">v1-v2</param>
        /// <returns></returns>
        public static Vector2 Substract(ref Vector2 v1, ref Vector2 v2)
        {
            return new Vector2(v1.X - v2.X, v1.Y - v2.Y);
        }

        /// <summary>
        /// Multiplies vector by scalar value and sets result to res
        /// </summary>
        /// <param name="v1">vector</param>
        /// <param name="newscale">scalar</param>
        /// <param name="res">Vector to save result to</param>
        public static void Mul(ref Vector2 v1, float newscale, out Vector2 res)
        {
            res.X = v1.X * newscale;
            res.Y = v1.Y * newscale;
        }

        /// <summary>
        /// Multiplies vector by scalar value and returns result
        /// </summary>
        /// <param name="v1">vector</param>
        /// <param name="newscale">scalar</param>
        /// <returns>V1*newscale</returns>
        public static Vector2 Mul(ref Vector2 v1, float newscale)
        {
            return new Vector2(v1.X * newscale, v1.Y * newscale);
        }

        /// <summary>
        /// Divides vector by scalar value and returns result
        /// </summary>
        /// <param name="v1">Vector</param>
        /// <param name="div">scalar</param>
        /// <returns>v1/div</returns>
        public static Vector2 Divide(ref Vector2 v1, float div)
        {
            Vector2 rval = new Vector2(v1);
            rval.Divide(div);
            return rval;
        }

        /// <summary>
        /// Divides vector by scalar value and returns result
        /// </summary>
        /// <param name="v1">Vector</param>
        /// <param name="div">scalar</param>
        /// <param name="res">Vector to save the result to</param>
        public static void Divide(ref Vector2 v1, float div, out Vector2 res)
        {
            res = new Vector2(v1);
            res.Divide(div);
        }

        #endregion


        #region Clamping

        /// <summary>
        /// Clamps value of the vector to minimum and maximum
        /// </summary>
        /// <param name="v1">Vector to be clamped</param>
        /// <param name="min">Minimal allowed values</param>
        /// <param name="max">Maximal allowed values</param>
        /// <param name="res">Ouput vector</param>
        public static void Clamp(ref Vector2 v1, ref Vector2 min, ref Vector2 max, out Vector2 res)
        {
            res = new Vector2(v1);
            res.Clamp(ref min, ref max);
        }

        /// <summary>
        /// Clamps value of the vector to minimum
        /// </summary>
        /// <param name="v1">Vector to be clamped</param>
        /// <param name="min">Minimal allowed values</param>
        /// <param name="res">Ouput vector</param>
        public static void ClampMin(ref Vector2 v1, ref Vector2 min, out Vector2 res)
        {
            res = new Vector2(v1);
            res.ClampMin(ref min);
        }

        /// <summary>
        /// Clamps value of the vector to maximum
        /// </summary>
        /// <param name="v1">Vector to be clamped</param>
        /// <param name="max">Maximal allowed values</param>
        /// <param name="res">Ouput vector</param>
        public static void ClampMax(ref Vector2 v1, ref Vector2 max, out Vector2 res)
        {
            res = new Vector2(v1);
            res.ClampMax(ref max);
        }

        /// <summary>
        /// Clamps value of the vector to minimum and maximum
        /// </summary>
        /// <param name="v1">Vector to be clamped</param>
        /// <param name="min">Minimal allowed values</param>
        /// <param name="max">Maximal allowed values</param>
        /// <returns>Clamped vector</returns>
        public static Vector2 Clamp(ref Vector2 v1, ref Vector2 min, ref Vector2 max)
        {
            Vector2 res = new Vector2(v1);
            res.Clamp(ref min, ref max);
            return res;
        }

        /// <summary>
        /// Clamps value of the vector to minimum
        /// </summary>
        /// <param name="v1">Vector to be clamped</param>
        /// <param name="min">Minimal allowed values</param>
        /// <returns>Clamped vector</returns>
        public static Vector2 ClampMin(Vector2 v1, ref Vector2 min)
        {
            v1.ClampMin(ref min);
            return v1;
        }

        /// <summary>
        /// Clamps value of the vector to maximum
        /// </summary>
        /// <param name="v1">Vector to be clamped</param>
        /// <param name="max">Maximal allowed values</param>
        /// <returns>Clamped vector</returns>
        public static Vector2 ClampMax(Vector2 v1, ref Vector2 max)
        {
            v1.ClampMax(ref max);
            return v1;
        }

        #endregion



        #region Interpolation

        /// <summary>
        /// Lineary interpolates vector to target vector
        /// </summary>
        /// <param name="source">Source vector</param>
        /// <param name="target">Target vector</param>
        /// <param name="inter">Interpolation value, assumes (0-1)</param>
        /// <param name="result">Vector to save result to</param>
        public static void Interpolate(ref Vector2 source, ref Vector2 target, float inter, out Vector2 result)
        {
            result.X = inter * (target.X - source.X) + source.X;
            result.Y = inter * (target.Y - source.Y) + source.Y;
        }


        /// <summary>
        /// Lineary interpolates vector to target vector
        /// </summary>
        /// <param name="source">Source vector</param>
        /// <param name="target">Target vector</param>
        /// <param name="inter">Interpolation value, assumes (0-1)</param>
        /// <returns></returns>
        public static Vector2 Interpolate(ref Vector2 source, ref Vector2 target, float inter)
        {
            Vector2 result = new Vector2(source);
            result.Interpolate(ref target, inter);
            return result;
        }

        #endregion







        #endregion


        #region overrides

        public override string ToString()
        {
            return String.Format("({0}, {1})", X, Y);
        }

        public override int GetHashCode()
        {
            return X.GetHashCode() ^ Y.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            if (!(obj is Vector2))
                return false;

            return this.Equals((Vector2)obj);
        }

        #endregion


        #region IEquatable<Vector2> Members

        public bool Equals(Vector2 other)
        {
            return
                X == other.X &&
                Y == other.Y;
        }

        #endregion

        #region IXmlSerializable Members

        /// <summary>
        /// Reqired by IXMLserializable
        /// </summary>
        /// <returns>Null</returns>
        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }

        /// <summary>
        /// Deserializes object from XML
        /// </summary>
        /// <param name="reader">XML reader</param>
        public void ReadXml(System.Xml.XmlReader reader)
        {
            X = XMLHelper.FloatFromString(reader["X"]);
            Y = XMLHelper.FloatFromString(reader["Y"]);
        }

        /// <summary>
        /// Serializes object to XML
        /// </summary>
        /// <param name="writer">XML writer to save values</param>
        public void WriteXml(System.Xml.XmlWriter writer)
        {
            XMLHelper.WriteFloatAttribute(writer, "X", X);
            XMLHelper.WriteFloatAttribute(writer, "Y", Y);
        }

        /// <summary>
        /// Serializes object to XML
        /// </summary>
        /// <param name="writer">XML writer to save values</param>
        /// <param name="rootname">Node to save value to</param>
        public void WriteXml(System.Xml.XmlWriter writer, string rootname)
        {
            writer.WriteStartElement(rootname);
            WriteXml(writer);
            writer.WriteEndElement();
        }

        #endregion
    }
}
