728x90
반응형
728x170
▶ Triangle.cs
using System.Drawing;
namespace TestProject
{
/// <summary>
/// 삼각형
/// </summary>
public class Triangle : Polygon
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - Triangle(p1, p2, p3)
/// <summary>
/// 생성자
/// </summary>
/// <param name="p1">포인트 1</param>
/// <param name="p2">포인트 2</param>
/// <param name="p3">포인트 3</param>
public Triangle(PointF p1, PointF p2, PointF p3)
{
PointArray = new PointF[] { p1, p2, p3 };
}
#endregion
}
}
728x90
▶ Polygon.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
namespace TestProject
{
/// <summary>
/// 다각형
/// </summary>
public class Polygon
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Public
#region Field
/// <summary>
/// 포인트 배열
/// </summary>
public PointF[] PointArray;
/// <summary>
/// 포인트 카운트
/// </summary>
private int pointCount = 0;
/// <summary>
/// 컨트롤 포인트 배열
/// </summary>
private int[] controlPointArray = new int[4];
/// <summary>
/// 엣지 체크 배열
/// </summary>
private bool[] edgeCheckArray;
/// <summary>
/// 현재 컨트롤 포인트
/// </summary>
private int currentControlPoint = -1;
/// <summary>
/// 현재 영역 1
/// </summary>
private float currentArea1 = float.MaxValue;
/// <summary>
/// 현재 영역 2
/// </summary>
private float currentArea2 = float.MaxValue;
/// <summary>
/// 현재 사각형 포인트 배열 1
/// </summary>
private PointF[] currentRectanglePointArray1 = null;
/// <summary>
/// 현재 사각형 포인트 배열 2
/// </summary>
private PointF[] currentRectanglePointArray2 = null;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - Polygon()
/// <summary>
/// 생성자
/// </summary>
public Polygon()
{
}
#endregion
#region 생성자 - Polygon(pointArray)
/// <summary>
/// 생성자
/// </summary>
/// <param name="pointArray">포인트 배열</param>
public Polygon(PointF[] pointArray)
{
PointArray = pointArray;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 다각형 면적 구하기 - GetPolygonArea()
/// <summary>
/// 다각형 면적 구하기
/// </summary>
/// <returns>다각형 면적</returns>
public float GetPolygonArea()
{
return Math.Abs(GetSignedPolygonArea());
}
#endregion
#region 중심점 구하기 - GetCentroid()
/// <summary>
/// 중심점 구하기
/// </summary>
/// <returns>중심점</returns>
public PointF GetCentroid()
{
int pointCount = PointArray.Length;
PointF[] temporaryArray = new PointF[pointCount + 1];
PointArray.CopyTo(temporaryArray, 0);
temporaryArray[pointCount] = PointArray[0];
float x = 0;
float y = 0;
float secondFactor;
for(int i = 0; i < pointCount; i++)
{
secondFactor = temporaryArray[i].X * temporaryArray[i + 1].Y -
temporaryArray[i + 1].X * temporaryArray[i].Y;
x += (temporaryArray[i].X + temporaryArray[i + 1].X) * secondFactor;
y += (temporaryArray[i].Y + temporaryArray[i + 1].Y) * secondFactor;
}
float polygonArea = GetPolygonArea();
x /= (6 * polygonArea);
y /= (6 * polygonArea);
if(x < 0)
{
x = -x;
y = -y;
}
return new PointF(x, y);
}
#endregion
#region 포인트 포함 여부 구하기 - IncludePoint(x, y)
/// <summary>
/// 포인트 포함 여부 구하기
/// </summary>
/// <param name="x">X 좌표</param>
/// <param name="y">Y 좌표</param>
/// <returns>포인트 포함 여부</returns>
public bool IncludePoint(float x, float y)
{
int maximumPoint = PointArray.Length - 1;
float totalAngle = GetAngle
(
PointArray[maximumPoint].X,
PointArray[maximumPoint].Y,
x,
y,
PointArray[0].X,
PointArray[0].Y
);
for(int i = 0; i < maximumPoint; i++)
{
totalAngle += GetAngle
(
PointArray[i].X,
PointArray[i].Y,
x,
y,
PointArray[i + 1].X,
PointArray[i + 1].Y
);
}
return (Math.Abs(totalAngle) > 0.000001);
}
#endregion
#region 시계 방향 여부 구하기 - IsOrientedClockwise()
/// <summary>
/// 시계 방향 여부 구하기
/// </summary>
/// <returns>시계 방향 여부</returns>
public bool IsOrientedClockwise()
{
return (GetSignedPolygonArea() < 0);
}
#endregion
#region 볼록 여부 구하기 - IsConvex()
/// <summary>
/// 볼록 여부 구하기
/// </summary>
/// <returns>볼록 여부</returns>
public bool IsConvex()
{
bool isNegative = false;
bool isPositive = false;
int pointCount = PointArray.Length;
int b;
int c;
for(int a = 0; a < pointCount; a++)
{
b = (a + 1) % pointCount;
c = (b + 1) % pointCount;
float crossProduct = GetCrossProduct
(
PointArray[a].X,
PointArray[a].Y,
PointArray[b].X,
PointArray[b].Y,
PointArray[c].X,
PointArray[c].Y
);
if(crossProduct < 0)
{
isNegative = true;
}
else if(crossProduct > 0)
{
isPositive = true;
}
if(isNegative && isPositive)
{
return false;
}
}
return true;
}
#endregion
#region 삼각형 리스트 구하기 - GetTriangleList()
/// <summary>
/// 삼각형 리스트 구하기
/// </summary>
/// <returns>삼각형 리스트</returns>
public List<Triangle> GetTriangleList()
{
PointF[] temporaryArray = new PointF[PointArray.Length];
Array.Copy(PointArray, temporaryArray, PointArray.Length);
Polygon polygon = new Polygon(temporaryArray);
polygon.OrientPolygonClockwise();
List<Triangle> triangleList = new List<Triangle>();
while(polygon.PointArray.Length > 3)
{
polygon.RemoveEar(triangleList);
}
triangleList.Add
(
new Triangle
(
polygon.PointArray[0],
polygon.PointArray[1],
polygon.PointArray[2]
)
);
return triangleList;
}
#endregion
#region 가장 작은 테두리 사각형 구하기 - GetSmallestBoundingRectangle()
/// <summary>
/// 가장 작은 테두리 사각형 구하기
/// </summary>
/// <returns>가장 작은 테두리 사각형 포인트 배열</returns>
public PointF[] GetSmallestBoundingRectangle()
{
Debug.Assert(!IsOrientedClockwise());
ResetBoundingRectangle();
for(int i = 0; i < PointArray.Length; i++)
{
CheckNextRectangle();
}
return this.currentRectanglePointArray2;
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Private
#region 부호 있는 다각형 영역 구하기 - GetSignedPolygonArea()
/// <summary>
/// 부호 있는 다각형 영역 구하기
/// </summary>
/// <returns>부호 있는 다각형 영역</returns>
/// <remarks>다각형이 시계 방향으로 향한 경우 음수값을 반환한다.</remarks>
private float GetSignedPolygonArea()
{
int pointCount = PointArray.Length;
PointF[] temporaryArray = new PointF[pointCount + 1];
PointArray.CopyTo(temporaryArray, 0);
temporaryArray[pointCount] = PointArray[0];
float area = 0;
for(int i = 0; i < pointCount; i++)
{
area += (temporaryArray[i + 1].X - temporaryArray[i].X) * (temporaryArray[i + 1].Y + temporaryArray[i].Y) / 2;
}
return area;
}
#endregion
#region 내적 구하기 - GetDotProduct(aX, aY, bX, bY, cX, cY)
/// <summary>
/// 내적 구하기
/// </summary>
/// <param name="aX">A 포인트 X 좌표</param>
/// <param name="aY">A 포인트 Y 좌표</param>
/// <param name="bX">B 포인트 X 좌표</param>
/// <param name="bY">B 포인트 Y 좌표</param>
/// <param name="cX">C 포인트 X 좌표</param>
/// <param name="cY">C 포인트 Y 좌표</param>
/// <returns>내적</returns>
private static float GetDotProduct(float aX, float aY, float bX, float bY, float cX, float cY)
{
float baX = aX - bX;
float baY = aY - bY;
float bcX = cX - bX;
float bcY = cY - bY;
return (baX * bcX + baY * bcY);
}
#endregion
#region 외적 구하기 - GetCrossProduct(aX, aY, bX, bY, cX, cY)
/// <summary>
/// 외적 구하기
/// </summary>
/// <param name="aX">A 포인트 X 좌표</param>
/// <param name="aY">A 포인트 Y 좌표</param>
/// <param name="bX">B 포인트 X 좌표</param>
/// <param name="bY">B 포인트 Y 좌표</param>
/// <param name="cX">C 포인트 X 좌표</param>
/// <param name="cY">C 포인트 Y 좌표</param>
/// <returns>외적</returns>
public static float GetCrossProduct(float aX, float aY, float bX, float bY, float cX, float cY)
{
float baX = aX - bX;
float baY = aY - bY;
float bcX = cX - bX;
float bcY = cY - bY;
return (baX * bcY - baY * bcX);
}
#endregion
#region 각도 구하기 - GetAngle(aX, aY, bX, bY, cX, cY)
/// <summary>
/// 각도 구하기
/// </summary>
/// <param name="aX">A 포인트 X 좌표</param>
/// <param name="aY">A 포인트 Y 좌표</param>
/// <param name="bX">B 포인트 X 좌표</param>
/// <param name="bY">B 포인트 Y 좌표</param>
/// <param name="cX">C 포인트 X 좌표</param>
/// <param name="cY">C 포인트 Y 좌표</param>
/// <returns>각도</returns>
public static float GetAngle(float aX, float aY, float bX, float bY, float cX, float cY)
{
float dotProduct = GetDotProduct(aX, aY, bX, bY, cX, cY);
float crossProduct = GetCrossProduct(aX, aY, bX, bY, cX, cY);
return (float)Math.Atan2(crossProduct, dotProduct);
}
#endregion
#region 3개의 점이 귀의 형태를 구성하는지 여부 구하기 - FormsEar(pointArray, a, b, c)
/// <summary>
/// 3개의 점이 귀의 형태를 구성하는지 여부 구하기
/// </summary>
/// <param name="pointArray">포인트 배열</param>
/// <param name="a">A 포인트 인덱스</param>
/// <param name="b">B 포인트 인덱스</param>
/// <param name="c">C 포인트 인덱스</param>
/// <returns>3개의 점이 귀의 형태를 구성하는지 여부</returns>
private static bool FormsEar(PointF[] pointArray, int a, int b, int c)
{
float angle = GetAngle
(
pointArray[a].X,
pointArray[a].Y,
pointArray[b].X,
pointArray[b].Y,
pointArray[c].X,
pointArray[c].Y
);
if(angle > 0)
{
return false;
}
Triangle triangle = new Triangle(pointArray[a], pointArray[b], pointArray[c]);
for(int i = 0; i < pointArray.Length; i++)
{
if((i != a) && (i != b) && (i != c))
{
if(triangle.IncludePoint(pointArray[i].X, pointArray[i].Y))
{
return false;
}
}
}
return true;
}
#endregion
#region 귀를 구성하는 3개의 점의 인덱스 찾기 - FindEar(a, b, c)
/// <summary>
/// 귀를 구성하는 3개의 점의 인덱스 찾기
/// </summary>
/// <param name="a">A 포인트 인덱스</param>
/// <param name="b">B 포인트 인덱스</param>
/// <param name="c">C 포인트 인덱스</param>
private void FindEar(ref int a, ref int b, ref int c)
{
int pointCount = PointArray.Length;
for(a = 0; a < pointCount; a++)
{
b = (a + 1) % pointCount;
c = (b + 1) % pointCount;
if(FormsEar(PointArray, a, b, c))
{
return;
}
}
Debug.Assert(false);
}
#endregion
#region 배열에서 포인트 제거하기 - RemovePointFromArray(target)
/// <summary>
/// 배열에서 포인트 제거하기
/// </summary>
/// <param name="target">타겟 인덱스</param>
private void RemovePointFromArray(int target)
{
PointF[] temporaryArray = new PointF[PointArray.Length - 1];
Array.Copy(PointArray, 0, temporaryArray, 0, target);
Array.Copy(PointArray, target + 1, temporaryArray, target, PointArray.Length - target - 1);
PointArray = temporaryArray;
}
#endregion
#region 다각형에서 귀를 제거하고 삼각형 리스트 추가하기 - RemoveEar(triangleList)
/// <summary>
/// 다각형에서 귀를 제거하고 삼각형 리스트 추가하기
/// </summary>
/// <param name="triangleList">삼각형 리스트</param>
private void RemoveEar(List<Triangle> triangleList)
{
int a = 0;
int b = 0;
int c = 0;
FindEar(ref a, ref b, ref c);
triangleList.Add(new Triangle(PointArray[a], PointArray[b], PointArray[c]));
RemovePointFromArray(b);
}
#endregion
#region 초기 컨트롤 포인트 배열 체크하기 - CheckInitialControlPointArray(index)
/// <summary>
/// 초기 컨트롤 포인트 배열 체크하기
/// </summary>
/// <param name="index">인덱스</param>
/// <returns>체크 결과</returns>
private bool CheckInitialControlPointArray(int index)
{
int nextIndex = (index + 1) % this.pointCount;
float xGap1 = PointArray[nextIndex].X - PointArray[index].X;
float yGap1 = PointArray[nextIndex].Y - PointArray[index].Y;
for(int i = 0; i < 4; i++)
{
this.controlPointArray[i] = index;
}
for(int i = 1; i < pointCount; i++)
{
int j = (index - i + pointCount) % pointCount;
int nextJ = (j + 1) % pointCount;
float xGap2 = PointArray[nextJ].X - PointArray[j].X;
float yGap2 = PointArray[nextJ].Y - PointArray[j].Y;
float dotProduct = xGap1 * xGap2 + yGap1 * yGap2;
if(dotProduct < 0)
{
this.controlPointArray[0] = nextJ;
break;
}
}
if(this.controlPointArray[0] == index)
{
return false;
}
for(int i = 1; i < pointCount; i++)
{
int j = (index + i) % pointCount;
int nextJ = (j + 1) % pointCount;
float xGap3 = PointArray[nextJ].X - PointArray[j].X;
float yGap3 = PointArray[nextJ].Y - PointArray[j].Y;
float dotProduct = xGap1 * xGap3 + yGap1 * yGap3;
if(dotProduct <= 0)
{
this.controlPointArray[2] = j;
break;
}
}
if(this.controlPointArray[2] == index)
{
return false;
}
index = this.controlPointArray[2] - 1;
float temporary = xGap1;
xGap1 = yGap1;
yGap1 = -temporary;
for(int i = 1; i < pointCount; i++)
{
int j = (index + i) % pointCount;
int nextJ = (j + 1) % pointCount;
float xGap4 = PointArray[nextJ].X - PointArray[j].X;
float yGap4 = PointArray[nextJ].Y - PointArray[j].Y;
float dotProduct = xGap1 * xGap4 + yGap1 * yGap4;
if(dotProduct <= 0)
{
this.controlPointArray[3] = j;
break;
}
}
if(this.controlPointArray[0] == index)
{
return false;
}
return true;
}
#endregion
#region 초기 컨트롤 포인트 배열 찾기 - FindInitialControlPointArray()
/// <summary>
/// 초기 컨트롤 포인트 배열 찾기
/// </summary>
private void FindInitialControlPointArray()
{
for(int i = 0; i < pointCount; i++)
{
if(CheckInitialControlPointArray(i))
{
return;
}
}
Debug.Assert(false, "초기 컨트롤 포인트 배열을 찾을 수 없습니다.");
}
#endregion
#region 다각형을 시계 방향으로 만들기 - OrientPolygonClockwise()
/// <summary>
/// 다각형을 시계 방향으로 만들기
/// </summary>
private void OrientPolygonClockwise()
{
if(!IsOrientedClockwise())
{
Array.Reverse(PointArray);
}
}
#endregion
#region 교차점 구하기 - FindIntersection(x1, y1, x2, y2, a1, b1, a2, b2, intersect)
/// <summary>
/// 교차점 구하기
/// </summary>
/// <param name="x1">X1</param>
/// <param name="y1">Y1</param>
/// <param name="x2">X2</param>
/// <param name="y2">Y2</param>
/// <param name="a1">A1</param>
/// <param name="b1">B1</param>
/// <param name="a2">A2</param>
/// <param name="b2">B2</param>
/// <param name="intersect">교차점</param>
/// <returns>처리 결과</returns>
private bool FindIntersection(float x1, float y1, float x2, float y2, float a1, float b1, float a2, float b2, ref PointF intersect)
{
float deltaX = x2 - x1;
float deltaY = y2 - y1;
float deltaA = a2 - a1;
float deltaB = b2 - b1;
float s;
float t;
if(Math.Abs(deltaA * deltaY - deltaB * deltaX) < 0.001)
{
return false;
}
s = (deltaX * (b1 - y1) + deltaY * (x1 - a1)) / (deltaA * deltaY - deltaB * deltaX);
t = (deltaA * (y1 - b1) + deltaB * (a1 - x1)) / (deltaB * deltaX - deltaA * deltaY);
intersect = new PointF(x1 + t * deltaX, y1 + t * deltaY);
return true;
}
#endregion
#region 테두리 사각형 찾기 - FindBoundingRectangle()
/// <summary>
/// 테두리 사각형 찾기
/// </summary>
private void FindBoundingRectangle()
{
int index1 = this.controlPointArray[this.currentControlPoint];
int index2 = (index1 + 1) % this.pointCount;
float deltaX = PointArray[index2].X - PointArray[index1].X;
float deltaY = PointArray[index2].Y - PointArray[index1].Y;
switch(this.currentControlPoint)
{
case 0 :
break;
case 1 :
float temporary1 = deltaX;
deltaX = -deltaY;
deltaY = temporary1;
break;
case 2 :
deltaX = -deltaX;
deltaY = -deltaY;
break;
case 3 :
float temporary2 = deltaX;
deltaX = deltaY;
deltaY = -temporary2;
break;
}
float px0 = PointArray[this.controlPointArray[0]].X;
float py0 = PointArray[this.controlPointArray[0]].Y;
float dx0 = deltaX;
float dy0 = deltaY;
float px1 = PointArray[this.controlPointArray[1]].X;
float py1 = PointArray[this.controlPointArray[1]].Y;
float dx1 = deltaY;
float dy1 = -deltaX;
float px2 = PointArray[this.controlPointArray[2]].X;
float py2 = PointArray[this.controlPointArray[2]].Y;
float dx2 = -deltaX;
float dy2 = -deltaY;
float px3 = PointArray[this.controlPointArray[3]].X;
float py3 = PointArray[this.controlPointArray[3]].Y;
float dx3 = -deltaY;
float dy3 = deltaX;
this.currentRectanglePointArray1 = new PointF[4];
FindIntersection(px0, py0, px0 + dx0, py0 + dy0, px1, py1, px1 + dx1, py1 + dy1, ref this.currentRectanglePointArray1[0]);
FindIntersection(px1, py1, px1 + dx1, py1 + dy1, px2, py2, px2 + dx2, py2 + dy2, ref this.currentRectanglePointArray1[1]);
FindIntersection(px2, py2, px2 + dx2, py2 + dy2, px3, py3, px3 + dx3, py3 + dy3, ref this.currentRectanglePointArray1[2]);
FindIntersection(px3, py3, px3 + dx3, py3 + dy3, px0, py0, px0 + dx0, py0 + dy0, ref this.currentRectanglePointArray1[3]);
float xGap1 = this.currentRectanglePointArray1[0].X - this.currentRectanglePointArray1[1].X;
float yGap1 = this.currentRectanglePointArray1[0].Y - this.currentRectanglePointArray1[1].Y;
float length1 = (float)Math.Sqrt(xGap1 * xGap1 + yGap1 * yGap1);
float xGap2 = this.currentRectanglePointArray1[1].X - this.currentRectanglePointArray1[2].X;
float yGap2 = this.currentRectanglePointArray1[1].Y - this.currentRectanglePointArray1[2].Y;
float length2 = (float)Math.Sqrt(xGap2 * xGap2 + yGap2 * yGap2);
this.currentArea2 = length1 * length2;
if(this.currentArea2 < this.currentArea1)
{
this.currentArea1 = this.currentArea2;
this.currentRectanglePointArray2 = this.currentRectanglePointArray1;
}
}
#endregion
#region 엣지 기울시 찾기 - FindEdgeSlope(deltaX, deltaY, index)
/// <summary>
/// 엣지 기울시 찾기
/// </summary>
/// <param name="deltaX">델타 X</param>
/// <param name="deltaY">델타 Y</param>
/// <param name="index">인덱스</param>
private void FindEdgeSlope(out float deltaX, out float deltaY, int index)
{
int nextIndex = (index + 1) % pointCount;
deltaX = PointArray[nextIndex].X - PointArray[index].X;
deltaY = PointArray[nextIndex].Y - PointArray[index].Y;
}
#endregion
#region 다음 사각형 체크하기 - CheckNextRectangle()
/// <summary>
/// 다음 사각형 체크하기
/// </summary>
private void CheckNextRectangle()
{
if(this.currentControlPoint >= 0)
{
this.controlPointArray[this.currentControlPoint] = (this.controlPointArray[this.currentControlPoint] + 1) % this.pointCount;
}
float deltaX0;
float deltaY0;
float deltaX1;
float deltaY1;
float deltaX2;
float deltaY2;
float deltaX3;
float deltaY3;
FindEdgeSlope(out deltaX0, out deltaY0, this.controlPointArray[0]);
FindEdgeSlope(out deltaX1, out deltaY1, this.controlPointArray[1]);
FindEdgeSlope(out deltaX2, out deltaY2, this.controlPointArray[2]);
FindEdgeSlope(out deltaX3, out deltaY3, this.controlPointArray[3]);
float opposite0 = deltaX0;
float adjust0 = deltaY0;
float opposite1 = -deltaY1;
float adjust1 = deltaX1;
float opposite2 = -deltaX2;
float adjust2 = -deltaY2;
float opposite3 = deltaY3;
float adjust3 = -deltaX3;
float currentOpposite = opposite0;
float currentAdjust = adjust0;
int currentControlPoint = 0;
if(opposite1 * currentAdjust < currentOpposite * adjust1)
{
currentOpposite = opposite1;
currentAdjust = adjust1;
currentControlPoint = 1;
}
if(opposite2 * currentAdjust < currentOpposite * adjust2)
{
currentOpposite = opposite2;
currentAdjust = adjust2;
currentControlPoint = 2;
}
if(opposite3 * currentAdjust < currentOpposite * adjust3)
{
currentOpposite = opposite3;
currentAdjust = adjust3;
currentControlPoint = 3;
}
this.currentControlPoint = currentControlPoint;
this.edgeCheckArray[this.controlPointArray[this.currentControlPoint]] = true;
FindBoundingRectangle();
}
#endregion
#region 테두리 사각형 리셋하기 - ResetBoundingRectangle()
/// <summary>
/// 테두리 사각형 리셋하기
/// </summary>
private void ResetBoundingRectangle()
{
this.pointCount = PointArray.Length;
FindInitialControlPointArray();
this.edgeCheckArray = new bool[pointCount];
this.currentControlPoint = 1;
this.currentArea1 = float.MaxValue;
FindBoundingRectangle();
this.edgeCheckArray[this.controlPointArray[this.currentControlPoint]] = true;
}
#endregion
}
}
300x250
▶ MainForm.cs
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace TestProject
{
/// <summary>
/// 메인 폼
/// </summary>
public partial class MainForm : Form
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// PT_RAD
/// </summary>
private const int PT_RAD = 2;
/// <summary>
/// PT_WID
/// </summary>
private const int PT_WID = PT_RAD * 2 + 1;
/// <summary>
/// 포인트 리스트
/// </summary>
private List<PointF> pointList = new List<PointF>();
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - MainForm()
/// <summary>
/// 생성자
/// </summary>
public MainForm()
{
InitializeComponent();
#region 이벤트를 설정한다.
MouseClick += Form_MouseClick;
Paint += Form_Paint;
this.clearMenuItem.Click += clearMenuItem_Click;
this.convexMenuItem.Click += convexMenuItem_Click;
this.includePointMenuItem.Click += includePointMenuItem_Click;
this.areaMenuItem.Click += areaMenuItem_Click;
this.centroidMenuItem.Click += centroidMenuItem_Click;
this.orientationMenuItem.Click += orientationMenuItem_Click;
this.reverseMenuItem.Click += reverseMenuItem_Click;
this.triangulateMenuItem.Click += triangulateMenuItem_Click;
this.boundingRectangleMenuItem.Click += boundingRectangleMenuItem_Click;
#endregion
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Private
//////////////////////////////////////////////////////////////////////////////// Event
#region 폼 마우스 클릭시 처리하기 - Form_MouseClick(sender, e)
/// <summary>
/// 폼 마우스 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void Form_MouseClick(object sender, MouseEventArgs e)
{
this.pointList.Add(new PointF(e.X, e.Y));
Invalidate();
}
#endregion
#region 폼 페인트시 처리하기 - Form_Paint(sender, e)
/// <summary>
/// 폼 페인트시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void Form_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(BackColor);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
if(this.pointList.Count >= 3)
{
e.Graphics.DrawPolygon(Pens.Blue, this.pointList.ToArray());
}
else if(this.pointList.Count == 2)
{
e.Graphics.DrawLines(Pens.Blue, this.pointList.ToArray());
}
if(this.pointList.Count > 0)
{
foreach(PointF point in this.pointList)
{
e.Graphics.FillRectangle(Brushes.White, point.X - PT_RAD, point.Y - PT_RAD, PT_WID, PT_WID);
e.Graphics.DrawRectangle(Pens.Black, point.X - PT_RAD, point.Y - PT_RAD, PT_WID, PT_WID);
}
}
EnableMenu();
}
#endregion
#region 지우기 메뉴 항목 클릭시 처리하기 - clearMenuItem_Click(sender, e)
/// <summary>
/// 지우기 메뉴 항목 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void clearMenuItem_Click(object sender, EventArgs e)
{
this.pointList = new List<PointF>();
EnableMenu();
Invalidate();
}
#endregion
#region 볼록 여부 구하기 메뉴 항목 클릭시 처리하기 - convexMenuItem_Click(sender, e)
/// <summary>
/// 볼록 여부 구하기 메뉴 항목 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void convexMenuItem_Click(object sender, EventArgs e)
{
Polygon polygon = new Polygon(this.pointList.ToArray());
if(polygon.IsConvex())
{
MessageBox.Show("다각형이 볼록입니다.", "확인", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show("다각형이 볼록이 아닙니다.", "확인", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
#endregion
#region 포인트 포함 여부 구하기 메뉴 항목 클릭시 처리하기 - includePointMenuItem_Click(sender, e)
/// <summary>
/// 포인트 포함 여부 구하기 메뉴 항목 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void includePointMenuItem_Click(object sender, EventArgs e)
{
Point point = Cursor.Position;
point = PointToClient(point);
Rectangle rectangle = new Rectangle(point.X - 3, point.Y - 3, 7, 7);
using(Graphics graphics = CreateGraphics())
{
Polygon polygon = new Polygon(this.pointList.ToArray());
if(polygon.IncludePoint(point.X, point.Y))
{
graphics.FillEllipse(Brushes.Lime, rectangle);
}
else
{
graphics.FillEllipse(Brushes.Red, rectangle);
}
graphics.DrawEllipse(Pens.Black, rectangle);
}
}
#endregion
#region 면적 구하기 메뉴 항목 클릭시 처리하기 - areaMenuItem_Click(sender, e)
/// <summary>
/// 면적 구하기 메뉴 항목 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void areaMenuItem_Click(object sender, EventArgs e)
{
Polygon polygon = new Polygon(this.pointList.ToArray());
MessageBox.Show("면적 : " + polygon.GetPolygonArea().ToString(), "확인", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
#endregion
#region 중심점 구하기 메뉴 항목 클릭시 처리하기 - centroidMenuItem_Click(sender, e)
/// <summary>
/// 중심점 구하기 메뉴 항목 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void centroidMenuItem_Click(object sender, EventArgs e)
{
Polygon polygon = new Polygon(this.pointList.ToArray());
PointF point = polygon.GetCentroid();
Rectangle rectangle = new Rectangle((int)point.X - 3, (int)point.Y - 3, 7, 7);
using(Graphics graphics = CreateGraphics())
{
graphics.FillEllipse(Brushes.Yellow, rectangle);
graphics.DrawEllipse(Pens.Black, rectangle);
}
}
#endregion
#region 방향 구하기 메뉴 항목 클릭시 처리하기 - orientationMenuItem_Click(sender, e)
/// <summary>
/// 방향 구하기 메뉴 항목 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void orientationMenuItem_Click(object sender, EventArgs e)
{
Polygon polygon = new Polygon(this.pointList.ToArray());
if(polygon.IsOrientedClockwise())
{
MessageBox.Show("시계 방향", "확인", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show("시계 반대 방향", "확인", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
#endregion
#region 반전 시키기 메뉴 항목 클릭시 처리하기 - reverseMenuItem_Click(sender, e)
/// <summary>
/// 반전 시키기 메뉴 항목 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void reverseMenuItem_Click(object sender, EventArgs e)
{
this.pointList.Reverse();
}
#endregion
#region 삼각형 리스트 구하기 메뉴 항목 클릭시 처리하기 - triangulateMenuItem_Click(sender, e)
/// <summary>
/// 삼각형 리스트 구하기 메뉴 항목 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void triangulateMenuItem_Click(object sender, EventArgs e)
{
Polygon polygon = new Polygon(this.pointList.ToArray());
List<Triangle> triangleList = polygon.GetTriangleList();
using(Graphics graphics = CreateGraphics())
{
foreach(Triangle triangle in triangleList)
{
graphics.DrawPolygon(Pens.Red, triangle.PointArray);
}
if(this.pointList.Count >= 3)
{
graphics.DrawPolygon(Pens.Blue, this.pointList.ToArray());
}
}
}
#endregion
#region 테두리 사각형 구하기 메뉴 항목 클릭시 처리하기 - boundingRectangleMenuItem_Click(sender, e)
/// <summary>
/// 테두리 사각형 구하기 메뉴 항목 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void boundingRectangleMenuItem_Click(object sender, EventArgs e)
{
Polygon polygon = new Polygon(this.pointList.ToArray());
if(polygon.IsOrientedClockwise())
{
Array.Reverse(polygon.PointArray);
}
PointF[] pointArray = polygon.GetSmallestBoundingRectangle();
using(Graphics graphics = CreateGraphics())
{
graphics.DrawPolygon(Pens.Orange, pointArray);
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Function
#region 메뉴 활성화 여부 설정하기 - EnableMenu()
/// <summary>
/// 메뉴 활성화 여부 설정하기
/// </summary>
private void EnableMenu()
{
bool enabled = (this.pointList.Count >= 3);
this.convexMenuItem.Enabled = enabled;
this.includePointMenuItem.Enabled = enabled;
this.areaMenuItem.Enabled = enabled;
this.centroidMenuItem.Enabled = enabled;
this.orientationMenuItem.Enabled = enabled;
this.reverseMenuItem.Enabled = enabled;
this.triangulateMenuItem.Enabled = enabled;
this.boundingRectangleMenuItem.Enabled = enabled;
}
#endregion
}
}
728x90
반응형
그리드형(광고전용)
'C# > WinForm' 카테고리의 다른 글
[C#/WINFORM] 포인트 리스트를 둘러싸는 원 구하기 (0) | 2018.12.05 |
---|---|
[C#/WINFORM] 2개 직선 사이 최단거리 구하기 (0) | 2018.12.05 |
[C#/WINFORM] 2개 직선의 교차 여부 구하기 (0) | 2018.12.05 |
[C#/WINFORM] 하이포트로코이드(Hypotrochoid) 그리기 (0) | 2018.12.05 |
[C#/WINFORM] Button 클래스 : 버튼 모양 설정하기 (0) | 2018.12.03 |
[C#/WINFORM] 다각형 처리하기 (0) | 2018.12.03 |
[C#/WINFORM] 시어핀스키 곡선(Sierpinski Curve) 그리기 (0) | 2018.12.03 |
[C#/WINFORM] 별난 끌개 프랙탈(Strange Attractor Fractal) 그리기 (0) | 2018.12.02 |
[C#/WINFORM] 포인트 리스트를 둘러싸는 외곽선(Convex Hull) 구하기 (0) | 2018.12.02 |
[C#/WINFORM] 이미지 사각형 선택하기 (0) | 2018.12.02 |
[C#/WINFORM] 이미지 파일명에 따라 적절한 포맷으로 이미지 저장하기 (0) | 2018.12.02 |
댓글을 달아 주세요