첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
본 블로그는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 블로그 콘텐츠 향상을 위해 쓰여집니다.

728x90
반응형
728x170

TestProject.zip
0.04MB

▶ ColoeScheme.cs

namespace TestProject
{
    /// <summary>
    /// 색상 구성표
    /// </summary>
    public enum ColoeScheme
    {
        /// <summary>
        /// 가을
        /// </summary>
        Autumn = 0,

        /// <summary>
        /// 색상 큐브
        /// </summary>
        ColorCube,

        /// <summary>
        /// 차가움
        /// </summary>
        Cool,

        /// <summary>
        /// 구리
        /// </summary>
        Copper,

        /// <summary>
        /// 플래그
        /// </summary>
        Flag,

        /// <summary>
        /// 뜨거움
        /// </summary>
        Hot,

        /// <summary>
        /// HSV 
        /// </summary>
        HSV,

        /// <summary>
        /// 선
        /// </summary>
        Line,

        /// <summary>
        /// 핑크
        /// </summary>
        Pink,

        /// <summary>
        /// 프리즘
        /// </summary>
        Prism,

        /// <summary>
        /// 레인보우 1
        /// </summary>
        Rainbow1,

        /// <summary>
        /// 레인보우 2
        /// </summary>
        Rainbow2,

        /// <summary>
        /// 봄
        /// </summary>
        Spring,

        /// <summary>
        /// 여름
        /// </summary>
        Summer,

        /// <summary>
        /// 겨울
        /// </summary>
        Winter
    }
}

 

728x90

 

▶ CoordinateType.cs

namespace TestProject
{
    /// <summary>
    /// 좌표 타입
    /// </summary>
    public enum CoordinateType
    {
        /// <summary>
        /// X
        /// </summary>
        X = 0,

        /// <summary>
        /// Y
        /// </summary>
        Y = 1,

        /// <summary>
        /// Z
        /// </summary>
        Z = 2
    }
}

 

300x250

 

▶ MouseAction.cs

namespace TestProject
{
    /// <summary>
    /// 마우스 액션
    /// </summary>
    public enum MouseAction
    {
        /// <summary>
        /// 해당 무
        /// </summary>
        None = 0,

        /// <summary>
        /// 이동
        /// </summary>
        Move,

        /// <summary>
        /// RHO
        /// </summary>
        /// <remarks>원점으로부터 거리</remarks>
        Rho,

        /// <summary>
        /// THETA
        /// </summary>
        /// <remarks>Z축의 양의 방향으로부터 원점과 P가 이루는 직선까지의 각</remarks>
        Theta,

        /// <summary>
        /// PHI
        /// </summary>
        /// <remarks>x축의 양의 방향으로부터 원점과 P가 이루는 직선을 XY 평면에 투영시킨 직선까지의 각</remarks>
        Phi
    }
}

 

반응형

 

▶ NormalizeType.cs

namespace TestProject
{
    /// <summary>
    /// 정규화 타입
    /// </summary>
    /// <remarks>
    /// 함수가 예를 들어 "콜백"과 같이 X 및 Y에 대한 비대칭 범위를 갖는 경우 별도의 정규화는 항상 X, Y 값 간의 관계에 대한 왜곡이 되는 정사각형 X, Y 창으로 이어진다.
    /// MaintenanceXY는 X와 Y 값 간의 관계가 유지되도록 한다.
    /// MaintenanceXYZ는 추가로 X, Y 및 Z 값 간의 관계가 유지되도록 보장한다.
    /// </remarks>
    public enum NormalizeType
    {
        /// <summary>
        /// 분리
        /// </summary>
        /// <remarks>X,Y,Z를 별도로 정규화(이산 값에 사용)</remarks>
        Separate,

        /// <summary>
        /// XY 유지
        /// </summary>
        /// <remarks>관계를 변경하지 않고 X,Y 정규화(함수에 사용)</remarks>
        MaintainXY,

        /// <summary>
        /// XYZ 유지
        /// </summary>
        /// <remarks>관계를 변경하지 않고 X,Y,Z 정규화(함수에 사용)</remarks>
        MaintainXYZ
    }
}

 

▶ RasterType.cs

namespace TestProject
{
    /// <summary>
    /// 래스터 타입
    /// </summary>
    public enum RasterType
    {
        /// <summary>
        /// OFF
        /// </summary>
        /// <remarks>좌표계를 그리지 않는다.</remarks>
        Off,

        /// <summary>
        /// 메인 축
        /// </summary>
        /// <remarks>X, Y, Z축을 그린다.</remarks>
        MainAxis,

        /// <summary>
        /// 래스터
        /// </summary>
        /// <remarks>축과 점선을 그린다.</remarks>
        Raster,

        /// <summary>
        /// 레이블
        /// </summary>
        /// <remarks>3사분면에서 축과 점선 그리고 레이블을 그린다.</remarks>
        Label,
    }
}

 

▶ CompilerDelegate.cs

namespace TestProject
{
    //////////////////////////////////////////////////////////////////////////////////////////////////// Delegate
    ////////////////////////////////////////////////////////////////////////////////////////// Public

    #region 컴파일러 대리자 - CompilerDelegate(xArray)

    /// <summary>
    /// 컴파일러 대리자
    /// </summary>
    /// <param name="xArray">X 배열</param>
    /// <returns>처리 결과</returns>
    public delegate double CompilerDelegate(params double[] xArray);

    #endregion
}

 

▶ RendererDelegate.cs

namespace TestProject
{
    //////////////////////////////////////////////////////////////////////////////////////////////////// Delegate
    ////////////////////////////////////////////////////////////////////////////////////////// Public

    #region 렌더러 대리자 - RendererDelegate(x, y)

    /// <summary>
    /// 렌더러 대리자
    /// </summary>
    /// <param name="x">X</param>
    /// <param name="y">Y</param>
    /// <returns>값</returns>
    public delegate double RendererDelegate(double x, double y);

    #endregion
}

 

▶ ColorSchema.cs

using System;
using System.Drawing;

namespace TestProject
{
    /// <summary>
    /// 색상 스키마
    /// </summary>
    public class ColorSchema
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 스키마 구하기 - GetSchema(schemaType)

        /// <summary>
        /// 스키마 구하기
        /// </summary>
        /// <param name="schemaType">스키마 타입</param>
        /// <returns>색상 배열</returns>
        public static Color[] GetSchema(ColoeScheme schemaType)
        {
            if(schemaType == ColoeScheme.Rainbow1)
            {
                Color[] colorArray = new Color[64 * 64];

                int c = 0;

                for(int y = 0; y < 64; y++)
                {
                    for(int x = 0; x < 64; x++)
                    {
                        int i = y * 64 + x;

                        double k = ((double)i) / 4095;

                        colorArray[c++] = GetRainbowColor(k);
                    }
                }

                return colorArray;
            }

            byte[,] rgbArray;

            switch(schemaType)
            {
                case ColoeScheme.Autumn :
                
                    rgbArray = new byte[,]
                    {
                        { 255, 0  , 0 }, { 255, 4  , 0 }, { 255, 8  , 0 }, { 255, 12 , 0 },
                        { 255, 16 , 0 }, { 255, 20 , 0 }, { 255, 24 , 0 }, { 255, 28 , 0 },
                        { 255, 32 , 0 }, { 255, 36 , 0 }, { 255, 40 , 0 }, { 255, 45 , 0 },
                        { 255, 49 , 0 }, { 255, 53 , 0 }, { 255, 57 , 0 }, { 255, 61 , 0 },
                        { 255, 65 , 0 }, { 255, 69 , 0 }, { 255, 73 , 0 }, { 255, 77 , 0 },
                        { 255, 81 , 0 }, { 255, 85 , 0 }, { 255, 89 , 0 }, { 255, 93 , 0 },
                        { 255, 97 , 0 }, { 255, 101, 0 }, { 255, 105, 0 }, { 255, 109, 0 },
                        { 255, 113, 0 }, { 255, 117, 0 }, { 255, 121, 0 }, { 255, 125, 0 },
                        { 255, 130, 0 }, { 255, 134, 0 }, { 255, 138, 0 }, { 255, 142, 0 },
                        { 255, 146, 0 }, { 255, 150, 0 }, { 255, 154, 0 }, { 255, 158, 0 },
                        { 255, 162, 0 }, { 255, 166, 0 }, { 255, 170, 0 }, { 255, 174, 0 },
                        { 255, 178, 0 }, { 255, 182, 0 }, { 255, 186, 0 }, { 255, 190, 0 },
                        { 255, 194, 0 }, { 255, 198, 0 }, { 255, 202, 0 }, { 255, 206, 0 },
                        { 255, 210, 0 }, { 255, 215, 0 }, { 255, 219, 0 }, { 255, 223, 0 },
                        { 255, 227, 0 }, { 255, 231, 0 }, { 255, 235, 0 }, { 255, 239, 0 },
                        { 255, 243, 0 }, { 255, 247, 0 }, { 255, 251, 0 }, { 255, 255, 0 }
                    };
                
                    break;

                case ColoeScheme.ColorCube :
                
                    rgbArray = new byte[,]
                    {
                        { 85 , 85 , 0   }, { 85 , 170, 0   }, { 85 , 255, 0   }, { 170, 85 , 0   },
                        { 170, 170, 0   }, { 170, 255, 0   }, { 255, 85 , 0   }, { 255, 170, 0   },
                        { 255, 255, 0   }, { 0  , 85 , 128 }, { 0  , 170, 128 }, { 0  , 255, 128 },
                        { 85 , 0  , 128 }, { 85 , 85 , 128 }, { 85 , 170, 128 }, { 85 , 255, 128 },
                        { 170, 0  , 128 }, { 170, 85 , 128 }, { 170, 170, 128 }, { 170, 255, 128 },
                        { 255, 0  , 128 }, { 255, 85 , 128 }, { 255, 170, 128 }, { 255, 255, 128 },
                        { 0  , 85 , 255 }, { 0  , 170, 255 }, { 0  , 255, 255 }, { 85 , 0  , 255 },
                        { 85 , 85 , 255 }, { 85 , 170, 255 }, { 85 , 255, 255 }, { 170, 0  , 255 },
                        { 170, 85 , 255 }, { 170, 170, 255 }, { 170, 255, 255 }, { 255, 0  , 255 },
                        { 255, 85 , 255 }, { 255, 170, 255 }, { 43 , 0  , 0   }, { 85 , 0  , 0   },
                        { 128, 0  , 0   }, { 170, 0  , 0   }, { 213, 0  , 0   }, { 255, 0  , 0   },
                        { 0  , 43 , 0   }, { 0  , 85 , 0   }, { 0  , 128, 0   }, { 0  , 170, 0   },
                        { 0  , 213, 0   }, { 0  , 255, 0   }, { 0  , 0  , 43  }, { 0  , 0  , 85  },
                        { 0  , 0  , 128 }, { 0  , 0  , 170 }, { 0  , 0  , 213 }, { 0  , 0  , 255 },
                        { 0  , 0  , 0   }, { 36 , 36 , 36  }, { 73 , 73 , 73  }, { 109, 109, 109 },
                        { 146, 146, 146 }, { 182, 182, 182 }, { 219, 219, 219 }, { 255, 255, 255 }
                    };
                    
                    break;

                case ColoeScheme.Cool :
                
                    rgbArray = new byte[,]
                    {
                        { 0  , 255, 255 }, { 4  , 251, 255 }, { 8  , 247, 255 }, { 12 , 243, 255 },
                        { 16 , 239, 255 }, { 20 , 235, 255 }, { 24 , 231, 255 }, { 28 , 227, 255 },
                        { 32 , 223, 255 }, { 36 , 219, 255 }, { 40 , 215, 255 }, { 45 , 210, 255 },
                        { 49 , 206, 255 }, { 53 , 202, 255 }, { 57 , 198, 255 }, { 61 , 194, 255 },
                        { 65 , 190, 255 }, { 69 , 186, 255 }, { 73 , 182, 255 }, { 77 , 178, 255 },
                        { 81 , 174, 255 }, { 85 , 170, 255 }, { 89 , 166, 255 }, { 93 , 162, 255 },
                        { 97 , 158, 255 }, { 101, 154, 255 }, { 105, 150, 255 }, { 109, 146, 255 },
                        { 113, 142, 255 }, { 117, 138, 255 }, { 121, 134, 255 }, { 125, 130, 255 },
                        { 130, 125, 255 }, { 134, 121, 255 }, { 138, 117, 255 }, { 142, 113, 255 },
                        { 146, 109, 255 }, { 150, 105, 255 }, { 154, 101, 255 }, { 158, 97 , 255 },
                        { 162, 93 , 255 }, { 166, 89 , 255 }, { 170, 85 , 255 }, { 174, 81 , 255 },
                        { 178, 77 , 255 }, { 182, 73 , 255 }, { 186, 69 , 255 }, { 190, 65 , 255 },
                        { 194, 61 , 255 }, { 198, 57 , 255 }, { 202, 53 , 255 }, { 206, 49 , 255 },
                        { 210, 45 , 255 }, { 215, 40 , 255 }, { 219, 36 , 255 }, { 223, 32 , 255 },
                        { 227, 28 , 255 }, { 231, 24 , 255 }, { 235, 20 , 255 }, { 239, 16 , 255 },
                        { 243, 12 , 255 }, { 247, 8  , 255 }, { 251, 4  , 255 }, { 255, 0  , 255 }
                    };
                    
                    break;

                case ColoeScheme.Copper :
                
                    rgbArray = new byte[,]
                    {
                        { 0  , 0  , 0   }, { 5  , 3  , 2   }, { 10 , 6  , 4   }, { 15 , 9  , 6   },
                        { 20 , 13 , 8   }, { 25 , 16 , 10  }, { 30 , 19 , 12  }, { 35 , 22 , 14  },
                        { 40 , 25 , 16  }, { 46 , 28 , 18  }, { 51 , 32 , 20  }, { 56 , 35 , 22  },
                        { 61 , 38 , 24  }, { 66 , 41 , 26  }, { 71 , 44 , 28  }, { 76 , 47 , 30  },
                        { 81 , 51 , 32  }, { 86 , 54 , 34  }, { 91 , 57 , 36  }, { 96 , 60 , 38  },
                        { 101, 63 , 40  }, { 106, 66 , 42  }, { 111, 70 , 44  }, { 116, 73 , 46  },
                        { 121, 76 , 48  }, { 126, 79 , 50  }, { 132, 82 , 52  }, { 137, 85 , 54  },
                        { 142, 89 , 56  }, { 147, 92 , 58  }, { 152, 95 , 60  }, { 157, 98 , 62  },
                        { 162, 101, 64  }, { 167, 104, 66  }, { 172, 108, 68  }, { 177, 111, 70  },
                        { 182, 114, 72  }, { 187, 117, 75  }, { 192, 120, 77  }, { 197, 123, 79  },
                        { 202, 126, 81  }, { 207, 130, 83  }, { 212, 133, 85  }, { 218, 136, 87  },
                        { 223, 139, 89  }, { 228, 142, 91  }, { 233, 145, 93  }, { 238, 149, 95  },
                        { 243, 152, 97  }, { 248, 155, 99  }, { 253, 158, 101 }, { 255, 161, 103 },
                        { 255, 164, 105 }, { 255, 168, 107 }, { 255, 171, 109 }, { 255, 174, 111 },
                        { 255, 177, 113 }, { 255, 180, 115 }, { 255, 183, 117 }, { 255, 187, 119 },
                        { 255, 190, 121 }, { 255, 193, 123 }, { 255, 196, 125 }, { 255, 199, 127 }
                    };
                
                    break;

                case ColoeScheme.Flag :
                
                    rgbArray = new byte[,]
                    {
                        { 255, 0, 0 }, { 255, 255, 255 }, { 0, 0, 255 }, { 0, 0, 0 },
                        { 255, 0, 0 }, { 255, 255, 255 }, { 0, 0, 255 }, { 0, 0, 0 },
                        { 255, 0, 0 }, { 255, 255, 255 }, { 0, 0, 255 }, { 0, 0, 0 },
                        { 255, 0, 0 }, { 255, 255, 255 }, { 0, 0, 255 }, { 0, 0, 0 },
                        { 255, 0, 0 }, { 255, 255, 255 }, { 0, 0, 255 }, { 0, 0, 0 },
                        { 255, 0, 0 }, { 255, 255, 255 }, { 0, 0, 255 }, { 0, 0, 0 },
                        { 255, 0, 0 }, { 255, 255, 255 }, { 0, 0, 255 }, { 0, 0, 0 },
                        { 255, 0, 0 }, { 255, 255, 255 }, { 0, 0, 255 }, { 0, 0, 0 },
                        { 255, 0, 0 }, { 255, 255, 255 }, { 0, 0, 255 }, { 0, 0, 0 },
                        { 255, 0, 0 }, { 255, 255, 255 }, { 0, 0, 255 }, { 0, 0, 0 },
                        { 255, 0, 0 }, { 255, 255, 255 }, { 0, 0, 255 }, { 0, 0, 0 },
                        { 255, 0, 0 }, { 255, 255, 255 }, { 0, 0, 255 }, { 0, 0, 0 },
                        { 255, 0, 0 }, { 255, 255, 255 }, { 0, 0, 255 }, { 0, 0, 0 },
                        { 255, 0, 0 }, { 255, 255, 255 }, { 0, 0, 255 }, { 0, 0, 0 },
                        { 255, 0, 0 }, { 255, 255, 255 }, { 0, 0, 255 }, { 0, 0, 0 },
                        { 255, 0, 0 }, { 255, 255, 255 }, { 0, 0, 255 }, { 0, 0, 0 }
                    };
                    
                    break;

                case ColoeScheme.Hot :
                
                    rgbArray = new byte[,]
                    {
                        { 11 , 0  , 0   }, { 21 , 0  , 0   }, { 32 , 0  , 0   }, { 43 , 0  , 0   },
                        { 53 , 0  , 0   }, { 64 , 0  , 0   }, { 74 , 0  , 0   }, { 85 , 0  , 0   },
                        { 96 , 0  , 0   }, { 106, 0  , 0   }, { 117, 0  , 0   }, { 128, 0  , 0   },
                        { 138, 0  , 0   }, { 149, 0  , 0   }, { 159, 0  , 0   }, { 170, 0  , 0   },
                        { 181, 0  , 0   }, { 191, 0  , 0   }, { 202, 0  , 0   }, { 213, 0  , 0   },
                        { 223, 0  , 0   }, { 234, 0  , 0   }, { 244, 0  , 0   }, { 255, 0  , 0   },
                        { 255, 11 , 0   }, { 255, 21 , 0   }, { 255, 32 , 0   }, { 255, 43 , 0   },
                        { 255, 53 , 0   }, { 255, 64 , 0   }, { 255, 74 , 0   }, { 255, 85 , 0   },
                        { 255, 96 , 0   }, { 255, 106, 0   }, { 255, 117, 0   }, { 255, 128, 0   },
                        { 255, 138, 0   }, { 255, 149, 0   }, { 255, 159, 0   }, { 255, 170, 0   },
                        { 255, 181, 0   }, { 255, 191, 0   }, { 255, 202, 0   }, { 255, 213, 0   },
                        { 255, 223, 0   }, { 255, 234, 0   }, { 255, 244, 0   }, { 255, 255, 0   },
                        { 255, 255, 16  }, { 255, 255, 32  }, { 255, 255, 48  }, { 255, 255, 64  },
                        { 255, 255, 80  }, { 255, 255, 96  }, { 255, 255, 112 }, { 255, 255, 128 },
                        { 255, 255, 143 }, { 255, 255, 159 }, { 255, 255, 175 }, { 255, 255, 191 },
                        { 255, 255, 207 }, { 255, 255, 223 }, { 255, 255, 239 }, { 255, 255, 255 }
                    };
                    
                    break;

                case ColoeScheme.HSV :
                
                    rgbArray = new byte[,]
                    {
                        { 255, 0  , 0   }, { 255, 24 , 0   }, { 255, 48 , 0   }, { 255, 72 , 0   },
                        { 255, 96 , 0   }, { 255, 120, 0   }, { 255, 143, 0   }, { 255, 167, 0   },
                        { 255, 191, 0   }, { 255, 215, 0   }, { 255, 239, 0   }, { 247, 255, 0   },
                        { 223, 255, 0   }, { 199, 255, 0   }, { 175, 255, 0   }, { 151, 255, 0   },
                        { 128, 255, 0   }, { 104, 255, 0   }, { 80 , 255, 0   }, { 56 , 255, 0   },
                        { 32 , 255, 0   }, { 8  , 255, 0   }, { 0  , 255, 16  }, { 0  , 255, 40  },
                        { 0  , 255, 64  }, { 0  , 255, 88  }, { 0  , 255, 112 }, { 0  , 255, 135 },
                        { 0  , 255, 159 }, { 0  , 255, 183 }, { 0  , 255, 207 }, { 0  , 255, 231 },
                        { 0  , 255, 255 }, { 0  , 231, 255 }, { 0  , 207, 255 }, { 0  , 183, 255 },
                        { 0  , 159, 255 }, { 0  , 135, 255 }, { 0  , 112, 255 }, { 0  , 88 , 255 },
                        { 0  , 64 , 255 }, { 0  , 40 , 255 }, { 0  , 16 , 255 }, { 8  , 0  , 255 },
                        { 32 , 0  , 255 }, { 56 , 0  , 255 }, { 80 , 0  , 255 }, { 104, 0  , 255 },
                        { 128, 0  , 255 }, { 151, 0  , 255 }, { 175, 0  , 255 }, { 199, 0  , 255 },
                        { 223, 0  , 255 }, { 247, 0  , 255 }, { 255, 0  , 239 }, { 255, 0  , 215 },
                        { 255, 0  , 191 }, { 255, 0  , 167 }, { 255, 0  , 143 }, { 255, 0  , 120 },
                        { 255, 0  , 96  }, { 255, 0  , 72  }, { 255, 0  , 48  }, { 255, 0  , 24  }
                    };
                    
                    break;

                case ColoeScheme.Rainbow2 :
                
                    rgbArray = new byte[,]
                    {
                        { 0  , 0  , 143 }, { 0  , 0  , 159 }, { 0  , 0  , 175 }, { 0  , 0  , 191 },
                        { 0  , 0  , 207 }, { 0  , 0  , 223 }, { 0  , 0  , 239 }, { 0  , 0  , 255 },
                        { 0  , 16 , 255 }, { 0  , 32 , 255 }, { 0  , 48 , 255 }, { 0  , 64 , 255 },
                        { 0  , 80 , 255 }, { 0  , 96 , 255 }, { 0  , 112, 255 }, { 0  , 128, 255 },
                        { 0  , 143, 255 }, { 0  , 159, 255 }, { 0  , 175, 255 }, { 0  , 191, 255 },
                        { 0  , 207, 255 }, { 0  , 223, 255 }, { 0  , 239, 255 }, { 0  , 255, 255 },
                        { 16 , 255, 239 }, { 32 , 255, 223 }, { 48 , 255, 207 }, { 64 , 255, 191 },
                        { 80 , 255, 175 }, { 96 , 255, 159 }, { 112, 255, 143 }, { 128, 255, 128 },
                        { 143, 255, 112 }, { 159, 255, 96  }, { 175, 255, 80  }, { 191, 255, 64  },
                        { 207, 255, 48  }, { 223, 255, 32  }, { 239, 255, 16  }, { 255, 255, 0   },
                        { 255, 239, 0   }, { 255, 223, 0   }, { 255, 207, 0   }, { 255, 191, 0   },
                        { 255, 175, 0   }, { 255, 159, 0   }, { 255, 143, 0   }, { 255, 128, 0   },
                        { 255, 112, 0   }, { 255, 96 , 0   }, { 255, 80 , 0   }, { 255, 64 , 0   },
                        { 255, 48 , 0   }, { 255, 32 , 0   }, { 255, 16 , 0   }, { 255, 0  , 0   },
                        { 239, 0  , 0   }, { 223, 0  , 0   }, { 207, 0  , 0   }, { 191, 0  , 0   },
                        { 175, 0  , 0   }, { 159, 0  , 0   }, { 143, 0  , 0   }, { 128, 0  , 0   }
                    };
                    
                    break;

                case ColoeScheme.Line :
                
                    rgbArray = new byte[,]
                    {
                        { 0  , 0  , 255 }, { 0  , 128, 0   }, { 255, 0  , 0   }, { 0  , 191, 191 },
                        { 191, 0  , 191 }, { 191, 191, 0   }, { 64 , 64 , 64  }, { 0  , 0  , 255 },
                        { 0  , 128, 0   }, { 255, 0  , 0   }, { 0  , 191, 191 }, { 191, 0  , 191 },
                        { 191, 191, 0   }, { 64 , 64 , 64  }, { 0  , 0  , 255 }, { 0  , 128, 0   },
                        { 255, 0  , 0   }, { 0  , 191, 191 }, { 191, 0  , 191 }, { 191, 191, 0   },
                        { 64 , 64 , 64  }, { 0  , 0  , 255 }, { 0  , 128, 0   }, { 255, 0  , 0   },
                        { 0  , 191, 191 }, { 191, 0  , 191 }, { 191, 191, 0   }, { 64 , 64 , 64  },
                        { 0  , 0  , 255 }, { 0  , 128, 0   }, { 255, 0  , 0   }, { 0  , 191, 191 },
                        { 191, 0  , 191 }, { 191, 191, 0   }, { 64 , 64 , 64  }, { 0  , 0  , 255 },
                        { 0  , 128, 0   }, { 255, 0  , 0   }, { 0  , 191, 191 }, { 191, 0  , 191 },
                        { 191, 191, 0   }, { 64 , 64 , 64  }, { 0  , 0  , 255 }, { 0  , 128, 0   },
                        { 255, 0  , 0   }, { 0  , 191, 191 }, { 191, 0  , 191 }, { 191, 191, 0   },
                        { 64 , 64 , 64  }, { 0  , 0  , 255 }, { 0  , 128, 0   }, { 255, 0  , 0   },
                        { 0  , 191, 191 }, { 191, 0  , 191 }, { 191, 191, 0   }, { 64 , 64 , 64  },
                        { 0  , 0  , 255 }, { 0  , 128, 0   }, { 255, 0  , 0   }, { 0  , 191, 191 },
                        { 191, 0  , 191 }, { 191, 191, 0   }, { 64 , 64 , 64  }, { 0  , 0  , 255 }
                    };
                    
                    break;

                case ColoeScheme.Pink :
                
                    rgbArray = new byte[,]
                    {
                        { 30 , 0  , 0   }, { 50 , 26 , 26  }, { 64 , 37 , 37  }, { 75 , 45 , 45  },
                        { 85 , 52 , 52  }, { 94 , 59 , 59  }, { 102, 64 , 64  }, { 110, 69 , 69  },
                        { 117, 74 , 74  }, { 123, 79 , 79  }, { 130, 83 , 83  }, { 136, 87 , 87  },
                        { 141, 91 , 91  }, { 147, 95 , 95  }, { 152, 98 , 98  }, { 157, 102, 102 },
                        { 162, 105, 105 }, { 167, 108, 108 }, { 172, 111, 111 }, { 176, 114, 114 },
                        { 181, 117, 117 }, { 185, 120, 120 }, { 189, 123, 123 }, { 194, 126, 126 },
                        { 195, 132, 129 }, { 197, 138, 131 }, { 199, 144, 134 }, { 201, 149, 136 },
                        { 202, 154, 139 }, { 204, 159, 141 }, { 206, 164, 144 }, { 207, 169, 146 },
                        { 209, 174, 148 }, { 211, 178, 151 }, { 212, 183, 153 }, { 214, 187, 155 },
                        { 216, 191, 157 }, { 217, 195, 160 }, { 219, 199, 162 }, { 220, 203, 164 },
                        { 222, 207, 166 }, { 223, 211, 168 }, { 225, 215, 170 }, { 226, 218, 172 },
                        { 228, 222, 174 }, { 229, 225, 176 }, { 231, 229, 178 }, { 232, 232, 180 },
                        { 234, 234, 185 }, { 235, 235, 191 }, { 237, 237, 196 }, { 238, 238, 201 },
                        { 240, 240, 206 }, { 241, 241, 211 }, { 243, 243, 216 }, { 244, 244, 221 },
                        { 245, 245, 225 }, { 247, 247, 230 }, { 248, 248, 234 }, { 250, 250, 238 },
                        { 251, 251, 243 }, { 252, 252, 247 }, { 254, 254, 251 }, { 255, 255, 255 }
                    };
                
                    break;

                case ColoeScheme.Prism :
                
                    rgbArray = new byte[,]
                    {
                        { 255, 0  , 0   }, { 255, 128, 0   }, { 255, 255, 0   }, { 0  , 255, 0   },
                        { 0  , 0  , 255 }, { 170, 0  , 255 }, { 255, 0  , 0   }, { 255, 128, 0   },
                        { 255, 255, 0   }, { 0  , 255, 0   }, { 0  , 0  , 255 }, { 170, 0  , 255 },
                        { 255, 0  , 0   }, { 255, 128, 0   }, { 255, 255, 0   }, { 0  , 255, 0   },
                        { 0  , 0  , 255 }, { 170, 0  , 255 }, { 255, 0  , 0   }, { 255, 128, 0   },
                        { 255, 255, 0   }, { 0  , 255, 0   }, { 0  , 0  , 255 }, { 170, 0  , 255 },
                        { 255, 0  , 0   }, { 255, 128, 0   }, { 255, 255, 0   }, { 0  , 255, 0   },
                        { 0  , 0  , 255 }, { 170, 0  , 255 }, { 255, 0  , 0   }, { 255, 128, 0   },
                        { 255, 255, 0   }, { 0  , 255, 0   }, { 0  , 0  , 255 }, { 170, 0  , 255 },
                        { 255, 0  , 0   }, { 255, 128, 0   }, { 255, 255, 0   }, { 0  , 255, 0   },
                        { 0  , 0  , 255 }, { 170, 0  , 255 }, { 255, 0  , 0   }, { 255, 128, 0   },
                        { 255, 255, 0   }, { 0  , 255, 0   }, { 0  , 0  , 255 }, { 170, 0  , 255 },
                        { 255, 0  , 0   }, { 255, 128, 0   }, { 255, 255, 0   }, { 0  , 255, 0   },
                        { 0  , 0  , 255 }, { 170, 0  , 255 }, { 255, 0  , 0   }, { 255, 128, 0   },
                        { 255, 255, 0   }, { 0  , 255, 0   }, { 0  , 0  , 255 }, { 170, 0  , 255 },
                        { 255, 0  , 0   }, { 255, 128, 0   }, { 255, 255, 0   }, { 0  , 255, 0   }
                    };
                    
                    break;

                case ColoeScheme.Spring :
                
                    rgbArray = new byte[,]
                    {
                        { 255, 0  , 255 }, { 255, 4  , 251 }, { 255, 8  , 247 }, { 255, 12 , 243 },
                        { 255, 16 , 239 }, { 255, 20 , 235 }, { 255, 24 , 231 }, { 255, 28 , 227 },
                        { 255, 32 , 223 }, { 255, 36 , 219 }, { 255, 40 , 215 }, { 255, 45 , 210 },
                        { 255, 49 , 206 }, { 255, 53 , 202 }, { 255, 57 , 198 }, { 255, 61 , 194 },
                        { 255, 65 , 190 }, { 255, 69 , 186 }, { 255, 73 , 182 }, { 255, 77 , 178 },
                        { 255, 81 , 174 }, { 255, 85 , 170 }, { 255, 89 , 166 }, { 255, 93 , 162 },
                        { 255, 97 , 158 }, { 255, 101, 154 }, { 255, 105, 150 }, { 255, 109, 146 },
                        { 255, 113, 142 }, { 255, 117, 138 }, { 255, 121, 134 }, { 255, 125, 130 },
                        { 255, 130, 125 }, { 255, 134, 121 }, { 255, 138, 117 }, { 255, 142, 113 },
                        { 255, 146, 109 }, { 255, 150, 105 }, { 255, 154, 101 }, { 255, 158, 97  },
                        { 255, 162, 93  }, { 255, 166, 89  }, { 255, 170, 85  }, { 255, 174, 81  },
                        { 255, 178, 77  }, { 255, 182, 73  }, { 255, 186, 69  }, { 255, 190, 65  },
                        { 255, 194, 61  }, { 255, 198, 57  }, { 255, 202, 53  }, { 255, 206, 49  },
                        { 255, 210, 45  }, { 255, 215, 40  }, { 255, 219, 36  }, { 255, 223, 32  },
                        { 255, 227, 28  }, { 255, 231, 24  }, { 255, 235, 20  }, { 255, 239, 16  },
                        { 255, 243, 12  }, { 255, 247, 8   }, { 255, 251, 4   }, { 255, 255, 0   }
                     };
                    
                    break;

                case ColoeScheme.Summer :
                
                    rgbArray = new byte[,]
                    {
                        { 0  , 128, 102 }, { 4  , 130, 102 }, { 8  , 132, 102 }, { 12 , 134, 102 },
                        { 16 , 136, 102 }, { 20 , 138, 102 }, { 24 , 140, 102 }, { 28 , 142, 102 },
                        { 32 , 144, 102 }, { 36 , 146, 102 }, { 40 , 148, 102 }, { 45 , 150, 102 },
                        { 49 , 152, 102 }, { 53 , 154, 102 }, { 57 , 156, 102 }, { 61 , 158, 102 },
                        { 65 , 160, 102 }, { 69 , 162, 102 }, { 73 , 164, 102 }, { 77 , 166, 102 },
                        { 81 , 168, 102 }, { 85 , 170, 102 }, { 89 , 172, 102 }, { 93 , 174, 102 },
                        { 97 , 176, 102 }, { 101, 178, 102 }, { 105, 180, 102 }, { 109, 182, 102 },
                        { 113, 184, 102 }, { 117, 186, 102 }, { 121, 188, 102 }, { 125, 190, 102 },
                        { 130, 192, 102 }, { 134, 194, 102 }, { 138, 196, 102 }, { 142, 198, 102 },
                        { 146, 200, 102 }, { 150, 202, 102 }, { 154, 204, 102 }, { 158, 206, 102 },
                        { 162, 208, 102 }, { 166, 210, 102 }, { 170, 212, 102 }, { 174, 215, 102 },
                        { 178, 217, 102 }, { 182, 219, 102 }, { 186, 221, 102 }, { 190, 223, 102 },
                        { 194, 225, 102 }, { 198, 227, 102 }, { 202, 229, 102 }, { 206, 231, 102 },
                        { 210, 233, 102 }, { 215, 235, 102 }, { 219, 237, 102 }, { 223, 239, 102 },
                        { 227, 241, 102 }, { 231, 243, 102 }, { 235, 245, 102 }, { 239, 247, 102 },
                        { 243, 249, 102 }, { 247, 251, 102 }, { 251, 253, 102 }, { 255, 255, 102 }
                    };
                    
                    break;

                case ColoeScheme.Winter :
                
                    rgbArray = new byte[,]
                    {
                        { 0, 0  , 255 }, { 0, 4  , 253 }, { 0, 8  , 251 }, { 0, 12 , 249 },
                        { 0, 16 , 247 }, { 0, 20 , 245 }, { 0, 24 , 243 }, { 0, 28 , 241 },
                        { 0, 32 , 239 }, { 0, 36 , 237 }, { 0, 40 , 235 }, { 0, 45 , 233 },
                        { 0, 49 , 231 }, { 0, 53 , 229 }, { 0, 57 , 227 }, { 0, 61 , 225 },
                        { 0, 65 , 223 }, { 0, 69 , 221 }, { 0, 73 , 219 }, { 0, 77 , 217 },
                        { 0, 81 , 215 }, { 0, 85 , 213 }, { 0, 89 , 210 }, { 0, 93 , 208 },
                        { 0, 97 , 206 }, { 0, 101, 204 }, { 0, 105, 202 }, { 0, 109, 200 },
                        { 0, 113, 198 }, { 0, 117, 196 }, { 0, 121, 194 }, { 0, 125, 192 },
                        { 0, 130, 190 }, { 0, 134, 188 }, { 0, 138, 186 }, { 0, 142, 184 },
                        { 0, 146, 182 }, { 0, 150, 180 }, { 0, 154, 178 }, { 0, 158, 176 },
                        { 0, 162, 174 }, { 0, 166, 172 }, { 0, 170, 170 }, { 0, 174, 168 },
                        { 0, 178, 166 }, { 0, 182, 164 }, { 0, 186, 162 }, { 0, 190, 160 },
                        { 0, 194, 158 }, { 0, 198, 156 }, { 0, 202, 154 }, { 0, 206, 152 },
                        { 0, 210, 150 }, { 0, 215, 148 }, { 0, 219, 146 }, { 0, 223, 144 },
                        { 0, 227, 142 }, { 0, 231, 140 }, { 0, 235, 138 }, { 0, 239, 136 },
                        { 0, 243, 134 }, { 0, 247, 132 }, { 0, 251, 130 }, { 0, 255, 128 }
                    };
                    
                    break;

                default :

                    throw new Exception("Invalid enumeration");
            }

            Color[] colorArray2 = new Color[rgbArray.GetLength(0)];

            for(int i = 0; i < colorArray2.Length; i++)
            {
                colorArray2[i] = Color.FromArgb(rgbArray[i, 0], rgbArray[i, 1], rgbArray[i, 2]);
            }

            return colorArray2;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////// Private

        #region 레인보우 색상 구하기 - GetRainbowColor(k)

        /// <summary>
        /// 레인보우 색상 구하기
        /// </summary>
        /// <param name="k">K</param>
        /// <returns>레인보우 색상</returns>
        private static Color GetRainbowColor(double k)
        {
            if(k < 0d)
            {
                k = 0d;
            }

            if(k > 1d)
            {
                k = 1d;
            }

            double red;
            double green;
            double blue;

            if(k < 0.25d)
            {
                red   = 0d;
                green = 4d * k;
                blue  = 1d;
            }
            else if(k < 0.5d)
            {
                red   = 0d;
                green = 1d;
                blue  = 1d - 4d * (k - 0.25d);
            }
            else if(k < 0.75d)
            {
                red   = 4d * (k - 0.5d);
                green = 1d;
                blue  = 0d;
            }
            else
            {
                red   = 1d;
                green = 1d - 4d * (k - 0.75d);
                blue  = 0d;
            }

            byte redByte   = (byte)(red   * 255);
            byte greenByte = (byte)(green * 255);
            byte blueByte  = (byte)(blue  * 255);

            return Color.FromArgb(255, redByte, greenByte, blueByte);
        }

        #endregion
    }
}

 

▶ DrawObject.cs

namespace TestProject
{
    /// <summary>
    /// 그리기 객체
    /// </summary>
    public class DrawObject
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region Field

        /// <summary>
        /// 다각형
        /// </summary>
        public Polygon Polygon;

        /// <summary>
        /// 스캐터
        /// </summary>
        public Scatter Scatter;

        /// <summary>
        /// 선
        /// </summary>
        public Line Line;

        /// <summary>
        /// 정렬
        /// </summary>
        public double Sort;

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 유효 여부
        /// </summary>
        private bool isValid;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 유효 여부 - IsValid

        /// <summary>
        /// 유효 여부
        /// </summary>
        public bool IsValid
        {
            get
            {
                return this.isValid;
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - DrawObject(polygon, sort)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="polygon">다각형</param>
        /// <param name="sort">정렬</param>
        public DrawObject(Polygon polygon, double sort)
        {
            Polygon = polygon;

            this.isValid = polygon.IsValid;

            Sort = sort;
        }

        #endregion
        #region 생성자 - DrawObject(scatter, sort)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="scatter">스캐터</param>
        /// <param name="sort">정렬</param>
        public DrawObject(Scatter scatter, double sort)
        {
            Scatter = scatter;

            this.isValid = scatter.IsValid;

            Sort = sort;
        }

        #endregion
        #region 생성자 - DrawObject(line, sort)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="line">선</param>
        /// <param name="sort">정렬</param>
        public DrawObject(Line line, double sort)
        {
            Line = line;

            this.isValid = line.IsValid;

            Sort = sort;
        }

        #endregion
    }
}

 

▶ FunctionCompiler.cs

using Microsoft.CSharp;
using System;
using System.CodeDom.Compiler;
using System.Reflection;
using System.Text;

namespace TestProject
{
    /// <summary>
    /// 함수 컴파일러
    /// </summary>
    public static class FunctionCompiler
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 클래스 평가 문자열
        /// </summary>
        private const string EVAL_CLASS = @"
using {1};
public class Eval
{{
    public static double e  {{ get {{ return System.Math.E;  }}  }}
    public static double pi {{ get {{ return System.Math.PI; }}  }}
    public static double abs  (double x)           {{ return System.Math.Abs(x);      }}
    public static double acos (double x)           {{ return System.Math.Acos(x);     }}
    public static double asin (double x)           {{ return System.Math.Asin(x);     }}
    public static double atan (double x)           {{ return System.Math.Atan(x);     }}
    public static double atan2(double x, double y) {{ return System.Math.Atan2(x, y); }}
    public static double ceil (double x)           {{ return System.Math.Ceiling(x);  }}
    public static double cos  (double x)           {{ return System.Math.Cos(x);      }}
    public static double cosh (double x)           {{ return System.Math.Cosh(x);     }}
    public static double exp  (double x)           {{ return System.Math.Exp(x);      }}
    public static double floor(double x)           {{ return System.Math.Floor(x);    }}
    public static double log  (double x)           {{ return System.Math.Log(x);      }}
    public static double log2 (double x)           {{ return System.Math.Log(x, 2.0); }}
    public static double log10(double x)           {{ return System.Math.Log10(x);    }}
    public static double max  (double x, double y) {{ return System.Math.Max(x, y);   }}
    public static double min  (double x, double y) {{ return System.Math.Min(x, y);   }}
    public static double pow  (double x, double y) {{ return System.Math.Pow(x, y);   }}
    public static double round(double x)           {{ return System.Math.Round(x);    }}
    public static double sign (double x)           {{ return System.Math.Sign(x);     }}
    public static double sin  (double x)           {{ return System.Math.Sin(x);      }}
    public static double sinh (double x)           {{ return System.Math.Sinh(x);     }}
    public static double sqrt (double x)           {{ return System.Math.Sqrt(x);     }}
    public static double tan  (double x)           {{ return System.Math.Tan(x);      }}
    public static double tanh (double x)           {{ return System.Math.Tanh(x);     }}
    public static double __eval(params double[] __X)
    {{
        double x = __X[0];
        double y = __X[1];
        return {0};
    }}
    public static {2} __get()
    {{
        return __eval;
    }}
}}";

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 컴파일하기 - Compile(sourceCode)

        /// <summary>
        /// 컴파일하기
        /// </summary>
        /// <param name="sourceCode">소스 코드</param>
        /// <returns>렌더러 대리자</returns>
        public static RendererDelegate Compile(string sourceCode)
        {
            sourceCode = sourceCode.Trim().ToLower();

            if(sourceCode.Contains(";"))
            {
                throw new Exception("Function string cannot contain semicolon");
            }

            string evalClass = string.Format(EVAL_CLASS, sourceCode, typeof(CompilerDelegate).Namespace, typeof(CompilerDelegate).Name);

            CSharpCodeProvider provider   = new CSharpCodeProvider();
            CompilerParameters parameters = new CompilerParameters();

            parameters.CompilerOptions  = "/t:library";
            parameters.GenerateInMemory = true;

            parameters.ReferencedAssemblies.Add("mscorlib.dll");
            parameters.ReferencedAssemblies.Add("System.dll");
            parameters.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);

            CompilerResults results = provider.CompileAssemblyFromSource(parameters, evalClass);

            if(results.Errors.HasErrors)
            {
                StringBuilder stringBuilder = new StringBuilder();

                if(results.Errors.Count == 1)
                {
                    stringBuilder.Append("Compilation error :\n");
                }
                else
                {
                    stringBuilder.AppendFormat("{0} Compilation errors :\n", results.Errors.Count);
                }

                foreach(CompilerError error in results.Errors)
                {
                    stringBuilder.Append(error.ErrorText);
                    stringBuilder.Append("\n");
                }

                stringBuilder.Append
                (
                    "\nSupported math functions are:\n" +
                    "e, pi, abs(), acos(), asin(), atan(), atan2(), ceil(), cos(), cosh(), " +
                    "exp(), floor(), log(), log2(), log10(), max(), min(), pow(), " +
                    "round(), sign(), sin(), sinh(), sqrt(), tan(), tanh()\n"
                );

                throw new Exception(stringBuilder.ToString());
            }

            MethodInfo methodInfo = results.CompiledAssembly.GetType("Eval").GetMethod("__get");

            CompilerDelegate compilerDelegate = (CompilerDelegate)methodInfo.Invoke(null, null);

            RendererDelegate redererDelegate = delegate(double X, double Y)
            {
                return compilerDelegate(X, Y);
            };

            return redererDelegate;
        }

        #endregion
    }
}

 

▶ Line.cs

using System;
using System.Drawing;

namespace TestProject
{
    /// <summary>
    /// 선
    /// </summary>
    public class Line
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region Field

        /// <summary>
        /// 메인 좌표 타입
        /// </summary>
        public CoordinateType MainCoordinateType;

        /// <summary>
        /// 보조 좌표 타입
        /// </summary>
        public CoordinateType SecondaryCoordinateType;

        /// <summary>
        /// 레이블
        /// </summary>
        public double Label;

        /// <summary>
        /// 펜
        /// </summary>
        public Pen Pen;

        /// <summary>
        /// 정렬
        /// </summary>
        public double Sort;

        /// <summary>
        /// 각도
        /// </summary>
        public double Angle;

        /// <summary>
        /// 포인트 3D 배열
        /// </summary>
        public Point3D[] Point3DArray = new Point3D[2] { new Point3D(), new Point3D() };

        /// <summary>
        /// 포인트 2D 배열
        /// </summary>
        public Point2D[] Point2DArray = new Point2D[2] { new Point2D(), new Point2D() };

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 유효 여부 - IsValid

        /// <summary>
        /// 유효 여부
        /// </summary>
        public bool IsValid
        {
            get
            {
                return Point2DArray[0].IsValid && Point2DArray[1].IsValid;
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 좌표 동일 여부 구하기 - EqualsCoordinate(line)

        /// <summary>
        /// 좌표 동일 여부 구하기
        /// </summary>
        /// <param name="line">선</param>
        /// <returns>좌표 동일 여부</returns>
        public bool EqualsCoordinate(Line line)
        {
            return Point3DArray[0].Equals(line.Point3DArray[0]) && Point3DArray[1].Equals(line.Point3DArray[1]);
        }

        #endregion
        #region 각도 계산하기 - CalculateAngle()

        /// <summary>
        /// 각도 계산하기
        /// </summary>
        public void CalculateAngle()
        {
            double deltaX = Point2DArray[1].X - Point2DArray[0].X;
            double deltaY = Point2DArray[1].Y - Point2DArray[0].Y;

            Angle = Math.Atan2(deltaY, deltaX) * 180.0 / Math.PI;

            if(Angle < 0.0)
            {
                Angle += 360.0;
            }
        }

        #endregion
    }
}

 

▶ Mouse.cs

using System;
using System.Drawing;
using System.Windows.Forms;

namespace TestProject
{
    /// <summary>
    /// 마우스
    /// </summary>
    public class Mouse
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region Field

        /// <summary>
        /// 마우스 액션
        /// </summary>
        public MouseAction MouseAction;

        /// <summary>
        /// 마지막 위치
        /// </summary>
        public Point LastPosition;

        /// <summary>
        /// 오프셋 포인트
        /// </summary>
        public Point OffsetPoint;

        /// <summary>
        /// 로 트랙바
        /// </summary>
        public TrackBar RhoTrackBar;

        /// <summary>
        /// 세타 트랙바
        /// </summary>
        public TrackBar ThetaTrackBar;

        /// <summary>
        /// 파이 트랙바
        /// </summary>
        public TrackBar PhiTrackBar;

        /// <summary>
        /// 로
        /// </summary>
        public double Rho = Chart3DControl.RHO_VALUE_ARRAY[2];

        /// <summary>
        /// 세타
        /// </summary>
        public double Theta = Chart3DControl.THETA_VALUE_ARRAY[2];

        /// <summary>
        /// 파이
        /// </summary>
        public double Phi = Chart3DControl.PHI_VALUE_ARRAY[2];

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 트랙바 할당하기 - AssignTrackBar(mouseAction, trackBar, scrollEventHandler)

        /// <summary>
        /// 트랙바 할당하기
        /// </summary>
        /// <param name="mouseAction">마우스 액션</param>
        /// <param name="trackBar">트랙바</param>
        /// <param name="scrollEventHandler">스크롤 이벤트 핸들러</param>
        public void AssignTrackBar(MouseAction mouseAction, TrackBar trackBar, EventHandler scrollEventHandler)
        {
            if(trackBar == null)
            {
                return;
            }

            double[] valueArray = null;

            switch(mouseAction)
            {
                case MouseAction.Rho :

                    valueArray = Chart3DControl.RHO_VALUE_ARRAY;

                    RhoTrackBar = trackBar;

                    break;

                case MouseAction.Theta :

                    valueArray = Chart3DControl.THETA_VALUE_ARRAY;

                    ThetaTrackBar = trackBar;

                    break;

                case MouseAction.Phi :

                    valueArray = Chart3DControl.PHI_VALUE_ARRAY;

                    PhiTrackBar = trackBar;

                    break;
            }

            trackBar.Minimum = (int)valueArray[0]; // 0 = 최소값
            trackBar.Maximum = (int)valueArray[1]; // 1 = 최대값
            trackBar.Value   = (int)valueArray[2]; // 2 = 디폴트 값

            trackBar.Scroll += scrollEventHandler;
        }

        #endregion

        #region 트랙바 스크롤시 처리하기 - ProcessTrackBarScroll()

        /// <summary>
        /// 트랙바 스크롤시 처리하기
        /// </summary>
        public void ProcessTrackBarScroll()
        {
            if(RhoTrackBar != null)
            {
                Rho = RhoTrackBar.Value;
            }

            if(ThetaTrackBar != null)
            {
                Theta = ThetaTrackBar.Value;
            }

            if(PhiTrackBar != null)
            {
                Phi = PhiTrackBar.Value;
            }
        }

        #endregion
        #region 마우스 휠 처리하기 - ProcessMouseWheel(delta)

        /// <summary>
        /// 마우스 휠 처리하기
        /// </summary>
        /// <param name="delta">델타</param>
        /// <returns>처리 결과</returns>
        public bool ProcessMouseWheel(int delta)
        {
            if(MouseAction != MouseAction.None)
            {
                return false;
            }

            MouseAction = MouseAction.Rho;

            ProcessMouseMove(0, delta / 10);

            MouseAction = MouseAction.None;

            return true;
        }

        #endregion
        #region 마우스 이동시 처리하기 - ProcessMouseMove(deltaX, deltaY)

        /// <summary>
        /// 마우스 이동시 처리하기
        /// </summary>
        /// <param name="deltaX">델타 X</param>
        /// <param name="deltaY">델타 Y</param>
        public void ProcessMouseMove(int deltaX, int deltaY)
        {
            switch(MouseAction)
            {
                case MouseAction.Rho :

                    Rho += deltaY * Chart3DControl.RHO_VALUE_ARRAY[3];

                    SetRho(Rho);

                    break;

                case MouseAction.Theta :

                    Theta -= deltaY * Chart3DControl.THETA_VALUE_ARRAY[3];

                    SetTheta(Theta);

                    break;

                case MouseAction.Phi:

                    Phi -= deltaX * Chart3DControl.PHI_VALUE_ARRAY[3];

                    SetPhi(Phi);

                    break;
            }
        }

        #endregion

        #region 로 설정하기 - SetRho(rho)

        /// <summary>
        /// 로 설정하기
        /// </summary>
        /// <param name="rho">로</param>
        public void SetRho(double rho)
        {
            Rho = rho;
            Rho = Math.Max(Rho, Chart3DControl.RHO_VALUE_ARRAY[0]);
            Rho = Math.Min(Rho, Chart3DControl.RHO_VALUE_ARRAY[1]);

            if(RhoTrackBar != null)
            {
                RhoTrackBar.Value = (int)Rho;
            }
        }

        #endregion
        #region 세타 설정하기 - SetTheta(theta)

        /// <summary>
        /// 세타 설정하기
        /// </summary>
        /// <param name="theta">세타</param>
        public void SetTheta(double theta)
        {
            Theta = theta;
            Theta = Math.Max(Theta, Chart3DControl.THETA_VALUE_ARRAY[0]);
            Theta = Math.Min(Theta, Chart3DControl.THETA_VALUE_ARRAY[1]);

            if(ThetaTrackBar != null)
            {
                ThetaTrackBar.Value = (int)Theta;
            }
        }

        #endregion
        #region 파이 설정하기 - SetPhi(phi)

        /// <summary>
        /// 파이 설정하기
        /// </summary>
        /// <param name="phi">파이</param>
        public void SetPhi(double phi)
        {
            Phi = phi;

            if(Phi > 360d)
            {
                Phi -= 360d;
            }

            if(Phi < 0d)
            {
                Phi += 360d;
            }

            if(PhiTrackBar != null)
            {
                PhiTrackBar.Value = (int)Phi;
            }
        }

        #endregion
    }
}

 

▶ Point2D.cs

using System;
using System.Drawing;

namespace TestProject
{
    /// <summary>
    /// 포인트 2D
    /// </summary>
    public class Point2D
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region Field

        /// <summary>
        /// X
        /// </summary>
        public double X;

        /// <summary>
        /// Y
        /// </summary>
        public double Y;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 좌표 - Coordinate

        /// <summary>
        /// 좌표
        /// </summary>
        public PointF Coordinate
        {
            get
            {
                return new PointF((float)X, (float)Y);
            }
        }

        #endregion
        #region 유효 여부 - IsValid

        /// <summary>
        /// 유효 여부
        /// </summary>
        public bool IsValid
        {
            get
            {
                return (!double.IsNaN(X) && Math.Abs(X) < 9999.9d && !double.IsNaN(Y) && Math.Abs(Y) < 9999.9d);
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 문자열 구하기 - ToString()

        /// <summary>
        /// 문자열 구하기
        /// </summary>
        /// <returns>문자열</returns>
        public override string ToString()
        {
            return string.Format("{0:0.00}, {1:0.00}", X, Y);
        }

        #endregion
    }
}

 

▶ Point3D.cs

namespace TestProject
{
    /// <summary>
    /// 포인트 3D
    /// </summary>
    public class Point3D
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region Field

        /// <summary>
        /// X
        /// </summary>
        public double X;

        /// <summary>
        /// Y
        /// </summary>
        public double Y;

        /// <summary>
        /// Z
        /// </summary>
        public double Z;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - Point3D

        /// <summary>
        /// 생성자
        /// </summary>
        public Point3D()
        {
        }

        #endregion
        #region 생성자 - Point3D(x, y, z)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="x">X</param>
        /// <param name="y">Y</param>
        /// <param name="z">Z</param>
        public Point3D(double x, double y, double z)
        {
            X = x;
            Y = y;
            Z = z;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 복제하기 - Clone()

        /// <summary>
        /// 복제하기
        /// </summary>
        /// <returns>포인트 3D</returns>
        public Point3D Clone()
        {
            return new Point3D(X, Y, Z);
        }

        #endregion
        #region 동일 여부 구하기 - Equals(point)

        /// <summary>
        /// 동일 여부 구하기
        /// </summary>
        /// <param name="point">포인트</param>
        /// <returns>동일 여부</returns>
        public bool Equals(Point3D point)
        {
            return X == point.X && Y == point.Y && Z == point.Z;
        }

        #endregion
 
        #region 값 설정하기 - SetValue(coordinateType, value)

        /// <summary>
        /// 값 설정하기
        /// </summary>
        /// <param name="coordinateType">좌표 타입</param>
        /// <param name="value">값</param>
        public void SetValue(CoordinateType coordinateType, double value)
        {
            switch(coordinateType)
            {
                case CoordinateType.X : X = value; break;
                case CoordinateType.Y : Y = value; break;
                case CoordinateType.Z : Z = value; break;
            }
        }

        #endregion
        #region 값 구하기 - GetValue(coordinateType)

        /// <summary>
        /// 값 구하기
        /// </summary>
        /// <param name="coordinateType">좌표 타입</param>
        /// <returns>값</returns>
        public double GetValue(CoordinateType coordinateType)
        {
            switch(coordinateType)
            {
                case CoordinateType.X : return X;
                case CoordinateType.Y : return Y;
                case CoordinateType.Z : return Z;
                default               : return 0d;
            }
        }

        #endregion

        #region 문자열 구하기 - ToString()

        /// <summary>
        /// 문자열 구하기
        /// </summary>
        /// <returns>문자열</returns>
        public override string ToString()
        {
            return string.Format("{0:0.00}, {1:0.00}, {2:0.00}", X, Y, Z);
        }

        #endregion
    }
}

 

▶ Polygon.cs

using System.Drawing;

namespace TestProject
{
    /// <summary>
    /// 다각형
    /// </summary>
    public class Polygon
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region Field

        /// <summary>
        /// 포인트 배열
        /// </summary>
        public PointF[] PointArray;

        /// <summary>
        /// 팩터 Z
        /// </summary>
        public double FactorZ;

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 유효 여부
        /// </summary>
        private bool isValid;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 유효 여부 - IsValid

        /// <summary>
        /// 유효 여부
        /// </summary>
        public bool IsValid
        {
            get
            {
                return this.isValid;
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - Polygon(pointArray)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="pointArray">포인트 배열</param>
        public Polygon(params Point2D[] pointArray)
        {
            this.isValid = true;

            PointArray = new PointF[pointArray.Length];

            for(int i = 0; i < pointArray.Length; i++)
            {
                if(pointArray[i].IsValid)
                {
                    PointArray[i] = pointArray[i].Coordinate;
                }
                else
                {
                    this.isValid = false;
                }
            }
        }

        #endregion
    }
}

 

▶ Quadrant.cs

using System;

namespace TestProject
{
    /// <summary>
    /// 사분면
    /// </summary>
    public class Quadrant
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region Field

        /// <summary>
        /// XY 정렬
        /// </summary>
        public double SortXY;

        /// <summary>
        /// XZ 정렬
        /// </summary>
        public double SortXZ;

        /// <summary>
        /// YZ 정렬
        /// </summary>
        public double SortYZ;

        /// <summary>
        /// 사분면 값
        /// </summary>
        public int QuadrantValue;

        /// <summary>
        /// 하단 뷰 여부
        /// </summary>
        public bool BottomView;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - Quadrant(phi, axisXLine, axisYLine, axisZLine)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="phi">파이</param>
        /// <param name="axisXLine">X축 선</param>
        /// <param name="axisYLine">Y축 선</param>
        /// <param name="axisZLine">Z축 선</param>
        public Quadrant(double phi, Line axisXLine, Line axisYLine, Line axisZLine)
        {
            int section45 = (int)phi + 45;

            if(section45 > 360)
            {
                section45 -= 360;
            }

            section45 = Math.Min(3, section45 / 90);

            switch(section45)
            {
                case 0 : BottomView = axisXLine.Angle < 180d; break;
                case 1 : BottomView = axisYLine.Angle < 180d; break;
                case 2 : BottomView = axisXLine.Angle > 180d; break;
                case 3 : BottomView = axisYLine.Angle > 180d; break;
            }

            if(BottomView)
            {
                switch(section45)
                {
                    case 0 : QuadrantValue = axisXLine.Angle + 180d < axisZLine.Angle ? 1 : 0; break;
                    case 1 : QuadrantValue = axisYLine.Angle + 180d < axisZLine.Angle ? 2 : 1; break;
                    case 2 : QuadrantValue = axisXLine.Angle        < axisZLine.Angle ? 3 : 2; break;
                    case 3 : QuadrantValue = axisYLine.Angle        < axisZLine.Angle ? 0 : 3; break;
                }
            }
            else
            {
                switch(section45)
                {
                    case 0 : QuadrantValue = axisXLine.Angle        > axisZLine.Angle ? 1 : 0; break;
                    case 1 : QuadrantValue = axisYLine.Angle        > axisZLine.Angle ? 2 : 1; break;
                    case 2 : QuadrantValue = axisXLine.Angle + 180d > axisZLine.Angle ? 3 : 2; break;
                    case 3 : QuadrantValue = axisYLine.Angle + 180d > axisZLine.Angle ? 0 : 3; break;
                }
            }

            SortXY = (BottomView) ? 99999.9 : -99999.9;
            SortXZ = (QuadrantValue == 1 || QuadrantValue == 2) ? 99999.9 : -99999.9;
            SortYZ = (QuadrantValue == 0 || QuadrantValue == 1) ? 99999.9 : -99999.9;

            axisXLine.Sort = SortXZ;
            axisYLine.Sort = SortYZ;
            axisZLine.Sort = 0.0;
        }

        #endregion
    }
}

 

▶ Range3D.cs

using System;

namespace TestProject
{
    /// <summary>
    /// 범위 3D
    /// </summary>
    public class Range3D
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region Field

        /// <summary>
        /// 최소 X
        /// </summary>
        public double MinimumX = double.PositiveInfinity;

        /// <summary>
        /// 최대 X
        /// </summary>
        public double MaximumX = double.NegativeInfinity;

        /// <summary>
        /// 최소 Y
        /// </summary>
        public double MinimumY = double.PositiveInfinity;

        /// <summary>
        /// 최대 Y
        /// </summary>
        public double MaximumY = double.NegativeInfinity;

        /// <summary>
        /// 최소 Z
        /// </summary>
        public double MinimumZ = double.PositiveInfinity;

        /// <summary>
        /// 최대 Z
        /// </summary>
        public double MaximumZ = double.NegativeInfinity;

        /// <summary>
        /// 중심 포인트
        /// </summary>
        public Point3D CenterPoint = new Point3D();

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - Range3D(pointArray)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="pointArray">포인트 배열</param>
        public Range3D(Point3D[,] pointArray)
        {
            for(int x = 0; x < pointArray.GetLength(0); x++)
            {
                for(int y = 0; y < pointArray.GetLength(1); y++)
                {
                    Point3D point = pointArray[x,y];

                    MinimumX = Math.Min(MinimumX, point.X);
                    MaximumX = Math.Max(MaximumX, point.X);
                    MinimumY = Math.Min(MinimumY, point.Y);
                    MaximumY = Math.Max(MaximumY, point.Y);
                    MinimumZ = Math.Min(MinimumZ, point.Z);
                    MaximumZ = Math.Max(MaximumZ, point.Z);
                }
            }
        }

        #endregion
        #region 생성자 - Range3D(scatterArray)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="scatterArray">스캐터 배열</param>
        public Range3D(Scatter[] scatterArray)
        {
            foreach(Scatter scatter in scatterArray)
            {
                Point3D point = scatter.Point3D;

                MinimumX = Math.Min(MinimumX, point.X);
                MaximumX = Math.Max(MaximumX, point.X);
                MinimumY = Math.Min(MinimumY, point.Y);
                MaximumY = Math.Max(MaximumY, point.Y);
                MinimumZ = Math.Min(MinimumZ, point.Z);
                MaximumZ = Math.Max(MaximumZ, point.Z);
            }
        }

        #endregion
    }
}

 

▶ Scatter.cs

using System.Drawing;

namespace TestProject
{
    /// <summary>
    /// 스캐터
    /// </summary>
    public class Scatter
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region Field

        /// <summary>
        /// 포인트 3D
        /// </summary>
        public Point3D Point3D;

        /// <summary>
        /// 포인트
        /// </summary>
        public PointF Point;

        /// <summary>
        /// 브러시
        /// </summary>
        public Brush Brush;

        /// <summary>
        /// 펜
        /// </summary>
        public Pen Pen;

        /// <summary>
        /// 팩터 Z
        /// </summary>
        public double FactorZ;

        /// <summary>
        /// 이전 스캐터
        /// </summary>
        public Scatter PreviousScatter;

        /// <summary>
        /// 결합 여부
        /// </summary>
        public bool Combine;

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 유효 여부
        /// </summary>
        private bool isValid;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 유효 여부 - IsValid

        /// <summary>
        /// 유효 여부
        /// </summary>
        public bool IsValid
        {
            get
            {
                return this.isValid;
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - Scatter(x, y, z, brush)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="x">X</param>
        /// <param name="y">Y</param>
        /// <param name="z">Z</param>
        /// <param name="brush">브러시</param>
        public Scatter(double x, double y, double z, Brush brush)
        {
            Point3D = new Point3D(x, y, z);
            Brush   = brush;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 포인트 2D 설정하기 - SetPoint2D(point2D)

        /// <summary>
        /// 포인트 2D 설정하기
        /// </summary>
        /// <param name="point2D">포인트 2D</param>
        public void SetPoint2D(Point2D point2D)
        {
            Point = point2D.Coordinate;

            this.isValid = point2D.IsValid;

            Point.X -= Chart3DControl.SCATTER_SIZE;
            Point.Y -= Chart3DControl.SCATTER_SIZE;
        }

        #endregion
    }
}

 

▶ Transform.cs

using System;
using System.Drawing;

namespace TestProject
{
    /// <summary>
    /// 변환
    /// </summary>
    public class Transform
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region Field

        /// <summary>
        /// 정규화 X
        /// </summary>
        public double NormalizeX;

        /// <summary>
        /// 정규화 Y
        /// </summary>
        public double NormalizeY;

        /// <summary>
        /// 정규화 Z
        /// </summary>
        public double NormalizeZ;

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 거리
        /// </summary>
        private double distance;

        /// <summary>
        /// 로
        /// </summary>
        private double rho;

        /// <summary>
        /// 세타 싸인
        /// </summary>
        private double thetaSine;

        /// <summary>
        /// 세타 코싸인
        /// </summary>
        private double thetaCosine;

        /// <summary>
        /// 파이 싸인
        /// </summary>
        private double phiSine;

        /// <summary>
        /// 파이 코싸인
        /// </summary>
        private double phiCosine;

        /// <summary>
        /// 팩터 X
        /// </summary>
        private double factorX;

        /// <summary>
        /// 오프셋 X
        /// </summary>
        private double offsetX;

        /// <summary>
        /// 팩터 Y
        /// </summary>
        private double factorY;

        /// <summary>
        /// 오프셋 Y
        /// </summary>
        private double offsetY;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 계수 설정하기 - SetCoeficients(mouse)

        /// <summary>
        /// 계수 설정하기
        /// </summary>
        /// <param name="mouse">마우스</param>
        public void SetCoeficients(Mouse mouse)
        {
            this.rho =  mouse.Rho;

            double theta = mouse.Theta * Math.PI / 180d;
            double phi   = (mouse.Phi -180d) * Math.PI / 180d;

            this.phiSine     = Math.Sin(phi);
            this.phiCosine   = Math.Cos(phi);
            this.thetaSine   = Math.Sin(theta);
            this.thetaCosine = Math.Cos(theta);
            this.distance    = 0.5d;
        }

        #endregion
        #region 크기 설정하기 - SetSize(size)

        /// <summary>
        /// 크기 설정하기
        /// </summary>
        /// <param name="size">크기</param>
        public void SetSize(Size size)
        {
            double width  = size.Width  * 0.0254d / 96d;
            double height = size.Height * 0.0254d / 96d;

            this.factorX =  size.Width  / width;
            this.factorY = -size.Height / height;
                
            this.offsetX =  this.factorX * width  / 2d;
            this.offsetY = -this.factorY * height / 2d;
        }

        #endregion
        #region 투영하기 - Project(point3D, centerPoint3D)

        /// <summary>
        /// 투영하기
        /// </summary>
        /// <param name="point3D">포인트 3D</param>
        /// <param name="centerPoint3D">중심 포인트 3D</param>
        /// <returns>포인트 2D</returns>
        public Point2D Project(Point3D point3D, Point3D centerPoint3D)
        {
            double x = (point3D.X - centerPoint3D.X) * NormalizeX;
            double y = (point3D.Y - centerPoint3D.Y) * NormalizeY;
            double z = (point3D.Z - centerPoint3D.Z) * NormalizeZ;

            double xNegative = -this.phiSine * x + this.phiCosine * y;
            double yNegative = -this.phiCosine * this.thetaCosine * x - this.phiSine * this.thetaCosine * y + this.thetaSine * z;
            double zNegative = -this.phiCosine * this.thetaSine * x - this.phiSine * this.thetaSine * y - this.thetaCosine * z + this.rho;

            if(zNegative <= 0)
            {
                zNegative = 0.01d;
            }

            Point2D point2D = new Point2D();

            point2D.X = this.factorX * xNegative * this.distance / zNegative + this.offsetX;
            point2D.Y = this.factorY * yNegative * this.distance / zNegative + this.offsetY;

            return point2D;
        }

        #endregion
        #region XY 투영하기 - ProjectXY(x, y)

        /// <summary>
        /// XY 투영하기
        /// </summary>
        /// <param name="x">X</param>
        /// <param name="y">Y</param>
        /// <returns>투영 값</returns>
        public double ProjectXY(double x, double y)
        {
            return x * this.phiCosine + y * this.phiSine;
        }

        #endregion
    }
}

 

▶ Chart3DControl.cs

using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Globalization;
using System.Windows.Forms;

namespace TestProject
{
    /// <summary>
    /// 차트 3D 컨트롤
    /// </summary>
    public class Chart3DControl : UserControl
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region Field

        // 마우스 동작 및 트랙바에 대한 제한 및 기본값
        // 주의 : MIN, MAX 값을 변경하지 않는 것이 좋다.
        // 마우스 요소는 변경에 필요한 마우스 움직임의 양을 정의한다.
        // 화면에서 마우스를 약 1000픽셀 이동하면 최소에서 최대로 또는 그 반대로 이동한다.
        // 배열 값 : MIN, MAX, DEFAULT, MOUSE FACTOR

        /// <summary>
        /// 로 값 배열
        /// </summary>
        public static readonly double[] RHO_VALUE_ARRAY = new double[] { 300, 1800, 1350, 2 };

        /// <summary>
        /// 세타 값 배열
        /// </summary>
        public static readonly double[] THETA_VALUE_ARRAY = new double[] { 10, 170, 70, 0.25 };

        /// <summary>
        /// 파이 값 배열
        /// </summary>
        public static readonly double[] PHI_VALUE_ARRAY = new double[] { 0, 360, 230, 0.4 };

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Instance
        //////////////////////////////////////////////////////////////////////////////// Public

        #region Field

        /// <summary>
        /// 스캐터 크기
        /// </summary>
        public const int SCATTER_SIZE = 3;

        #endregion

        //////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 축 초과
        /// </summary>
        /// <remarks>축이 가장 높은 X, Y, Z 값보다 10% 더 길다.</remarks>
        private const double AXIS_EXCESS = 1.1;

        /// <summary>
        /// 수직 오프셋
        /// </summary>
        /// <remarks>이상한 이유로 그래프가 세로로 중앙에 있지 않는다.</remarks>
        private const int VERTICAL_OFFSET = -30;

        /// <summary>
        /// 래스터 타입
        /// </summary>
        private RasterType rasterType = RasterType.Off;

        /// <summary>
        /// 축 펜 배열
        /// </summary>
        private Pen[] axisPenArray = new Pen[3];

        /// <summary>
        /// 래스터 펜 배열
        /// </summary>
        private Pen[] rasterPenArray = new Pen[3];

        /// <summary>
        /// 변환
        /// </summary>
        private Transform transform = new Transform();

        /// <summary>
        /// 그리기 객체 리스트
        /// </summary>
        private List<DrawObject> drawObjectList = new List<DrawObject>();

        /// <summary>
        /// 마우스
        /// </summary>
        private Mouse mouse = new Mouse();

        /// <summary>
        /// 오프셋 포인트
        /// </summary>
        private Point offsetPoint = new Point();

        /// <summary>
        /// 축 레전드 문자열 배열
        /// </summary>
        private string[] axisLegendStringArray = new string[3];

        /// <summary>
        /// 축 브러시 배열
        /// </summary>
        private SolidBrush[] axisBrushArray = new SolidBrush[3];

        /// <summary>
        /// 다각선 펜
        /// </summary>
        private Pen polyLinePen;

        /// <summary>
        /// 테두리 펜
        /// </summary>
        private Pen borderPen;

        /// <summary>
        /// 상위 레전드 브러시
        /// </summary>
        private SolidBrush topLegendBrush;

        /// <summary>
        /// 색상 구성표 브러시 배열
        /// </summary>
        private SolidBrush[] colorSchemeBrusheArray;

        /// <summary>
        /// 색상 구성표 펜 배열
        /// </summary>
        private Pen[] colorSchemePenArray;

        /// <summary>
        /// 포인트 배열
        /// </summary>
        private Point3D[,] pointArray;

        /// <summary>
        /// 스캐터 배열
        /// </summary>
        private Scatter[] scatterArray;

        /// <summary>
        /// 범위
        /// </summary>
        private Range3D range;

        /// <summary>
        /// 사분면
        /// </summary>
        private Quadrant quadrant;

        /// <summary>
        /// 포인트 카운트
        /// </summary>
        private int pointCount;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 래스터 타입 - RasterType

        /// <summary>
        /// 래스터 타입
        /// </summary>
        public RasterType RasterType
        {
            set
            {
                if(this.rasterType != value)
                {
                    this.rasterType = value;

                    this.drawObjectList.Clear();

                    Invalidate();
                }
            }
            get
            {
                return this.rasterType;
            }
        }

        #endregion
        #region 다각형 선 색상 - PolygonLineColor

        /// <summary>
        /// 다각형 선 색상
        /// </summary>
        public Color PolygonLineColor
        {
            set
            {
                if(value.A == 0)
                {
                    this.polyLinePen = null;
                }
                else
                {
                    this.polyLinePen = new Pen(value);
                }

                Invalidate();
            }
            get
            {
                if(this.polyLinePen != null)
                {
                    return this.polyLinePen.Color;
                }
                else
                {
                    return Color.Empty;
                }
            }
        }

        #endregion
        #region 테두리 색상 - BorderColor

        /// <summary>
        /// 테두리 색상
        /// </summary>
        public Color BorderColor
        {
            set
            {
                if(value.A == 0)
                {
                    this.borderPen = null;
                }
                else
                {
                    this.borderPen = new Pen(value);
                }

                Invalidate();
            }
            get
            {
                if(this.borderPen != null)
                {
                    return this.borderPen.Color;
                }
                else
                {
                    return Color.Empty;
                }
            }
        }

        #endregion
        #region 상위 레전드 색상 - TopLegendColor

        /// <summary>
        /// 상위 레전드 색상
        /// </summary>
        public Color TopLegendColor
        {
            set
            {
                this.topLegendBrush = new SolidBrush(value);

                Invalidate();
            }
            get
            {
                if(this.topLegendBrush != null)
                {
                    return this.topLegendBrush.Color;
                }
                else
                {
                    return Color.Empty;
                }
            }
        }

        #endregion
        #region X축 레전드 - AxisXLegend

        /// <summary>
        /// X축 레전드
        /// </summary>
        public string AxisXLegend
        {
            set
            {
                this.axisLegendStringArray[(int)CoordinateType.X] = value;
                
                Invalidate();
            }
            get
            {
                return this.axisLegendStringArray[(int)CoordinateType.X];
            }
        }

        #endregion
        #region Y축 레전드 - AxisYLegend

        /// <summary>
        /// Y축 레전드
        /// </summary>
        public string AxisYLegend
        {
            set
            {
                this.axisLegendStringArray[(int)CoordinateType.Y] = value;
                
                Invalidate();
            }
            get
            {
                return this.axisLegendStringArray[(int)CoordinateType.Y];
            }
        }

        #endregion
        #region Z축 레전드 - AxisZLegend

        /// <summary>
        /// Z축 레전드
        /// </summary>
        public string AxisZLegend
        {
            set
            {
                this.axisLegendStringArray[(int)CoordinateType.Z] = value;
                
                Invalidate();
            }
            get
            {
                return this.axisLegendStringArray[(int)CoordinateType.Z];
            }
        }

        #endregion
        #region X축 색상 - AxisXColor

        /// <summary>
        /// X축 색상
        /// </summary>
        public Color AxisXColor
        {
            set
            {
                SetAxisColor(CoordinateType.X, value);
                
                Invalidate();
            }
            get
            {
                return this.axisPenArray[(int)CoordinateType.X].Color;
            }
        }

        #endregion
        #region Y축 색상 - AxisYColor

        /// <summary>
        /// Y축 색상
        /// </summary>
        public Color AxisYColor
        {
            set
            {
                SetAxisColor(CoordinateType.Y, value);
                
                Invalidate();
            }
            get
            {
                return this.axisPenArray[(int)CoordinateType.Y].Color;
            }
        }

        #endregion
        #region Z축 색상 - AxisZColor

        /// <summary>
        /// Z축 색상
        /// </summary>
        public Color AxisZColor
        {
            set
            {
                SetAxisColor(CoordinateType.Z, value);
                
                Invalidate();
            }
            get
            {
                return this.axisPenArray[(int)CoordinateType.Z].Color;
            }
        }

        #endregion
        #region 포인트 카운트 - PointCount

        /// <summary>
        /// 포인트 카운트
        /// </summary>
        [ReadOnly(true)]
        [Browsable(false)]
        public int PointCount
        {
            get
            {
                return this.pointCount;
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - Chart3DControl()

        /// <summary>
        /// 생성자
        /// </summary>
        public Chart3DControl()
        {
            SetStyle(ControlStyles.AllPaintingInWmPaint,  true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

            BackColor = Color.White;

            SetAxisColor(CoordinateType.X, Color.DarkBlue );
            SetAxisColor(CoordinateType.Y, Color.DarkGreen);
            SetAxisColor(CoordinateType.Z, Color.DarkRed  );

            this.polyLinePen    = new Pen(Color.Black, 1);
            this.borderPen      = new Pen(Color.FromArgb(255,180,180,180), 1);
            this.topLegendBrush = new SolidBrush(Color.FromArgb(255,200,200,150));

            this.transform.SetCoeficients(this.mouse);
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public
        //////////////////////////////////////////////////////////////////////////////// Function

        #region 색상 구성표 설정하기 - SetColorScheme(colorArray, lineWidth)

        /// <summary>
        /// 색상 구성표 설정하기
        /// </summary>
        /// <param name="colorArray">색상 배열</param>
        /// <param name="lineWidth">선 너비</param>
        public void SetColorScheme(Color[] colorArray, float lineWidth)
        {
            this.colorSchemeBrusheArray = new SolidBrush[colorArray.Length];
            this.colorSchemePenArray    = new Pen       [colorArray.Length];

            for(int i = 0; i < this.colorSchemeBrusheArray.Length; i++)
            {
                this.colorSchemeBrusheArray[i] = new SolidBrush(colorArray[i]);
                this.colorSchemePenArray   [i] = new Pen(this.colorSchemeBrusheArray[i], lineWidth);
            }

            Invalidate();
        }

        #endregion
        #region 트랙바 할당하기 - AssignTrackBars(rhoTrackBar, thetaTrackBar, phiTrackBar)

        /// <summary>
        /// 트랙바 할당하기
        /// </summary>
        /// <param name="rhoTrackBar">로 트랙바</param>
        /// <param name="thetaTrackBar">세타 트랙바</param>
        /// <param name="phiTrackBar">파이 트랙바</param>
        public void AssignTrackBars(TrackBar rhoTrackBar, TrackBar thetaTrackBar, TrackBar phiTrackBar)
        {
            this.mouse.AssignTrackBar(MouseAction.Rho,   rhoTrackBar,   new EventHandler(trackBar_Scroll));
            this.mouse.AssignTrackBar(MouseAction.Theta, thetaTrackBar, new EventHandler(trackBar_Scroll));
            this.mouse.AssignTrackBar(MouseAction.Phi,   phiTrackBar,   new EventHandler(trackBar_Scroll));
        }

        #endregion
        #region 표면 포인트 설정하기 - SetSurfacePoints(pointArray, normalizeType)

        /// <summary>
        /// 표면 포인트 설정하기
        /// </summary>
        /// <param name="pointArray">포인트 배열</param>
        /// <param name="normalizeType">정규화 타입</param>
        public void SetSurfacePoints(Point3D[,] pointArray, NormalizeType normalizeType)
        {
            this.scatterArray = null;
            this.pointArray   = pointArray;
            this.pointCount   = pointArray.Length;
            this.range        = new Range3D(pointArray);

            if(this.pointCount < 4)
            {
                throw new Exception("Insufficient 3D points specified");
            }

            NormalizeRanges(normalizeType);

            this.mouse.OffsetPoint = Point.Empty;

            this.drawObjectList.Clear();

            Invalidate();
        }

        #endregion
        #region 함수 설정하기 - SetFunction(rendererDelegate, startPoint, endPoint, density, normalizeType)

        /// <summary>
        /// 함수 설정하기
        /// </summary>
        /// <param name="rendererDelegate">렌더러 대리자</param>
        /// <param name="startPoint">시작 포인트</param>
        /// <param name="endPoint">종료 포인트</param>
        /// <param name="density">밀도</param>
        /// <param name="normalizeType">정규화 타입</param>
        public void SetFunction(RendererDelegate rendererDelegate, PointF startPoint, PointF endPoint, double density, NormalizeType normalizeType)
        {
            int countX = (int)((endPoint.X - startPoint.X) / density + 1);
            int countY = (int)((endPoint.Y - startPoint.Y) / density + 1);

            Point3D[,] pointArray = new Point3D[countX, countY];

            for(int c = 0; c < countX; c++)
            {
                double x = startPoint.X + density * c;

                for(int r = 0; r < countY; r++)
                {
                    double Y = startPoint.Y + density * r;
                    double Z = rendererDelegate(x, Y);

                    pointArray[c, r] = new Point3D(x, Y, Z);
                }
            }

            SetSurfacePoints(pointArray, normalizeType);
        }

        #endregion
        #region 스캐터 포인트 설정하기 - SetScatterPoints(scatterArray, normalizeType)

        /// <summary>
        /// 스캐터 포인트 설정하기
        /// </summary>
        /// <param name="scatterArray">스캐터 배열</param>
        /// <param name="normalizeType">정규화 타입</param>
        public void SetScatterPoints(Scatter[] scatterArray, NormalizeType normalizeType)
        {
            this.pointArray   = null;
            this.scatterArray = scatterArray;
            this.pointCount   = scatterArray.Length;
            this.range        = new Range3D(scatterArray);

            NormalizeRanges(normalizeType);

            this.mouse.OffsetPoint = Point.Empty;

            this.drawObjectList.Clear();

            Invalidate();
        }

        #endregion
        #region 스캐터 라인 설정하기 - SetScatterLines(scatterArrary, normalizeType, lineWidth)

        /// <summary>
        /// 스캐터 라인 설정하기
        /// </summary>
        /// <param name="scatterArrary">스캐터 배열</param>
        /// <param name="normalizeType">정규화 타입</param>
        /// <param name="lineWidth">선 너비</param>
        public void SetScatterLines(Scatter[] scatterArrary, NormalizeType normalizeType, float lineWidth)
        {
            Scatter previousScatter = null;

            foreach(Scatter scatter in scatterArrary)
            {
                scatter.Combine         = true;
                scatter.PreviousScatter = previousScatter;

                if(scatter.Brush != null)
                {
                    scatter.Pen = new Pen(scatter.Brush, lineWidth);
                }

                previousScatter = scatter;
            }

            SetScatterPoints(scatterArrary, normalizeType);
        }

        #endregion
        #region 계수 설정하기 - SetCoefficients(rho, theta, phi)

        /// <summary>
        /// 계수 설정하기
        /// </summary>
        /// <param name="rho">로</param>
        /// <param name="theta">세타</param>
        /// <param name="phi">파이</param>
        public void SetCoefficients(double rho, double theta, double phi)
        {
            this.mouse.SetRho(rho);
            this.mouse.SetTheta(theta);
            this.mouse.SetPhi(phi);

            this.transform.SetCoeficients(this.mouse);

            this.drawObjectList.Clear();

            Invalidate();
        }

        #endregion
        #region 비트맵 구하기 - GetBitmap()

        /// <summary>
        /// 비트맵 구하기
        /// </summary>
        /// <returns>비트맵</returns>
        public Bitmap GetBitmap()
        {
            Bitmap bitmap = new Bitmap(ClientSize.Width, ClientSize.Height);

            using(Graphics graphics = Graphics.FromImage(bitmap))
            {
                Draw(graphics);
            }

            return bitmap;
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Protected
        //////////////////////////////////////////////////////////////////////////////// Function

        #region 크기 변경시 처리하기 - OnSizeChanged(e)

        /// <summary>
        /// 크기 변경시 처리하기
        /// </summary>
        /// <param name="e">이벤트 인자</param>
        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);

            this.transform.SetSize(ClientSize);

            this.drawObjectList.Clear();

            Invalidate();
        }

        #endregion
        #region 배경 페인트시 처리하기 - OnPaintBackground(e)

        /// <summary>
        /// 배경 페인트시 처리하기
        /// </summary>
        /// <param name="e">이벤트 인자</param>
        protected override void OnPaintBackground(PaintEventArgs e)
        {
        }

        #endregion
        #region 페인트시 처리하기 - OnPaint(e)

        /// <summary>
        /// 페인트시 처리하기
        /// </summary>
        /// <param name="e">이벤트 인자</param>
        protected override void OnPaint(PaintEventArgs e)
        {
            Draw(e.Graphics);
        }

        #endregion
        #region 마우스 DOWN 처리하기 - OnMouseDown(e)

        /// <summary>
        /// 마우스 DOWN 처리하기
        /// </summary>
        /// <param name="e">이벤트 인자</param>
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);

            this.mouse.LastPosition = e.Location;

            if(this.drawObjectList.Count == 0)
            {
                return;
            }
           
            switch(Control.ModifierKeys)
            {
                case Keys.None :

                    if(e.Button == MouseButtons.Left)
                    {
                        Cursor = Cursors.NoMoveVert;

                        this.mouse.MouseAction = MouseAction.Theta;
                    }

                    if(e.Button == MouseButtons.Right)
                    {
                        Cursor = Cursors.NoMoveHoriz;

                        this.mouse.MouseAction = MouseAction.Phi;
                    }

                    break;

                case Keys.Shift :

                    if(e.Button == MouseButtons.Left)
                    {
                        Cursor = Cursors.NoMove2D;

                        this.mouse.MouseAction = MouseAction.Move;
                    }

                    break;

                case Keys.Control :

                    if(e.Button == MouseButtons.Left)
                    {
                        Cursor = Cursors.SizeNS;

                        this.mouse.MouseAction = MouseAction.Rho;
                    }

                    break;
            }
        }

        #endregion
        #region 마우스 이동시 처리하기 - OnMouseMove(e)

        /// <summary>
        /// 마우스 이동시 처리하기
        /// </summary>
        /// <param name="e">이벤트 인자</param>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            int deltaX = e.X - this.mouse.LastPosition.X;
            int deltaY = e.Y - this.mouse.LastPosition.Y;

            this.mouse.LastPosition = e.Location;

            switch(this.mouse.MouseAction)
            {
                case MouseAction.Move :

                    this.mouse.OffsetPoint.X += deltaX;
                    this.mouse.OffsetPoint.Y += deltaY;

                    Invalidate();

                    break;

                case MouseAction.Rho   :
                case MouseAction.Theta :
                case MouseAction.Phi   :

                    this.mouse.ProcessMouseMove(deltaX, deltaY);

                    this.transform.SetCoeficients(this.mouse);

                    this.drawObjectList.Clear();

                    Invalidate();

                    break;
            }
        }

        #endregion
        #region 마우스 UP 처리하기 - OnMouseUp(e)

        /// <summary>
        /// 마우스 UP 처리하기
        /// </summary>
        /// <param name="e">이벤트 인자</param>
        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);

            this.mouse.MouseAction = MouseAction.None;

            Cursor = Cursors.Arrow;
        }

        #endregion
        #region 마우스 이탈시 처리하기 - OnMouseLeave(e)

        /// <summary>
        /// 마우스 이탈시 처리하기
        /// </summary>
        /// <param name="e">이벤트 인자</param>
        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);

            this.mouse.MouseAction = MouseAction.None;

            Cursor = Cursors.Arrow;
        }

        #endregion
        #region 마우스 WHEEL 처리하기 - OnMouseWheel(e)

        /// <summary>
        /// 마우스 WHEEL 처리하기
        /// </summary>
        /// <param name="e">이벤트 인자</param>
        protected override void OnMouseWheel(MouseEventArgs e)
        {
            base.OnMouseWheel(e);

            if(this.mouse.ProcessMouseWheel(e.Delta))
            {
                this.transform.SetCoeficients(this.mouse);

                this.drawObjectList.Clear();

                Invalidate();
            }
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Private
        //////////////////////////////////////////////////////////////////////////////// Event

        #region 트랙바 스크롤시 처리하기 - trackBar_Scroll(sender, e)

        /// <summary>
        /// 트랙바 스크롤시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void trackBar_Scroll(object sender, EventArgs e)
        {
            this.mouse.ProcessTrackBarScroll();

            this.transform.SetCoeficients(this.mouse);

            this.drawObjectList.Clear();

            Invalidate();
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////// Function

        #region 범위 정규화하기 - NormalizeRanges(normalizeType)

        /// <summary>
        /// 범위 정규화하기
        /// </summary>
        /// <param name="normalizeType">정규화 타입</param>
        private void NormalizeRanges(NormalizeType normalizeType)
        {
            if(this.range.MaximumX == this.range.MinimumX)
            {
                this.range.MinimumX -= 1.0d;
                this.range.MaximumX += 1.0d;
            }

            if(this.range.MaximumY == this.range.MinimumY)
            {
                this.range.MinimumY -= 1.0d;
                this.range.MaximumY += 1.0d;
            }

            if(this.range.MaximumZ == this.range.MinimumZ)
            {
                this.range.MinimumZ -= 1.0d;
                this.range.MaximumZ += 1.0d;
            }

            double rangeX = this.range.MaximumX - this.range.MinimumX;
            double rangeY = this.range.MaximumY - this.range.MinimumY;

            double rangeZ;

            if(this.rasterType == RasterType.Off)
            {
                rangeZ = this.range.MaximumZ - this.range.MinimumZ;
            }
            else
            {
                rangeZ = Math.Max(0d, this.range.MaximumZ) - Math.Min(0d, this.range.MinimumZ);
            }

            switch(normalizeType)
            {
                case NormalizeType.MaintainXY :

                    double rangeXY = (rangeX + rangeY) / 2d;

                    rangeX = rangeXY;
                    rangeY = rangeXY;

                    break;

                case NormalizeType.MaintainXYZ :

                    double rangeXYZ = (rangeX + rangeY + rangeZ) / 3d;

                    rangeX = rangeXYZ;
                    rangeY = rangeXYZ;
                    rangeZ = rangeXYZ;

                    break;
            }

            this.transform.NormalizeX = 250.0d / rangeX;
            this.transform.NormalizeY = 250.0d / rangeY;
            this.transform.NormalizeZ = 250.0d / rangeZ;

            this.range.CenterPoint.X = (this.range.MaximumX + this.range.MinimumX) / 2.0d;
            this.range.CenterPoint.Y = (this.range.MaximumY + this.range.MinimumY) / 2.0d;

            if(this.rasterType == RasterType.Off)
            {
                this.range.CenterPoint.Z = (this.range.MaximumZ + this.range.MinimumZ) / 2.0d;
            }
            else
            {
                this.range.CenterPoint.Z = (Math.Max(0d, this.range.MaximumZ) + Math.Min(0d, this.range.MinimumZ)) / 2.0d;
            }
        }

        #endregion
        #region 좌표계 생성하기 - CreateCoordinateSystem(graphics)

        /// <summary>
        /// 좌표계 생성하기
        /// </summary>
        /// <param name="graphics">그래픽스</param>
        private void CreateCoordinateSystem(Graphics graphics)
        {
            this.offsetPoint = new Point(0, VERTICAL_OFFSET);

            if(this.rasterType == RasterType.Off)
            {
                return;
            }

            List<Line> lineList = new List<Line>();

            for(int a = 0; a < 3; a++)
            {
                Line axisLine  = new Line();

                axisLine.Pen = this.axisPenArray[a];

                switch((CoordinateType)a)
                {
                    case CoordinateType.X : // 청색

                        axisLine.Point3DArray[0].X = Math.Min(0.0d, this.range.MinimumX * AXIS_EXCESS);
                        axisLine.Point3DArray[1].X = Math.Max(0.0d, this.range.MaximumX * AXIS_EXCESS);

                        axisLine.Point3DArray[0].Y = Math.Min(0.0d, this.range.MinimumY * AXIS_EXCESS);
                        axisLine.Point3DArray[1].Y = Math.Min(0.0d, this.range.MinimumY * AXIS_EXCESS);

                        axisLine.MainCoordinateType      = CoordinateType.X;
                        axisLine.SecondaryCoordinateType = CoordinateType.X;

                        break;

                    case CoordinateType.Y : // 녹색

                        axisLine.Point3DArray[0].Y = Math.Min(0.0d, this.range.MinimumY * AXIS_EXCESS);
                        axisLine.Point3DArray[1].Y = Math.Max(0.0d, this.range.MaximumY * AXIS_EXCESS);

                        axisLine.Point3DArray[0].X = Math.Min(0.0d, this.range.MinimumX * AXIS_EXCESS);
                        axisLine.Point3DArray[1].X = Math.Min(0.0d, this.range.MinimumX * AXIS_EXCESS);

                        axisLine.MainCoordinateType      = CoordinateType.Y;
                        axisLine.SecondaryCoordinateType = CoordinateType.Z;
                        break;

                    case CoordinateType.Z : // 적색

                        axisLine.Point3DArray[0].Z = Math.Min(0.0d, this.range.MinimumZ * AXIS_EXCESS);
                        axisLine.Point3DArray[1].Z = Math.Max(0.0d, this.range.MaximumZ * AXIS_EXCESS);

                        axisLine.Point3DArray[0].X = Math.Min(0.0d, this.range.MinimumX * AXIS_EXCESS);
                        axisLine.Point3DArray[1].X = Math.Min(0.0d, this.range.MinimumX * AXIS_EXCESS);
                        axisLine.Point3DArray[0].Y = Math.Min(0.0d, this.range.MinimumY * AXIS_EXCESS);
                        axisLine.Point3DArray[1].Y = Math.Min(0.0d, this.range.MinimumY * AXIS_EXCESS);

                        axisLine.MainCoordinateType      = CoordinateType.Z;
                        axisLine.SecondaryCoordinateType = CoordinateType.Z;

                        break;
                }

                axisLine.Point2DArray[0] = this.transform.Project(axisLine.Point3DArray[0], this.range.CenterPoint);
                axisLine.Point2DArray[1] = this.transform.Project(axisLine.Point3DArray[1], this.range.CenterPoint);

                axisLine.CalculateAngle();

                lineList.Add(axisLine);
            }

            this.quadrant = new Quadrant
            (
                this.mouse.Phi,
                lineList[(int)CoordinateType.X],
                lineList[(int)CoordinateType.Y],
                lineList[(int)CoordinateType.Z]
            );

            if(this.rasterType >= RasterType.Raster)
            {
                for(int a = 0; a < 3; a++)
                {
                    CoordinateType firstCoordinateType  = (CoordinateType)(a);
                    CoordinateType secondCoordinateType = (CoordinateType)((a + 1) % 3);

                    for(int d = 0; d < 2; d++)
                    {
                        Line firstAxisLine  = lineList[(int)firstCoordinateType ];
                        Line secondAxisLine = lineList[(int)secondCoordinateType];

                        double secondStart = secondAxisLine.Point3DArray[0].GetValue(secondCoordinateType);
                        double secondEnd   = secondAxisLine.Point3DArray[1].GetValue(secondCoordinateType);

                        double interval = CalculateInterval(secondEnd - secondStart);

                        for(int l = -11; l < 11; l++)
                        {
                            double offset = interval * l;

                            if(offset < secondStart || offset > secondEnd)
                            {
                                continue;
                            }
                                
                            Line rasterLine = new Line();

                            rasterLine.Pen                     = this.rasterPenArray[(int)secondCoordinateType];
                            rasterLine.MainCoordinateType      = firstCoordinateType;
                            rasterLine.SecondaryCoordinateType = secondCoordinateType;
                            rasterLine.Label                   = offset;
                            rasterLine.Point3DArray[0]         = firstAxisLine.Point3DArray[0].Clone();
                            rasterLine.Point3DArray[1]         = firstAxisLine.Point3DArray[1].Clone();

                            rasterLine.Point3DArray[0].SetValue(secondCoordinateType, offset);
                            rasterLine.Point3DArray[1].SetValue(secondCoordinateType, offset);

                            if
                            (
                                rasterLine.EqualsCoordinate(lineList[(int)CoordinateType.X]) ||
                                rasterLine.EqualsCoordinate(lineList[(int)CoordinateType.Y]) ||
                                rasterLine.EqualsCoordinate(lineList[(int)CoordinateType.Z])
                            )
                            {
                                continue;
                            }

                            if
                            (
                                (firstCoordinateType == CoordinateType.X && secondCoordinateType == CoordinateType.Z) ||
                                (firstCoordinateType == CoordinateType.Z && secondCoordinateType == CoordinateType.X)
                            )
                            {
                                rasterLine.Sort = this.quadrant.SortXZ;
                            }
                            else if
                            (
                                (firstCoordinateType == CoordinateType.Z && secondCoordinateType == CoordinateType.Y) ||
                                (firstCoordinateType == CoordinateType.Y && secondCoordinateType == CoordinateType.Z)
                            )
                            {
                                rasterLine.Sort = this.quadrant.SortYZ;
                            }
                            else
                            {
                                rasterLine.Sort = this.quadrant.SortXY;

                                Line axisZLine = lineList[(int)CoordinateType.Z];

                                rasterLine.Point3DArray[0].Z = axisZLine.Point3DArray[0].Z;
                                rasterLine.Point3DArray[1].Z = axisZLine.Point3DArray[0].Z;
                            }

                            lineList.Add(rasterLine);
                        }

                        CoordinateType temporaryCoordinateType = firstCoordinateType;

                        firstCoordinateType  = secondCoordinateType;
                        secondCoordinateType = temporaryCoordinateType;
                    }
                }
            }

            foreach(Line line in lineList)
            {
                line.Point2DArray[0] = this.transform.Project(line.Point3DArray[0], this.range.CenterPoint);
                line.Point2DArray[1] = this.transform.Project(line.Point3DArray[1], this.range.CenterPoint);

                AddDrawObject(new DrawObject(line, line.Sort));
            }

            if(this.rasterType == RasterType.Label)
            {
                int labelWidth = 0;

                foreach(Line line in lineList)
                {
                    if(line.MainCoordinateType == CoordinateType.Y && line.SecondaryCoordinateType == CoordinateType.Z)
                    {
                        string label = FormatLabel(line.Label);

                        SizeF size = graphics.MeasureString(label, Font);

                        labelWidth = Math.Max(labelWidth, (int)size.Width);
                    }
                }

                this.offsetPoint.X -= labelWidth / 2;
            }
        }

        #endregion
        #region 다각형 생성하기 - CreatePolygons()

        /// <summary>
        /// 다각형 생성하기
        /// </summary>
        private void CreatePolygons()
        {
            Point2D[,] pointArray = new Point2D[this.pointArray.GetLength(0), this.pointArray.GetLength(1)];

            for(int x = 0; x < this.pointArray.GetLength(0); x++)
            {
                for(int y = 0; y < this.pointArray.GetLength(1); y++)
                {
                    pointArray[x, y] = this.transform.Project(this.pointArray[x, y], this.range.CenterPoint);
                }
            }

            for(int x = 0; x < this.pointArray.GetLength(0) - 1; x++)
            {
                for(int y = 0; y < this.pointArray.GetLength(1) - 1; y++)
                {
                    Polygon polygon = new Polygon
                    (
                        pointArray[x    , y    ],
                        pointArray[x    , y + 1],
                        pointArray[x + 1, y + 1],
                        pointArray[x + 1, y    ]
                    );
                    
                    double z1 = this.pointArray[x    , y    ].Z;
                    double z2 = this.pointArray[x    , y + 1].Z;
                    double z3 = this.pointArray[x + 1, y + 1].Z;
                    double z4 = this.pointArray[x + 1, y    ].Z;

                    double zAverage = (z1 + z2 + z3 + z4) / 4.0d;

                    polygon.FactorZ = (zAverage - this.range.MinimumZ) / (this.range.MaximumZ - this.range.MinimumZ);

                    double sort = this.transform.ProjectXY(x + 1, y + 1);

                    AddDrawObject(new DrawObject(polygon, sort));
                }
            }
        }

        #endregion
        #region 스캐터 점 생성하기 - CreateScatterDots()

        /// <summary>
        /// 스캐터 점 생성하기
        /// </summary>
        private void CreateScatterDots()
        {
            foreach(Scatter scatter in this.scatterArray)
            {
                scatter.SetPoint2D(this.transform.Project(scatter.Point3D, this.range.CenterPoint));

                if(scatter.Brush == null)
                {
                    scatter.FactorZ = (scatter.Point3D.Z - this.range.MinimumZ) / (this.range.MaximumZ - this.range.MinimumZ);
                }

                double sort = this.transform.ProjectXY
                (
                    scatter.Point3D.X + 1.0d, 
                    scatter.Point3D.Y + 1.0d
                );

                AddDrawObject(new DrawObject(scatter, sort));
            }
        }

        #endregion
        #region 그리기 객체 추가하기 - AddDrawObject(drawObject)

        /// <summary>
        /// 그리기 객체 추가하기
        /// </summary>
        /// <param name="drawObject">그리기 객체</param>
        private void AddDrawObject(DrawObject drawObject)
        {
            int p;

            for(p = 0; p < this.drawObjectList.Count; p++)
            {
                if(this.drawObjectList[p].Sort > drawObject.Sort)
                {
                    break;
                }
            }

            this.drawObjectList.Insert(p, drawObject);
        }

        #endregion
        #region 색상 구성표 브러시 구하기 - GetColorSchemeBrush(factorZ)

        /// <summary>
        /// 색상 구성표 브러시 구하기
        /// </summary>
        /// <param name="factorZ">팩터 Z</param>
        /// <returns>색상 구성표 브러시</returns>
        private Brush GetColorSchemeBrush(double factorZ)
        {
            if(this.colorSchemeBrusheArray == null || double.IsNaN(factorZ))
            {
                return Brushes.Goldenrod;
            }

            factorZ = Math.Min(1.0d, factorZ);
            factorZ = Math.Max(0.0d, factorZ);

            int index = (int)(factorZ * (this.colorSchemeBrusheArray.Length - 1));

            return this.colorSchemeBrusheArray[index];
        }

        #endregion
        #region 색상 구성표 펜 구하기 - GetColorSchemePen(factorZ)

        /// <summary>
        /// 색상 구성표 펜 구하기
        /// </summary>
        /// <param name="factorZ">팩터 Z</param>
        /// <returns>색상 구성표 펜</returns>
        private Pen GetColorSchemePen(double factorZ)
        {
            if(this.colorSchemePenArray == null || double.IsNaN(factorZ))
            {
                return Pens.Goldenrod;
            }

            factorZ = Math.Min(1.0, factorZ);
            factorZ = Math.Max(0.0, factorZ);

            int index = (int)(factorZ * (this.colorSchemePenArray.Length - 1));

            return this.colorSchemePenArray[index];
        }

        #endregion
        #region 축 색상 설정하기 - SetAxisColor(coordinateType, color)

        /// <summary>
        /// 축 색상 설정하기
        /// </summary>
        /// <param name="coordinateType">좌표 타입</param>
        /// <param name="color">색상</param>
        private void SetAxisColor(CoordinateType coordinateType, Color color)
        {
            this.axisBrushArray[(int)coordinateType] = new SolidBrush(color);

            this.axisPenArray[(int)coordinateType] = new Pen(color, 3);

            this.rasterPenArray[(int)coordinateType] = new Pen(BrightenColor(color), 1);
        }

        #endregion
        #region 색상 밝게 만들기 - BrightenColor(color)

        /// <summary>
        /// 색상 밝게 만들기
        /// </summary>
        /// <param name="color">색상</param>
        /// <returns>색상</returns>
        private Color BrightenColor(Color color)
        {
            int red   = color.R + (255 - color.R) / 2;
            int green = color.G + (255 - color.G) / 2;
            int blue  = color.B + (255 - color.B) / 2;

            return Color.FromArgb(255, red, green, blue);
        }

        #endregion
        #region 간격 계산하기 - CalculateInterval(range)

        /// <summary>
        /// 간격 계산하기
        /// </summary>
        /// <param name="range">범위</param>
        /// <returns>간격</returns>
        private double CalculateInterval(double range)
        {
            double factor = Math.Pow(10.0d, Math.Floor(Math.Log10(range)));

            if(range / factor >= 5.0d)
            {
                return factor;
            }
            else if(range / (factor / 2.0d) >= 5.0d)
            {
                return factor / 2.0d;
            }
            else
            {
                return factor / 5.0d;
            }
        }

        #endregion
        #region 레이블 포맷 적용하기 - FormatLabel(label)

        /// <summary>
        /// 레이블 포맷 적용하기
        /// </summary>
        /// <param name="label">레이블</param>
        /// <returns>레이블</returns>
        /// <remarks>
        /// 123.000 --> "123"
        ///  15.700 --> "15.7"  
        ///   4.260 --> "4.26"
        ///   0.834 --> "0.834"
        /// </remarks>
        private string FormatLabel(double label)
        {
            return label.ToString("0.000", CultureInfo.InvariantCulture).TrimEnd('0').TrimEnd('.');
        }

        #endregion
        #region 그리기 - Draw(graphics)

        /// <summary>
        /// 그리기
        /// </summary>
        /// <param name="graphics">그래픽스</param>
        private void Draw(Graphics graphics)
        {
            if(this.drawObjectList.Count == 0)
            {
                CreateCoordinateSystem(graphics);

                if(this.pointArray != null)
                {
                    CreatePolygons();
                }

                if(this.scatterArray != null)
                {
                    CreateScatterDots();
                }
            }

            graphics.Clear(BackColor);

            int x = 4;
            int y = ClientSize.Height - Font.Height - 4;

            for(int i = 2; i >= 0; i--)
            {
                if(string.IsNullOrEmpty(this.axisLegendStringArray[i]))
                {
                    continue;
                }

                string legend = string.Format("{0} : {1}", (CoordinateType)i, this.axisLegendStringArray[i]);

                graphics.DrawString(legend, Font, this.axisBrushArray[i], x,  y);

                y -= Font.Height;
            }

            if(this.topLegendBrush != null)
            {
                string[] legendArray = new string[]
                {
                    "Rotation  : ",
                    "Elevation : ",
                    "Distance  : "
                };
                
                string[] valueArray  = new string[]
                {
                    string.Format("{0:+#;-#;0}°", (int)this.mouse.Phi  ),
                    string.Format("{0:+#;-#;0}°", (int)this.mouse.Theta),
                    string.Format("{0}"          , (int)this.mouse.Rho  )
                };

                SizeF size = graphics.MeasureString(legendArray[1], Font);

                x = 4;
                y = 3;

                for(int i = 0; i < 3; i++)
                {
                    graphics.DrawString(legendArray[i], Font, this.topLegendBrush, x,  y);

                    graphics.DrawString(valueArray [i], Font, this.topLegendBrush, x + size.Width, y);

                    y += Font.Height;
                }
            }

            graphics.TranslateTransform
            (
                this.mouse.OffsetPoint.X + this.offsetPoint.X, 
                this.mouse.OffsetPoint.Y + this.offsetPoint.Y
            );

            SmoothingMode smoothingMode = SmoothingMode.Invalid;

            foreach(DrawObject drawObject in this.drawObjectList)
            {
                if(!drawObject.IsValid)
                {
                    continue;
                }

                if(drawObject.Polygon != null)
                {
                    if(smoothingMode != SmoothingMode.None)
                    {
                        smoothingMode = SmoothingMode.None;

                        graphics.SmoothingMode = SmoothingMode.None;
                    }

                    Polygon polygon = drawObject.Polygon;
                    Brush   brush   = GetColorSchemeBrush(polygon.FactorZ);

                    graphics.FillPolygon(brush, polygon.PointArray);

                    if(this.polyLinePen != null)
                    {
                        graphics.DrawPolygon(this.polyLinePen, polygon.PointArray);
                    }
                }
                else if(drawObject.Scatter != null)
                {
                    if(smoothingMode != SmoothingMode.AntiAlias)
                    {
                        smoothingMode = SmoothingMode.AntiAlias;

                        graphics.SmoothingMode = SmoothingMode.AntiAlias;
                    }

                    Scatter scatter = drawObject.Scatter;

                    if(scatter.Combine)
                    {
                        if(scatter.PreviousScatter != null)
                        {
                            Pen pen = scatter.Pen;

                            if(pen == null)
                            {
                                pen = GetColorSchemePen(scatter.FactorZ);
                            }

                            graphics.DrawLine(pen, scatter.PreviousScatter.Point, scatter.Point);
                        }
                    }
                    else
                    {
                        Brush brush = scatter.Brush;

                        if(brush == null)
                        {
                            brush = GetColorSchemeBrush(scatter.FactorZ);
                        }

                        graphics.FillEllipse(brush, scatter.Point.X, scatter.Point.Y, SCATTER_SIZE * 2, SCATTER_SIZE * 2);
                    }
                }
                else
                {
                    if(smoothingMode != SmoothingMode.AntiAlias)
                    {
                        smoothingMode = SmoothingMode.AntiAlias;

                        graphics.SmoothingMode = SmoothingMode.AntiAlias;
                    }

                    Line line = drawObject.Line;

                    graphics.DrawLine(line.Pen, line.Point2DArray[0].Coordinate, line.Point2DArray[1].Coordinate);

                    if(this.rasterType == RasterType.Label && this.quadrant.BottomView == false && this.quadrant.QuadrantValue == 3)
                    {
                        PointF position = line.Point2DArray[1].Coordinate;

                        StringFormat stringFormat = new StringFormat();

                        if(line.MainCoordinateType == CoordinateType.Y && line.SecondaryCoordinateType == CoordinateType.Z)
                        {
                            position.X += 5;
                            position.Y -= Font.Height / 2;
                        }
                        else if(line.MainCoordinateType == CoordinateType.Y && line.SecondaryCoordinateType == CoordinateType.X)
                        {
                            position.X += (float)this.transform.ProjectXY(5, -5);
                            position.Y += (float)this.transform.ProjectXY(-Font.Height / 2, 5);
                        }
                        else if(line.MainCoordinateType == CoordinateType.X && line.SecondaryCoordinateType == CoordinateType.Y)
                        {
                            position.X += (float)this.transform.ProjectXY(5, -5);
                            position.Y += (float)this.transform.ProjectXY(5, -Font.Height / 2);

                            stringFormat.Alignment = StringAlignment.Far;
                        }
                        else
                        {
                            continue;
                        }

                        string label = FormatLabel(line.Label);

                        Brush  brush = this.axisBrushArray[(int)line.SecondaryCoordinateType];

                        graphics.DrawString(label, Font, brush, position, stringFormat);
                    }
                }
            }

            if(this.borderPen != null)
            {
                graphics.ResetTransform();

                Rectangle borderRectangle = ClientRectangle;

                graphics.DrawRectangle
                (
                    this.borderPen,
                    borderRectangle.X,
                    borderRectangle.Y,
                    borderRectangle.Width - 1,
                    borderRectangle.Height - 1
                );
            }
        }

        #endregion
    }
}

 

▶ MainForm.cs

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;

namespace TestProject
{
    /// <summary>
    /// 메인 폼
    /// </summary>
    public partial class MainForm : Form
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MainForm()

        /// <summary>
        /// 생성자
        /// </summary>
        public MainForm()
        {
            InitializeComponent();

            this.dataSourceComboBox.SelectedIndexChanged  += dataSourceComboBox_SelectedIndexChanged;
            this.colorSchemeComboBox.SelectedIndexChanged += colorSchemeComboBox_SelectedIndexChanged;
            this.rasterTypeComboBox.SelectedIndexChanged  += rasterTypeComboBox_SelectedIndexChanged;
            this.resetPositionButton.Click                += resetPositionButton_Click;
            this.saveImageButton.Click                    += saveImageButton_Click;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Protected

        #region 로드시 처리하기 - OnLoad(e)

        /// <summary>
        /// 로드시 처리하기
        /// </summary>
        /// <param name="e">이벤트 인자</param>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            this.dataSourceComboBox.SelectedIndex = 0;

            this.colorSchemeComboBox.Sorted = false;

            foreach(ColoeScheme schemaType in Enum.GetValues(typeof(ColoeScheme)))
            {
                this.colorSchemeComboBox.Items.Add(schemaType);
            }

            this.colorSchemeComboBox.SelectedIndex = (int)ColoeScheme.Rainbow1;

            this.rasterTypeComboBox.Sorted = false;

            foreach(RasterType rasterType in Enum.GetValues(typeof(RasterType)))
            {
                this.rasterTypeComboBox.Items.Add(rasterType);
            }

            this.rasterTypeComboBox.SelectedIndex = (int)RasterType.Label;

            this.chart3DControl.AssignTrackBars(this.rhoTrackBar, this.thetaTrackBar, this.phiTrackBar);
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Private
        //////////////////////////////////////////////////////////////////////////////// Event

        #region 데이터 소스 콤보 박스 선택 인덱스 변경시 처리하기 - dataSourceComboBox_SelectedIndexChanged(sender, e)

        /// <summary>
        /// 데이터 소스 콤보 박스 선택 인덱스 변경시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void dataSourceComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.chart3DControl.AxisXLegend = null;
            this.chart3DControl.AxisYLegend = null;
            this.chart3DControl.AxisZLegend = null;

            switch(this.dataSourceComboBox.SelectedIndex)
            {
                case 0: SetFunction1();          break;
                case 1: SetFunction2();          break;
                case 2: SetSurfacePoints();      break;
                case 3: SetScatterPoints(false); break;
                case 4: SetScatterPoints(true);  break;
                case 5: SetScatterPoints();      break;
            }

            this.informationLabel.Text = "포인트 수 : " + this.chart3DControl.PointCount;
        }

        #endregion
        #region 색상 구성표 콤보 박스 선택 인덱스 변경시 처리하기 - colorSchemeComboBox_SelectedIndexChanged(sender, e)

        /// <summary>
        /// 색상 구성표 콤보 박스 선택 인덱스 변경시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void colorSchemeComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            Color[] colorArray = ColorSchema.GetSchema((ColoeScheme)this.colorSchemeComboBox.SelectedIndex);

            this.chart3DControl.SetColorScheme(colorArray, 3);
        }

        #endregion
        #region 래스터 타입 콤보 박스 선택 인덱스 변경시 처리하기 - rasterTypeComboBox_SelectedIndexChanged(sender, e)

        /// <summary>
        /// 래스터 타입 콤보 박스 선택 인덱스 변경시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void rasterTypeComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.chart3DControl.RasterType = (RasterType)this.rasterTypeComboBox.SelectedIndex;
        }

        #endregion
        #region 위치 초기화 버튼 클릭시 처리하기 - resetPositionButton_Click(sender, e)

        /// <summary>
        /// 위치 초기화 버튼 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void resetPositionButton_Click(object sender, EventArgs e)
        {
            this.chart3DControl.SetCoefficients(1350, 70, 230);
        }

        #endregion
        #region 이미지 저장 버튼 클릭시 처리하기 - saveImageButton_Click(sender, e)

        /// <summary>
        /// 이미지 저장 버튼 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void saveImageButton_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveFileDialog = new SaveFileDialog();

            saveFileDialog.Title      = "PNG 이미지 저장하기";
            saveFileDialog.Filter     = "PNG 이미지|*.png";
            saveFileDialog.DefaultExt = ".png";

            if(DialogResult.Cancel == saveFileDialog.ShowDialog(this))
            {
                return;
            }

            Bitmap bitmap = this.chart3DControl.GetBitmap();

            try
            {
                bitmap.Save(saveFileDialog.FileName, ImageFormat.Png);
            }
            catch(Exception exception)
            {
                MessageBox.Show(this, exception.Message, "에러", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////// Function

        #region 함수 설정하기 1 - SetFunction1()

        /// <summary>
        /// 함수 설정하기 1
        /// </summary>
        private void SetFunction1()
        {
            RendererDelegate rendererDelegate = delegate(double X, double Y)
            {
                double r = 0.15 * Math.Sqrt(X * X + Y * Y);

                if(r < 1e-10)
                {
                    return 120;
                }
                else
                {
                    return 120 * Math.Sin(r) / r;
                }
            };

            this.chart3DControl.SetFunction
            (
                rendererDelegate,
                new PointF(-120f, -80f),
                new PointF(120f, 80f),
                5d,
                NormalizeType.MaintainXYZ
            );
        }

        #endregion
        #region 함수 설정하기 2 - SetFunction2()

        /// <summary>
        /// 함수 설정하기 2
        /// </summary>
        private void SetFunction2()
        {
            string formula = "12 * sin(x) * cos(y) / (sqrt(sqrt(x * x + y * y)) + 0.2)";

            try
            {
                RendererDelegate rendererDelegate = FunctionCompiler.Compile(formula);

                this.chart3DControl.SetFunction
                (
                    rendererDelegate,
                    new PointF(-10f, -10f),
                    new PointF(10f, 10f),
                    0.5d,
                    NormalizeType.MaintainXYZ
                );
            }
            catch(Exception exception)
            {
                MessageBox.Show(exception.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        #endregion
        #region 표면 포인트 설정하기 - SetSurfacePoints()

        /// <summary>
        /// 표면 포인트 설정하기
        /// </summary>
        private void SetSurfacePoints()
        {
            int[,] valueArray = new int[,]
            {
                { 34767, 34210, 33718, 33096, 32342, 31851, 31228, 30867, 31457, 30867, 30266, 28934, 27984, 26492, 25167, 25167, 25167},
                { 34669, 34210, 33653, 33096, 32539, 32047, 31490, 30933, 31293, 30671, 29983, 28803, 27886, 26492, 25167, 25167, 25167},
                { 34603, 34144, 33718, 33227, 32768, 32342, 31719, 30999, 31228, 30333, 29622, 28606, 27886, 26492, 25167, 25167, 25167},
                { 34472, 34079, 33653, 33161, 32768, 32408, 31785, 31162, 30802, 30048, 29360, 28312, 27755, 26367, 25049, 25049, 25049},
                { 34210, 33784, 33423, 33161, 32801, 32408, 31785, 31097, 30474, 29622, 29000, 28115, 27623, 26367, 25049, 25049, 25049},
                { 33980, 33587, 33161, 32935, 32588, 32342, 31621, 30802, 29852, 29000, 28377, 27689, 27421, 26367, 25049, 25049, 25049},
                { 33522, 33227, 32702, 32615, 32452, 31851, 30933, 30179, 29295, 28358, 27984, 27132, 27301, 26367, 25049, 25049, 25049},
                { 32672, 32178, 31916, 31469, 31246, 30540, 29852, 29065, 28377, 27623, 27263, 26706, 26935, 26367, 25049, 25049, 25049},
                { 30769, 30423, 29917, 29231, 29392, 28705, 28075, 27726, 27263, 26691, 26417, 26182, 26575, 26575, 25246, 25246, 25246},
                { 27525, 27518, 26701, 27334, 27682, 27402, 26903, 26707, 26444, 25887, 25719, 25690, 26122, 26122, 26122, 26122, 26122},
                { 23475, 23888, 24478, 25330, 26212, 26199, 25701, 25664, 25740, 25013, 24904, 25068, 25374, 25374, 25374, 25374, 25374},
                { 20677, 21445, 22544, 23593, 24441, 24785, 24538, 24644, 24773, 24299, 24062, 24576, 24510, 24510, 24510, 24510, 24510},
                { 18743, 19792, 20808, 22086, 22805, 23167, 23486, 23366, 23757, 23411, 23691, 23822, 23822, 23822, 23822, 23822, 23822},
                { 17334, 18579, 19497, 20775, 21463, 21848, 22288, 22446, 22643, 22446, 22643, 22708, 23069, 23069, 23069, 23069, 23069},
                { 16155, 17236, 18350, 19399, 20251, 20677, 21016, 21332, 21660, 21791, 21889, 21955, 22217, 22217, 22217, 22217, 22217},
                { 14746, 15860, 17039, 17990, 18842, 19595, 20050, 20349, 20546, 20840, 20972, 20972, 21332, 21332, 21332, 21332, 21332},
                { 13337, 14516, 15729, 16679, 17564, 18514, 18907, 19169, 19399, 19661, 19792, 19594, 20152, 20152, 20152, 20152, 20152},
                { 12452, 13435, 14615, 15499, 16253, 17105, 17596, 17924, 18153, 18285, 18428, 18776, 19104, 19104, 19104, 19104, 19104},
                { 11469, 12354, 13533, 14287, 15008, 15925, 16187, 16482, 16690, 16976, 17105, 17302, 17531, 17531, 17531, 17531, 17531},
                { 10486, 11370, 12255, 13009, 13861, 14746, 15172, 15368, 15434, 15630, 15794, 15991, 16351, 16351, 16351, 16351, 16351},
                {  9684, 10387, 11141, 11796, 12546, 13337, 14029, 14320, 14549, 14811, 14939, 15434, 15794, 15794, 15794, 15794, 15794},
                {  9059,  9634, 10617, 11141, 11838, 12681, 13411, 13861, 14121, 14624, 14868, 15172, 15368, 15368, 15368, 15368, 15368}
            };

            Point3D[,] pointArray = new Point3D[valueArray.GetLength(0), valueArray.GetLength(1)];

            for(int x = 0; x < valueArray.GetLength(0); x++)
            {
                for(int y = 0; y < valueArray.GetLength(1); y++)
                {
                    pointArray[x,y] = new Point3D(x * 10, y * 500, valueArray[x, y]);
                }
            }

            this.chart3DControl.AxisXLegend = "MAP (kPa)";
            this.chart3DControl.AxisYLegend = "Engine Speed (rpm)";
            this.chart3DControl.AxisZLegend = "ADS";

            this.chart3DControl.SetSurfacePoints(pointArray, NormalizeType.Separate);
        }

        #endregion
        #region 스캐터 포인터 설정하기 - SetScatterPoints(drawLine)

        /// <summary>
        /// 스캐터 포인터 설정하기
        /// </summary>
        /// <param name="drawLine">선 그리기 여부</param>
        private void SetScatterPoints(bool drawLine)
        {
            List<Scatter> scallterList = new List<Scatter>();

            for(double p = -22d; p < 22d; p += 0.1d)
            {
                double x = Math.Sin(p) * p;
                double y = Math.Cos(p) * p;
                double z = p;

                if(z > 0d)
                {
                    z /= 3d;
                }

                scallterList.Add(new Scatter(x, y, z, null));
            }

            if(drawLine)
            {
                this.chart3DControl.SetScatterLines(scallterList.ToArray(), NormalizeType.Separate, 3f);
            }
            else
            {
                this.chart3DControl.SetScatterPoints(scallterList.ToArray(), NormalizeType.Separate);
            }
        }

        #endregion
        #region 스캐터 포인트 설정하기 - SetScatterPoints()

        /// <summary>
        /// 스캐터 포인트 설정하기
        /// </summary>
        private void SetScatterPoints()
        {
            List<Scatter> scatterList = new List<Scatter>();

            double x = 0.0d;
            double z = 0.0d;

            for(double p = 0.0d; p <= Math.PI * 1.32d; p += 0.025d)
            {
                x = Math.Cos(p) * 1.5d - 1.5d;
                z = Math.Sin(p) * 3.0d + 6.0d;

                scatterList.Add(new Scatter( x, -x, z, Brushes.Red));
                scatterList.Add(new Scatter(-x,  x, z, Brushes.Red));
            }

            double deltaX = x / 70d;
            double deltaZ = z / 70d;

            while(z >= 0.0d)
            {
                scatterList.Add(new Scatter( x, -x, z, Brushes.Red));
                scatterList.Add(new Scatter(-x,  x, z, Brushes.Red));

                x -= deltaX;
                z -= deltaZ;
            }

            this.chart3DControl.SetScatterPoints(scatterList.ToArray(), NormalizeType.MaintainXYZ);
        }

        #endregion
    }
}
728x90
반응형
그리드형(광고전용)
Posted by 사용자 icodebroker

댓글을 달아 주세요