[imgui] 8. WallClock 구현
2023년 7월 11일
목표 #
- 아날로그 시계

구현코드 #
메인함수 #
1class WindowClass
2{
3private:
4 static constexpr auto PI = std::numbers::pi_v<float>;
5 static constexpr auto circleRadius = 250.0f;
6 static constexpr auto offset = PI / 2.0f;
7 static constexpr auto innerRadius = 5.0f;
8
9 // 시계의 시,분,초침 길이
10 static constexpr auto hrsClockHandLength = 0.75F;
11 static constexpr auto minsClockHandLength = 0.85F;
12 static constexpr auto secsClockHandLength = 0.95F;
13
14 // 시계의 한칸을 나타내는 선 길이
15 static constexpr auto hrsStrokesLength = 0.90f;
16 static constexpr auto minsStrokesLength = 0.95f;
17
18public:
19 WindowClass() : secs(0), mins(0), hrs(0), center({}){};
20 void Draw(std::string_view label);
21
22private:
23 void DrawCircle(const float radius); // 시계 테두리 그리는함수
24 void DrawClockHand(const float radius, // 바늘 그리는 함수
25 const float theta,
26 const ImColor color);
27 void DrawAllHourStrokes(); // 시단위 한칸 표시
28 void DrawAllMinuteStrokes(); // 분단위 한칸 표시
29 void DrawDigitalClock(); // 디버깅용 디지털시계
30
31 void GetTime(); // 현재시간 멤버에 업데이트
32 std::tuple<float, float, float> GetTheta(); // 각도얻어오기
33
34public:
35 std::int32_t secs;
36 std::int32_t mins;
37 std::int32_t hrs;
38
39private:
40 ImVec2 center;
41};
1void WindowClass::Draw(std::string_view label)
2{
3 constexpr static auto window_flags =
4 ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
5 ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar;
6 constexpr static auto window_size = ImVec2(1280.0F, 720.0F);
7 constexpr static auto window_pos = ImVec2(0.0F, 0.0F);
8
9 ImGui::SetNextWindowSize(window_size);
10 ImGui::SetNextWindowPos(window_pos);
11
12 ImGui::Begin(label.data(), nullptr, window_flags);
13
14 // 시계의 center 위치 업데이트
15 const auto cursor_pos = ImGui::GetCursorScreenPos();
16 center = ImVec2(cursor_pos.x + circleRadius, cursor_pos.y + circleRadius);
17
18 DrawCircle(circleRadius);
19
20 GetTime();
21 const auto [hour_theta, minute_theta, second_theta] = GetTheta();
22
23 DrawClockHand(circleRadius * hrsClockHandLength,
24 hour_theta,
25 ImColor(1.0F, 0.5F, 0.5F, 1.0F));
26 DrawClockHand(circleRadius * minsClockHandLength,
27 minute_theta,
28 ImColor(0.5F, 1.0F, 0.5F, 1.0F));
29 DrawClockHand(circleRadius * secsClockHandLength,
30 second_theta,
31 ImColor(0.5F, 0.5F, 1.0F, 1.0F));
32
33 DrawAllHourStrokes();
34 DrawAllMinuteStrokes();
35
36 DrawCircle(innerRadius);
37
38 DrawDigitalClock();
39
40 ImGui::End();
41}
DrawCircle #
1void WindowClass::DrawCircle(const float radius)
2{
3 // DrawList에 원 그리기 추가.
4 // 3번째 인자: 색상 지정. 현재 ImGui의 텍스트 컬러와 동일한색 지정
5 // 4번째 인자: 선분 몇개로 원을 그릴건지 지정 0은 무한대, 1~3까지는 삼각형 고정
6 ImGui::GetWindowDrawList()->AddCircle(center,
7 radius,
8 ImGui::GetColorU32(ImGuiCol_Text),
9 100,
10 2.0f);
11}
GetTime #
1void WindowClass::GetTime()
2{
3 // 현재시간 가져오기. time_point 타입
4 const auto timestamp_now = std::chrono::system_clock::now();
5 // time_t 로 변경
6 const auto time_now = std::chrono::system_clock::to_time_t(timestamp_now);
7 // time_t 타입을 tm 구조체에 집어넣음
8 const auto time_struct = std::localtime(&time_now);
9
10 // tm 구조체에서 시간 분 초만 꺼내온다.
11 secs = time_struct->tm_sec;
12 mins = time_struct->tm_min;
13 hrs = time_struct->tm_hour;
14}
GetTheta #
시, 분, 초침들의 각도를 계산하는 함수
1std::tuple<float, float, float> WindowClass::GetTheta()
2{
3 // 초침은 그대로 가지고있어도 되지만,
4 // 분침은 초침이 움직인만큼 추가로 더 움직여야함
5 // 10분 0초의 분침 != 10분 30초의 분침
6 const auto seconds_frac = static_cast<float>(secs);
7 const auto minutes_frac = static_cast<float>(mins) + seconds_frac / 60.0f;
8 const auto hours_frac = static_cast<float>(hrs) + minutes_frac / 60.0f;
9
10 // 2PI가 360이니까 12로 나눠서 시침의 theta를 구한다.
11 // 9시 방향에서 시작하기 때문에 offset 90도를 더해서 12시부터 시작되게 한다.
12 const auto hour_theta = (hours_frac * ((2.0f * PI) / 12.0f)) + offset;
13 const auto minute_theta = (minutes_frac * ((2.0f * PI) / 60.0f)) + offset;
14 const auto second_theta = (seconds_frac * ((2.0f * PI) / 60.0f)) + offset;
15
16 return std::make_tuple(hour_theta, minute_theta, second_theta);
17}
DrawClockHand #
시, 분, 초 침을 그린다.
(시작지점 center부터 end_point 까지 잇는 선분)
1void WindowClass::DrawClockHand(const float radius,
2 const float theta,
3 const ImColor color)
4{
5 const auto c = std::cos(theta); // r이 1일때 x 좌표
6 const auto s = std::sin(theta); // r이 1일때 y 좌표
7
8 // 정규화된 x, y 좌표에 r을 곱한 마이너스 값을 찾는다
9 // 마이너스값인 이유는 y축이
10 const auto end_point = ImVec2(center.x - radius * c, center.y - radius * s);
11
12 ImGui::GetWindowDrawList()->AddLine(center, end_point, color, 3.0f);
13}
DrawAllHourStrokes #
12개의 시 눈금을 그린다. 위에서 했던 시침 그리는것과 같음
1void WindowClass::DrawAllHourStrokes()
2{
3 for (std::uint32_t hr = 0; hr < 12; ++hr)
4 {
5 const auto theta = (hr * ((2.0f * PI) / 12.0f)) + offset;
6 const auto c = std::cos(theta);
7 const auto s = std::sin(theta);
8
9 const auto start_point =
10 ImVec2(center.x + (circleRadius * hrsStrokesLength) * c,
11 center.y + (circleRadius * hrsStrokesLength) * s);
12
13 const auto end_point =
14 ImVec2(center.x + circleRadius * c,
15 center.y + circleRadius * s);
16
17 ImGui::GetWindowDrawList()->AddLine(start_point,
18 end_point,
19 ImGui::GetColorU32(ImGuiCol_Text),
20 3.0f);
21 }
22}