This commit is contained in:
이형구 2025-04-08 10:59:41 +09:00 committed by chodadoo
parent 31f761faca
commit 6cfea47a0f
5 changed files with 247 additions and 47 deletions

Binary file not shown.

View File

@ -23,7 +23,7 @@
<ProjectGuid>{61F95EA6-D645-4EE0-B5B7-1C6D8CFB19B1}</ProjectGuid> <ProjectGuid>{61F95EA6-D645-4EE0-B5B7-1C6D8CFB19B1}</ProjectGuid>
<Keyword>MFCProj</Keyword> <Keyword>MFCProj</Keyword>
<RootNamespace>GlimWork</RootNamespace> <RootNamespace>GlimWork</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
@ -44,9 +44,9 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
<UseOfMfc>Dynamic</UseOfMfc> <UseOfMfc>Dynamic</UseOfMfc>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>

View File

@ -52,13 +52,18 @@ END_MESSAGE_MAP()
CGlimWorkDlg::CGlimWorkDlg(CWnd* pParent /*=nullptr*/) CGlimWorkDlg::CGlimWorkDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_GLIMWORK_DIALOG, pParent) : CDialogEx(IDD_GLIMWORK_DIALOG, pParent)
, m_dRaius(0)
, m_dExternBorder(0)
{ {
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_bThreadReady = true;
} }
void CGlimWorkDlg::DoDataExchange(CDataExchange* pDX) void CGlimWorkDlg::DoDataExchange(CDataExchange* pDX)
{ {
CDialogEx::DoDataExchange(pDX); CDialogEx::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT_RADIUS, m_dRaius);
DDX_Text(pDX, IDC_EDIT_EXTERN_BORDER, m_dExternBorder);
} }
BEGIN_MESSAGE_MAP(CGlimWorkDlg, CDialogEx) BEGIN_MESSAGE_MAP(CGlimWorkDlg, CDialogEx)
@ -68,6 +73,12 @@ BEGIN_MESSAGE_MAP(CGlimWorkDlg, CDialogEx)
ON_WM_LBUTTONUP() ON_WM_LBUTTONUP()
ON_WM_LBUTTONDOWN() ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE() ON_WM_MOUSEMOVE()
ON_EN_CHANGE(IDC_EDIT_RADIUS, &CGlimWorkDlg::OnEnChangeEditRadius)
ON_EN_CHANGE(IDC_EDIT_EXTERN_BORDER, &CGlimWorkDlg::OnEnChangeEditExternBorder)
ON_BN_CLICKED(IDC_BUTTON_RESET, &CGlimWorkDlg::OnBnClickedButtonReset)
ON_BN_CLICKED(IDC_BUTTON_RANDOM, &CGlimWorkDlg::OnBnClickedButtonRandom)
ON_BN_CLICKED(IDC_BUTTON_RANDOM_THREAD, &CGlimWorkDlg::OnBnClickedButtonRandomThread)
ON_MESSAGE(USER_MESSAGE, &CGlimWorkDlg::USER_MESSAGE_FNC)
END_MESSAGE_MAP() END_MESSAGE_MAP()
@ -105,10 +116,10 @@ BOOL CGlimWorkDlg::OnInitDialog()
// TODO: 여기에 추가 초기화 작업을 추가합니다. // TODO: 여기에 추가 초기화 작업을 추가합니다.
CRect rect; CRect rect;
GetDlgItem(IDC_STATIC)->GetWindowRect(&rect); GetDlgItem(IDC_STATIC_PIC)->GetWindowRect(&rect);
ScreenToClient(&rect); ScreenToClient(&rect);
m_Image.Create(rect.Width(), rect.Height(), 8); m_Image.Create(rect.Width(), -rect.Height(), 8);
static RGBQUAD rgb[256]; static RGBQUAD rgb[256];
for (int i = 0; i < 256; i++) for (int i = 0; i < 256; i++)
@ -118,10 +129,15 @@ BOOL CGlimWorkDlg::OnInitDialog()
unsigned char* fm = (unsigned char*)m_Image.GetBits(); unsigned char* fm = (unsigned char*)m_Image.GetBits();
// '(전체 줄 - 1) * 한줄의 바이트수'를 빼서 시작 줄의 주소로 변경한다. // '(전체 줄 - 1) * 한줄의 바이트수'를 빼서 시작 줄의 주소로 변경한다.
fm -= m_Image.GetWidth() * (m_Image.GetHeight() - 1) * (8 / 8); //fm -= m_Image.GetWidth() * (m_Image.GetHeight() - 1);
memset(fm, 0xFF, m_Image.GetWidth() * m_Image.GetHeight()); memset(fm, 0xFF, m_Image.GetWidth() * m_Image.GetHeight());
// 컨트롤러 값 초기화 으떻게 하던거라?
m_dRaius = 20;
m_dExternBorder = 5;
UpdateData(false);
return TRUE; // 포커스를 컨트롤에 설정하지 않으면 TRUE를 반환합니다. return TRUE; // 포커스를 컨트롤에 설정하지 않으면 TRUE를 반환합니다.
} }
@ -164,10 +180,9 @@ void CGlimWorkDlg::OnPaint()
else else
{ {
CRect rect; CRect rect;
GetDlgItem(IDC_STATIC)->GetWindowRect(&rect); GetDlgItem(IDC_STATIC_PIC)->GetClientRect(&rect);
ScreenToClient(&rect);
CClientDC DC(this); CClientDC DC(GetDlgItem(IDC_STATIC_PIC));
m_Image.Draw(DC, rect); m_Image.Draw(DC, rect);
CDialogEx::OnPaint(); CDialogEx::OnPaint();
@ -181,13 +196,20 @@ HCURSOR CGlimWorkDlg::OnQueryDragIcon()
return static_cast<HCURSOR>(m_hIcon); return static_cast<HCURSOR>(m_hIcon);
} }
LRESULT CGlimWorkDlg::USER_MESSAGE_FNC(WPARAM wparam, LPARAM lparam)
{
CirclePrc();
return 0;
}
void CGlimWorkDlg::OnLButtonDown(UINT nFlags, CPoint point) void CGlimWorkDlg::OnLButtonDown(UINT nFlags, CPoint point)
{ {
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다. // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
// UI 반응 범주 // UI 반응 범주
CRect rect; CRect rect;
GetDlgItem(IDC_STATIC)->GetWindowRect(&rect); GetDlgItem(IDC_STATIC_PIC)->GetWindowRect(&rect);
ScreenToClient(&rect); ScreenToClient(&rect);
if (!rect.PtInRect(point)) if (!rect.PtInRect(point))
@ -226,7 +248,7 @@ void CGlimWorkDlg::OnLButtonUp(UINT nFlags, CPoint point)
// UI 반응 범주 // UI 반응 범주
CRect rect; CRect rect;
GetDlgItem(IDC_STATIC)->GetWindowRect(&rect); GetDlgItem(IDC_STATIC_PIC)->GetWindowRect(&rect);
ScreenToClient(&rect); ScreenToClient(&rect);
if (!rect.PtInRect(point)) if (!rect.PtInRect(point))
@ -253,48 +275,67 @@ void CGlimWorkDlg::CirclePrc(void)
// TODO: 여기에 구현 코드 추가. // TODO: 여기에 구현 코드 추가.
unsigned char* fm = (unsigned char*)m_Image.GetBits(); unsigned char* fm = (unsigned char*)m_Image.GetBits();
// '(전체 줄 - 1) * 한줄의 바이트수'를 빼서 시작 줄의 주소로 변경한다.
fm -= m_Image.GetWidth() * (m_Image.GetHeight() - 1) * (8 / 8);
memset(fm, 0xFF, m_Image.GetWidth() * m_Image.GetHeight()); memset(fm, 0xFF, m_Image.GetWidth() * m_Image.GetHeight());
for (int i = 0; i < m_dCircleCnt; i++)
{
if (m_Circle[i]._Create)
m_Circle[i]._Drwa((unsigned char *)m_Image.GetBits(), m_Image.GetPitch());
}
// 세점의 외접원 // 세점의 외접원
if (CircleMaxCount <= m_dCircleCnt) if (CircleMaxCount <= m_dCircleCnt)
{ {
unsigned char* fm2 = (unsigned char*)m_Image.GetBits();
CPoint _Center = GetCenter(m_Circle[0]._ClickPoint, m_Circle[1]._ClickPoint, m_Circle[2]._ClickPoint); CPoint _Center = GetCenter(m_Circle[0]._ClickPoint, m_Circle[1]._ClickPoint, m_Circle[2]._ClickPoint);
// 중심점에서 반지름 // 중심점에서 반지름
int distance = sqrt(pow(_Center.x - m_Circle[0]._ClickPoint.x, 2) + pow(_Center.y - m_Circle[0]._ClickPoint.y, 2)); int distance = sqrt(pow(_Center.x - m_Circle[0]._ClickPoint.x, 2) + pow(_Center.y - m_Circle[0]._ClickPoint.y, 2));
int nStartX = _Center.x - distance; // 큰거그리고 작은거 그리자
int nStartY = _Center.y - distance; UpdateData(false);
int nCenterX = _Center.x; int dExternD = distance + (m_dExternBorder / 2);
int nCenterY = _Center.y; int dInternalD = distance - (m_dExternBorder / 2);
for (int i = nStartX; i < nStartX + (distance * 2); i++) for (int i = _Center.x - dExternD; i < _Center.x - dExternD + (dExternD * 2); i++)
{ {
for (int j = nStartY; j < nStartY + (distance * 2); j++) for (int j = _Center.y - dExternD; j < _Center.y - dExternD + (dExternD * 2); j++)
{ {
// 픽셀단위로 원에 해당 여부를 판정 // 픽셀단위로 원에 해당 여부를 판정
if (isInCircle(i, j, nCenterX, nCenterY, distance)) if (isInCircle(i, j, _Center.x, _Center.y, dExternD))
fm2[(j * m_Image.GetPitch()) + i] = 0x00; // memey validation
if (i >= 0 && j >= 0 && i < m_Image.GetWidth() && j < m_Image.GetHeight())
fm[(j * m_Image.GetPitch()) + i] = 0x00;
}
}
for (int i = _Center.x - dInternalD; i < _Center.x - dInternalD + (dInternalD * 2); i++)
{
for (int j = _Center.y - dInternalD; j < _Center.y - dInternalD + (dInternalD * 2); j++)
{
// 픽셀단위로 원에 해당 여부를 판정
if (isInCircle(i, j, _Center.x, _Center.y, dInternalD))
// memey validation
if (i >= 0 && j >= 0 && i < m_Image.GetWidth() && j < m_Image.GetHeight())
fm[(j * m_Image.GetPitch()) + i] = 0xFF;
} }
} }
} }
for (int i = 0; i < m_dCircleCnt; i++)
{
if (m_Circle[i]._Create)
m_Circle[i]._Drwa((unsigned char *)m_Image.GetBits(), m_Image.GetWidth(), m_Image.GetHeight(), m_Image.GetPitch());
}
OnPaint(); OnPaint();
// info
CString str;
str.Format(_T("X[0] : %d, Y[0]: %d\r\nX[1] : %d, Y[1]: %d\r\nX[2] : %d, Y[2]: %d\r\n")
, m_Circle[0]._ClickPoint.x, m_Circle[0]._ClickPoint.y
, m_Circle[1]._ClickPoint.x, m_Circle[1]._ClickPoint.y
, m_Circle[2]._ClickPoint.x, m_Circle[2]._ClickPoint.y);
GetDlgItem(IDC_STATIC_POS_INFO)->SetWindowText(str);
} }
bool CGlimWorkDlg::isInCircle(int i, int j, int nCenterX, int nCenterY, int nRadius) bool CGlimWorkDlg::isInCircle(int i, int j, int nCenterX, int nCenterY, int nRadius)
{ {
// 샘플 코드 참조
bool bRet = false; bool bRet = false;
double dX = i - nCenterX; double dX = i - nCenterX;
@ -344,3 +385,126 @@ void CGlimWorkDlg::OnMouseMove(UINT nFlags, CPoint point)
CDialogEx::OnMouseMove(nFlags, point); CDialogEx::OnMouseMove(nFlags, point);
} }
void CGlimWorkDlg::OnEnChangeEditRadius()
{
// TODO: RICHEDIT 컨트롤인 경우, 이 컨트롤은
// CDialogEx::OnInitDialog() 함수를 재지정
//하고 마스크에 OR 연산하여 설정된 ENM_CHANGE 플래그를 지정하여 CRichEditCtrl().SetEventMask()를 호출하지 않으면
// 이 알림 메시지를 보내지 않습니다.
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
UpdateData(true);
for (int i = 0; i < CircleMaxCount; i++)
{
m_Circle[i]._nRadius = m_dRaius;
}
}
void CGlimWorkDlg::OnEnChangeEditExternBorder()
{
// TODO: RICHEDIT 컨트롤인 경우, 이 컨트롤은
// CDialogEx::OnInitDialog() 함수를 재지정
//하고 마스크에 OR 연산하여 설정된 ENM_CHANGE 플래그를 지정하여 CRichEditCtrl().SetEventMask()를 호출하지 않으면
// 이 알림 메시지를 보내지 않습니다.
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
UpdateData(true);
}
void CGlimWorkDlg::OnBnClickedButtonReset()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
for (int i = 0; i < CircleMaxCount; i++)
{
m_Circle[i].Reset();
}
m_dCircleCnt = 0;
CirclePrc();
}
void CGlimWorkDlg::OnBnClickedButtonRandom()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
// 세점의 외접원
if (!(CircleMaxCount <= m_dCircleCnt))
{
return;
}
for (int i = 0; i < CircleMaxCount; i++)
{
CPoint point = CPoint(rand() % m_Image.GetWidth(), rand() % m_Image.GetHeight());
m_Circle[i].Hold(point);
}
CirclePrc();
}
void CGlimWorkDlg::OnBnClickedButtonRandomThread()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
// 세점의 외접원
if (!(CircleMaxCount <= m_dCircleCnt))
{
return;
}
if (!m_bThreadReady)
{
return;
}
m_bThreadReady = !m_bThreadReady;
// 좀 더 신박한 쓰레드 사용방법들이 있었던 것 같은데;;;
// 실패 요건은 생략
m_pThread = AfxBeginThread(thread_fnc, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
m_pThread->ResumeThread();
}
UINT CGlimWorkDlg::thread_fnc(LPVOID _lparam)
{
CGlimWorkDlg *pDlg = (CGlimWorkDlg*)_lparam;
// 5회 (초당 2회 * 5회 : 총 10회로 이해)
for (int j = 0; j < 5; j++)
{
// 2회
for (int i = 0; i < 2; i++)
{
for (int i = 0; i < CircleMaxCount; i++)
{
CPoint point = CPoint(rand() % pDlg->m_Image.GetWidth(), rand() % pDlg->m_Image.GetHeight());
pDlg->m_Circle[i].Hold(point);
}
pDlg->SendMessage(USER_MESSAGE);
// 초당 2회, 500ms
Sleep(500);
}
Sleep(0);
}
pDlg->m_bThreadReady = true;
// 드로잉 자체를 쓰레드로 하라는건가???
return 0;
}

View File

@ -4,6 +4,7 @@
#pragma once #pragma once
#define USER_MESSAGE WM_USER + 0x01
// CGlimWorkDlg 대화 상자 // CGlimWorkDlg 대화 상자
class CGlimWorkDlg : public CDialogEx class CGlimWorkDlg : public CDialogEx
@ -62,6 +63,14 @@ private:
_Create = false; // 이게 뭐여 ㅋㅋㅋ _Create = false; // 이게 뭐여 ㅋㅋㅋ
} }
void Reset(void)
{
_Create = false;
_Moving = false;
_ClickPoint = CPoint();
_CirclePos = CRect();
}
void Create(CRect& rect/*offset*/, CPoint point) void Create(CRect& rect/*offset*/, CPoint point)
{ {
_Xoffset = -rect.left; _Xoffset = -rect.left;
@ -105,8 +114,9 @@ private:
return rect.PtInRect(point); return rect.PtInRect(point);
} }
void _Drwa(unsigned char *p, int nPitch) void _Drwa(unsigned char *p, int limx, int limy, int nPitch)
{ {
// 샘플 코드 참조
int nStartX = _ClickPoint.x - _nRadius; int nStartX = _ClickPoint.x - _nRadius;
int nStartY = _ClickPoint.y - _nRadius; int nStartY = _ClickPoint.y - _nRadius;
int nCenterX = _ClickPoint.x; int nCenterX = _ClickPoint.x;
@ -118,13 +128,16 @@ private:
{ {
// 픽셀단위로 원에 해당 여부를 판정 // 픽셀단위로 원에 해당 여부를 판정
if (isInCircle(i, j, nCenterX, nCenterY, _nRadius)) if (isInCircle(i, j, nCenterX, nCenterY, _nRadius))
p[(j * nPitch) + i] = 0x00; // memey validation
if (i>=0 && j>=0 && i<limx && j<limy)
p[(j * nPitch) + i] = 0x00;
} }
} }
} }
bool isInCircle(int i, int j, int nCenterX, int nCenterY, int nRadius) bool isInCircle(int i, int j, int nCenterX, int nCenterY, int nRadius)
{ {
// 샘플 코드 참조
bool bRet = false; bool bRet = false;
double dX = i - nCenterX; double dX = i - nCenterX;
@ -144,22 +157,37 @@ private:
_Circle *ActiveCircle = NULL; _Circle *ActiveCircle = NULL;
public: public:
afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg void OnMouseMove(UINT nFlags, CPoint point);
private:
int m_dRaius;
public:
afx_msg void OnEnChangeEditRadius();
private:
int m_dExternBorder;
CWinThread *m_pThread = NULL;
static UINT thread_fnc(LPVOID _lparam);
bool m_bThreadReady;
LRESULT USER_MESSAGE_FNC(WPARAM wparam, LPARAM lparam);
public:
afx_msg void OnEnChangeEditExternBorder();
afx_msg void OnBnClickedButtonReset();
afx_msg void OnBnClickedButtonRandom();
afx_msg void OnBnClickedButtonRandomThread();
}; };
// ToDo // ToDo
/* /*
- . - .
- 3 1 . //- 세 번째 클릭 이후에 클릭 지점 3개를 모두 지나가는 정원 1개를 그립니다.
- . //- 클릭 지점 원을 그릴 때의 반지름 크기는 사용자로부터 입력 받습니다.
- UI에 . //- 각 클릭 지점 원의 중심 좌표를 UI에 표시합니다.
- . //- 네 번째 클릭부터는 클릭 지점 원을 그리지 않습니다.
- , . //- 세 클릭 지점을 지나가는 정원의 내부는 채워지지 않아야 하며, 가장자리 두께는 사용자로부터 입력 받습니다.
- 3 . //- 클릭 지점 3개 중 하나를 클릭하고 드래그 했을 때 정원을 다시 그립니다.
- , , . //- 이 때, 마우스 커서 좌표가 바뀌는 동안 즉, 마우스 드래그 상태가 끝날 때 까지 정원이 계속해서 이동하며 그려져야 합니다.
- [] . //- [초기화] 버튼을 누르면 그려졌던 모든 내용들을 삭제하고 처음부터 입력 받을 수 있는 상태가 되어야 합니다.
- [ ] 3 . //- 정원이 그려진 상태에서[랜덤 이동] 버튼을 누르면 3개의 클릭 지점 원 모두를 랜덤한 위치로 이동시킵니다.
- , . //- 이 때, 정원 또한 마찬가지로 다시 그려져야 합니다.
- 2, 10 UI가 . //- 랜덤한 위치로 이동 및 정원 그리기 동작을 초당 2회, 총 10번 자동으로 반복하되 메인UI가 프리징 상태가 되지 않도록 별도 쓰레드로 구현해야 합니다.
- MFC Dialog . //- MFC Dialog 기반 프로젝트로 작성해야 합니다.
- CDC . ( ) //- 클릭 지점 원과 정원을 그릴 때 CDC 클래스를 사용하면 안됩니다. (안내한 유튜브 영상 참고)
*/ */

View File

@ -7,6 +7,14 @@
#define IDS_ABOUTBOX 101 #define IDS_ABOUTBOX 101
#define IDD_GLIMWORK_DIALOG 102 #define IDD_GLIMWORK_DIALOG 102
#define IDR_MAINFRAME 128 #define IDR_MAINFRAME 128
#define IDC_EDIT_RADIUS 1000
#define IDC_STATIC_POS_INFO 1001
#define IDC_STATIC_PIC 1002
#define IDC_EDIT_EXTERN_BORDER 1003
#define IDC_BUTTON_RESET 1004
#define IDC_BUTTON_RANDOM 1005
#define IDC_BUTTON_RANDOM2 1006
#define IDC_BUTTON_RANDOM_THREAD 1006
// Next default values for new objects // Next default values for new objects
// //
@ -14,7 +22,7 @@
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 130 #define _APS_NEXT_RESOURCE_VALUE 130
#define _APS_NEXT_COMMAND_VALUE 32771 #define _APS_NEXT_COMMAND_VALUE 32771
#define _APS_NEXT_CONTROL_VALUE 1000 #define _APS_NEXT_CONTROL_VALUE 1006
#define _APS_NEXT_SYMED_VALUE 101 #define _APS_NEXT_SYMED_VALUE 101
#endif #endif
#endif #endif