From dfbae29faa43cfd33ec66fc93c84320e6bbe8a2f Mon Sep 17 00:00:00 2001 From: Relintai Date: Wed, 20 Apr 2022 03:24:50 +0200 Subject: [PATCH] An another set of codestyle cleanups for the wfc module. --- modules/wfc/array_2d.h | 77 +++++------------- modules/wfc/array_3d.h | 56 ++++--------- modules/wfc/direction.h | 2 +- modules/wfc/overlapping_wfc.h | 145 ++++++++-------------------------- modules/wfc/propagator.cpp | 4 +- modules/wfc/propagator.h | 60 +++----------- modules/wfc/tiling_wfc.h | 141 +++++++++------------------------ modules/wfc/wave.cpp | 19 ++--- modules/wfc/wave.h | 95 +++++++--------------- modules/wfc/wfc.cpp | 13 ++- modules/wfc/wfc.h | 70 +++++----------- 11 files changed, 184 insertions(+), 498 deletions(-) diff --git a/modules/wfc/array_2d.h b/modules/wfc/array_2d.h index da25be876..63638242c 100644 --- a/modules/wfc/array_2d.h +++ b/modules/wfc/array_2d.h @@ -4,62 +4,37 @@ #include "assert.h" #include -/** - * Represent a 2D array. - * The 2D array is stored in a single array, to improve cache usage. - */ template class Array2D { public: - /** - * Height and width of the 2D array. - */ std::size_t height; std::size_t width; - /** - * The array containing the data of the 2D array. - */ std::vector data; - /** - * Build a 2D array given its height and width. - * All the array elements are initialized to default value. - */ - Array2D(std::size_t height, std::size_t width) noexcept - : - height(height), width(width), data(width * height) {} + Array2D(std::size_t p_height, std::size_t p_width) { + height = p_height; + width = p_width; + data.resize(width * height); + } - /** - * Build a 2D array given its height and width. - * All the array elements are initialized to value. - */ - Array2D(std::size_t height, std::size_t width, T value) noexcept - : - height(height), width(width), data(width * height, value) {} + Array2D(std::size_t p_height, std::size_t p_width, T p_value) { + height = p_height; + width = p_width; + data.resize(width * height, value); + } - /** - * Return a const reference to the element in the i-th line and j-th column. - * i must be lower than height and j lower than width. - */ - const T &get(std::size_t i, std::size_t j) const noexcept { + const T &get(std::size_t i, std::size_t j) const { assert(i < height && j < width); return data[j + i * width]; } - /** - * Return a reference to the element in the i-th line and j-th column. - * i must be lower than height and j lower than width. - */ - T &get(std::size_t i, std::size_t j) noexcept { + T &get(std::size_t i, std::size_t j) { assert(i < height && j < width); return data[j + i * width]; } - /** - * Return the current 2D array reflected along the x axis. - */ - Array2D reflected() const noexcept { + Array2D reflected() const { Array2D result = Array2D(width, height); for (std::size_t y = 0; y < height; y++) { for (std::size_t x = 0; x < width; x++) { @@ -69,10 +44,7 @@ public: return result; } - /** - * Return the current 2D array rotated 90° anticlockwise - */ - Array2D rotated() const noexcept { + Array2D rotated() const { Array2D result = Array2D(width, height); for (std::size_t y = 0; y < width; y++) { for (std::size_t x = 0; x < height; x++) { @@ -82,12 +54,7 @@ public: return result; } - /** - * Return the sub 2D array starting from (y,x) and with size (sub_width, - * sub_height). The current 2D array is considered toric for this operation. - */ - Array2D get_sub_array(std::size_t y, std::size_t x, std::size_t sub_width, - std::size_t sub_height) const noexcept { + Array2D get_sub_array(std::size_t y, std::size_t x, std::size_t sub_width, std::size_t sub_height) const { Array2D sub_array_2d = Array2D(sub_width, sub_height); for (std::size_t ki = 0; ki < sub_height; ki++) { for (std::size_t kj = 0; kj < sub_width; kj++) { @@ -97,10 +64,7 @@ public: return sub_array_2d; } - /** - * Check if two 2D arrays are equals. - */ - bool operator==(const Array2D &a) const noexcept { + bool operator==(const Array2D &a) const { if (height != a.height || width != a.width) { return false; } @@ -114,14 +78,11 @@ public: } }; -/** - * Hash function. - */ namespace std { template class hash> { public: - std::size_t operator()(const Array2D &a) const noexcept { + std::size_t operator()(const Array2D &a) const { std::size_t seed = a.data.size(); for (const T &i : a.data) { seed ^= hash()(i) + (std::size_t)0x9e3779b9 + (seed << 6) + (seed >> 2); @@ -129,6 +90,6 @@ public: return seed; } }; -} // namespace std +} //namespace std -#endif // FAST_WFC_UTILS_ARRAY2D_HPP_ +#endif diff --git a/modules/wfc/array_3d.h b/modules/wfc/array_3d.h index 8256ad6b9..405c357a2 100644 --- a/modules/wfc/array_3d.h +++ b/modules/wfc/array_3d.h @@ -4,65 +4,39 @@ #include "assert.h" #include -/** - * Represent a 3D array. - * The 3D array is stored in a single array, to improve cache usage. - */ template class Array3D { public: - /** - * The dimensions of the 3D array. - */ std::size_t height; std::size_t width; std::size_t depth; - /** - * The array containing the data of the 3D array. - */ std::vector data; - /** - * Build a 2D array given its height, width and depth. - * All the arrays elements are initialized to default value. - */ - Array3D(std::size_t height, std::size_t width, std::size_t depth) noexcept - : - height(height), width(width), depth(depth), data(width * height * depth) {} + Array3D(std::size_t p_height, std::size_t p_width, std::size_t p_depth) { + height = p_height; + width = p_width; + depth = p_depth; + data.resize(width * height * depth); + } - /** - * Build a 2D array given its height, width and depth. - * All the arrays elements are initialized to value - */ - Array3D(std::size_t height, std::size_t width, std::size_t depth, - T value) noexcept - : - height(height), width(width), depth(depth), data(width * height * depth, value) {} + Array3D(std::size_t height, std::size_t width, std::size_t depth, T value) { + height = p_height; + width = p_width; + depth = p_depth; + data.resize(width * height * depth, value); + } - /** - * Return a const reference to the element in the i-th line, j-th column, and - * k-th depth. i must be lower than height, j lower than width, and k lower - * than depth. - */ - const T &get(std::size_t i, std::size_t j, std::size_t k) const noexcept { + const T &get(std::size_t i, std::size_t j, std::size_t k) const { assert(i < height && j < width && k < depth); return data[i * width * depth + j * depth + k]; } - /** - * Return a reference to the element in the i-th line, j-th column, and k-th - * depth. i must be lower than height, j lower than width, and k lower than - * depth. - */ - T &get(std::size_t i, std::size_t j, std::size_t k) noexcept { + T &get(std::size_t i, std::size_t j, std::size_t k) { return data[i * width * depth + j * depth + k]; } - /** - * Check if two 3D arrays are equals. - */ - bool operator==(const Array3D &a) const noexcept { + bool operator==(const Array3D &a) const { if (height != a.height || width != a.width || depth != a.depth) { return false; } diff --git a/modules/wfc/direction.h b/modules/wfc/direction.h index f5bd2708f..f82900833 100644 --- a/modules/wfc/direction.h +++ b/modules/wfc/direction.h @@ -4,7 +4,7 @@ constexpr int directions_x[4] = { 0, -1, 1, 0 }; constexpr int directions_y[4] = { -1, 0, 0, 1 }; -constexpr unsigned get_opposite_direction(unsigned direction) noexcept { +constexpr unsigned get_opposite_direction(unsigned direction) { return 3 - direction; } diff --git a/modules/wfc/overlapping_wfc.h b/modules/wfc/overlapping_wfc.h index 543ef2612..3f59ee18e 100644 --- a/modules/wfc/overlapping_wfc.h +++ b/modules/wfc/overlapping_wfc.h @@ -8,9 +8,6 @@ #include "array_2d.h" #include "wfc.h" -/** - * Options needed to use the overlapping wfc. - */ struct OverlappingWFCOptions { bool periodic_input; // True if the input is toric. bool periodic_output; // True if the output is toric. @@ -20,59 +17,33 @@ struct OverlappingWFCOptions { bool ground; // True if the ground needs to be set (see init_ground). unsigned pattern_size; // The width and height in pixel of the patterns. - /** - * Get the wave height given these options. - */ - unsigned get_wave_height() const noexcept { + //Get the wave height given these options. + unsigned get_wave_height() const { return periodic_output ? out_height : out_height - pattern_size + 1; } - /** - * Get the wave width given these options. - */ - unsigned get_wave_width() const noexcept { + //Get the wave width given these options. + unsigned get_wave_width() const { return periodic_output ? out_width : out_width - pattern_size + 1; } }; -/** - * Class generating a new image with the overlapping WFC algorithm. - */ template class OverlappingWFC { private: - /** - * The input image. T is usually a color. - */ Array2D input; - /** - * Options needed by the algorithm. - */ OverlappingWFCOptions options; - /** - * The array of the different patterns extracted from the input. - */ std::vector> patterns; - /** - * The underlying generic WFC algorithm. - */ WFC wfc; - /** - * Constructor initializing the wfc. - * This constructor is called by the other constructors. - * This is necessary in order to initialize wfc only once. - */ OverlappingWFC( const Array2D &input, const OverlappingWFCOptions &options, const int &seed, const std::pair>, std::vector> &patterns, - const std::vector, 4>> - &propagator) noexcept - : + const std::vector, 4>> &propagator) : input(input), options(options), patterns(patterns.first), wfc(options.periodic_output, seed, patterns.second, propagator, options.get_wave_height(), options.get_wave_width()) { // If necessary, the ground is set. if (options.ground) { @@ -80,58 +51,32 @@ private: } } - /** - * Constructor used only to call the other constructor with more computed - * parameters. - */ OverlappingWFC(const Array2D &input, const OverlappingWFCOptions &options, const int &seed, const std::pair>, std::vector> - &patterns) noexcept - : + &patterns) : OverlappingWFC(input, options, seed, patterns, generate_compatible(patterns.first)) {} - /** - * Init the ground of the output image. - * The lowest middle pattern is used as a floor (and ceiling when the input is - * toric) and is placed at the lowest possible pattern position in the output - * image, on all its width. The pattern cannot be used at any other place in - * the output image. - */ - void init_ground(WFC &wfc, const Array2D &input, - const std::vector> &patterns, - const OverlappingWFCOptions &options) noexcept { - unsigned ground_pattern_id = - get_ground_pattern_id(input, patterns, options); + void init_ground(WFC &wfc, const Array2D &input, const std::vector> &patterns, const OverlappingWFCOptions &options) { + unsigned ground_pattern_id = get_ground_pattern_id(input, patterns, options); - // Place the pattern in the ground. for (unsigned j = 0; j < options.get_wave_width(); j++) { set_pattern(ground_pattern_id, options.get_wave_height() - 1, j); } - // Remove the pattern from the other positions. for (unsigned i = 0; i < options.get_wave_height() - 1; i++) { for (unsigned j = 0; j < options.get_wave_width(); j++) { wfc.remove_wave_pattern(i, j, ground_pattern_id); } } - // Propagate the information with wfc. wfc.propagate(); } - /** - * Return the id of the lowest middle pattern. - */ - static unsigned - get_ground_pattern_id(const Array2D &input, - const std::vector> &patterns, - const OverlappingWFCOptions &options) noexcept { + static unsigned get_ground_pattern_id(const Array2D &input, const std::vector> &patterns, const OverlappingWFCOptions &options) { // Get the pattern. - Array2D ground_pattern = - input.get_sub_array(input.height - 1, input.width / 2, - options.pattern_size, options.pattern_size); + Array2D ground_pattern = input.get_sub_array(input.height - 1, input.width / 2, options.pattern_size, options.pattern_size); // Retrieve the id of the pattern. for (unsigned i = 0; i < patterns.size(); i++) { @@ -145,12 +90,8 @@ private: return 0; } - /** - * Return the list of patterns, as well as their probabilities of apparition. - */ - static std::pair>, std::vector> - get_patterns(const Array2D &input, - const OverlappingWFCOptions &options) noexcept { + //Return the list of patterns, as well as their probabilities of apparition. + static std::pair>, std::vector> get_patterns(const Array2D &input, const OverlappingWFCOptions &options) { std::unordered_map, unsigned> patterns_id; std::vector> patterns; @@ -202,12 +143,8 @@ private: return { patterns, patterns_weight }; } - /** - * Return true if the pattern1 is compatible with pattern2 - * when pattern2 is at a distance (dy,dx) from pattern1. - */ - static bool agrees(const Array2D &pattern1, const Array2D &pattern2, - int dy, int dx) noexcept { + //Return true if the pattern1 is compatible with pattern2 when pattern2 is at a distance (dy,dx) from pattern1. + static bool agrees(const Array2D &pattern1, const Array2D &pattern2, int dy, int dx) { unsigned xmin = dx < 0 ? 0 : dx; unsigned xmax = dx < 0 ? dx + pattern2.width : pattern1.width; unsigned ymin = dy < 0 ? 0 : dy; @@ -225,16 +162,12 @@ private: return true; } - /** - * Precompute the function agrees(pattern1, pattern2, dy, dx). - * If agrees(pattern1, pattern2, dy, dx), then compatible[pattern1][direction] - * contains pattern2, where direction is the direction defined by (dy, dx) - * (see direction.hpp). - */ - static std::vector, 4>> - generate_compatible(const std::vector> &patterns) noexcept { - std::vector, 4>> compatible = - std::vector, 4>>(patterns.size()); + // Precompute the function agrees(pattern1, pattern2, dy, dx). + // If agrees(pattern1, pattern2, dy, dx), then compatible[pattern1][direction] + // contains pattern2, where direction is the direction defined by (dy, dx) + // (see direction.hpp). + static std::vector, 4>> generate_compatible(const std::vector> &patterns) { + std::vector, 4>> compatible = std::vector, 4>>(patterns.size()); // Iterate on every dy, dx, pattern1 and pattern2 for (unsigned pattern1 = 0; pattern1 < patterns.size(); pattern1++) { @@ -251,11 +184,8 @@ private: return compatible; } - /** - * Transform a 2D array containing the patterns id to a 2D array containing - * the pixels. - */ - Array2D to_image(const Array2D &output_patterns) const noexcept { + // Transform a 2D array containing the patterns id to a 2D array containing the pixels. + Array2D to_image(const Array2D &output_patterns) const { Array2D output = Array2D(options.out_height, options.out_width); if (options.periodic_output) { @@ -308,11 +238,9 @@ private: return std::nullopt; } - /** - * Set the pattern at a specific position, given its pattern id - * pattern_id needs to be a valid pattern id, and i and j needs to be in the wave range - */ - void set_pattern(unsigned pattern_id, unsigned i, unsigned j) noexcept { + // Set the pattern at a specific position, given its pattern id + // pattern_id needs to be a valid pattern id, and i and j needs to be in the wave range + void set_pattern(unsigned pattern_id, unsigned i, unsigned j) { for (unsigned p = 0; p < patterns.size(); p++) { if (pattern_id != p) { wfc.remove_wave_pattern(i, j, p); @@ -321,20 +249,13 @@ private: } public: - /** - * The constructor used by the user. - */ - OverlappingWFC(const Array2D &input, const OverlappingWFCOptions &options, - int seed) noexcept - : + OverlappingWFC(const Array2D &input, const OverlappingWFCOptions &options, int seed) : OverlappingWFC(input, options, seed, get_patterns(input, options)) {} - /** - * Set the pattern at a specific position. - * Returns false if the given pattern does not exist, or if the - * coordinates are not in the wave - */ - bool set_pattern(const Array2D &pattern, unsigned i, unsigned j) noexcept { + // Set the pattern at a specific position. + // Returns false if the given pattern does not exist, or if the + // coordinates are not in the wave + bool set_pattern(const Array2D &pattern, unsigned i, unsigned j) { auto pattern_id = get_pattern_id(pattern); if (pattern_id == std::nullopt || i >= options.get_wave_height() || j >= options.get_wave_width()) { @@ -345,10 +266,8 @@ public: return true; } - /** - * Run the WFC algorithm, and return the result if the algorithm succeeded. - */ - std::optional> run() noexcept { + // Run the WFC algorithm, and return the result if the algorithm succeeded. + std::optional> run() { std::optional> result = wfc.run(); if (result.has_value()) { return to_image(*result); diff --git a/modules/wfc/propagator.cpp b/modules/wfc/propagator.cpp index 05b5e076f..4e0d70ac6 100644 --- a/modules/wfc/propagator.cpp +++ b/modules/wfc/propagator.cpp @@ -1,7 +1,7 @@ #include "propagator.h" #include "wave.h" -void Propagator::init_compatible() noexcept { +void Propagator::init_compatible() { std::array value; // We compute the number of pattern compatible in all directions. for (unsigned y = 0; y < wave_height; y++) { @@ -18,7 +18,7 @@ void Propagator::init_compatible() noexcept { } } -void Propagator::propagate(Wave &wave) noexcept { +void Propagator::propagate(Wave &wave) { // We propagate every element while there is element to propagate. while (propagating.size() != 0) { // The cell and pattern that has been set to false. diff --git a/modules/wfc/propagator.h b/modules/wfc/propagator.h index d7dd0b786..3f6e3dd72 100644 --- a/modules/wfc/propagator.h +++ b/modules/wfc/propagator.h @@ -1,72 +1,45 @@ #ifndef FAST_WFC_PROPAGATOR_HPP_ #define FAST_WFC_PROPAGATOR_HPP_ -#include "direction.h" #include "array_3d.h" +#include "direction.h" #include #include #include class Wave; -/** - * Propagate information about patterns in the wave. - */ class Propagator { public: using PropagatorState = std::vector, 4>>; private: - /** - * The size of the patterns. - */ const std::size_t patterns_size; - /** - * propagator[pattern1][direction] contains all the patterns that can - * be placed in next to pattern1 in the direction direction. - */ PropagatorState propagator_state; - /** - * The wave width and height. - */ const unsigned wave_width; const unsigned wave_height; - /** - * True if the wave and the output is toric. - */ const bool periodic_output; - /** - * All the tuples (y, x, pattern) that should be propagated. - * The tuple should be propagated when wave.get(y, x, pattern) is set to - * false. - */ + // All the tuples (y, x, pattern) that should be propagated. + // The tuple should be propagated when wave.get(y, x, pattern) is set to + // false. std::vector> propagating; - /** - * compatible.get(y, x, pattern)[direction] contains the number of patterns - * present in the wave that can be placed in the cell next to (y,x) in the - * opposite direction of direction without being in contradiction with pattern - * placed in (y,x). If wave.get(y, x, pattern) is set to false, then - * compatible.get(y, x, pattern) has every element negative or null - */ + // compatible.get(y, x, pattern)[direction] contains the number of patterns + // present in the wave that can be placed in the cell next to (y,x) in the + // opposite direction of direction without being in contradiction with pattern + // placed in (y,x). If wave.get(y, x, pattern) is set to false, then + // compatible.get(y, x, pattern) has every element negative or null Array3D> compatible; - /** - * Initialize compatible. - */ - void init_compatible() noexcept; + void init_compatible(); public: - /** - * Constructor building the propagator and initializing compatible. - */ Propagator(unsigned wave_height, unsigned wave_width, bool periodic_output, - PropagatorState propagator_state) noexcept - : + PropagatorState propagator_state) : patterns_size(propagator_state.size()), propagator_state(propagator_state), wave_width(wave_width), @@ -76,21 +49,14 @@ public: init_compatible(); } - /** - * Add an element to the propagator. - * This function is called when wave.get(y, x, pattern) is set to false. - */ - void add_to_propagator(unsigned y, unsigned x, unsigned pattern) noexcept { + void add_to_propagator(unsigned y, unsigned x, unsigned pattern) { // All the direction are set to 0, since the pattern cannot be set in (y,x). std::array temp = {}; compatible.get(y, x, pattern) = temp; propagating.emplace_back(y, x, pattern); } - /** - * Propagate the information given with add_to_propagator. - */ - void propagate(Wave &wave) noexcept; + void propagate(Wave &wave); }; #endif // FAST_WFC_PROPAGATOR_HPP_ diff --git a/modules/wfc/tiling_wfc.h b/modules/wfc/tiling_wfc.h index 7ca229365..5586509db 100644 --- a/modules/wfc/tiling_wfc.h +++ b/modules/wfc/tiling_wfc.h @@ -7,10 +7,8 @@ #include "array_2d.h" #include "wfc.h" -/** - * The distinct symmetries of a tile. - * It represents how the tile behave when it is rotated or reflected - */ +// The distinct symmetries of a tile. +// It represents how the tile behave when it is rotated or reflected enum class Symmetry { X, T, @@ -21,8 +19,8 @@ enum class Symmetry { }; /** - * Return the number of possible distinct orientations for a tile. - * An orientation is a combination of rotations and reflections. +// Return the number of possible distinct orientations for a tile. +// An orientation is a combination of rotations and reflections. */ constexpr unsigned nb_of_possible_orientations(const Symmetry &symmetry) { switch (symmetry) { @@ -39,21 +37,16 @@ constexpr unsigned nb_of_possible_orientations(const Symmetry &symmetry) { } } -/** - * A tile that can be placed on the board. - */ +// A tile that can be placed on the board. template struct Tile { std::vector> data; // The different orientations of the tile Symmetry symmetry; // The symmetry of the tile double weight; // Its weight on the distribution of presence of tiles - /** - * Generate the map associating an orientation id to the orientation - * id obtained when rotating 90° anticlockwise the tile. - */ - static std::vector - generate_rotation_map(const Symmetry &symmetry) noexcept { + // Generate the map associating an orientation id to the orientation + // id obtained when rotating 90° anticlockwise the tile. + static std::vector generate_rotation_map(const Symmetry &symmetry) { switch (symmetry) { case Symmetry::X: return { 0 }; @@ -69,12 +62,10 @@ struct Tile { } } - /** - * Generate the map associating an orientation id to the orientation - * id obtained when reflecting the tile along the x axis. - */ + // Generate the map associating an orientation id to the orientation + // id obtained when reflecting the tile along the x axis. static std::vector - generate_reflection_map(const Symmetry &symmetry) noexcept { + generate_reflection_map(const Symmetry &symmetry) { switch (symmetry) { case Symmetry::X: return { 0 }; @@ -92,15 +83,12 @@ struct Tile { } } - /** - * Generate the map associating an orientation id and an action to the - * resulting orientation id. - * Actions 0, 1, 2, and 3 are 0°, 90°, 180°, and 270° anticlockwise rotations. - * Actions 4, 5, 6, and 7 are actions 0, 1, 2, and 3 preceded by a reflection - * on the x axis. - */ - static std::vector> - generate_action_map(const Symmetry &symmetry) noexcept { + // Generate the map associating an orientation id and an action to the + // resulting orientation id. + // Actions 0, 1, 2, and 3 are 0°, 90°, 180°, and 270° anticlockwise rotations. + // Actions 4, 5, 6, and 7 are actions 0, 1, 2, and 3 preceded by a reflection + // on the x axis. + static std::vector> generate_action_map(const Symmetry &symmetry) { std::vector rotation_map = generate_rotation_map(symmetry); std::vector reflection_map = generate_reflection_map(symmetry); size_t size = rotation_map.size(); @@ -126,11 +114,9 @@ struct Tile { return action_map; } - /** - * Generate all distincts rotations of a 2D array given its symmetries; - */ + // Generate all distincts rotations of a 2D array given its symmetries; static std::vector> generate_oriented(Array2D data, - Symmetry symmetry) noexcept { + Symmetry symmetry) { std::vector> oriented; oriented.push_back(data); @@ -161,80 +147,43 @@ struct Tile { return oriented; } - /** - * Create a tile with its differents orientations, its symmetries and its - * weight on the distribution of tiles. - */ - Tile(std::vector> data, Symmetry symmetry, double weight) noexcept - : + // Create a tile with its differents orientations, its symmetries and its + // weight on the distribution of tiles. + Tile(std::vector> data, Symmetry symmetry, double weight) : data(data), symmetry(symmetry), weight(weight) {} - /* - * Create a tile with its base orientation, its symmetries and its - * weight on the distribution of tiles. - * The other orientations are generated with its first one. - */ - Tile(Array2D data, Symmetry symmetry, double weight) noexcept - : + // Create a tile with its base orientation, its symmetries and its + // weight on the distribution of tiles. + // The other orientations are generated with its first one. + Tile(Array2D data, Symmetry symmetry, double weight) : data(generate_oriented(data, symmetry)), symmetry(symmetry), weight(weight) {} }; -/** - * Options needed to use the tiling wfc. - */ struct TilingWFCOptions { bool periodic_output; }; -/** - * Class generating a new image with the tiling WFC algorithm. - */ +// Class generating a new image with the tiling WFC algorithm. template class TilingWFC { private: - /** - * The distincts tiles. - */ std::vector> tiles; - - /** - * Map ids of oriented tiles to tile and orientation. - */ std::vector> id_to_oriented_tile; - - /** - * Map tile and orientation to oriented tile id. - */ std::vector> oriented_tile_ids; - /** - * Otions needed to use the tiling wfc. - */ TilingWFCOptions options; - /** - * The underlying generic WFC algorithm. - */ WFC wfc; public: - /** - * The number of vertical tiles - */ unsigned height; - - /** - * The number of horizontal tiles - */ unsigned width; private: - /** - * Generate mapping from id to oriented tiles and vice versa. - */ + // Generate mapping from id to oriented tiles and vice versa. static std::pair>, std::vector>> - generate_oriented_tile_ids(const std::vector> &tiles) noexcept { + generate_oriented_tile_ids(const std::vector> &tiles) { std::vector> id_to_oriented_tile; std::vector> oriented_tile_ids; @@ -251,9 +200,7 @@ private: return { id_to_oriented_tile, oriented_tile_ids }; } - /** - * Generate the propagator which will be used in the wfc algorithm. - */ + // Generate the propagator which will be used in the wfc algorithm. static std::vector, 4>> generate_propagator( const std::vector> &neighbors, @@ -313,9 +260,7 @@ private: return propagator; } - /** - * Get probability of presence of tiles. - */ + // Get probability of presence of tiles. static std::vector get_tiles_weights(const std::vector> &tiles) { std::vector frequencies; @@ -327,9 +272,7 @@ private: return frequencies; } - /** - * Translate the generic WFC result into the image result - */ + // Translate the generic WFC result into the image result Array2D id_to_tiling(Array2D ids) { unsigned size = tiles[0].data[0].height; Array2D tiling(size * ids.height, size * ids.width); @@ -348,7 +291,7 @@ private: return tiling; } - void set_tile(unsigned tile_id, unsigned i, unsigned j) noexcept { + void set_tile(unsigned tile_id, unsigned i, unsigned j) { for (unsigned p = 0; p < id_to_oriented_tile.size(); p++) { if (tile_id != p) { wfc.remove_wave_pattern(i, j, p); @@ -357,9 +300,7 @@ private: } public: - /** - * Construct the TilingWFC class to generate a tiled image. - */ + // Construct the TilingWFC class to generate a tiled image. TilingWFC( const std::vector> &tiles, const std::vector> @@ -377,12 +318,10 @@ public: height(height), width(width) {} - /** - * Set the tile at a specific position. - * Returns false if the given tile and orientation does not exist, - * or if the coordinates are not in the wave - */ - bool set_tile(unsigned tile_id, unsigned orientation, unsigned i, unsigned j) noexcept { + // Set the tile at a specific position. + // Returns false if the given tile and orientation does not exist, + // or if the coordinates are not in the wave + bool set_tile(unsigned tile_id, unsigned orientation, unsigned i, unsigned j) { if (tile_id >= oriented_tile_ids.size() || orientation >= oriented_tile_ids[tile_id].size() || i >= height || j >= width) { return false; } @@ -392,9 +331,7 @@ public: return true; } - /** - * Run the tiling wfc and return the result if the algorithm succeeded - */ + // Run the tiling wfc and return the result if the algorithm succeeded std::optional> run() { auto a = wfc.run(); if (a == std::nullopt) { diff --git a/modules/wfc/wave.cpp b/modules/wfc/wave.cpp index 2e5a63b9c..b50aeb589 100644 --- a/modules/wfc/wave.cpp +++ b/modules/wfc/wave.cpp @@ -4,11 +4,9 @@ namespace { -/** - * Return distribution * log(distribution). - */ +// Return distribution * log(distribution). std::vector -get_plogp(const std::vector &distribution) noexcept { +get_plogp(const std::vector &distribution) { std::vector plogp; for (unsigned i = 0; i < distribution.size(); i++) { plogp.push_back(distribution[i] * log(distribution[i])); @@ -16,10 +14,8 @@ get_plogp(const std::vector &distribution) noexcept { return plogp; } -/** - * Return min(v) / 2. - */ -double get_min_abs_half(const std::vector &v) noexcept { +// Return min(v) / 2. +double get_min_abs_half(const std::vector &v) { double min_abs_half = std::numeric_limits::infinity(); for (unsigned i = 0; i < v.size(); i++) { min_abs_half = std::min(min_abs_half, std::abs(v[i] / 2.0)); @@ -30,8 +26,7 @@ double get_min_abs_half(const std::vector &v) noexcept { } // namespace Wave::Wave(unsigned height, unsigned width, - const std::vector &patterns_frequencies) noexcept - : + const std::vector &patterns_frequencies) : patterns_frequencies(patterns_frequencies), plogp_patterns_frequencies(get_plogp(patterns_frequencies)), min_abs_half_plogp(get_min_abs_half(plogp_patterns_frequencies)), @@ -58,7 +53,7 @@ Wave::Wave(unsigned height, unsigned width, memoisation.entropy = std::vector(width * height, entropy_base); } -void Wave::set(unsigned index, unsigned pattern, bool value) noexcept { +void Wave::set(unsigned index, unsigned pattern, bool value) { bool old_value = data.get(index, pattern); // If the value isn't changed, nothing needs to be done. if (old_value == value) { @@ -80,7 +75,7 @@ void Wave::set(unsigned index, unsigned pattern, bool value) noexcept { } } -int Wave::get_min_entropy(std::minstd_rand &gen) const noexcept { +int Wave::get_min_entropy(std::minstd_rand &gen) const { if (is_impossible) { return -2; } diff --git a/modules/wfc/wave.h b/modules/wfc/wave.h index 3a9f6fd6b..4ad71cf2e 100644 --- a/modules/wfc/wave.h +++ b/modules/wfc/wave.h @@ -5,110 +5,75 @@ #include #include -/** - * Struct containing the values needed to compute the entropy of all the cells. - * This struct is updated every time the wave is changed. - * p'(pattern) is equal to patterns_frequencies[pattern] if wave.get(cell, - * pattern) is set to true, otherwise 0. - */ +// Struct containing the values needed to compute the entropy of all the cells. +// This struct is updated every time the wave is changed. +// p'(pattern) is equal to patterns_frequencies[pattern] if wave.get(cell, +// pattern) is set to true, otherwise 0. struct EntropyMemoisation { - std::vector plogp_sum; // The sum of p'(pattern) * log(p'(pattern)). + std::vector plogp_sum; // The sum of p'(pattern)// log(p'(pattern)). std::vector sum; // The sum of p'(pattern). std::vector log_sum; // The log of sum. std::vector nb_patterns; // The number of patterns present std::vector entropy; // The entropy of the cell. }; -/** - * Contains the pattern possibilities in every cell. - * Also contains information about cell entropy. - */ +// Contains the pattern possibilities in every cell. +// Also contains information about cell entropy. class Wave { private: - /** - * The patterns frequencies p given to wfc. - */ + // The patterns frequencies p given to wfc. const std::vector patterns_frequencies; - /** - * The precomputation of p * log(p). - */ + // The precomputation of p * log(p). const std::vector plogp_patterns_frequencies; - /** - * The precomputation of min (p * log(p)) / 2. - * This is used to define the maximum value of the noise. - */ + // The precomputation of min (p * log(p)) / 2. + // This is used to define the maximum value of the noise. const double min_abs_half_plogp; - /** - * The memoisation of important values for the computation of entropy. - */ EntropyMemoisation memoisation; - /** - * This value is set to true if there is a contradiction in the wave (all - * elements set to false in a cell). - */ + // This value is set to true if there is a contradiction in the wave (all elements set to false in a cell). bool is_impossible; - /** - * The number of distinct patterns. - */ + // The number of distinct patterns. const size_t nb_patterns; - /** - * The actual wave. data.get(index, pattern) is equal to 0 if the pattern can - * be placed in the cell index. - */ + // The actual wave. data.get(index, pattern) is equal to 0 if the pattern can + // be placed in the cell index. Array2D data; public: - /** - * The size of the wave. - */ + // The size of the wave. const unsigned width; const unsigned height; const unsigned size; - /** - * Initialize the wave with every cell being able to have every pattern. - */ - Wave(unsigned height, unsigned width, - const std::vector &patterns_frequencies) noexcept; + // Initialize the wave with every cell being able to have every pattern. + Wave(unsigned height, unsigned width, const std::vector &patterns_frequencies); - /** - * Return true if pattern can be placed in cell index. - */ - bool get(unsigned index, unsigned pattern) const noexcept { + // Return true if pattern can be placed in cell index. + bool get(unsigned index, unsigned pattern) const { return data.get(index, pattern); } - /** - * Return true if pattern can be placed in cell (i,j) - */ - bool get(unsigned i, unsigned j, unsigned pattern) const noexcept { + // Return true if pattern can be placed in cell (i,j) + bool get(unsigned i, unsigned j, unsigned pattern) const { return get(i * width + j, pattern); } - /** - * Set the value of pattern in cell index. - */ - void set(unsigned index, unsigned pattern, bool value) noexcept; + // Set the value of pattern in cell index. + void set(unsigned index, unsigned pattern, bool value); - /** - * Set the value of pattern in cell (i,j). - */ - void set(unsigned i, unsigned j, unsigned pattern, bool value) noexcept { + // Set the value of pattern in cell (i,j). + void set(unsigned i, unsigned j, unsigned pattern, bool value) { set(i * width + j, pattern, value); } - /** - * Return the index of the cell with lowest entropy different of 0. - * If there is a contradiction in the wave, return -2. - * If every cell is decided, return -1. - */ - int get_min_entropy(std::minstd_rand &gen) const noexcept; + // Return the index of the cell with lowest entropy different of 0. + // If there is a contradiction in the wave, return -2. + // If every cell is decided, return -1. + int get_min_entropy(std::minstd_rand &gen) const; }; #endif // FAST_WFC_WAVE_HPP_ diff --git a/modules/wfc/wfc.cpp b/modules/wfc/wfc.cpp index 645944e53..8044a62ba 100644 --- a/modules/wfc/wfc.cpp +++ b/modules/wfc/wfc.cpp @@ -2,9 +2,7 @@ #include namespace { -/** - * Normalize a vector so the sum of its elements is equal to 1.0f - */ +// Normalize a vector so the sum of its elements is equal to 1.0f std::vector &normalize(std::vector &v) { double sum_weights = 0.0; for (double weight : v) { @@ -20,7 +18,7 @@ std::vector &normalize(std::vector &v) { } } //namespace -Array2D WFC::wave_to_output() const noexcept { +Array2D WFC::wave_to_output() const { Array2D output_patterns(wave.height, wave.width); for (unsigned i = 0; i < wave.size; i++) { for (unsigned k = 0; k < nb_patterns; k++) { @@ -35,11 +33,10 @@ Array2D WFC::wave_to_output() const noexcept { WFC::WFC(bool periodic_output, int seed, std::vector patterns_frequencies, Propagator::PropagatorState propagator, unsigned wave_height, - unsigned wave_width) noexcept - : + unsigned wave_width) : gen(seed), patterns_frequencies(normalize(patterns_frequencies)), wave(wave_height, wave_width, patterns_frequencies), nb_patterns(propagator.size()), propagator(wave.height, wave.width, periodic_output, propagator) {} -std::optional> WFC::run() noexcept { +std::optional> WFC::run() { while (true) { // Define the value of an undefined cell. ObserveStatus result = observe(); @@ -56,7 +53,7 @@ std::optional> WFC::run() noexcept { } } -WFC::ObserveStatus WFC::observe() noexcept { +WFC::ObserveStatus WFC::observe() { // Get the cell with lowest entropy. int argmin = wave.get_min_entropy(gen); diff --git a/modules/wfc/wfc.h b/modules/wfc/wfc.h index 499725a06..51ac7ab44 100644 --- a/modules/wfc/wfc.h +++ b/modules/wfc/wfc.h @@ -4,84 +4,56 @@ #include #include -#include "propagator.h" #include "array_2d.h" +#include "propagator.h" #include "wave.h" -/** - * Class containing the generic WFC algorithm. - */ +// Class containing the generic WFC algorithm. class WFC { private: - /** - * The random number generator. - */ + // The random number generator. std::minstd_rand gen; - /** - * The distribution of the patterns as given in input. - */ + // The distribution of the patterns as given in input. const std::vector patterns_frequencies; - /** - * The wave, indicating which patterns can be put in which cell. - */ Wave wave; - /** - * The number of distinct patterns. - */ + // The number of distinct patterns. const size_t nb_patterns; - /** - * The propagator, used to propagate the information in the wave. - */ + // The propagator, used to propagate the information in the wave. Propagator propagator; - /** - * Transform the wave to a valid output (a 2d array of patterns that aren't in - * contradiction). This function should be used only when all cell of the wave - * are defined. - */ - Array2D wave_to_output() const noexcept; + // Transform the wave to a valid output (a 2d array of patterns that aren't in + // contradiction). This function should be used only when all cell of the wave + // are defined. + Array2D wave_to_output() const; public: - /** - * Basic constructor initializing the algorithm. - */ + // Basic constructor initializing the algorithm. WFC(bool periodic_output, int seed, std::vector patterns_frequencies, Propagator::PropagatorState propagator, unsigned wave_height, - unsigned wave_width) - noexcept; + unsigned wave_width); - /** - * Run the algorithm, and return a result if it succeeded. - */ - std::optional> run() noexcept; + // Run the algorithm, and return a result if it succeeded. + std::optional> run(); - /** - * Return value of observe. - */ + // Return value of observe. enum ObserveStatus { success, // WFC has finished and has succeeded. failure, // WFC has finished and failed. to_continue // WFC isn't finished. }; - /** - * Define the value of the cell with lowest entropy. - */ - ObserveStatus observe() noexcept; + // Define the value of the cell with lowest entropy. + ObserveStatus observe(); - /** - * Propagate the information of the wave. - */ - void propagate() noexcept { propagator.propagate(wave); } + // Propagate the information of the wave. + void propagate() { propagator.propagate(wave); } - /** - * Remove pattern from cell (i,j). - */ - void remove_wave_pattern(unsigned i, unsigned j, unsigned pattern) noexcept { + // Remove pattern from cell (i,j). + void remove_wave_pattern(unsigned i, unsigned j, unsigned pattern) { if (wave.get(i, j, pattern)) { wave.set(i, j, pattern, false); propagator.add_to_propagator(i, j, pattern);