Skip to content

Commit

Permalink
Add examples/histogram (#1)
Browse files Browse the repository at this point in the history
* Add examples/histogram

* Add build CI.

* Fix tests, update CMake presets.

* Fix non-constexpr function.
  • Loading branch information
karnkaul authored Sep 23, 2023
1 parent f7221dc commit 9bf2a15
Show file tree
Hide file tree
Showing 9 changed files with 200 additions and 23 deletions.
29 changes: 29 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: ci
on: [push]
jobs:
build-linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: init
run: sudo apt update -yqq && sudo apt install -yqq ninja-build g++-13 clang-15
- name: configure gcc
run: cmake -S . --preset=default -B build -DCMAKE_CXX_COMPILER=g++-13
- name: configure clang
run: cmake -S . --preset=ninja-clang -B clang -DCMAKE_CXX_COMPILER=clang++-15
- name: build gcc
run: cmake --build build --config=Release
- name: build clang
run: cmake --build clang --config=Release
- name: test
run: cd build && ctest -C Release
build-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: configure
run: cmake -S . --preset=vs22 -B build
- name: build
run: cmake --build build --config=Release
- name: test
run: cd build && ctest -C Release
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
endif()

option(NOIZ_BUILD_TESTS "Build noiz tests" ${is_project_root})
option(NOIZ_BUILD_EXAMPLES "Build noiz examples" ${is_project_root})

add_library(noiz-compile-options INTERFACE)
add_library(noiz::noiz-compile-options ALIAS noiz-compile-options)
Expand All @@ -29,6 +30,10 @@ endif()

add_subdirectory(noiz)

if(NOIZ_BUILD_EXAMPLES)
add_subdirectory(examples)
endif()

if(NOIZ_BUILD_TESTS)
enable_testing()
add_subdirectory(tests)
Expand Down
44 changes: 25 additions & 19 deletions CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
},
{
"name": "ninja-asan",
"description": "ASan build configuration using Ninja Multi-config",
"inherits": "ninja-ubsan",
"binaryDir": "${sourceDir}/out/asan",
"cacheVariables": {
Expand All @@ -45,36 +46,21 @@
{
"name": "ninja-tsan",
"inherits": "ninja-ubsan",
"description": "TSan build configuration using Ninja Multi-config",
"binaryDir": "${sourceDir}/out/tsan",
"cacheVariables": {
"CMAKE_CXX_FLAGS": "-fsanitize=thread -O1"
}
},
{
"name": "vs19",
"description": "Build configuration using Visual Studio 16 (2019)",
"generator": "Visual Studio 16 2019",
"name": "vs22",
"description": "Build configuration using Visual Studio 17 (2022)",
"generator": "Visual Studio 17 2022",
"binaryDir": "${sourceDir}/out/vs",
"architecture": {
"value": "x64",
"strategy": "external"
}
},
{
"name": "vs22",
"description": "Build configuration using Visual Studio 17 (2022)",
"inherits": "vs19",
"generator": "Visual Studio 17 2022"
},
{
"name": "pre-install",
"description": "Debug build using Ninja Multi-config and install prefix",
"inherits": "default",
"binaryDir": "${sourceDir}/out/pre",
"cacheVariables": {
"CMAKE_PREFIX_PATH": "${sourceDir}/out/install",
"RR_PREINSTALLED": "ON"
}
}
],
"buildPresets": [
Expand All @@ -92,6 +78,16 @@
"name": "RelWithDebInfo",
"configurePreset": "default",
"configuration": "RelWithDebInfo"
},
{
"name": "UBSan-Debug",
"configurePreset": "ninja-ubsan",
"configuration": "Debug"
},
{
"name": "ASan-Debug",
"configurePreset": "ninja-asan",
"configuration": "Debug"
}
],
"testPresets": [
Expand All @@ -109,6 +105,16 @@
"name": "RelWithDebInfo",
"configurePreset": "default",
"configuration": "RelWithDebInfo"
},
{
"name": "UBSan Debug",
"configurePreset": "ninja-ubsan",
"configuration": "Debug"
},
{
"name": "ASan Debug",
"configurePreset": "ninja-asan",
"configuration": "Debug"
}
]
}
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_subdirectory(histogram)
12 changes: 12 additions & 0 deletions examples/histogram/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
project(noiz-histogram)

add_executable(${PROJECT_NAME})

target_link_libraries(${PROJECT_NAME} PRIVATE
noiz::noiz-lib
noiz::noiz-compile-options
)

target_sources(${PROJECT_NAME} PRIVATE
histogram.cpp
)
126 changes: 126 additions & 0 deletions examples/histogram/histogram.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#include <noiz/noise2.hpp>
#include <charconv>
#include <filesystem>
#include <format>
#include <iostream>
#include <vector>

namespace {
template <typename Type>
concept NumberT = std::integral<Type> || std::floating_point<Type>;

template <NumberT Type>
auto parse_as(Type& out, std::string_view const value) -> bool {
if (value.empty()) { return false; }

auto const* end = value.data() + value.size();
auto const [ptr, ec] = std::from_chars(value.data(), end, out);

return ec == std::errc{} && ptr == end;
}

struct Args {
std::span<char const* const> args{};

[[nodiscard]] constexpr auto next() -> std::string_view {
if (args.empty()) { return {}; }
auto const* ret = args.front();
args = args.subspan(1);
return ret;
}

template <NumberT Type>
auto next_as(Type& out, std::string_view const key) -> bool {
auto value = next();
if (value.empty()) { return true; }

if (!parse_as(out, value)) {
std::cerr << std::format("invalid argument: '{}' for '{}'\n", value, key);
return false;
}

return true;
}
};

struct Config {
noiz::Seed seed{noiz::detail::Generator::make_random_seed()};
noiz::GridExtent2 grid_extent{50, 1}; // NOLINT
int count{100}; // NOLINT
float step{0.1f}; // NOLINT

// syntax: [count] [step]
auto parse_args(Args args) -> bool {
if (!args.next_as(count, "count")) { return false; }
if (!args.next_as(step, "step")) { return false; }
if (!args.args.empty()) {
std::cerr << std::format("unrecognized argument: '{}'\n", args.next());
return false;
}
return true;
}
};

// contains logic to store data points and draw them
class Histogram {
public:
explicit Histogram(std::size_t const levels = 10) : rows(levels) {}

auto add(float const value) -> Histogram& {
// compute height relative to number of rows/levels
auto const height = static_cast<std::size_t>((value + 1.0f) * 0.5f * static_cast<float>(rows.size()));
// add a new column
for (std::size_t index = 0; index < rows.size(); ++index) {
// set output "pixel" value (0 or 1)
auto const ch = index > height ? symbol : background;
// append to each row
rows.at(index) += ch;
}
return *this;
}

[[nodiscard]] auto build() const -> std::string {
auto ret = std::string{};
for (auto const& row : rows) {
ret += row;
ret += '\n';
}
return ret;
}

char symbol{'x'};
char background{'-'};

private:
std::vector<std::string> rows{};
};
} // namespace

auto main(int argc, char** argv) -> int {
auto config = Config{};
auto noise = noiz::Noise2f{noiz::Seed{config.seed}, config.grid_extent};

// skip exe name (argv[0])
auto const args = Args{std::span{argv, static_cast<std::size_t>(argc)}.subspan(1)};

// handle --help
if (!args.args.empty() && args.args.front() == std::string_view{"--help"}) {
std::cout << std::format("Usage: {} [count(=100)] [step(=0.1)]\n", std::filesystem::path{*argv}.stem().string());
return EXIT_SUCCESS;
}

// parse args, if any
if (!config.parse_args(args)) { return EXIT_FAILURE; }

// build histogram
auto histogram = Histogram{};
for (int i = 0; i < config.count; ++i) {
// build point on line (y = 0)
auto const point = noiz::Vec2f{.x = static_cast<float>(i) * config.step};
// add noise at point
histogram.add(noise.at(point));
}

// output histogram
std::cout << histogram.build();
}
2 changes: 1 addition & 1 deletion noiz/include/noiz/vec2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ struct Vec2 {
return ret;
}

[[nodiscard]] constexpr auto is_normalized() const -> bool { return std::abs(sqr_magnitude() - Type(1)) < epsilon_v; }
[[nodiscard]] auto is_normalized() const -> bool { return std::abs(sqr_magnitude() - Type(1)) < epsilon_v; }

[[nodiscard]] auto modulo(Vec2<Type> const extent) const -> Vec2<Type> {
assert(extent.x > Type(0) && extent.y > Type(0));
Expand Down
2 changes: 1 addition & 1 deletion tests/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ file(GLOB SOURCES CONFIGURE_DEPENDS "*.cpp")
target_sources(${PROJECT_NAME} PRIVATE ${SOURCES})
target_link_libraries(${PROJECT_NAME} PRIVATE noiz-test)

add_test(NAME noiz-test-${NAME} COMMAND noiz-test-${NAME})
add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME})
2 changes: 0 additions & 2 deletions tests/tests/test_vec2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ static_assert(noiz::Vec2f{4.0f, 9.0f} / noiz::Vec2f{2.0f, 3.0f} == noiz::Vec2f{2
static_assert(noiz::dot(noiz::Vec2f{2.0f, 3.0f}, noiz::Vec2f{4.0f, 5.0f}) == 23.0f); // NOLINT
static_assert(noiz::Vec2f{2.0f, 3.0f}.sqr_magnitude() == 13.0f); // NOLINT

static_assert(noiz::Vec2f{1.0f, 0.0f}.is_normalized());

ADD_TEST(vec2_magnitude) {
auto const vec = noiz::Vec2f{3.0f, 4.0f}; // NOLINT
EXPECT(vec.magnitude() == 5.0f); // NOLINT
Expand Down

0 comments on commit 9bf2a15

Please sign in to comment.