Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
26ed66a
new vec tests pass
thinks Oct 21, 2024
f7a5786
clang-format
thinks Oct 21, 2024
2e8e124
refactor vec test
thinks Oct 21, 2024
b1d769e
c style comments
thinks Oct 21, 2024
1e5ae3e
code cov
thinks Oct 22, 2024
77dfc28
code cov
thinks Oct 22, 2024
bb60460
clang-format
thinks Oct 22, 2024
c16ac90
code cov
thinks Oct 22, 2024
fa878d8
code cov
thinks Oct 22, 2024
13085dc
lint
thinks Oct 22, 2024
47ebf69
code cov
thinks Oct 22, 2024
038a35c
lint
thinks Oct 22, 2024
a091629
newline
thinks Oct 22, 2024
96a7fb7
code cov
thinks Oct 22, 2024
7d6941d
use tph_poisson_vec in vec_test
thinks Oct 22, 2024
7c1cd1e
tidy vec_test
thinks Oct 25, 2024
078daf8
alloc_test
thinks Oct 25, 2024
7ced23c
clang-format
thinks Oct 25, 2024
ab54988
code cov
thinks Oct 25, 2024
bacea00
code cov
thinks Oct 25, 2024
b564202
code cov
thinks Oct 25, 2024
8c30220
alloc test
thinks Oct 26, 2024
ef4bfe7
alloc test
thinks Oct 26, 2024
214aa8f
Merge branch 'master' into code-coverage
thinks Oct 26, 2024
c39b187
clang-format
thinks Oct 26, 2024
9ad3874
clang-tidy
thinks Oct 26, 2024
24181f6
ci
thinks Oct 26, 2024
1e914c1
CI
thinks Oct 26, 2024
ebf0734
cppcheck
thinks Oct 26, 2024
f545344
ci
thinks Oct 26, 2024
4665e8d
CI
thinks Oct 26, 2024
3c8d741
CI
thinks Oct 26, 2024
8370f4a
alloc test
thinks Oct 26, 2024
7dc0446
lint
thinks Oct 26, 2024
7ebe90d
ci
thinks Oct 26, 2024
6b5530c
ci
thinks Oct 28, 2024
d7e95e1
clang-tidy
thinks Oct 28, 2024
58a4dab
clang-format
thinks Oct 28, 2024
e0aec93
clang-tidy
thinks Oct 28, 2024
8adfd0e
clang-tidy
thinks Oct 28, 2024
f5c8b00
clang-tidy
thinks Oct 28, 2024
8cca2cc
clang-tidy
thinks Oct 28, 2024
40608a6
custom_malloc example
thinks Oct 28, 2024
2c64e84
custom_malloc
thinks Oct 28, 2024
be3ead1
libc_test
thinks Oct 29, 2024
82deb0f
docs
thinks Nov 6, 2024
86403df
fftw
thinks Nov 6, 2024
9ac3623
lint
thinks Nov 6, 2024
ca78570
fftw
thinks Nov 8, 2024
a70714d
fftw
thinks Nov 8, 2024
7a6277f
fftw
thinks Nov 8, 2024
61b516c
fftw
thinks Nov 8, 2024
afb55fc
fftw
thinks Nov 8, 2024
b43e772
nothings_stb
thinks Nov 8, 2024
d984654
periodogram
thinks Nov 8, 2024
e2ecff4
CI
thinks Nov 8, 2024
4079580
update examples
thinks Nov 10, 2024
1ded464
CI
thinks Nov 10, 2024
e2b2057
CI
thinks Nov 10, 2024
3e94a29
custom alloc example
thinks Nov 10, 2024
117ab27
periodogram example
thinks Nov 12, 2024
a943ce5
docs
thinks Nov 12, 2024
66293f2
docs
thinks Nov 13, 2024
00092c7
docs
thinks Nov 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .clang-tidy
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
---
# Enable ALL the things! Except not really
# Enable ALL the things! Except not really.
#
# NOTE(thinks):
# Sadly, clang-analyzer-unix.Malloc gives false positives when using our
# custom allocators.
Checks: "-*,\
-google-readability-todo,\
clang-analyzer-*,\
-clang-analyzer-unix.Malloc,\
-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,\
cert-*,\
bugprone-*,\
Expand All @@ -16,7 +21,7 @@ Checks: "-*,\
-readability-magic-numbers,\
-readability-identifier-length,\
-readability-function-cognitive-complexity"
WarningsAsErrors: ''
WarningsAsErrors: '*'
CheckOptions:
- key: 'bugprone-argument-comment.StrictMode'
value: 'true'
Expand Down
85 changes: 53 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Standard](https://img.shields.io/badge/c-11-blue.svg)](https://en.wikipedia.org/wiki/C11_(C_standard_revision))
[![Standard](https://img.shields.io/badge/c%2B%2B-17-blue.svg)](https://en.wikipedia.org/wiki/C%2B%2B17)

![CI](https://github.com/thinks/poisson-disk-sampling/actions/workflows/ci.yml/badge.svg?branch=master)
[![codecov](https://codecov.io/github/thinks/poisson-disk-sampling/graph/badge.svg?token=NXIAKWPKAB)](https://codecov.io/github/thinks/poisson-disk-sampling)

Expand All @@ -11,7 +12,7 @@ This repository contains a [single file](include/thinks/tph_poisson.h), header-o

## Usage

Poisson disk sampling aims to generate a set of samples within a bounded region such that no two samples are closer than some user-specified radius to each other. Let's consider a simple [example](examples(simple_c.c)) written in C.
Poisson disk sampling aims to generate a set of points within a bounded region such that no two points are closer than some user-specified radius to each other. Let's consider a simple [example](examples/simple.c) written in C.

```C
/* C11 */
Expand All @@ -26,51 +27,62 @@ Poisson disk sampling aims to generate a set of samples within a bounded region
#define TPH_POISSON_IMPLEMENTATION
#include "thinks/tph_poisson.h"

static_assert(sizeof(tph_poisson_real) == sizeof(float), "");

int main(int argc, char *argv[])
{
(void)argc;
(void)argv;

/* Configure arguments. */
const tph_poisson_real bounds_min[2] = {
(tph_poisson_real)-10,
(tph_poisson_real)-10 };
(tph_poisson_real)-10, (tph_poisson_real)-10 };
const tph_poisson_real bounds_max[2] = {
(tph_poisson_real)10,
(tph_poisson_real)10 };
(tph_poisson_real)10, (tph_poisson_real)10 };

/* Configure arguments. */
const tph_poisson_args args = {
.bounds_min = bounds_min,
.bounds_max = bounds_max,
.radius = (tph_poisson_real)3,
.ndims = INT32_C(2),
.max_sample_attempts = UINT32_C(30),
.seed = UINT64_C(1981) };

/* Using default allocator (libc malloc). */
const tph_poisson_allocator *alloc = NULL;

/* Create samples. */
/* Initialize empty sampling. */
tph_poisson_sampling sampling;
memset(&sampling, 0, sizeof(tph_poisson_sampling));

/* Populate sampling with points. */
const int ret = tph_poisson_create(&args, alloc, &sampling);
if (ret != TPH_POISSON_SUCCESS) {
/* No need to destroy sampling here! */
printf("tph_poisson error, code: %d\n", ret);
printf("Failed creating Poisson sampling! Error code: %d\n", ret);
return EXIT_FAILURE;
}

/* Retrieve samples. */
/* Retrieve sampling points. */
const tph_poisson_real *samples = tph_poisson_get_samples(&sampling);
assert(samples != NULL);
if (samples == NULL) {
/* Shouldn't happen since we check the return value from tph_poisson_create! */
printf("Bad samples!\n");
tph_poisson_destroy(&sampling);
return EXIT_FAILURE;
}

/* Print first and last sample positions. */
printf("\nsimple_c:\n");
printf("samples[%td] = ( %.3f, %.3f )\n",
assert(sampling.nsamples >= 2);
printf("\n%s:\n"
"samples[%td] = ( %.3f, %.3f )\n"
"...\n"
"samples[%td] = ( %.3f, %.3f )\n\n",
"simple (C)",
(ptrdiff_t)0,
(double)samples[0],
(double)samples[1]);
printf("...\n");
printf("samples[%td] = ( %.3f, %.3f )\n\n",
sampling.nsamples - 1,
(double)samples[1],
(ptrdiff_t)(sampling.nsamples - 1),
(double)samples[(sampling.nsamples - 1) * sampling.ndims],
(double)samples[(sampling.nsamples - 1) * sampling.ndims + 1]);

Expand All @@ -81,7 +93,7 @@ int main(int argc, char *argv[])
}
```

When using C++ it is possible to safely manage the memory allocated by the tph_poisson functions, as illustrated below:
When using C++ it is possible to safely manage the memory allocated by the tph_poisson functions ([example](examples/simple.cpp)), as illustrated below:

```C++
// C++17
Expand All @@ -96,14 +108,14 @@ When using C++ it is possible to safely manage the memory allocated by the tph_p
#define TPH_POISSON_IMPLEMENTATION
#include "thinks/tph_poisson.h"

static_assert(std::is_same_v<tph_poisson_real, float>);

int main(int /*argc*/, char * /*argv*/[])
{
constexpr std::array<tph_poisson_real, 2> bounds_min{
static_cast<tph_poisson_real>(-10),
static_cast<tph_poisson_real>(-10) };
static_cast<tph_poisson_real>(-10), static_cast<tph_poisson_real>(-10) };
constexpr std::array<tph_poisson_real, 2> bounds_max{
static_cast<tph_poisson_real>(10),
static_cast<tph_poisson_real>(10) };
static_cast<tph_poisson_real>(10), static_cast<tph_poisson_real>(10) };

// Configure arguments.
tph_poisson_args args = {};
Expand All @@ -113,35 +125,44 @@ int main(int /*argc*/, char * /*argv*/[])
args.bounds_max = bounds_max.data();
args.max_sample_attempts = UINT32_C(30);
args.seed = UINT64_C(1981);

// Using default allocator (libc malloc).
const tph_poisson_allocator *alloc = NULL;

// Create samples.
// Initialize empty sampling.
using unique_poisson_ptr =
std::unique_ptr<tph_poisson_sampling, std::function<void(tph_poisson_sampling *)>>;
auto sampling = unique_poisson_ptr{ new tph_poisson_sampling{}, [](tph_poisson_sampling *s) {
tph_poisson_destroy(s);
delete s;
} };

// Populate sampling with points.
if (const int ret = tph_poisson_create(&args, alloc, sampling.get());
ret != TPH_POISSON_SUCCESS) {
std::printf("tph_poisson error, code: %d\n", ret);
return EXIT_FAILURE;
};

// Retrieve samples.
// Retrieve sampling points.
const tph_poisson_real *samples = tph_poisson_get_samples(sampling.get());
assert(samples != nullptr);
if (samples == nullptr) {
/* Shouldn't happen since we check the return value from tph_poisson_create! */
std::printf("Bad samples!\n");
return EXIT_FAILURE;
}

// Print first and last sample positions.
std::printf("\nsimple_cpp:\n");
std::printf("sample[%td] = ( %.3f, %.3f )\n",
assert(sampling->nsamples >= 2);
std::printf("\n%s:\n"
"samples[%td] = ( %.3f, %.3f )\n"
"...\n"
"samples[%td] = ( %.3f, %.3f )\n\n",
"simple (Cpp)",
(ptrdiff_t)0,
(double)samples[0],
(double)samples[1]);
std::printf("...\n");
std::printf("sample[%td] = ( %.3f, %.3f )\n\n",
sampling->nsamples - 1,
(double)samples[1],
(ptrdiff_t)(sampling->nsamples - 1),
(double)samples[(sampling->nsamples - 1) * sampling->ndims],
(double)samples[(sampling->nsamples - 1) * sampling->ndims + 1]);

Expand All @@ -163,9 +184,9 @@ Besides radius and bounds, there are two additional arguments: `seed` and `max_s

Poisson disk sampling generates samples from a blue noise distribution. We can verify this by plotting the corresponding periodogram, noticing that there are minimal low frequency components (close to the center) and no concentrated spikes in energy.

The image below was generated using the code in one of the provided [examples](https://github.com/thinks/poisson-disk-sampling/blob/master/thinks/poisson_disk_sampling/examples/periodogram_example.cc) and is an average over 100 sampling patterns (original pixel resolution was 2048x2048).
The image below was generated using the provided [periodogram example](examples/periodogram_example.cc) and is an average over 100 sampling patterns (original pixel resolution was 2048x2048).

![Average periodogram](images/avg_periodogram_512.png "Average periodogram")
![Average periodogram](images/tph_poisson_periodogram_512.png "Average periodogram")

# Building and installing

Expand Down
8 changes: 4 additions & 4 deletions cmake/dev-mode.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ if(BUILD_TESTING)
add_subdirectory(test)
endif()

option(BUILD_MCSS_DOCS "Build documentation using Doxygen and m.css" OFF)
if(BUILD_MCSS_DOCS)
include(cmake/docs.cmake)
endif()
# option(BUILD_MCSS_DOCS "Build documentation using Doxygen and m.css" OFF)
# if(BUILD_MCSS_DOCS)
# include(cmake/docs.cmake)
# endif()

option(ENABLE_COVERAGE "Enable coverage support separate from CTest's" OFF)
if(ENABLE_COVERAGE)
Expand Down
136 changes: 136 additions & 0 deletions cmake/fetch-fftw.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
# ---- Fetch and install FFTW ----

cmake_policy(PUSH)

if(POLICY CMP0169)
# Allow calling FetchContent_Populate directly.
cmake_policy(SET CMP0169 OLD)
endif()
if(POLICY CMP0135)
# Set the timestamps of extracted contents to the time of extraction.
cmake_policy(SET CMP0135 NEW)
endif()

include(FetchContent)

function(fetch_fftw)
set(options)
set(oneValueArgs VERSION)
set(multiValueArgs)
cmake_parse_arguments(args
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)

FetchContent_Declare(fftw
URL "http://fftw.org/fftw-${args_VERSION}.tar.gz"
)

FetchContent_GetProperties(fftw)
if(NOT fftw_POPULATED)
FetchContent_Populate(fftw)

set(fftw_CACHE_ARGS
"-DCMAKE_INSTALL_PREFIX=${fftw_BINARY_DIR}/install"
"-DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON" # PIC

"-DBUILD_SHARED_LIBS:BOOL=OFF" # static libs
"-DBUILD_TESTS:BOOL=OFF" # no tests

"-DENABLE_THREADS:BOOL=ON" # Use pthread
"-DWITH_COMBINED_THREADS:BOOL=ON" # Don't need to link in fftw3f_threads

# "-DENABLE_FLOAT:BOOL=ON" # <float>

# Use SSE, but not AVX.
"-DENABLE_SSE:BOOL=ON"
"-DENABLE_SSE2:BOOL=ON"
"-DENABLE_AVX:BOOL=OFF"
"-DENABLE_AVX2:BOOL=OFF"

"-DDISABLE_FORTRAN:BOOL=ON"
)

if(CMAKE_TOOLCHAIN_FILE)
list(APPEND fftw_CACHE_ARGS
"-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${CMAKE_TOOLCHAIN_FILE}"
)
else()
list(APPEND fftw_CACHE_ARGS
"-DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER}"
)
endif()

get_property(isMulti GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(NOT isMulti)
list(APPEND fftw_CACHE_ARGS "-DCMAKE_BUILD_TYPE:STRING=Release")
endif()
unset(isMulti)

set(fftw_GENERATOR_ARGS "")
if(CMAKE_GENERATOR_PLATFORM)
list(APPEND fftw_GENERATOR_ARGS
--build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
)
endif()
if(CMAKE_GENERATOR_TOOLSET)
list(APPEND fftw_GENERATOR_ARGS
--build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
)
endif()

message(STATUS "Configuring and building FFTW-${args_VERSION} immediately")
if (MSVC)
set(generator "Visual Studio 17 2022")
else()
set(generator "Unix Makefiles")
endif()

execute_process(
COMMAND ${CMAKE_CTEST_COMMAND}
--build-and-test ${fftw_SOURCE_DIR} ${fftw_BINARY_DIR}
--build-generator ${generator} ${fftw_GENERATOR_ARGS}
--build-target install
--build-noclean
--build-options ${fftw_CACHE_ARGS}
WORKING_DIRECTORY ${fftw_SOURCE_DIR}
OUTPUT_FILE ${fftw_BINARY_DIR}/build_output.log
ERROR_FILE ${fftw_BINARY_DIR}/build_output.log
RESULT_VARIABLE result
)

unset(generator)

if(result)
file(READ ${fftw_BINARY_DIR}/build_output.log build_log)
message(FATAL_ERROR "Result = ${result}\nFailed FFTW-${args_VERSION} build, see build log:\n"
"${build_log}")
unset(build_log)
endif()
unset(result)
message(STATUS "FFTW-${args_VERSION} build complete")
endif() # fftw_POPULATED

# Confirm that we can find FFTW.

# Ugly work-around for CMake errors in CI builds.
set(_cmake_import_check_xcframework_for_FFTW3::fftw3 "")

find_package(FFTW3
QUIET
REQUIRED
CONFIG
PATHS "${fftw_BINARY_DIR}/install"
NO_DEFAULT_PATH
)

unset(_cmake_import_check_xcframework_for_FFTW3::fftw3)

if(NOT FFTW3_FOUND)
message(FATAL_ERROR "FFTW-${args_VERSION} not found")
endif()
endfunction()

cmake_policy(POP)
11 changes: 6 additions & 5 deletions cmake/fetch-nlohmann_json.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@

cmake_policy(PUSH)

# Allow calling FetchContent_Populate directly.
if(POLICY CMP0169)
# Allow calling FetchContent_Populate directly.
cmake_policy(SET CMP0169 OLD)
endif()
if(POLICY CMP0135)
# Set the timestamps of extracted contents to the time of extraction.
cmake_policy(SET CMP0135 NEW)
endif()

include(FetchContent)

Expand All @@ -21,10 +25,7 @@ function(fetch_nlohmann_json)
)

FetchContent_Declare(nlohmann_json
GIT_REPOSITORY https://github.com/nlohmann/json.git
GIT_TAG v${args_VERSION}
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
URL "https://github.com/nlohmann/json/releases/download/v${args_VERSION}/json.tar.xz"
)

FetchContent_GetProperties(nlohmann_json)
Expand Down
Loading