Click here to Skip to main content
15,881,882 members
Articles / Artificial Intelligence

The Game of Clue (C# 2010)

Rate me:
Please Sign up or sign in to vote.
4.93/5 (55 votes)
13 Aug 2010CPOL29 min read 132.2K   3K   102  
You are a suspect!
  • clue_c_2010.zip
    • Clue CS2010
      • Clue CS2010.sln
      • Clue CS2010
        • About.rtf
        • Arranging The Cards.rtf
        • classPicTray_V2.cs
        • classSprite.cs
        • cLibPicBoxViewer.cs
        • Clue CS2010.csproj
        • Clue CS2010.csproj.user
        • Clue_Icon.ico
        • Dealing the cards.rtf
        • Equipment.rtf
        • formClue.cs
        • formClue.Designer.cs
        • formClue.resx
        • formInstructions.cs
        • formInstructions.Designer.cs
        • formInstructions.resx
        • Getting out of a room.rtf
        • Interesting notes and hints.rtf
        • Introduction.rtf
        • JESSICA_RABBIT.SP2
        • Movement of tokens.rtf
        • Moving into a room.rtf
        • Notes.bfs
        • Preparation.rtf
        • Program.cs
        • Properties
        • Proving the suggestion true or false.rtf
        • PulseButton.cs
        • PulseButton.designer.cs
        • PulseButton.dll
        • RATPROTESTER.SP2
        • Resources
          • baize.png
          • bars.bmp
          • Board Under Lense.jpg
          • CanShowACard.bmp
          • cardback.Jpeg
          • CardBilliardRoom.Jpeg
          • CardRoomBallroom.Jpeg
          • CardRoomConservatory.Jpeg
          • CardRoomDiningRoom.Jpeg
          • CardRoomHall.Jpeg
          • CardRoomKitchen.Jpeg
          • CardRoomLibrary.Jpeg
          • CardRoomLounge.Jpeg
          • CardRoomStudy.Jpeg
          • CardSuspectColMustard.Jpeg
          • CardSuspectMissScarlet.Jpeg
          • CardSuspectMrsPeacock.jpg
          • CardSuspectMrsWhite.Jpeg
          • CardSuspectProfPlum.Jpeg
          • CardSuspectRevGreen.Jpeg
          • CardWeaponCandleStick.Jpeg
          • CardWeaponKnife.Jpeg
          • CardWeaponLeadPipe.Jpeg
          • CardWeaponRevolver.Jpeg
          • CardWeaponRope.Jpeg
          • CardWeaponWrench.Jpeg
          • Clue logo mask.bmp
          • clue logo.bmp
          • ClueBoardMarble.Jpeg
          • ClueFloor.bmp
          • CrimeSceneBallRoom.bmp
          • CrimeSceneBilliardRoom.bmp
          • CrimeSceneConservatory.bmp
          • CrimeSceneDiningRoom.bmp
          • CrimeSceneHall.bmp
          • CrimeSceneKitchen.bmp
          • CrimeSceneLibrary.bmp
          • CrimeSceneLounge.bmp
          • CrimeSceneStudy.bmp
          • die1.bmp
          • die2.bmp
          • die3.bmp
          • die4.bmp
          • die5.bmp
          • die6.bmp
          • magnifying_glass.bmp
          • magnifying_handle.png
          • mainblock.bmp
          • Mouse00.bmp
          • Mouse01.bmp
          • Mouse02.bmp
          • newsprint.jpg
          • NoCardsToShow.bmp
          • notebook.jpg
          • noteBox_blank.bmp
          • noteBox_check.bmp
          • noteBox_ColMustard.bmp
          • noteBox_highlight.bmp
          • noteBox_MissScarlet.bmp
          • noteBox_MrsPeacock.bmp
          • noteBox_MrsWhite.bmp
          • noteBox_ProfPlum.bmp
          • noteBox_questionMark.bmp
          • noteBox_RevGreen.bmp
          • noteBox_X.bmp
          • picture frame oval.bmp
          • Piece_ColMustard.bmp
          • Piece_MissScarlet.bmp
          • Piece_MrsPeacock.bmp
          • Piece_MrsWhite.bmp
          • Piece_ProfPlum.bmp
          • Piece_RevGreen.bmp
          • prison bars large.bmp
          • setAI.bmp
          • SuggestionBubble.bmp
          • SuspectColMustard.bmp
          • SuspectMissScarlet.bmp
          • SuspectMrsPeacock.bmp
          • SuspectMrsWhite.bmp
          • SuspectProfPlum.bmp
          • SuspectRevGreen.bmp
          • WeaponBoard_Candlestick.bmp
          • WeaponBoard_Knife.bmp
          • WeaponBoard_LeadPipe.bmp
          • WeaponBoard_Revolver.bmp
          • WeaponBoard_Rope.bmp
          • WeaponBoard_Wrench.bmp
          • WeaponCandlestick.bmp
          • WeaponKnife.bmp
          • WeaponLeadPipe.bmp
          • WeaponRevolver.bmp
          • WeaponRope.bmp
          • WeaponWrench.bmp
          • Winner.bmp
        • Scream.aiff
        • Secret Passages.rtf
        • The accusation.rtf
        • The Suggestion.rtf
        • To Begin.rtf
        • User Interface.rtf
        • WALDO.SP2
        • Winning the game.rtf
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.IO;

namespace Sprite
{
    public enum enuMirror { none, vertical, horizontal, VerticalAndHorizontal }

    public struct udtSprite_StorageRetrieval
    {
        public string myName;
        public udtLimb_StorageRetrieval[] limbs;
    }

    public struct udtLimb_StorageRetrieval
    {
        public string myName;
        public Bitmap[] bmp;
        public bool IRotate;
        public bool AlwaysVertical;
        public classMath.classRadialCoor radMaster;
        public int MasterIndex;
        public classMath.classRadialCoor radSlave;
        public string hingeName;
    }

    /// <summary>
    /// a hinge connects to limbs together
    /// radial coordinates are relative to the center of each image
    /// the slave's master coordinate is place at the same location as its master's slave coordinate onto the screen
    /// </summary>
    public class classSpriteHinge
    {
        string myName;
        public bool bolFlag = true;

        public string name
        {
            get { return myName; }
        }

        double myAngle;
        /// <summary>
        /// angle of slave limb relative to angle of master limb
        /// </summary>
        public double Angle
        {
            get { return myAngle; }
            set
            {
                double dblTestAngle = value - (Math.PI / 16.0);
                if (dblTestAngle < 0)
                    dblTestAngle += (Math.PI * 2.0);
                int intDir = (int)(Math.Ceiling(dblTestAngle / (Math.PI / 8.0)));
                myAngle = intDir * Math.PI / 8.0;
            }
        }

        public classSpriteHinge(string name) { myName = name; }
        /// <summary>
        /// a hinge connects to limbs together
        /// radial coordinates are relative to the center of each image
        /// the slave's master coordinate is place at the same location as its master's slave coordinate onto the screen    
        /// </summary>
        /// <param name="name">name of this hinge, e.g. "elbow"</param>
        /// <param name="RadCoor_Master">radial coordinate (radians, pixels) of location of joint on master image relative to center</param>
        /// <param name="RadCoor_Slave">radial coordinate (radians, pixels) of location of joint on slave image relative to center</param>
        /// <param name="LimbMaster">pointer to Master-Limb</param>
        /// <param name="LimbSlave">pointer to Slave-Limb</param>
        public classSpriteHinge(string name, classMath.classRadialCoor RadCoor_Master, classMath.classRadialCoor RadCoor_Slave, classSpriteLimb LimbMaster, classSpriteLimb LimbSlave)
        {
            udrRadCoor_Master = RadCoor_Master;
            udrRadCoor_Slave = RadCoor_Slave;
            classLimb_Master = LimbMaster;
            classLimb_Slave = LimbSlave;
            myName = name;
        }

        classMath.classRadialCoor udrRadCoor_Master;
        /// <summary>
        /// radial coordinate location relative to center of image
        /// </summary>
        public classMath.classRadialCoor RadCoor_Master
        {
            get { return udrRadCoor_Master; }
            set { udrRadCoor_Master = value; }
        }

        classMath.classRadialCoor udrRadCoor_Slave;
        /// <summary>
        /// radial coordinate location relative to center of image
        /// </summary>
        public classMath.classRadialCoor RadCoor_Slave
        {
            get { return udrRadCoor_Slave; }
            set { udrRadCoor_Slave = value; }
        }

        classSpriteLimb classLimb_Master;
        /// <summary>
        /// pointer to limb connected to this hinge
        /// </summary>
        public classSpriteLimb Limb_Master
        {
            get { return classLimb_Master; }
            set { classLimb_Master = value; }
        }

        classSpriteLimb classLimb_Slave;
        /// <summary>
        /// pointer to limb connected to this hinge
        /// </summary>
        public classSpriteLimb Limb_Slave
        {
            get { return classLimb_Slave; }
            set { classLimb_Slave = value; }
        }
    }

    /// <summary>
    /// one element in array of 16 that describes a limb's position relative to its master
    /// as well as the locations of any number of slaves relative to it
    /// </summary>
    public class classSpriteLimbImage
    {
        public classSpriteLimbImage() { }
        public classSpriteLimbImage(Bitmap bmpOriginal) { bmp = bmpOriginal; }

        /// <summary>
        /// this sprite limb's image for this angle
        /// </summary>
        public Bitmap bmp;
    }

    public class classSpriteLimb
    {
        Sprite.classSprite mainSprite;
        public bool bolFlag = true;
        public Rectangle recDest;
        public classSpriteLimbImage myCurrentImage;

        public classSpriteLimb[] mySlaveLimbs;
        int intMySlaveID;
        /// <summary>
        /// my index in my master's slave limb array
        /// </summary>
        public int MySlaveID
        {
            get { return intMySlaveID; }
            set { intMySlaveID = value; }
        }

        bool bolAlwaysVertical = false;
        /// <summary>
        /// determines whether generated images are flipped to remain vertical or rotated 360 degrees
        /// </summary>
        public bool AlwaysVertical { get { return bolAlwaysVertical; } }

        string myName;
        public string Name { get { return myName; } }

        Point ptLoc;
        /// <summary>
        /// location of top-left corner of image's rectangle
        /// </summary>
        public Point Loc
        {
            get { return ptLoc; }
            set { ptLoc = value; }
        }

        int dir;
        /// <summary>
        /// 0-15 where 0 is east, 4 north, etc.
        /// also corresponds to the udrSpriteLimbImages's index of currently displayed image
        /// </summary>
        public int Dir
        {
            get { return dir; }
            set { dir = value; }
        }

        double angle;
        /// <summary>
        /// at which this limb currently has on the screen
        /// </summary>
        public double Angle
        {
            get { return -angle; }
            set { angle = -value; }
        }

        /// <summary>
        /// this limb's images
        /// </summary>
        public classSpriteLimbImage[] udrSpriteLimbImages;

        bool bolIRotate = true;
        /// <summary>
        /// boolean variable which determines whether this limb rotates or animates
        /// when true, SpriteLimbImages is expected to consist of 16 images at 16 angles
        /// when false, SpriteLimbImages is either one or many images which are used to animate this limb
        /// </summary>
        public bool IRotate
        {
            get { return bolIRotate; }
            set { bolIRotate = value; }
        }

        //bool bolIHaveNoMaster = false;
        //public bool IHaveNoMaster { get { return bolIHaveNoMaster; } }
        public classSpriteHinge MasterHinge;

        /// <summary>
        /// a limb consists of an array of images with their corresponding hinge locations
        /// </summary>
        /// <param name="IRotate">
        /// when this is set the indices of udrSpriteLimbImage are direction of rotation, e.g. action-arm, these are created if not provided
        /// when this is not set these are animation images, e.g. walking legs</param>
        /// </param>
        /// <param name="AlwaysVertical">
        /// determines whether generated images are flipped to remain vertical or rotated 360 degrees
        /// </param>
        /// <param name="_myName">
        /// used for ease of debugging e.g. "Torso", "left arm", "right hand"
        /// </param>
        /// <param name="bmpOriginal">
        /// first elements of array of images
        /// </param>
        public classSpriteLimb(ref classSprite sprite, bool IRotate, bool AlwaysVertical, string _myName, params Bitmap[] bmpOriginal)
        {
            mainSprite = sprite;
            myName = _myName;
            bolIRotate = IRotate;
            bolAlwaysVertical = AlwaysVertical;
            initImages(bmpOriginal);
        }

        public void initImages(Bitmap[] bmpOriginal)
        {
            //myName = "arm(near fuck)";
            if (bolIRotate)
            {
                udrSpriteLimbImages = new classSpriteLimbImage[16];
                for (int intBmpCounter = 0; intBmpCounter < bmpOriginal.Length; intBmpCounter++)
                    udrSpriteLimbImages[intBmpCounter] = new classSpriteLimbImage(bmpOriginal[intBmpCounter]);


                if (bmpOriginal.Length < 4)
                { // generate 1, 2 & 3 from 0
                    generateBaseFourImagesFromOriginal();
                }

                if (bmpOriginal.Length < 15)
                { // generate all from 0,1,2 & 3
                    for (int intImageCounter = 4; intImageCounter < 16; intImageCounter++)
                    {
                        udrSpriteLimbImages[intImageCounter] = getLimbImageFromArray_ByDir(ref udrSpriteLimbImages, intImageCounter);
                    }
                }

            }
            else
            {
                udrSpriteLimbImages = new classSpriteLimbImage[bmpOriginal.Length];
                for (int intBmpCounter = 0; intBmpCounter < bmpOriginal.Length; intBmpCounter++)
                {
                    udrSpriteLimbImages[intBmpCounter] = new classSpriteLimbImage();
                    udrSpriteLimbImages[intBmpCounter].bmp = bmpOriginal[intBmpCounter];
                }
            }
        }



        #region "initialize images"
        /// <summary>
        /// generates three angled copies of the original(udrSpriteLimbImage[0]) and stores them in udrSpriteLimbImage[1,2,3]
        /// </summary>
        void generateBaseFourImagesFromOriginal()
        {
            classMath cLibMath = new classMath();
            Color clrTransparent = udrSpriteLimbImages[0].bmp.GetPixel(0, 0);
            double dblRotationAngle = 0;
            for (int intImageCounter = 1; intImageCounter < 4; intImageCounter++)
            {
                dblRotationAngle = Math.PI + (Math.PI * (double)intImageCounter / 8.0);
                udrSpriteLimbImages[intImageCounter] = new classSpriteLimbImage();
                udrSpriteLimbImages[intImageCounter].bmp = rotate(udrSpriteLimbImages[0].bmp, dblRotationAngle, ref cLibMath);
            }
        }

        Bitmap rotate(Bitmap bmpInput, double dblAngleRotation, ref classMath cLibMath)
        {
            int intMinSquare = bmpInput.Width > bmpInput.Height ?
                                3 * bmpInput.Width
                                : 3 * bmpInput.Height;
            Color clrHole = Color.YellowGreen;// some color assumed NOT in the input bmp

            Bitmap bmpCopy = new Bitmap(intMinSquare, intMinSquare);
            Point ptTL;
            Point ptBR;
            Point ptCopyCenter = new Point(bmpCopy.Width / 2, bmpCopy.Height / 2);
            Point ptOriginalCenter = new Point(bmpInput.Width / 2, bmpInput.Height / 2);
            using (Graphics g = Graphics.FromImage(bmpCopy))
            {
                g.FillRectangle(new SolidBrush(clrHole), new Rectangle(new Point(0, 0), bmpCopy.Size));
                ptTL = new Point(ptCopyCenter.X, ptCopyCenter.Y);
                ptBR = new Point(ptCopyCenter.X, ptCopyCenter.Y);

                for (int intX = 0; intX < bmpInput.Width; intX++)
                {
                    for (int intY = 0; intY < bmpInput.Height; intY++)
                    {
                        int intDX = ptOriginalCenter.X - intX;
                        int intDY = ptOriginalCenter.Y - intY;
                        classMath.classRadialCoor udrOriginalRad = new classMath.classRadialCoor(classMath.arcTan(intDX, intDY), Math.Sqrt(intDX * intDX + intDY * intDY));
                        classMath.classRadialCoor udrCopyRad = new classMath.classRadialCoor(udrOriginalRad.angle - dblAngleRotation, udrOriginalRad.radius);
                        Point ptCopy = new Point((int)(ptCopyCenter.X + udrCopyRad.radius * Math.Cos(udrCopyRad.angle)),
                                                 (int)(ptCopyCenter.Y + udrCopyRad.radius * Math.Sin(udrCopyRad.angle)));

                        try { bmpCopy.SetPixel(ptCopy.X, ptCopy.Y, bmpInput.GetPixel(intX, intY)); }
                        catch (Exception) { }

                        // keep track of limits of output image
                        if (ptCopy.X < ptTL.X)
                            ptTL.X = ptCopy.X;
                        if (ptCopy.Y < ptTL.Y)
                            ptTL.Y = ptCopy.Y;
                        if (ptCopy.X > ptBR.X)
                            ptBR.X = ptCopy.X;
                        if (ptCopy.Y > ptBR.Y)
                            ptBR.Y = ptCopy.Y;
                    }
                }
            }

            // write image to output array
            Size szOfImage = new Size(ptBR.X - ptTL.X, ptBR.Y - ptTL.Y);
            Rectangle recSrc = new Rectangle(ptTL, szOfImage);
            Rectangle recDest = new Rectangle(new Point(0, 0), szOfImage);

            // fill the blanks missed when rotating image
            // scanning x from 0 to width created a problem in the fill-blank
            for (int intX = ptTL.X; intX < ptBR.X; intX++)
                for (int intY = ptTL.Y; intY < ptBR.Y; intY++)
                {
                    Color clrTest = bmpCopy.GetPixel(intX, intY);
                    if (clrTest.A == clrHole.A
                        && clrTest.R == clrHole.R
                        && clrTest.G == clrHole.G
                        && clrTest.B == clrHole.B)
                    {
                        udtPixilateColorFind[] udrColorFind = new udtPixilateColorFind[0];
                        if (intX > 0 && intX < bmpCopy.Width - 2 && intY > 0 && intY < bmpCopy.Height - 2)
                        {
                            Point ptUp = new Point(intX, intY - 1);
                            Point ptDown = new Point(intX, intY + 1);
                            Point ptLeft = new Point(intX - 1, intY);
                            Point ptRight = new Point(intX + 1, intY);
                            Point ptUL = new Point(intX - 1, intY - 1);
                            Point ptUR = new Point(intX + 1, intY - 1);
                            Point ptDR = new Point(intX + 1, intY + 1);
                            Point ptDL = new Point(intX - 1, intY + 1);

                            addPixilateColorFound(ref udrColorFind, bmpCopy.GetPixel(ptUp.X, ptUp.Y));
                            addPixilateColorFound(ref udrColorFind, bmpCopy.GetPixel(ptDown.X, ptDown.Y));
                            addPixilateColorFound(ref udrColorFind, bmpCopy.GetPixel(ptLeft.X, ptLeft.Y));
                            addPixilateColorFound(ref udrColorFind, bmpCopy.GetPixel(ptRight.X, ptRight.Y));
                            addPixilateColorFound(ref udrColorFind, bmpCopy.GetPixel(ptDL.X, ptDL.Y));
                            addPixilateColorFound(ref udrColorFind, bmpCopy.GetPixel(ptDR.X, ptDR.Y));
                            addPixilateColorFound(ref udrColorFind, bmpCopy.GetPixel(ptUL.X, ptUL.Y));
                            addPixilateColorFound(ref udrColorFind, bmpCopy.GetPixel(ptUR.X, ptUR.Y));
                            reorderPixilateColorFound(ref udrColorFind);
                            if (udrColorFind[0].numFound >= 2)
                                try { bmpCopy.SetPixel(intX, intY, udrColorFind[0].clr); }
                                catch (Exception) { }
                            else
                            {
                                int intDX = ptCopyCenter.X - intX;
                                int intDY = ptCopyCenter.Y - intY;
                                classMath.classRadialCoor udrOriginalRad = new classMath.classRadialCoor(classMath.arcTan(intDX, intDY), Math.Sqrt(intDX * intDX + intDY * intDY));
                                classMath.classRadialCoor udrCopyRad = new classMath.classRadialCoor(udrOriginalRad.angle + dblAngleRotation, udrOriginalRad.radius);
                                Point ptCopy = new Point((int)(ptOriginalCenter.X + udrCopyRad.radius * Math.Cos(udrCopyRad.angle)),
                                                         (int)(ptOriginalCenter.Y + udrCopyRad.radius * Math.Sin(udrCopyRad.angle)));

                                if (ptCopy.X >= 0 && ptCopy.X < bmpCopy.Width && ptCopy.Y >= 0 && ptCopy.Y < bmpCopy.Height)
                                    try { bmpCopy.SetPixel(intX, intY, bmpInput.GetPixel(ptCopy.X, ptCopy.Y)); }
                                    catch (Exception) { }
                            }
                        }
                    }
                }
            if (recDest.Width < 1)
                recDest.Width = 1;
            if (recDest.Height < 1)
                recDest.Height = 1;
            Bitmap bmpTemp = new Bitmap(recDest.Width, recDest.Height);

            using (Graphics g = Graphics.FromImage(bmpTemp))
            {
                g.FillRectangle(new SolidBrush(Color.White), new Rectangle(0, 0, bmpTemp.Width, bmpTemp.Height));
                bmpCopy.MakeTransparent(bmpCopy.GetPixel(0, 0));
                g.DrawImage(bmpCopy, recDest, recSrc, GraphicsUnit.Pixel);
            }

            return bmpTemp;
        }

        public struct udtPixilateColorFind
        {
            public Color clr;
            public int numFound;
        }

        private void addPixilateColorFound(ref udtPixilateColorFind[] udrPixilateColorFind, Color clrFound)
        {
            if (udrPixilateColorFind == null)
            {
                udrPixilateColorFind = new udtPixilateColorFind[1];
                udrPixilateColorFind[0] = new udtPixilateColorFind();
                udrPixilateColorFind[0].clr = clrFound;
                udrPixilateColorFind[0].numFound = 1;
            }
            else
            {
                for (int intClrCounter = 0; intClrCounter < udrPixilateColorFind.Length; intClrCounter++)
                    if (udrPixilateColorFind[intClrCounter].clr == clrFound)
                    {
                        udrPixilateColorFind[intClrCounter].numFound++;
                        return;
                    }
                Array.Resize<udtPixilateColorFind>(ref udrPixilateColorFind, udrPixilateColorFind.Length + 1);
                udrPixilateColorFind[udrPixilateColorFind.Length - 1] = new udtPixilateColorFind();
                udrPixilateColorFind[udrPixilateColorFind.Length - 1].clr = clrFound;
                udrPixilateColorFind[udrPixilateColorFind.Length - 1].numFound = 1;
            }
        }

        void reorderPixilateColorFound(ref udtPixilateColorFind[] udrPixilateColorFind)
        {
            int intBestFind;
            for (int intOuterLoop = 0; intOuterLoop < udrPixilateColorFind.Length - 1; intOuterLoop++)
            {
                intBestFind = intOuterLoop;
                for (int intInnerLoop = intOuterLoop + 1; intInnerLoop < udrPixilateColorFind.Length; intInnerLoop++)
                {
                    if (udrPixilateColorFind[intInnerLoop].numFound > udrPixilateColorFind[intBestFind].numFound)
                        intBestFind = intInnerLoop;
                }
                if (intBestFind != intOuterLoop)
                {
                    udtPixilateColorFind udrTemp = udrPixilateColorFind[intOuterLoop];
                    udrPixilateColorFind[intOuterLoop] = udrPixilateColorFind[intBestFind];
                    udrPixilateColorFind[intBestFind] = udrTemp;
                }
            }
        }

        /// <summary>
        /// returns image appropriate for this limb at current angle
        /// selected from array of 16 images
        /// </summary>
        public classSpriteLimbImage getSpriteImageFromArray() { return getSpriteImageFromArray(ref udrSpriteLimbImages, angle); }

        /// <summary>
        /// returns image appropriate for this limb at input angle
        /// selected from array of 16 images
        /// </summary>
        /// <param name="dblAngle">
        /// angled image to be returned
        /// </param>
        /// <returns></returns>
        public classSpriteLimbImage getSpriteImageFromArray(double dblAngle) { return getSpriteImageFromArray(ref udrSpriteLimbImages, dblAngle); }

        /// <summary>
        /// returns image appropriate for this limb at input angle
        /// selected from array of 16 images
        /// </summary>
        /// <param name="udrSpriteImage">array of 4 images pointing in 16 angles where east is 0th, North-east is 2nd, North 4th, etc.</param>
        /// <param name="dblAngle">angle in radians where 0 is east Pi/2 is north, Pi is west, and 3Pi/2 is south</param>
        /// <returns></returns>
        public classSpriteLimbImage getSpriteImageFromArray(ref classSpriteLimbImage[] udrSpriteImage, double dblAngle)
        {
            angle = dblAngle;
            while (angle < 0)
                angle += (2.0 * Math.PI);

            while (angle > 2.0 * Math.PI)
                angle -= (2.0 * Math.PI);

            setDir();
            return getLimbImageFromArray_ByDir(ref udrSpriteImage, dir);
        }

        public void setDir() { setDir(angle); }
        public void setDir(double dblAngle)
        {
            double dblTestAngle = dblAngle - (Math.PI / 16.0);
            if (dblTestAngle < 0)
                dblTestAngle += (Math.PI * 2.0);
            int intPicIndex = (int)(Math.Ceiling(dblTestAngle / (Math.PI / 8.0)));

            if (intPicIndex == 16)
                intPicIndex = 0;
            dir = intPicIndex;

            angle = dir * (Math.PI / 8);
        }

        /// <summary>
        /// returns image appropriate for this limb at input direction
        /// selected from array of 16 images
        /// </summary>
        /// <param name="udrSpriteImage">array of 4 images pointing in 16 angles where east is 0th, North-east is 2nd, North 4th, etc.</param>
        /// <param name="intDir">indicates the desired direction of image where 0th is east, 4th is north, 8 is west and 12th south, etc.</param>
        /// <returns></returns>
        public classSpriteLimbImage getLimbImageFromArray_ByDir(ref classSpriteLimbImage[] udrSpriteImage, int intDir)
        {
            if (udrSpriteImage == null)
                return null;
            if (intDir < 0 || intDir > 15)
            {
                MessageBox.Show("error getLimbImageFromArray_ByDir");
                return udrSpriteImage[0];
            }
            else
            {
                if (udrSpriteImage.Length > 1)
                {
                    if (intDir < udrSpriteImage.Length && false)
                    {
                        return udrSpriteImage[intDir];
                    }
                    else
                        switch (intDir)
                        {
                            case 0:
                            case 1:
                            case 2:
                            case 3:
                                return udrSpriteImage[intDir];

                            default:
                                if (udrSpriteLimbImages[intDir] != null)
                                    return udrSpriteLimbImages[intDir];
                                else
                                {
                                    if (bolAlwaysVertical)
                                    {
                                        classSpriteLimbImage udrRetVal = new classSpriteLimbImage();
                                        switch (intDir)
                                        {
                                            case 4:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[0].bmp.Width, udrSpriteImage[0].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[0].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate270FlipNone);

                                                return udrRetVal;

                                            case 5:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[3].bmp.Width, udrSpriteImage[3].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[3].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.RotateNoneFlipX);
                                                return udrRetVal;

                                            case 6:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[2].bmp.Width, udrSpriteImage[2].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[2].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.RotateNoneFlipX);
                                                return udrRetVal;

                                            case 7:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[1].bmp.Width, udrSpriteImage[1].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[1].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.RotateNoneFlipX);
                                                return udrRetVal;

                                            case 8:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[0].bmp.Width, udrSpriteImage[0].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[0].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.RotateNoneFlipX);
                                                return udrRetVal;

                                            case 9:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[3].bmp.Width, udrSpriteImage[3].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[3].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate90FlipX);
                                                return udrRetVal;

                                            case 10:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[2].bmp.Width, udrSpriteImage[2].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[2].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate90FlipX);
                                                return udrRetVal;

                                            case 11:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[1].bmp.Width, udrSpriteImage[1].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[1].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate270FlipY);
                                                return udrRetVal;

                                            case 12:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[0].bmp.Width, udrSpriteImage[0].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[0].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate90FlipNone);
                                                return udrRetVal;

                                            case 13:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[1].bmp.Width, udrSpriteImage[1].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[1].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate90FlipNone);
                                                return udrRetVal;

                                            case 14:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[2].bmp.Width, udrSpriteImage[2].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[2].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate90FlipNone);
                                                return udrRetVal;

                                            default:  // case 15
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[3].bmp.Width, udrSpriteImage[3].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[3].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate90FlipNone);
                                                return udrRetVal;
                                        }
                                    }
                                    else
                                    {
                                        classSpriteLimbImage udrRetVal = new classSpriteLimbImage();
                                        switch (intDir)
                                        {
                                            case 4:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[0].bmp.Width, udrSpriteImage[0].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[0].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate270FlipNone);

                                                return udrRetVal;

                                            case 5:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[1].bmp.Width, udrSpriteImage[1].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[1].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate270FlipNone);
                                                return udrRetVal;

                                            case 6:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[2].bmp.Width, udrSpriteImage[2].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[2].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate270FlipNone);
                                                return udrRetVal;

                                            case 7:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[3].bmp.Width, udrSpriteImage[3].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[3].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate270FlipNone);
                                                return udrRetVal;

                                            case 8:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[0].bmp.Width, udrSpriteImage[0].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[0].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate180FlipNone);
                                                //udrRetVal.bmp.Save("c:\\temp\\temp.bmp");                                                
                                                return udrRetVal;

                                            case 9:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[1].bmp.Width, udrSpriteImage[1].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[1].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate180FlipNone);
                                                return udrRetVal;

                                            case 10:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[2].bmp.Width, udrSpriteImage[2].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[2].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate180FlipNone);
                                                return udrRetVal;

                                            case 11:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[3].bmp.Width, udrSpriteImage[3].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[3].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate180FlipNone);
                                                return udrRetVal;

                                            case 12:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[0].bmp.Width, udrSpriteImage[0].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[0].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate90FlipNone);
                                                return udrRetVal;

                                            case 13:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[1].bmp.Width, udrSpriteImage[1].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[1].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate90FlipNone);
                                                return udrRetVal;

                                            case 14:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[2].bmp.Width, udrSpriteImage[2].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[2].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate90FlipNone);
                                                return udrRetVal;

                                            default:  // case 15
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[3].bmp.Width, udrSpriteImage[3].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[3].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate90FlipNone);
                                                return udrRetVal;
                                        }
                                    }
                                }
                        }
                }
                else
                {
                    return udrSpriteImage[0];
                }
            }
        }
        #endregion

        public void addLimb(classSpriteLimb newLimb, string hingeName, classMath.classRadialCoor radMasterJoint, classMath.classRadialCoor radSlaveJoint)
        {
            if (mySlaveLimbs == null)
                mySlaveLimbs = new classSpriteLimb[0];
            Array.Resize<classSpriteLimb>(ref mySlaveLimbs, mySlaveLimbs.Length + 1);
            mySlaveLimbs[mySlaveLimbs.Length - 1] = newLimb;
            mySlaveLimbs[mySlaveLimbs.Length - 1].MasterHinge = new classSpriteHinge(hingeName, radMasterJoint, radSlaveJoint, this, newLimb);

            Array.Resize<Sprite.classSpriteHinge>(ref mainSprite.hinges, mainSprite.hinges.Length + 1);
            mainSprite.hinges[mainSprite.hinges.Length - 1] = mySlaveLimbs[mySlaveLimbs.Length - 1].MasterHinge;
            newLimb.intMySlaveID = mainSprite.hinges.Length - 1;
        }

        public void subLimb(ref classSpriteLimb thisLimb)
        {
            if (thisLimb.myName.CompareTo(mySlaveLimbs[thisLimb.MySlaveID].myName) != 0)
                MessageBox.Show("we have a problem!");

            disposeAllHinges(ref thisLimb);

            mySlaveLimbs[thisLimb.MySlaveID] = mySlaveLimbs[mySlaveLimbs.Length - 1];
            Array.Resize<Sprite.classSpriteLimb>(ref mySlaveLimbs, mySlaveLimbs.Length - 1);
        }

        void disposeAllHinges(ref Sprite.classSpriteLimb thisLimb)
        {
            for (int intSlaveCounter = 0; intSlaveCounter < mySlaveLimbs.Length; intSlaveCounter++)
                disposeAllHinges(ref mySlaveLimbs[intSlaveCounter]);

            for (int intHingeCounter = 0; intHingeCounter < mainSprite.hinges.Length; intHingeCounter++)
                if (mainSprite.hinges[intHingeCounter].name.CompareTo(thisLimb.MasterHinge.name) == 0)
                {
                    mainSprite.hinges[intHingeCounter] = mainSprite.hinges[mainSprite.hinges.Length - 1];
                    Array.Resize<Sprite.classSpriteHinge>(ref mainSprite.hinges, mainSprite.hinges.Length - 1);
                }
        }
    }

    public class classSpriteMaker
    {
        udtSprite_StorageRetrieval udrStorageSprite;
        const int conMaxNameStringSize = 50;
        const string conStrNull = "---NULL---";

        public classSprite getSprite(bool masterLimbRotates, bool AlwaysVertical, string _myName, string MasterLimb_Name, params Bitmap[] bmpOriginal)
        {
            classSprite spriteRetVal = new classSprite();
            spriteRetVal.myName = _myName;
            spriteRetVal.MasterLimb = new classSpriteLimb(ref spriteRetVal, masterLimbRotates, AlwaysVertical, MasterLimb_Name, bmpOriginal);
            return spriteRetVal;
        }

        #region "Storage and Retrieval"
        public classSprite loadSprite(string strFilename)
        {
            udtSprite_StorageRetrieval udrThisSprite = new udtSprite_StorageRetrieval();

            int intcutchr = strFilename.IndexOf(".");
            if (intcutchr > 0)
                strFilename = strFilename.Substring(0, intcutchr);
            strFilename += ".sp2";
            if (System.IO.File.Exists(strFilename))
                return loadSprite_V2(strFilename);
            else
            {
                classSprite sprRetVal = loadSprite_V1(strFilename);
                saveSprite(ref sprRetVal, strFilename);
                return sprRetVal;
            }
        }

        public classSprite loadSprite_V2(string strFilename)
        {
            udtSprite_StorageRetrieval udrThisSprite = new udtSprite_StorageRetrieval();

            int intcutchr = strFilename.LastIndexOf(".");
            if (intcutchr > 0)
                strFilename = strFilename.Substring(0, intcutchr);
            strFilename += ".sp2";

            FileStream fs = new FileStream(strFilename, FileMode.Open);

            BinaryFormatter formatter = new BinaryFormatter();
            udrThisSprite.myName = (string)formatter.Deserialize(fs);

            int intNumLimbs = (int)formatter.Deserialize(fs);

            udrThisSprite.limbs = new udtLimb_StorageRetrieval[intNumLimbs];

            for (int intLimbCounter = 0; intLimbCounter < intNumLimbs; intLimbCounter++)
            {
                udrThisSprite.limbs[intLimbCounter].myName = (string)formatter.Deserialize(fs);

                udrThisSprite.limbs[intLimbCounter].IRotate = (bool)formatter.Deserialize(fs);
                udrThisSprite.limbs[intLimbCounter].AlwaysVertical = (bool)formatter.Deserialize(fs);

                int intNumBaseImages = (int)formatter.Deserialize(fs);
                udrThisSprite.limbs[intLimbCounter].bmp = new Bitmap[intNumBaseImages];
                for (int intBaseImageCounter = 0; intBaseImageCounter < intNumBaseImages; intBaseImageCounter++)
                    udrThisSprite.limbs[intLimbCounter].bmp[intBaseImageCounter] = (Bitmap)formatter.Deserialize(fs);

                udrThisSprite.limbs[intLimbCounter].radMaster = new classMath.classRadialCoor();
                udrThisSprite.limbs[intLimbCounter].radMaster.angle = (double)formatter.Deserialize(fs);
                udrThisSprite.limbs[intLimbCounter].radMaster.radius = (double)formatter.Deserialize(fs);

                udrThisSprite.limbs[intLimbCounter].radSlave = new classMath.classRadialCoor();
                udrThisSprite.limbs[intLimbCounter].radSlave.angle = (double)formatter.Deserialize(fs);
                udrThisSprite.limbs[intLimbCounter].radSlave.radius = (double)formatter.Deserialize(fs);

                udrThisSprite.limbs[intLimbCounter].MasterIndex = (int)formatter.Deserialize(fs);
                udrThisSprite.limbs[intLimbCounter].hingeName = (string)formatter.Deserialize(fs);
            }

            classSprite retval = getSprite(udrThisSprite.limbs[0].IRotate, udrThisSprite.limbs[0].AlwaysVertical, udrThisSprite.myName, udrThisSprite.limbs[0].myName, udrThisSprite.limbs[0].bmp);

            for (int intLimbCounter = 1; intLimbCounter < udrThisSprite.limbs.Length; intLimbCounter++)
            {
                Sprite.classSpriteLimb masterLimb = retval.getLimbByName(udrThisSprite.limbs[udrThisSprite.limbs[intLimbCounter].MasterIndex].myName);
                if (masterLimb == null)
                    masterLimb = retval.MasterLimb;
                Sprite.classSpriteLimb newLimb = new Sprite.classSpriteLimb(ref retval,
                                            udrThisSprite.limbs[intLimbCounter].IRotate,
                                            udrThisSprite.limbs[intLimbCounter].AlwaysVertical,
                                            udrThisSprite.limbs[intLimbCounter].myName.Trim(),
                                            udrThisSprite.limbs[intLimbCounter].bmp);
                masterLimb.addLimb(newLimb,
                                   udrThisSprite.limbs[intLimbCounter].hingeName.Trim(),
                                   new classMath.classRadialCoor(udrThisSprite.limbs[intLimbCounter].radMaster.angle, udrThisSprite.limbs[intLimbCounter].radMaster.radius),
                                   new classMath.classRadialCoor(udrThisSprite.limbs[intLimbCounter].radSlave.angle, udrThisSprite.limbs[intLimbCounter].radSlave.radius));
            }

            // load limb draw sequence here
            //
            int intNumDrawPointers = (int)formatter.Deserialize(fs);
            retval.limbDrawSequence = new classSpriteLimb[intNumDrawPointers];
            for (int intDrawCounter = 0; intDrawCounter < intNumDrawPointers; intDrawCounter++)
            {
                string strNameLimb = ((string)formatter.Deserialize(fs)).Trim();
                retval.limbDrawSequence[intDrawCounter] = retval.getLimbByName(strNameLimb);
                if (retval.limbDrawSequence[intDrawCounter] == null)
                    retval.limbDrawSequence[intDrawCounter] = retval.MasterLimb;
            }

            // load configurations
            int intNumConfigurations = (int)formatter.Deserialize(fs);

            Array.Resize<classConfiguration>(ref retval.Configurations, intNumConfigurations);
            for (int intConfigurationCounter = 0; intConfigurationCounter < retval.Configurations.Length; intConfigurationCounter++)
            {
                classConfiguration thisCon = new classConfiguration();
                thisCon.name = ((string)formatter.Deserialize(fs)).Trim();

                int intNumberLimbs = (int)formatter.Deserialize(fs);
                Array.Resize<classSpriteLimb>(ref thisCon.LimbDrawSequence, intNumberLimbs);
                for (int intLimbCounter = 0; intLimbCounter < thisCon.LimbDrawSequence.Length; intLimbCounter++)
                {
                    string strConLimbName = ((string)formatter.Deserialize(fs)).Trim();
                    thisCon.LimbDrawSequence[intLimbCounter] = retval.getLimbByName(strConLimbName);

                    if (thisCon.LimbDrawSequence[intLimbCounter] == null)
                        if (retval.MasterLimb.Name.ToUpper().Trim().CompareTo(strConLimbName.Trim().ToUpper()) == 0)
                            thisCon.LimbDrawSequence[intLimbCounter] = retval.MasterLimb;
                }

                int intNumSteps = (int)formatter.Deserialize(fs);
                Array.Resize<udtConfigurationStep>(ref thisCon.steps, intNumSteps);
                for (int intStepCounter = 0; intStepCounter < thisCon.steps.Length; intStepCounter++)
                {
                    Array.Resize<udtConfigurationStepHinge>(ref thisCon.steps[intStepCounter].hingeDetails, intNumberLimbs);
                    for (int intHingeCounter = 0; intHingeCounter < thisCon.steps[intStepCounter].hingeDetails.Length; intHingeCounter++)
                    {
                        string strConStepHingeName = ((string)formatter.Deserialize(fs)).Trim();
                        thisCon.steps[intStepCounter].hingeDetails[intHingeCounter].hinge = retval.getHingeByName(strConStepHingeName);
                        thisCon.steps[intStepCounter].hingeDetails[intHingeCounter].angle = (double)formatter.Deserialize(fs);
                        thisCon.steps[intStepCounter].BmpCacheByMirrorType = new udtConfigurationStepBmpMirrortype[4];
                        for (int intMirrorType = 0; intMirrorType < 4; intMirrorType++)
                            thisCon.steps[intStepCounter].BmpCacheByMirrorType[intMirrorType].dir = new udtBmpAndPtTLInfo[16];
                    }
                }

                retval.Configurations[intConfigurationCounter] = thisCon;
            }
            fs.Close();

            return retval;
        }


        public classSprite loadSprite_V1(string strFilename)
        {
            udtSprite_StorageRetrieval udrThisSprite = new udtSprite_StorageRetrieval();

            int intcutchr = strFilename.IndexOf(".");
            if (intcutchr > 0)
                strFilename = strFilename.Substring(0, intcutchr);
            strFilename += ".spr";

            FileStream fs = new FileStream(strFilename, FileMode.Open);

            BinaryFormatter formatter = new BinaryFormatter();
            udrThisSprite.myName = (string)formatter.Deserialize(fs);

            int intNumLimbs = (int)formatter.Deserialize(fs);

            udrThisSprite.limbs = new udtLimb_StorageRetrieval[intNumLimbs];

            for (int intLimbCounter = 0; intLimbCounter < intNumLimbs; intLimbCounter++)
            {
                udrThisSprite.limbs[intLimbCounter].myName = (string)formatter.Deserialize(fs);

                udrThisSprite.limbs[intLimbCounter].IRotate = (bool)formatter.Deserialize(fs);
                udrThisSprite.limbs[intLimbCounter].AlwaysVertical = (bool)formatter.Deserialize(fs);

                udrThisSprite.limbs[intLimbCounter].bmp = new Bitmap[1];
                udrThisSprite.limbs[intLimbCounter].bmp[0] = (Bitmap)formatter.Deserialize(fs);

                udrThisSprite.limbs[intLimbCounter].radMaster = new classMath.classRadialCoor();
                udrThisSprite.limbs[intLimbCounter].radMaster.angle = (double)formatter.Deserialize(fs);
                udrThisSprite.limbs[intLimbCounter].radMaster.radius = (double)formatter.Deserialize(fs);

                udrThisSprite.limbs[intLimbCounter].radSlave = new classMath.classRadialCoor();
                udrThisSprite.limbs[intLimbCounter].radSlave.angle = (double)formatter.Deserialize(fs);
                udrThisSprite.limbs[intLimbCounter].radSlave.radius = (double)formatter.Deserialize(fs);

                udrThisSprite.limbs[intLimbCounter].MasterIndex = (int)formatter.Deserialize(fs);
                udrThisSprite.limbs[intLimbCounter].hingeName = (string)formatter.Deserialize(fs);
            }

            classSprite retval = getSprite(udrThisSprite.limbs[0].IRotate, udrThisSprite.limbs[0].AlwaysVertical, udrThisSprite.myName, udrThisSprite.limbs[0].myName, udrThisSprite.limbs[0].bmp);

            for (int intLimbCounter = 1; intLimbCounter < udrThisSprite.limbs.Length; intLimbCounter++)
            {
                Sprite.classSpriteLimb masterLimb = retval.getLimbByName(udrThisSprite.limbs[udrThisSprite.limbs[intLimbCounter].MasterIndex].myName);
                if (masterLimb == null)
                    masterLimb = retval.MasterLimb;
                Sprite.classSpriteLimb newLimb = new Sprite.classSpriteLimb(ref retval,
                                            udrThisSprite.limbs[intLimbCounter].IRotate,
                                            udrThisSprite.limbs[intLimbCounter].AlwaysVertical,
                                            udrThisSprite.limbs[intLimbCounter].myName.Trim(),
                                            udrThisSprite.limbs[intLimbCounter].bmp);
                masterLimb.addLimb(newLimb,
                                   udrThisSprite.limbs[intLimbCounter].hingeName.Trim(),
                                   new classMath.classRadialCoor(udrThisSprite.limbs[intLimbCounter].radMaster.angle, udrThisSprite.limbs[intLimbCounter].radMaster.radius),
                                   new classMath.classRadialCoor(udrThisSprite.limbs[intLimbCounter].radSlave.angle, udrThisSprite.limbs[intLimbCounter].radSlave.radius));
            }

            // load limb draw sequence here
            //
            int intNumDrawPointers = (int)formatter.Deserialize(fs);
            retval.limbDrawSequence = new classSpriteLimb[intNumDrawPointers];
            for (int intDrawCounter = 0; intDrawCounter < intNumDrawPointers; intDrawCounter++)
            {
                string strNameLimb = ((string)formatter.Deserialize(fs)).Trim();
                retval.limbDrawSequence[intDrawCounter] = retval.getLimbByName(strNameLimb);
                if (retval.limbDrawSequence[intDrawCounter] == null)
                    retval.limbDrawSequence[intDrawCounter] = retval.MasterLimb;
            }

            // load configurations
            int intNumConfigurations = (int)formatter.Deserialize(fs);

            Array.Resize<classConfiguration>(ref retval.Configurations, intNumConfigurations);
            for (int intConfigurationCounter = 0; intConfigurationCounter < retval.Configurations.Length; intConfigurationCounter++)
            {
                classConfiguration thisCon = new classConfiguration();
                thisCon.name = ((string)formatter.Deserialize(fs)).Trim();

                int intNumberLimbs = (int)formatter.Deserialize(fs);
                Array.Resize<classSpriteLimb>(ref thisCon.LimbDrawSequence, intNumberLimbs);
                for (int intLimbCounter = 0; intLimbCounter < thisCon.LimbDrawSequence.Length; intLimbCounter++)
                {
                    string strConLimbName = ((string)formatter.Deserialize(fs)).Trim();
                    thisCon.LimbDrawSequence[intLimbCounter] = retval.getLimbByName(strConLimbName);

                    if (thisCon.LimbDrawSequence[intLimbCounter] == null)
                        if (retval.MasterLimb.Name.ToUpper().Trim().CompareTo(strConLimbName.Trim().ToUpper()) == 0)
                            thisCon.LimbDrawSequence[intLimbCounter] = retval.MasterLimb;
                }

                int intNumSteps = (int)formatter.Deserialize(fs);
                Array.Resize<udtConfigurationStep>(ref thisCon.steps, intNumSteps);
                for (int intStepCounter = 0; intStepCounter < thisCon.steps.Length; intStepCounter++)
                {
                    Array.Resize<udtConfigurationStepHinge>(ref thisCon.steps[intStepCounter].hingeDetails, intNumberLimbs);
                    for (int intHingeCounter = 0; intHingeCounter < thisCon.steps[intStepCounter].hingeDetails.Length; intHingeCounter++)
                    {
                        string strConStepHingeName = ((string)formatter.Deserialize(fs)).Trim();
                        thisCon.steps[intStepCounter].hingeDetails[intHingeCounter].hinge = retval.getHingeByName(strConStepHingeName);
                        thisCon.steps[intStepCounter].hingeDetails[intHingeCounter].angle = (double)formatter.Deserialize(fs);
                        thisCon.steps[intStepCounter].BmpCacheByMirrorType = new udtConfigurationStepBmpMirrortype[4];
                        for (int intMirrorType = 0; intMirrorType < 4; intMirrorType++)
                            thisCon.steps[intStepCounter].BmpCacheByMirrorType[intMirrorType].dir = new udtBmpAndPtTLInfo[16];
                    }
                }

                retval.Configurations[intConfigurationCounter] = thisCon;
            }
            fs.Close();

            return retval;
        }

        /// <summary>
        /// turns any string into a string of exact size (conMaxNameStringSize) for storage
        /// </summary>
        /// <param name="strName">input string of any length</param>
        /// <returns>output copy of input parameter set to specific storage string length</returns>
        string getNameFromString(string strName) { return (strName.Trim().PadRight(conMaxNameStringSize)).Substring(0, conMaxNameStringSize); }

        public void saveSprite(ref Sprite.classSprite thisSprite, string strFilename)
        {
            udrStorageSprite = new udtSprite_StorageRetrieval();
            udrStorageSprite.myName = getNameFromString(thisSprite.myName);
            udrStorageSprite.limbs = new udtLimb_StorageRetrieval[0];
            createStorageSpriteLimbs(ref thisSprite.MasterLimb);
            strFilename = strFilename.ToUpper().Replace(".SPR", ".SP2");
            FileStream fs = new FileStream(strFilename, FileMode.Create);

            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(fs, udrStorageSprite.myName);

            formatter.Serialize(fs, udrStorageSprite.limbs.Length);

            for (int intLimbCounter = 0; intLimbCounter < udrStorageSprite.limbs.Length; intLimbCounter++)
            {
                formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].myName);
                formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].IRotate);
                formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].AlwaysVertical);

                formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].bmp.Length);
                for (int intImageCounter = 0; intImageCounter < udrStorageSprite.limbs[intLimbCounter].bmp.Length; intImageCounter++)
                    formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].bmp[intImageCounter]);

                formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].radMaster.angle);
                formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].radMaster.radius);

                formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].radSlave.angle);
                formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].radSlave.radius);

                formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].MasterIndex);
                formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].hingeName);
            }

            // save limb drawsequence
            formatter.Serialize(fs, thisSprite.limbDrawSequence.Length);
            for (int intLimbCounter = 0; intLimbCounter < thisSprite.limbDrawSequence.Length; intLimbCounter++)
            {
                if (thisSprite.limbDrawSequence[intLimbCounter] == null)
                    formatter.Serialize(fs, getNameFromString("---NULL---"));
                else
                    formatter.Serialize(fs, getNameFromString(thisSprite.limbDrawSequence[intLimbCounter].Name));
            }
            // save configuration info
            if (thisSprite.Configurations == null)
                formatter.Serialize(fs, 0);
            else
            {
                formatter.Serialize(fs, thisSprite.Configurations.Length);

                for (int intConfigurationCounter = 0; intConfigurationCounter < thisSprite.Configurations.Length; intConfigurationCounter++)
                {
                    classConfiguration thisCon = thisSprite.Configurations[intConfigurationCounter];
                    formatter.Serialize(fs, getNameFromString(thisCon.name));
                    formatter.Serialize(fs, thisCon.LimbDrawSequence.Length);

                    for (int intHingeCounter = 0; intHingeCounter < thisCon.LimbDrawSequence.Length; intHingeCounter++)
                        formatter.Serialize(fs, getNameFromString(thisCon.LimbDrawSequence[intHingeCounter].Name));

                    formatter.Serialize(fs, thisCon.steps.Length);

                    for (int intStepCounter = 0; intStepCounter < thisCon.steps.Length; intStepCounter++)
                    {
                        for (int intHingeCounter = 0; intHingeCounter < thisCon.steps[intStepCounter].hingeDetails.Length; intHingeCounter++)
                        {
                            if (thisCon.steps[intStepCounter].hingeDetails[intHingeCounter].hinge == null)
                            {
                                formatter.Serialize(fs, (getNameFromString(conStrNull)));
                                formatter.Serialize(fs, (double)0.0);
                            }
                            else
                            {
                                formatter.Serialize(fs, getNameFromString(thisCon.steps[intStepCounter].hingeDetails[intHingeCounter].hinge.name));
                                formatter.Serialize(fs, thisCon.steps[intStepCounter].hingeDetails[intHingeCounter].angle);
                            }
                        }
                    }

                    thisSprite.Configurations[intConfigurationCounter] = thisCon;
                }
            }
            fs.Close();
        }

        //public void saveSprite_V1(ref Sprite.classSprite thisSprite, string strFilename)
        //{
        //    udrStorageSprite = new udtSprite_StorageRetrieval();
        //    udrStorageSprite.myName = getNameFromString(thisSprite.myName);
        //    udrStorageSprite.limbs = new udtLimb_StorageRetrieval[0];
        //    createStorageSpriteLimbs(ref thisSprite.MasterLimb);

        //    FileStream fs = new FileStream(strFilename, FileMode.Create);

        //    BinaryFormatter formatter = new BinaryFormatter();
        //    formatter.Serialize(fs, udrStorageSprite.myName);

        //    formatter.Serialize(fs, udrStorageSprite.limbs.Length);

        //    for (int intLimbCounter = 0; intLimbCounter < udrStorageSprite.limbs.Length; intLimbCounter++)
        //    {
        //        formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].myName);
        //        formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].IRotate);
        //        formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].AlwaysVertical);

        //        formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].bmp);

        //        formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].radMaster.angle);
        //        formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].radMaster.radius);

        //        formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].radSlave.angle);
        //        formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].radSlave.radius);

        //        formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].MasterIndex);
        //        formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].hingeName);
        //    }

        //    // save limb drawsequence
        //    formatter.Serialize(fs, thisSprite.limbDrawSequence.Length);
        //    for (int intLimbCounter = 0; intLimbCounter < thisSprite.limbDrawSequence.Length; intLimbCounter++)
        //    {
        //        if (thisSprite.limbDrawSequence[intLimbCounter] == null)
        //            formatter.Serialize(fs, getNameFromString("---NULL---"));
        //        else 
        //        formatter.Serialize(fs, getNameFromString(thisSprite.limbDrawSequence[intLimbCounter].Name));
        //    }
        //    // save configuration info
        //    if (thisSprite.Configurations == null)
        //        formatter.Serialize(fs, 0);
        //    else
        //    {
        //        formatter.Serialize(fs, thisSprite.Configurations.Length);

        //        for (int intConfigurationCounter = 0; intConfigurationCounter < thisSprite.Configurations.Length; intConfigurationCounter++)
        //        {
        //            classConfiguration thisCon = thisSprite.Configurations[intConfigurationCounter];
        //            formatter.Serialize(fs, getNameFromString(thisCon.name));
        //            formatter.Serialize(fs, thisCon.LimbDrawSequence.Length);

        //            for (int intHingeCounter = 0; intHingeCounter < thisCon.LimbDrawSequence.Length; intHingeCounter++)
        //                formatter.Serialize(fs, getNameFromString(thisCon.LimbDrawSequence[intHingeCounter].Name));

        //            formatter.Serialize(fs, thisCon.steps.Length);

        //            for (int intStepCounter = 0; intStepCounter < thisCon.steps.Length; intStepCounter++)
        //            {
        //                for (int intHingeCounter = 0; intHingeCounter < thisCon.steps[intStepCounter].hingeDetails.Length; intHingeCounter++)
        //                {                            
        //                    if (thisCon.steps[intStepCounter].hingeDetails[intHingeCounter].hinge == null)
        //                    {
        //                        formatter.Serialize(fs, (getNameFromString(conStrNull)));
        //                        formatter.Serialize(fs, (double)0.0);
        //                    }
        //                    else
        //                    {
        //                        formatter.Serialize(fs, getNameFromString(thisCon.steps[intStepCounter].hingeDetails[intHingeCounter].hinge.name));
        //                        formatter.Serialize(fs, thisCon.steps[intStepCounter].hingeDetails[intHingeCounter].angle);
        //                    }
        //                }
        //            }

        //            thisSprite.Configurations[intConfigurationCounter] = thisCon;
        //        }
        //    }
        //    fs.Close();
        //}

        void createStorageSpriteLimbs(ref Sprite.classSpriteLimb thisLimb)
        {
            Array.Resize<udtLimb_StorageRetrieval>(ref udrStorageSprite.limbs, udrStorageSprite.limbs.Length + 1);
            udtLimb_StorageRetrieval udrTemp = new udtLimb_StorageRetrieval();

            udrTemp.myName = getNameFromString(thisLimb.Name);

            udrTemp.AlwaysVertical = thisLimb.AlwaysVertical;
            udrTemp.IRotate = thisLimb.IRotate;

            udrTemp.bmp = new Bitmap[thisLimb.udrSpriteLimbImages.Length];
            for (int intBaseImageCounter = 0; intBaseImageCounter < thisLimb.udrSpriteLimbImages.Length; intBaseImageCounter++)
                udrTemp.bmp[intBaseImageCounter] = thisLimb.udrSpriteLimbImages[intBaseImageCounter].bmp;

            udrTemp.radMaster = new classMath.classRadialCoor();
            udrTemp.radSlave = new classMath.classRadialCoor();

            try
            {
                udrTemp.radMaster.angle = thisLimb.MasterHinge.RadCoor_Master.angle;
                udrTemp.radMaster.radius = thisLimb.MasterHinge.RadCoor_Master.radius;
            }
            catch (Exception)
            {
                udrTemp.radMaster.angle = 0;
                udrTemp.radMaster.radius = 0;
            }

            try
            {
                udrTemp.radSlave.angle = thisLimb.MasterHinge.RadCoor_Slave.angle;
                udrTemp.radSlave.radius = thisLimb.MasterHinge.RadCoor_Slave.radius;
            }
            catch (Exception)
            {
                udrTemp.radSlave.angle = 0;
                udrTemp.radSlave.radius = 0;
            }

            try
            { udrTemp.MasterIndex = getLimbIndex(thisLimb.MasterHinge.Limb_Master.Name); }
            catch (Exception)
            { udrTemp.MasterIndex = 0; }

            try
            { udrTemp.hingeName = getNameFromString(thisLimb.MasterHinge.name); }
            catch (Exception)
            { udrTemp.hingeName = ""; }

            udrStorageSprite.limbs[udrStorageSprite.limbs.Length - 1] = udrTemp;
            if (thisLimb.mySlaveLimbs != null)
                for (int intSlaveCounter = 0; intSlaveCounter < thisLimb.mySlaveLimbs.Length; intSlaveCounter++)
                    createStorageSpriteLimbs(ref thisLimb.mySlaveLimbs[intSlaveCounter]);
        }

        int getLimbIndex(string strName)
        {
            for (int intLimbCounter = 0; intLimbCounter < udrStorageSprite.limbs.Length; intLimbCounter++)
                if (udrStorageSprite.limbs[intLimbCounter].myName.Trim().CompareTo(strName) == 0)
                    return intLimbCounter;
            return -1;
        }

        #endregion
    }

    public struct udtBmpAndPtTLInfo
    {
        public Bitmap bmp;
        public Point ptTL;
        public udtConfigStepLimbPosition[] limbPositions;
    }

    public struct udtConfigStepLimbPosition
    {
        public classSpriteLimb limb;
        public Point pt;
        public double dblAngle;
    }

    public struct udtConfigurationStepBmpMirrortype
    {
        public udtBmpAndPtTLInfo[] dir;
    }

    public struct udtConfigurationStep
    {
        public udtConfigurationStepHinge[] hingeDetails;
        public udtConfigurationStepBmpMirrortype[] BmpCacheByMirrorType;
    }

    public struct udtConfigurationStepHinge
    {
        public classSpriteHinge hinge;
        public double angle;
    }

    public class classConfiguration
    {
        public string name;
        public classSpriteLimb[] LimbDrawSequence;
        public udtConfigurationStep[] steps;

        /// <summary>
        /// returns the position of the limb identified by a string with reference to the master limb centered at the sprite's 'loc' for this specific configuration
        /// </summary>
        /// <param name="strLimbName">name of limb whose position is to be determined</param>
        /// <param name="mirror">type of mirror image : vertical, horizontal or both</param>
        /// <param name="intStep">configuration's step index</param>
        /// <param name="intDir">direction(0-15 where east is 0) of the master block</param>
        /// <returns>returns the location of limb relative to master limb</returns>
        public Point getLimbPos(string strLimbName, enuMirror mirror, int intStep, int intDir)
        {
            strLimbName = strLimbName.ToUpper().Trim();
            for (int intLimbCounter = 0; intLimbCounter < LimbDrawSequence.Length; intLimbCounter++)
            {
                if (strLimbName.CompareTo(LimbDrawSequence[intLimbCounter].Name.Trim().ToUpper()) == 0)
                {
                    return getLimbPos(intLimbCounter, mirror, intStep, intDir);
                }
            }
            return new Point(0, 0);
        }

        /// <summary>
        /// returns the position of the limb identified by a string with reference to the master limb centered at the sprite's 'loc' for this specific configuration
        /// assumes mirror = none, and intDir = 0(east)
        /// </summary>
        /// <param name="intLimbDrawSequenceIndex">index in drawsequence of limb whose position is to be determined</param>
        /// <param name="intStep">configuration's step index</param>
        /// <returns>returns the location of limb relative to master limb</returns>
        public Point getLimbPos(int intLimbDrawSequenceIndex, int intStep)
        { return getLimbPos(intLimbDrawSequenceIndex, enuMirror.none, intStep, 0); }

        /// <summary>
        /// returns the position of the limb identified by a string with reference to the master limb centered at the sprite's 'loc' for this specific configuration
        /// assumes intDir =0(east)
        /// </summary>
        /// <param name="intLimbDrawSequenceIndex">index in drawsequence of limb whose position is to be determined</param>
        /// <param name="mirror">type of mirror image : vertical, horizontal or both</param>
        /// <param name="intStep">configuration's step index</param>
        /// <returns>returns the location of limb relative to master limb</returns>
        public Point getLimbPos(int intLimbDrawSequenceIndex, enuMirror mirror, int intStep)
        { return getLimbPos(intLimbDrawSequenceIndex, mirror, 0, intStep); }

        /// <summary>
        /// returns the position of the limb identified by a string with reference to the master limb centered at the sprite's 'loc' for this specific configuration
        /// assumes mirror = none
        /// </summary>
        /// <param name="intLimbDrawSequenceIndex">index in drawsequence of limb whose position is to be determined</param>
        /// <param name="intStep">configuration's step index</param>
        /// <param name="intDir">direction(0-15 where east is 0) of the master block</param>
        /// <returns>returns the location of limb relative to master limb</returns>
        public Point getLimbPos(int intLimbDrawSequenceIndex, int intStep, int intDir)
        { return getLimbPos(intLimbDrawSequenceIndex, enuMirror.none, intStep, intDir); }

        /// <summary>
        /// returns the position of the limb identified by a string with reference to the master limb centered at the sprite's 'loc' for this specific configuration
        /// </summary>
        /// <param name="intLimbDrawSequenceIndex">index in drawsequence of limb whose position is to be determined</param>
        /// <param name="mirror">type of mirror image : vertical, horizontal or both</param>
        /// <param name="intStep">configuration's step index</param>
        /// <param name="intDir">direction(0-15 where east is 0) of the master block</param>
        /// <returns>returns the location of limb relative to master limb</returns>
        public Point getLimbPos(int intLimbDrawSequenceIndex, enuMirror mirror, int intStep, int intDir)
        { return steps[intStep].BmpCacheByMirrorType[(int)mirror].dir[intDir].limbPositions[intLimbDrawSequenceIndex].pt; }

        /// <summary>
        /// returns the index of a limb in this configuration's DrawSequence identified by its name string
        /// </summary>
        /// <param name="strLimbName">name of limb to find</param>
        /// <returns>integer index of limb in drawSequence array, -1 if not found</returns>
        public int getLimbDrawSequenceIndex(string strLimbName)
        {
            strLimbName = strLimbName.ToUpper().Trim();
            for (int intLimbCounter = 0; intLimbCounter < LimbDrawSequence.Length; intLimbCounter++)
                if (strLimbName.CompareTo(LimbDrawSequence[intLimbCounter].Name.Trim().ToUpper()) == 0)
                    return intLimbCounter;

            return -1;
        }
    }

    public class classSprite
    {
        public classSpriteLimb MasterLimb;
        public classConfiguration[] Configurations;
        public classConfiguration conCurrent;
        public int intConfigurationStep_Current;

        /// <summary>
        /// array of pointers to the sprite's limbs equal in size to the size of the actual limbs & hinges arrays
        /// the order in which the limbs are drawn is controlled by the order in which their pointers appear in this array.
        /// only the limbs listed in this array will be drawn by the 'putSpriteToScreen()' function
        /// </summary>
        public classSpriteLimb[] limbDrawSequence;

        string strMyName = "";
        public string myName
        {
            get { return strMyName; }
            set { strMyName = value; }
        }

        double dblDisplaySize = 1.0;
        /// <summary>
        /// double variable factor which determines size of output image relative to original images size where 1.0 is the same
        /// </summary>
        public double DisplaySize
        {
            get { return dblDisplaySize; }
            set { dblDisplaySize = value; }
        }

        public Sprite.classSpriteHinge[] hinges = new classSpriteHinge[0];
        /// <summary>
        /// displays the sprite in the specified configuration and step at a point on referenced bitmap
        /// all of the sprite's hinges are set to their specified configuration and step values
        /// </summary>
        /// <param name="bmpOutput">reference bitmap on which the sprite is to be drawn</param>
        /// <param name="intConfigurationIndex">sprite's output configuration index value</param>
        /// <param name="intConfigurationStep">sprite's output configuration step value</param>
        /// <param name="ptOnScreenLocation">point on the screen where the center of the sprite's master limb is to be located</param>
        public void putConfigurationOnScreen(ref Bitmap bmpOutput,
                                                 int intConfigurationIndex,
                                                 int intConfigurationStep,
                                                 Point ptOnScreenLocation)
        {
            putConfigurationOnScreen(ref bmpOutput,
                                         intConfigurationIndex,
                                         intConfigurationStep,
                                         ptOnScreenLocation,
                                         0,
                                         DisplaySize,
                                         enuMirror.none,
                                        false);
        }

        /// <summary>
        /// displays the sprite in the specified configuration and step at a point on referenced bitmap
        /// all of the sprite's hinges are set to their specified configuration and step values
        /// </summary>
        /// <param name="bmpOutput">reference bitmap on which the sprite is to be drawn</param>
        /// <param name="strConfigurationName">sprite's output configuration name</param>
        /// <param name="intConfigurationStep">sprite's output configuration step value</param>
        /// <param name="ptOnScreenLocation">point on the screen where the center of the sprite's master limb is to be located</param>
        public void putConfigurationOnScreen(ref Bitmap bmpOutput,
                                                 string strConfigurationName,
                                                 int intConfigurationStep,
                                                 Point ptOnScreenLocation)
        {
            putConfigurationOnScreen(ref bmpOutput,
                                         getIndexOfConfigurationByName(strConfigurationName),
                                         intConfigurationStep,
                                         ptOnScreenLocation,
                                         0,
                                         DisplaySize,
                                         enuMirror.none,
                                        false);
        }

        /// <summary>
        /// displays the sprite in the specified configuration and step at a point on referenced bitmap
        /// all of the sprite's hinges are set to their specified configuration and step values
        /// </summary>
        /// <param name="bmpOutput">reference bitmap on which the sprite is to be drawn</param>
        /// <param name="strConfigurationName">sprite's output configuration name</param>
        /// <param name="intConfigurationStep">sprite's output configuration step value</param>
        /// <param name="ptOnScreenLocation">point on the screen where the center of the sprite's master limb is to be located</param>
        /// <param name="DisplaySize">double variable which is multiplied times all size relevant parameters in the drawing sequence 1.0=original image size</param>
        /// <param name="mirror">configuration image reflected in any of four directions, (none, vertical, horizontal or both)</param>
        public void putConfigurationOnScreen(ref Bitmap bmpOutput,
                                                 string strConfigurationName,
                                                 int intConfigurationStep,
                                                 Point ptOnScreenLocation,
                                                 double displaySize,
                                                 enuMirror mirror)
        {
            putConfigurationOnScreen(ref bmpOutput,
                                        getIndexOfConfigurationByName(strConfigurationName),
                                        intConfigurationStep,
                                        ptOnScreenLocation,
                                        0,
                                        displaySize,
                                        mirror,
                                        false);
        }

        /// <summary>
        /// displays the sprite in the specified configuration and step at a point on referenced bitmap
        /// all of the sprite's hinges are set to their specified configuration and step values
        /// </summary>
        /// <param name="bmpOutput">reference bitmap on which the sprite is to be drawn</param>
        /// <param name="intConfigurationIndex">sprite's output configuration index value</param>
        /// <param name="intConfigurationStep">sprite's output configuration step value</param>
        /// <param name="ptOnScreenLocation">point on the screen where the center of the sprite's master limb is to be located</param>
        /// <param name="DisplaySize">double variable which is multiplied times all size relevant parameters in the drawing sequence 1.0=original image size</param>
        /// <param name="mirror">configuration image reflected in any of four directions, (none, vertical, horizontal or both)</param>
        public void putConfigurationOnScreen(ref Bitmap bmpOutput,
                                                 int intConfigurationIndex,
                                                 int intConfigurationStep,
                                                 Point ptOnScreenLocation,
                                                 double dblAngle,
                                                 double DisplaySize,
                                                 enuMirror mirror,
                                                 bool bolForceRebuild)
        {
            if (bmpOutput == null)
                return;

            if (Configurations.Length <= intConfigurationIndex
                || intConfigurationIndex < 0
                || intConfigurationStep < 0
                || Configurations[intConfigurationIndex].steps == null
                || Configurations[intConfigurationIndex].steps.Length <= intConfigurationStep
               )
                return;

            conCurrent = Configurations[intConfigurationIndex];
            intConfigurationStep_Current = intConfigurationStep;

            if (MasterLimb.IRotate)
            {
                MasterLimb.Angle = dblAngle;
                MasterLimb.setDir();
            }

            setSpriteHingesToConfiguration(intConfigurationIndex, intConfigurationStep);

            if (Configurations[intConfigurationIndex].steps != null)
            {
                if (Configurations[intConfigurationIndex].steps[intConfigurationStep].BmpCacheByMirrorType[(int)mirror].dir[MasterLimb.Dir].bmp == null
                    || bolForceRebuild)
                {
                    classSpriteLimb[] limDrawSequence = Configurations[intConfigurationIndex].LimbDrawSequence;
                    Configurations[intConfigurationIndex].steps[intConfigurationStep].BmpCacheByMirrorType[(int)mirror].dir[MasterLimb.Dir] = getImageOnBitmap(DisplaySize, mirror, limDrawSequence);
                }
                drawImageOnoutPutBitmap(ref bmpOutput,
                                            Configurations[intConfigurationIndex].steps[intConfigurationStep].BmpCacheByMirrorType[(int)mirror].dir[MasterLimb.Dir],
                                            ptOnScreenLocation);
            }
        }

        /// <summary>
        /// this function arranges the sprite's hinges according to the values stored in its configurations for a specific configuration & step
        /// </summary>
        /// <param name="intConfigurationIndex">configuration index to which hinges are to be set</param>
        /// <param name="intConfigurationStep">configuration step to which hinges are to be set</param>
        public void setSpriteHingesToConfiguration(int intConfigurationIndex, int intConfigurationStep)
        {

            for (int intHingeCounter = 0;
                 intHingeCounter < Configurations[intConfigurationIndex].steps[intConfigurationStep].hingeDetails.Length;
                 intHingeCounter++)
                try
                {
                    Configurations[intConfigurationIndex]
                        .steps[intConfigurationStep]
                        .hingeDetails[intHingeCounter].hinge.Angle
                          = Configurations[intConfigurationIndex].steps[intConfigurationStep].hingeDetails[intHingeCounter]
                                            .angle;
                }
                catch (Exception) { }
        }

        /// <summary>
        /// draws this sprite onto bitmap at point
        /// </summary>
        /// <param name="bmpOutput">bitmap onto which this sprite is drawn given its current configuration</param>
        /// <param name="ptOnScreenLocation">location on bitmap where this sprite is drawn</param>
        public void putImageOnScreen(ref Bitmap bmpOutput, Point ptOnScreenLocation)
        { putImageOnScreen(ref bmpOutput, ptOnScreenLocation, dblDisplaySize, enuMirror.none); }

        /// <summary>
        /// draws this sprite onto bitmap at point
        /// </summary>
        /// <param name="bmpOutput">bitmap onto which this sprite is drawn given its current configuration</param>
        /// <param name="ptOnScreenLocation">location on bitmap where this sprite is drawn</param>
        /// <param name="DisplaySize">factor by which images are multiplied, e.g. 1.0 original size, 2.0 twice original & 0.5 half original size</param>
        public void putImageOnScreen(ref Bitmap bmpOutput, Point ptOnScreenLocation, double DisplaySize, enuMirror mirror)
        {
            if (bmpOutput == null)
                return;

            if (MasterLimb.IRotate)
                MasterLimb.setDir();

            udtBmpAndPtTLInfo udrTemp = getImageOnBitmap(DisplaySize, mirror, limbDrawSequence);
            drawImageOnoutPutBitmap(ref bmpOutput, udrTemp, ptOnScreenLocation);
        }

        void drawImageOnoutPutBitmap(ref Bitmap bmpOutput, udtBmpAndPtTLInfo udrBmpAndPtTL, Point ptOnScreenLocation)
        {
            using (Graphics g = Graphics.FromImage(bmpOutput))
            { g.DrawImage(udrBmpAndPtTL.bmp, new Point(ptOnScreenLocation.X + udrBmpAndPtTL.ptTL.X, ptOnScreenLocation.Y + udrBmpAndPtTL.ptTL.Y)); }

            for (int intLimbCounter = 0; intLimbCounter < hinges.Length; intLimbCounter++)
            {
                hinges[intLimbCounter].Limb_Slave.Loc = new Point(ptOnScreenLocation.X + udrBmpAndPtTL.ptTL.X + hinges[intLimbCounter].Limb_Slave.Loc.X,
                                                                  ptOnScreenLocation.Y + udrBmpAndPtTL.ptTL.Y + hinges[intLimbCounter].Limb_Slave.Loc.Y);
            }
            MasterLimb.Loc = ptOnScreenLocation;
        }

        /// <summary>
        /// this function returns the sprite's image, as it appears with the hinges
        /// already set, onto the smallest bitmap that will fit the resultant image
        /// </summary>
        /// <param name="DisplaySize">factor by which the original image size is multiplied before out is generated</param>
        /// <param name="mirror">mirror option, e.g. horizontal, vertical, both or neither</param>
        /// <param name="limDrawSequence">classSpriteLimb array specifying in which order the different limbs are to be put onto the screen/param>
        /// <returns>returns a structure of type udtBmpAndPTTLInfo which holds the smallest bitmap that will fit the output image it contains.
        /// the center of the image is not necessarily the center of the bitmap but is described by the point ptTL</returns>
        public udtBmpAndPtTLInfo getImageOnBitmap(double DisplaySize,
                                                  enuMirror mirror,
                                                  classSpriteLimb[] limDrawSequence)
        {
            udtBmpAndPtTLInfo udrRetVal = new udtBmpAndPtTLInfo();

            MasterLimb.Loc = new Point(0, 0);
            putImageOntoScreen_recursion(ref MasterLimb, DisplaySize);

            udrRetVal.ptTL = new Point(-MasterLimb.myCurrentImage.bmp.Width / 2, -MasterLimb.myCurrentImage.bmp.Height / 2);
            Point ptBR = new Point(MasterLimb.myCurrentImage.bmp.Width / 2, MasterLimb.myCurrentImage.bmp.Height / 2);

            for (int intHingeCounter = 0; intHingeCounter < hinges.Length; intHingeCounter++)
            {
                Sprite.classSpriteLimb thisLimb = hinges[intHingeCounter].Limb_Slave;
                if (thisLimb.recDest.Left < udrRetVal.ptTL.X)
                    udrRetVal.ptTL.X = thisLimb.recDest.Left;
                if (thisLimb.recDest.Left + thisLimb.recDest.Width > ptBR.X)
                    ptBR.X = thisLimb.recDest.Left + thisLimb.recDest.Width;
                if (thisLimb.recDest.Top < udrRetVal.ptTL.Y)
                    udrRetVal.ptTL.Y = thisLimb.recDest.Top;
                if (thisLimb.recDest.Top + thisLimb.recDest.Height > ptBR.Y)
                    ptBR.Y = thisLimb.recDest.Top + thisLimb.recDest.Height;
            }

            if (ptBR.X == udrRetVal.ptTL.X)
                ptBR.X += 1;
            if (ptBR.Y == udrRetVal.ptTL.Y)
                ptBR.Y += 1;

            udrRetVal.bmp = new Bitmap(ptBR.X - udrRetVal.ptTL.X, ptBR.Y - udrRetVal.ptTL.Y);
            using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
            {
                if (limDrawSequence != null)
                {
                    udrRetVal.limbPositions = new udtConfigStepLimbPosition[limDrawSequence.Length];

                    for (int intLimbCounter = 0; intLimbCounter < limDrawSequence.Length; intLimbCounter++)
                    {
                        Sprite.classSpriteLimb thisLimb = limDrawSequence[intLimbCounter];

                        if (thisLimb != null)
                        {
                            thisLimb.myCurrentImage.bmp.MakeTransparent();
                            Point ptPos = new Point((int)(-udrRetVal.ptTL.X + thisLimb.recDest.Left), (int)(-udrRetVal.ptTL.Y + thisLimb.recDest.Top));
                            thisLimb.Loc = new Point(ptPos.X + (int)(thisLimb.myCurrentImage.bmp.Width * DisplaySize / 2),
                                                     ptPos.Y + (int)(thisLimb.myCurrentImage.bmp.Height * DisplaySize / 2));
                            if (conCurrent != null)
                            {
                                int intDrawSequenceIndex = conCurrent.getLimbDrawSequenceIndex(thisLimb.Name.ToString());
                                if (intDrawSequenceIndex >= 0)
                                {
                                    udrRetVal.limbPositions[intDrawSequenceIndex].limb = thisLimb;
                                    udrRetVal.limbPositions[intDrawSequenceIndex].pt = new Point(thisLimb.Loc.X - MasterLimb.Loc.X, thisLimb.Loc.Y - MasterLimb.Loc.Y);
                                    udrRetVal.limbPositions[intDrawSequenceIndex].dblAngle = thisLimb.Angle;
                                }
                            }
                            g.DrawImage(new Bitmap(thisLimb.myCurrentImage.bmp, thisLimb.recDest.Size), ptPos);
                        }
                    }
                }
            }

            if (mirror == enuMirror.vertical)
            {
                udrRetVal.bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);
                for (int intLimbCounter = 0; intLimbCounter < hinges.Length; intLimbCounter++)
                {
                    if (conCurrent != null)
                    {
                        int intDrawSequenceIndex = conCurrent.getLimbDrawSequenceIndex(hinges[intLimbCounter].Limb_Slave.Name.ToString());
                        if (intDrawSequenceIndex >= 0)
                        {
                            udrRetVal.limbPositions[intDrawSequenceIndex].limb = hinges[intLimbCounter].Limb_Slave;

                            udrRetVal.limbPositions[intDrawSequenceIndex].pt = new Point(udrRetVal.limbPositions[intDrawSequenceIndex].pt.X,
                                                                                         -udrRetVal.limbPositions[intDrawSequenceIndex].pt.Y);
                            udrRetVal.limbPositions[intDrawSequenceIndex].dblAngle = udrRetVal.limbPositions[intDrawSequenceIndex].limb.Angle;
                        }
                    }
                    hinges[intLimbCounter].Limb_Slave.Loc = new Point(hinges[intLimbCounter].Limb_Slave.Loc.X, udrRetVal.bmp.Height - hinges[intLimbCounter].Limb_Slave.Loc.Y);
                }
                udrRetVal.ptTL.Y = -ptBR.Y;
            }
            else if (mirror == enuMirror.horizontal)
            {
                udrRetVal.bmp.RotateFlip(RotateFlipType.RotateNoneFlipX);
                for (int intLimbCounter = 0; intLimbCounter < hinges.Length; intLimbCounter++)
                {
                    if (conCurrent != null)
                    {
                        int intDrawSequenceIndex = conCurrent.getLimbDrawSequenceIndex(hinges[intLimbCounter].Limb_Slave.Name.ToString());
                        if (intDrawSequenceIndex >= 0)
                        {
                            udrRetVal.limbPositions[intDrawSequenceIndex].limb = hinges[intLimbCounter].Limb_Slave;
                            udrRetVal.limbPositions[intDrawSequenceIndex].pt = new Point(-udrRetVal.limbPositions[intDrawSequenceIndex].pt.X,
                                                                                         udrRetVal.limbPositions[intDrawSequenceIndex].pt.Y);
                            udrRetVal.limbPositions[intDrawSequenceIndex].dblAngle = udrRetVal.limbPositions[intDrawSequenceIndex].limb.Angle;
                        }
                    }
                    hinges[intLimbCounter].Limb_Slave.Loc = new Point(udrRetVal.bmp.Width - hinges[intLimbCounter].Limb_Slave.Loc.X, hinges[intLimbCounter].Limb_Slave.Loc.Y);
                }
                udrRetVal.ptTL.X = -ptBR.X;
            }
            else if (mirror == enuMirror.VerticalAndHorizontal)
            {
                udrRetVal.bmp.RotateFlip(RotateFlipType.RotateNoneFlipXY);
                for (int intLimbCounter = 0; intLimbCounter < hinges.Length; intLimbCounter++)
                {
                    if (conCurrent != null)
                    {
                        int intDrawSequenceIndex = conCurrent.getLimbDrawSequenceIndex(hinges[intLimbCounter].Limb_Slave.Name.ToString());
                        if (intDrawSequenceIndex >= 0)
                        {
                            udrRetVal.limbPositions[intDrawSequenceIndex].limb = hinges[intLimbCounter].Limb_Slave;
                            udrRetVal.limbPositions[intDrawSequenceIndex].pt = new Point(-udrRetVal.limbPositions[intDrawSequenceIndex].pt.X,
                                                                                         -udrRetVal.limbPositions[intDrawSequenceIndex].pt.Y);
                            udrRetVal.limbPositions[intDrawSequenceIndex].dblAngle = udrRetVal.limbPositions[intDrawSequenceIndex].limb.Angle;
                        }
                    }
                    hinges[intLimbCounter].Limb_Slave.Loc = new Point(udrRetVal.bmp.Width - hinges[intLimbCounter].Limb_Slave.Loc.X,
                                                                          udrRetVal.bmp.Height - hinges[intLimbCounter].Limb_Slave.Loc.Y);
                }
                udrRetVal.ptTL = new Point(-ptBR.X, -ptBR.Y);
            }
            udrRetVal.bmp.MakeTransparent();
            return udrRetVal;
        }

        /// <summary>
        /// this function receives a limb which has already been angled and positioned
        /// this limb then places all of its slaves limbs by setting their respective positions & angles
        /// then calls itself once for each slave that recurses with each of these limbs
        /// </summary>
        /// <param name="thisLimb">reference to this recursion's master-limb which will recurse for each of its slave limbs</param>
        /// <param name="dblLocalSizeFactor">factor by which original image is multiplied when calculating positions of slave limbs</param>
        public void putImageOntoScreen_recursion(ref classSpriteLimb thisLimb,
                                                 double dblLocalSizeFactor)
        {
            if (thisLimb.IRotate)
                thisLimb.setDir();
            thisLimb.myCurrentImage = thisLimb.getSpriteImageFromArray();
            thisLimb.recDest = new Rectangle(new Point(thisLimb.Loc.X - (int)(thisLimb.myCurrentImage.bmp.Width * dblLocalSizeFactor / 2),
                                                       thisLimb.Loc.Y - (int)(thisLimb.myCurrentImage.bmp.Height * dblLocalSizeFactor / 2)),
                                             new Size((int)((double)thisLimb.myCurrentImage.bmp.Size.Width * dblLocalSizeFactor),
                                                      (int)((double)thisLimb.myCurrentImage.bmp.Size.Height * dblLocalSizeFactor)));
            if (thisLimb.recDest.Width < 1)
                thisLimb.recDest.Width = 1;
            if (thisLimb.recDest.Height < 1)
                thisLimb.recDest.Height = 1;

            if (thisLimb.mySlaveLimbs != null)
                for (int intSlaveCounter = 0; intSlaveCounter < thisLimb.mySlaveLimbs.Length; intSlaveCounter++)
                {
                    double dblNewAngle = thisLimb.Angle
                                       + thisLimb.mySlaveLimbs[intSlaveCounter].MasterHinge.Angle;
                    thisLimb.mySlaveLimbs[intSlaveCounter].Angle = dblNewAngle;
                    thisLimb.mySlaveLimbs[intSlaveCounter].setDir();

                    Point ptOnMaster = new Point(thisLimb.Loc.X + (int)(thisLimb.mySlaveLimbs[intSlaveCounter].MasterHinge.RadCoor_Master.radius * dblLocalSizeFactor * Math.Cos(thisLimb.mySlaveLimbs[intSlaveCounter].MasterHinge.RadCoor_Master.angle - thisLimb.Angle)),
                                                 thisLimb.Loc.Y - (int)(thisLimb.mySlaveLimbs[intSlaveCounter].MasterHinge.RadCoor_Master.radius * dblLocalSizeFactor * Math.Sin(thisLimb.mySlaveLimbs[intSlaveCounter].MasterHinge.RadCoor_Master.angle - thisLimb.Angle)));

                    thisLimb.mySlaveLimbs[intSlaveCounter].Loc = new Point(ptOnMaster.X + (int)(thisLimb.mySlaveLimbs[intSlaveCounter].MasterHinge.RadCoor_Slave.radius * dblLocalSizeFactor * Math.Cos(thisLimb.mySlaveLimbs[intSlaveCounter].MasterHinge.RadCoor_Slave.angle + thisLimb.mySlaveLimbs[intSlaveCounter].Angle + Math.PI)),
                                                                           ptOnMaster.Y + (int)(thisLimb.mySlaveLimbs[intSlaveCounter].MasterHinge.RadCoor_Slave.radius * dblLocalSizeFactor * Math.Sin(thisLimb.mySlaveLimbs[intSlaveCounter].MasterHinge.RadCoor_Slave.angle + thisLimb.mySlaveLimbs[intSlaveCounter].Angle + Math.PI)));

                    putImageOntoScreen_recursion(ref  thisLimb.mySlaveLimbs[intSlaveCounter],
                                                dblLocalSizeFactor);
                }
        }

        /// <summary>
        /// returns a pointer to the limb identified by name
        /// </summary>
        /// <param name="LimbName">name of the limb to be searched</param>
        /// <returns>returns a pointer to an object of type classSpriteLimb</returns>
        public Sprite.classSpriteLimb getLimbByName(string LimbName)
        {
            LimbName = LimbName.Trim().ToUpper();
            for (int intHingeCounter = 0; intHingeCounter < hinges.Length; intHingeCounter++)
            {
                if (hinges[intHingeCounter].Limb_Slave.Name.Trim().ToUpper().CompareTo(LimbName) == 0)
                    return hinges[intHingeCounter].Limb_Slave;
            }
            if (MasterLimb.Name.Trim().CompareTo(LimbName) == 0)
                return MasterLimb;
            return null;
        }

        /// <summary>
        /// returns a pointer to the hinge identified by name
        /// </summary>
        /// <param name="HingeName">name of hinge to be searched</param>
        /// <returns>returns a pointer to an object of type classSpriteHinge </returns>
        public Sprite.classSpriteHinge getHingeByName(string HingeName)
        {
            HingeName = HingeName.ToUpper();
            for (int intHingeCounter = 0; intHingeCounter < hinges.Length; intHingeCounter++)
                if (hinges[intHingeCounter].name.ToUpper().CompareTo(HingeName) == 0)
                    return hinges[intHingeCounter];
            return null;
        }

        public Sprite.classConfiguration getConfigurationByName(string ConfigurationName)
        {
            ConfigurationName = ConfigurationName.Trim().ToUpper();
            for (int intConfigurationCounter = 0; intConfigurationCounter < Configurations.Length; intConfigurationCounter++)
                if (Configurations[intConfigurationCounter].name.Trim().ToUpper().CompareTo(ConfigurationName) == 0)
                    return Configurations[intConfigurationCounter];
            return null;
        }

        public int getIndexOfConfigurationByName(string ConfigurationName)
        {
            ConfigurationName = ConfigurationName.Trim().ToUpper();
            for (int intConfigurationCounter = 0; intConfigurationCounter < Configurations.Length; intConfigurationCounter++)
                if (Configurations[intConfigurationCounter].name.Trim().ToUpper().CompareTo(ConfigurationName) == 0)
                    return intConfigurationCounter;
            return -1;
        }

        public int getIndexOfHingeByName(string hingeName)
        {
            hingeName = hingeName.Trim().ToUpper();
            for (int intHingeCounter = 0; intHingeCounter < hinges.Length; intHingeCounter++)
                if (hinges[intHingeCounter].name.Trim().ToUpper().CompareTo(hingeName) == 0)
                    return intHingeCounter;
            return -1;
        }

        public int getIndexOfLimbByName(string limbName)
        {
            limbName = limbName.Trim().ToUpper();
            for (int intlimbCounter = 0; intlimbCounter < hinges.Length; intlimbCounter++)
                if (hinges[intlimbCounter].Limb_Slave.Name.Trim().ToUpper().CompareTo(limbName) == 0)
                    return intlimbCounter;
            return -1;
        }
    }


    public class classMath
    {
        public class classMaxMinDouble
        {
            public double Min;
            public double Max;

            public classMaxMinDouble()
            {
                Min = 0.0;
                Max = 0.0;
            }

            public classMaxMinDouble(double min, double max)
            {
                Min = min;
                Max = max;
            }
        }

        public class classRadialCoor
        {
            public double angle;
            public double radius;

            public classRadialCoor()
            {
                angle = 0;
                radius = 0;
            }
            public classRadialCoor(double Angle, double Radius)
            {
                angle = Angle;
                radius = Radius;
            }
        }

        /// <summary>
        /// converts a radial coordinate system into cartesian with origin as initial coordinate
        /// </summary>
        /// <param name="radCoor">radial vector</param>
        /// <returns>cartesian point</returns>
        public static Point getRadLocation(classRadialCoor radCoor) { return getRadLocation(new Point(0, 0), radCoor); }

        /// <summary>
        /// calculates the cartesian location away from input point using radial vector
        /// </summary>
        /// <param name="pt">input point from which </param>
        /// <param name="radCoor">radial vector</param>
        /// <returns>cartesian point</returns>
        public static Point getRadLocation(Point pt, classRadialCoor radCoor)
        { return new Point((int)(pt.X + radCoor.radius * Math.Cos(radCoor.angle)), (int)(pt.Y + radCoor.radius * Math.Sin(radCoor.angle))); }

        /// <summary>
        /// returns the angle in radians between the points ptA and ptB
        /// </summary>
        /// <param name="ptA">first point</param>
        /// <param name="ptB">second point</param>
        /// <returns>double variable equal to angle between origin and point(dX, dY) in radians</returns>
        public static double arcTan(Point ptA, Point ptB) { return arcTan(ptA.X - ptB.X, ptA.Y - ptB.Y); }
        /// <summary>
        /// returns the angle in radians between the origin and the point located at (dX, dY)
        /// </summary>
        /// <param name="dX">x coordinate of vector end</param>
        /// <param name="dY">y coordinate of vector end</param>
        /// <returns>double variable equal to angle between origin and point(dX, dY) in radians</returns>
        public static double arcTan(double dX, double dY)
        {
            double dblAngle = 0;
            if (dX == 0)
                if (dY < 0)
                    dblAngle = 3.0 * Math.PI / 2.0;
                else
                    dblAngle = Math.PI / 2.0;
            else
            {
                dblAngle = Math.Atan((double)dY / (double)dX);
                //  Q2 Q1
                //  Q3 Q4
                if (dX < 0)
                {
                    if (dY < 0) // Q3
                        dblAngle = Math.PI + dblAngle;
                    else              // Q2
                        dblAngle = Math.PI + dblAngle;
                }
                else if (dX > 0)
                {
                    if (dY < 0) // Q4
                        dblAngle = 2.0 * Math.PI + dblAngle;
                    else              // Q1
                        ;
                }
            }
            cleanAngle(ref dblAngle);
            return dblAngle;
        }

        public static void cleanRadians(ref classRadialCoor udrRadCoor) { cleanAngle(ref udrRadCoor.angle); }
        public static double cleanAngle(ref double angle)
        {
            while (angle < 0)
                angle += 2 * Math.PI;

            while (angle > 2 * Math.PI)
                angle -= 2 * Math.PI;

            return angle;
        }

        public static double distanceBetweenTwoPoints(Point pt1, Point pt2) { return Math.Sqrt(Math.Pow(pt1.X - pt2.X, 2) + Math.Pow(pt1.Y - pt2.Y, 2)); }
    }
}

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
CEO unemployable
Canada Canada
Christ Kennedy grew up in the suburbs of Montreal and is a bilingual Quebecois with a bachelor’s degree in computer engineering from McGill University. He is unemployable and currently living in Moncton, N.B. writing his next novel.

Comments and Discussions