728x90
반응형
728x170
▶ 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
반응형
그리드형(광고전용)
'C# > WinForm' 카테고리의 다른 글
[C#/WINFORM] WebBrowser 클래스 : Internet Explorer의 브라우저 에뮬레이션 모드 구하기 (0) | 2021.11.23 |
---|---|
[C#/WINFORM] WebBrowser 클래스 : Internet Explorer 버전 11 사용하기 (0) | 2021.11.23 |
[C#/WINFORM] 카카오 링크를 사용해 나에게 카카오톡 메시지 보내기 (기능 개선) (0) | 2021.11.23 |
[C#/WINFORM] 카카오 링크를 사용해 나에게 카카오톡 메시지 보내기 (0) | 2021.11.23 |
[C#/WINFORM] PrintWindow API 함수를 사용해 윈도우 비트맵 구하기 (0) | 2021.11.14 |
[C#/WINFORM] 3D 차트 사용하기 (0) | 2021.10.22 |
[C#/WINFORM] 가상 데스크톱 전환하기 (0) | 2021.09.10 |
[C#/WINFORM] Screen 클래스 : FromHandle 정적 메소드를 사용해 특정 윈도우가 속한 화면 구하기 (0) | 2021.09.04 |
[C#/WINFORM] Form 클래스 : MouseDown/MouseMove/MouseUp 이벤트를 사용해 테두리 없는 폼 만들기 (0) | 2021.08.30 |
[C#/WINFORM] SendKeys 클래스 : SendWait 정적 메소드를 사용해 메모장에 문자열 추가하기 (0) | 2021.08.30 |
[C#/WINFORM] Control 클래스 : IsKeyLocked 정적 메소드를 사용해 CAPS LOCK 키 눌림 여부 구하기 (0) | 2021.08.27 |
댓글을 달아 주세요