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>
<Keyword>MFCProj</Keyword>
<RootNamespace>GlimWork</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
@ -44,9 +44,9 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>Dynamic</UseOfMfc>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>

View File

@ -52,13 +52,18 @@ END_MESSAGE_MAP()
CGlimWorkDlg::CGlimWorkDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_GLIMWORK_DIALOG, pParent)
, m_dRaius(0)
, m_dExternBorder(0)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_bThreadReady = true;
}
void CGlimWorkDlg::DoDataExchange(CDataExchange* 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)
@ -68,6 +73,12 @@ BEGIN_MESSAGE_MAP(CGlimWorkDlg, CDialogEx)
ON_WM_LBUTTONUP()
ON_WM_LBUTTONDOWN()
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()
@ -105,10 +116,10 @@ BOOL CGlimWorkDlg::OnInitDialog()
// TODO: 여기에 추가 초기화 작업을 추가합니다.
CRect rect;
GetDlgItem(IDC_STATIC)->GetWindowRect(&rect);
GetDlgItem(IDC_STATIC_PIC)->GetWindowRect(&rect);
ScreenToClient(&rect);
m_Image.Create(rect.Width(), rect.Height(), 8);
m_Image.Create(rect.Width(), -rect.Height(), 8);
static RGBQUAD rgb[256];
for (int i = 0; i < 256; i++)
@ -118,10 +129,15 @@ BOOL CGlimWorkDlg::OnInitDialog()
unsigned char* fm = (unsigned char*)m_Image.GetBits();
// '(전체 줄 - 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());
// 컨트롤러 값 초기화 으떻게 하던거라?
m_dRaius = 20;
m_dExternBorder = 5;
UpdateData(false);
return TRUE; // 포커스를 컨트롤에 설정하지 않으면 TRUE를 반환합니다.
}
@ -164,11 +180,10 @@ void CGlimWorkDlg::OnPaint()
else
{
CRect rect;
GetDlgItem(IDC_STATIC)->GetWindowRect(&rect);
ScreenToClient(&rect);
GetDlgItem(IDC_STATIC_PIC)->GetClientRect(&rect);
CClientDC DC(this);
m_Image.Draw(DC, rect);
CClientDC DC(GetDlgItem(IDC_STATIC_PIC));
m_Image.Draw(DC, rect);
CDialogEx::OnPaint();
}
@ -181,13 +196,20 @@ HCURSOR CGlimWorkDlg::OnQueryDragIcon()
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)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
// UI 반응 범주
CRect rect;
GetDlgItem(IDC_STATIC)->GetWindowRect(&rect);
GetDlgItem(IDC_STATIC_PIC)->GetWindowRect(&rect);
ScreenToClient(&rect);
if (!rect.PtInRect(point))
@ -226,7 +248,7 @@ void CGlimWorkDlg::OnLButtonUp(UINT nFlags, CPoint point)
// UI 반응 범주
CRect rect;
GetDlgItem(IDC_STATIC)->GetWindowRect(&rect);
GetDlgItem(IDC_STATIC_PIC)->GetWindowRect(&rect);
ScreenToClient(&rect);
if (!rect.PtInRect(point))
@ -251,50 +273,69 @@ void CGlimWorkDlg::OnLButtonUp(UINT nFlags, CPoint point)
void CGlimWorkDlg::CirclePrc(void)
{
// TODO: 여기에 구현 코드 추가.
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());
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)
{
unsigned char* fm2 = (unsigned char*)m_Image.GetBits();
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 nStartX = _Center.x - distance;
int nStartY = _Center.y - distance;
int nCenterX = _Center.x;
int nCenterY = _Center.y;
// 큰거그리고 작은거 그리자
UpdateData(false);
int dExternD = distance + (m_dExternBorder / 2);
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))
fm2[(j * m_Image.GetPitch()) + i] = 0x00;
if (isInCircle(i, j, _Center.x, _Center.y, dExternD))
// 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();
// 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 bRet = false;
double dX = i - nCenterX;
@ -344,3 +385,126 @@ void CGlimWorkDlg::OnMouseMove(UINT nFlags, CPoint 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
#define USER_MESSAGE WM_USER + 0x01
// CGlimWorkDlg 대화 상자
class CGlimWorkDlg : public CDialogEx
@ -62,6 +63,14 @@ private:
_Create = false; // 이게 뭐여 ㅋㅋㅋ
}
void Reset(void)
{
_Create = false;
_Moving = false;
_ClickPoint = CPoint();
_CirclePos = CRect();
}
void Create(CRect& rect/*offset*/, CPoint point)
{
_Xoffset = -rect.left;
@ -105,8 +114,9 @@ private:
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 nStartY = _ClickPoint.y - _nRadius;
int nCenterX = _ClickPoint.x;
@ -118,13 +128,16 @@ private:
{
// 픽셀단위로 원에 해당 여부를 판정
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 bRet = false;
double dX = i - nCenterX;
@ -144,22 +157,37 @@ private:
_Circle *ActiveCircle = NULL;
public:
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
/*
- .
- 3 1 .
- .
- UI에 .
- .
- , .
- 3 .
- , , .
- [] .
- [ ] 3 .
- , .
- 2, 10 UI가 .
- MFC Dialog .
- CDC . ( )
//- 세 번째 클릭 이후에 클릭 지점 3개를 모두 지나가는 정원 1개를 그립니다.
//- 클릭 지점 원을 그릴 때의 반지름 크기는 사용자로부터 입력 받습니다.
//- 각 클릭 지점 원의 중심 좌표를 UI에 표시합니다.
//- 네 번째 클릭부터는 클릭 지점 원을 그리지 않습니다.
//- 세 클릭 지점을 지나가는 정원의 내부는 채워지지 않아야 하며, 가장자리 두께는 사용자로부터 입력 받습니다.
//- 클릭 지점 3개 중 하나를 클릭하고 드래그 했을 때 정원을 다시 그립니다.
//- 이 때, 마우스 커서 좌표가 바뀌는 동안 즉, 마우스 드래그 상태가 끝날 때 까지 정원이 계속해서 이동하며 그려져야 합니다.
//- [초기화] 버튼을 누르면 그려졌던 모든 내용들을 삭제하고 처음부터 입력 받을 수 있는 상태가 되어야 합니다.
//- 정원이 그려진 상태에서[랜덤 이동] 버튼을 누르면 3개의 클릭 지점 원 모두를 랜덤한 위치로 이동시킵니다.
//- 이 때, 정원 또한 마찬가지로 다시 그려져야 합니다.
//- 랜덤한 위치로 이동 및 정원 그리기 동작을 초당 2회, 총 10번 자동으로 반복하되 메인UI가 프리징 상태가 되지 않도록 별도 쓰레드로 구현해야 합니다.
//- MFC Dialog 기반 프로젝트로 작성해야 합니다.
//- 클릭 지점 원과 정원을 그릴 때 CDC 클래스를 사용하면 안됩니다. (안내한 유튜브 영상 참고)
*/

View File

@ -7,6 +7,14 @@
#define IDS_ABOUTBOX 101
#define IDD_GLIMWORK_DIALOG 102
#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
//
@ -14,7 +22,7 @@
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 130
#define _APS_NEXT_COMMAND_VALUE 32771
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_CONTROL_VALUE 1006
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif