[imgui] 8. WallClock 구현

[imgui] 8. WallClock 구현

2023년 7월 11일
imgui

목표 #

  • 아날로그 시계

WallClock

구현코드 #

github 링크

메인함수 #

 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}
comments powered by Disqus