cmake_minimum_required(VERSION 3.20)

# 使用传统计算机视觉读取仪表和表盘的主 C++ 项目。
project(instrument_reader_cpp VERSION 0.1.0 LANGUAGES CXX)

# C++17 已支持 filesystem，同时可保持代码兼容 Ubuntu 22.04。
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# OpenCV 是唯一的大型依赖，用于图像读写和基础视觉运算。
find_package(OpenCV REQUIRED)

# 演示目标使用的可选样例根目录，可通过 CMake、环境变量或仓库布局设置。
set(INSTRUMENT_READER_SAMPLE_ROOT "" CACHE PATH "Sample data root containing original_crops and generated_scales")
if(NOT INSTRUMENT_READER_SAMPLE_ROOT)
    if(DEFINED ENV{INSTRUMENT_READER_SAMPLE_ROOT})
        set(INSTRUMENT_READER_SAMPLE_ROOT "$ENV{INSTRUMENT_READER_SAMPLE_ROOT}" CACHE PATH "Sample data root containing original_crops and generated_scales" FORCE)
    elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../2/original_crops")
        set(INSTRUMENT_READER_SAMPLE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../2" CACHE PATH "Sample data root containing original_crops and generated_scales" FORCE)
    endif()
endif()

# CLI 工具和演示程序共用的核心库。
add_library(instrument_reader_core
    src/airspeed_reader.cpp
    src/dispatcher.cpp
    src/instrument_classifier.cpp
    src/lut_mapper.cpp
    src/non_linear_gauge_reader.cpp
    src/types.cpp
)

# 导出公共头文件，便于未来集成到 ROS 2 节点。
target_include_directories(instrument_reader_core
    PUBLIC
        ${CMAKE_CURRENT_SOURCE_DIR}/include
        ${OpenCV_INCLUDE_DIRS}
)

# 公共头文件暴露了 cv::Mat/cv::Point 类型，因此以传递方式链接 OpenCV。
target_link_libraries(instrument_reader_core
    PUBLIC
        ${OpenCV_LIBS}
)

# 启用严格警告，并为边缘设备吞吐量优化 Release 构建。
if(MSVC)
    target_compile_options(instrument_reader_core PRIVATE /EHsc /W4 $<$<CONFIG:Release>:/O2>)
else()
    target_compile_options(instrument_reader_core PRIVATE -Wall -Wextra -Wpedantic $<$<CONFIG:Release>:-O3>)
endif()

# 批量图像处理的主入口程序。
add_executable(instrument_reader_cli apps/instrument_reader_cli.cpp)
target_link_libraries(instrument_reader_cli PRIVATE instrument_reader_core)

add_executable(airspeed_lut_cli apps/airspeed_lut_cli.cpp)
target_link_libraries(airspeed_lut_cli PRIVATE instrument_reader_core)

# 通用非线性分段插值的独立演示程序。
add_executable(non_linear_gauge_demo apps/non_linear_gauge_demo.cpp)
target_link_libraries(non_linear_gauge_demo PRIVATE instrument_reader_core)

add_executable(clion_demo apps/clion_demo.cpp)
target_link_libraries(clion_demo PRIVATE instrument_reader_core)

# Windows 下从 CLion/Visual Studio 启动调试时，需要在 PATH 中加入 OpenCV DLL。
if(WIN32 AND OpenCV_DIR)
    get_filename_component(INSTRUMENT_READER_OPENCV_BIN "${OpenCV_DIR}/../bin" ABSOLUTE)
    set(INSTRUMENT_READER_RUN_ENV "PATH=${INSTRUMENT_READER_OPENCV_BIN};$ENV{PATH}")
    foreach(target_name instrument_reader_cli airspeed_lut_cli non_linear_gauge_demo clion_demo)
        set_target_properties(${target_name} PROPERTIES
            VS_DEBUGGER_ENVIRONMENT "${INSTRUMENT_READER_RUN_ENV}"
        )
    endforeach()
else()
    set(INSTRUMENT_READER_RUN_ENV "PATH=$ENV{PATH}")
endif()

# 运行目标在此根目录下创建 output/outputN 目录。
set(INSTRUMENT_READER_OUTPUT_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/output" CACHE PATH "Output root for CLion run targets")

if(INSTRUMENT_READER_SAMPLE_ROOT AND EXISTS "${INSTRUMENT_READER_SAMPLE_ROOT}/original_crops")
    # 空速表底图用于在指针检测时去除静态表盘标记。
    set(INSTRUMENT_READER_AIRSPEED_BASE "${INSTRUMENT_READER_SAMPLE_ROOT}/generated_scales/01_airspeed_indicator/_restored_base_no_pointer.png" CACHE FILEPATH "Airspeed no-pointer base/template image")

    # 完整演示会写出叠加图和 dispatch_results.json。
    add_custom_target(run_demo
        COMMAND ${CMAKE_COMMAND} -E make_directory "${INSTRUMENT_READER_OUTPUT_ROOT}"
        COMMAND ${CMAKE_COMMAND} -E env "${INSTRUMENT_READER_RUN_ENV}"
                $<TARGET_FILE:instrument_reader_cli>
                --input "${INSTRUMENT_READER_SAMPLE_ROOT}/original_crops"
                --input "${INSTRUMENT_READER_SAMPLE_ROOT}/generated_scales/01_airspeed_indicator"
                --airspeed-template "${INSTRUMENT_READER_AIRSPEED_BASE}"
                --airspeed-base "${INSTRUMENT_READER_AIRSPEED_BASE}"
                --airspeed-lut "${CMAKE_CURRENT_SOURCE_DIR}/configs/airspeed_lut_example.json"
                --out-dir "${INSTRUMENT_READER_OUTPUT_ROOT}"
        DEPENDS instrument_reader_cli
        VERBATIM
    )

    # 无叠加图目标用于将算法耗时与 PNG 写出耗时分离。
    add_custom_target(run_demo_no_overlay
        COMMAND ${CMAKE_COMMAND} -E make_directory "${INSTRUMENT_READER_OUTPUT_ROOT}"
        COMMAND ${CMAKE_COMMAND} -E env "${INSTRUMENT_READER_RUN_ENV}"
                $<TARGET_FILE:instrument_reader_cli>
                --input "${INSTRUMENT_READER_SAMPLE_ROOT}/original_crops"
                --input "${INSTRUMENT_READER_SAMPLE_ROOT}/generated_scales/01_airspeed_indicator"
                --airspeed-template "${INSTRUMENT_READER_AIRSPEED_BASE}"
                --airspeed-base "${INSTRUMENT_READER_AIRSPEED_BASE}"
                --airspeed-lut "${CMAKE_CURRENT_SOURCE_DIR}/configs/airspeed_lut_example.json"
                --out-dir "${INSTRUMENT_READER_OUTPUT_ROOT}"
                --no-overlays
        DEPENDS instrument_reader_cli
        VERBATIM
    )
endif()

# 用于验证角度到物理值转换的 LUT 冒烟测试目标。
add_custom_target(run_lut_example
    COMMAND ${CMAKE_COMMAND} -E env "${INSTRUMENT_READER_RUN_ENV}"
            $<TARGET_FILE:airspeed_lut_cli>
            --map "${CMAKE_CURRENT_SOURCE_DIR}/configs/airspeed_lut_example.json"
            --theta 4.5
    DEPENDS airspeed_lut_cli
    VERBATIM
)

# 小型合成非线性插值可视化的演示目标。
add_custom_target(run_non_linear_gauge_demo
    COMMAND ${CMAKE_COMMAND} -E make_directory "${INSTRUMENT_READER_OUTPUT_ROOT}"
    COMMAND ${CMAKE_COMMAND} -E env "${INSTRUMENT_READER_RUN_ENV}"
            $<TARGET_FILE:non_linear_gauge_demo>
    DEPENDS non_linear_gauge_demo
    WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
    VERBATIM
)

# 安装库和可执行工具，供外部项目使用。
install(TARGETS instrument_reader_core instrument_reader_cli airspeed_lut_cli non_linear_gauge_demo
    RUNTIME DESTINATION bin
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib
)

# 将公共头文件安装到标准 include 目录树。
install(DIRECTORY include/ DESTINATION include)
