mirror of
https://github.com/Relintai/pandemonium_engine.git
synced 2025-01-11 13:21:10 +01:00
unsigned to uint32_t conversion for the wfc module.
This commit is contained in:
parent
531dc783d8
commit
ec6b52f5d8
@ -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) {
|
||||
constexpr uint32_t get_opposite_direction(uint32_t direction) {
|
||||
return 3 - direction;
|
||||
}
|
||||
|
||||
|
@ -11,19 +11,19 @@
|
||||
struct OverlappingWFCOptions {
|
||||
bool periodic_input; // True if the input is toric.
|
||||
bool periodic_output; // True if the output is toric.
|
||||
unsigned out_height; // The height of the output in pixels.
|
||||
unsigned out_width; // The width of the output in pixels.
|
||||
unsigned symmetry; // The number of symmetries (the order is defined in wfc).
|
||||
uint32_t out_height; // The height of the output in pixels.
|
||||
uint32_t out_width; // The width of the output in pixels.
|
||||
uint32_t symmetry; // The number of symmetries (the order is defined in wfc).
|
||||
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.
|
||||
uint32_t pattern_size; // The width and height in pixel of the patterns.
|
||||
|
||||
//Get the wave height given these options.
|
||||
unsigned get_wave_height() const {
|
||||
uint32_t 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 {
|
||||
uint32_t get_wave_width() const {
|
||||
return periodic_output ? out_width : out_width - pattern_size + 1;
|
||||
}
|
||||
};
|
||||
@ -43,7 +43,7 @@ private:
|
||||
const Array2D<T> &input, const OverlappingWFCOptions &options,
|
||||
const int &seed,
|
||||
const std::pair<Vector<Array2D<T>>, Vector<double>> &patterns,
|
||||
const Vector<std::array<Vector<unsigned>, 4>> &propagator) :
|
||||
const Vector<std::array<Vector<uint32_t>, 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) {
|
||||
@ -59,14 +59,14 @@ private:
|
||||
generate_compatible(patterns.first)) {}
|
||||
|
||||
void init_ground(WFC &wfc, const Array2D<T> &input, const Vector<Array2D<T>> &patterns, const OverlappingWFCOptions &options) {
|
||||
unsigned ground_pattern_id = get_ground_pattern_id(input, patterns, options);
|
||||
uint32_t ground_pattern_id = get_ground_pattern_id(input, patterns, options);
|
||||
|
||||
for (unsigned j = 0; j < options.get_wave_width(); j++) {
|
||||
for (uint32_t j = 0; j < options.get_wave_width(); j++) {
|
||||
set_pattern(ground_pattern_id, options.get_wave_height() - 1, j);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < options.get_wave_height() - 1; i++) {
|
||||
for (unsigned j = 0; j < options.get_wave_width(); j++) {
|
||||
for (uint32_t i = 0; i < options.get_wave_height() - 1; i++) {
|
||||
for (uint32_t j = 0; j < options.get_wave_width(); j++) {
|
||||
wfc.remove_wave_pattern(i, j, ground_pattern_id);
|
||||
}
|
||||
}
|
||||
@ -74,12 +74,12 @@ private:
|
||||
wfc.propagate();
|
||||
}
|
||||
|
||||
static unsigned get_ground_pattern_id(const Array2D<T> &input, const Vector<Array2D<T>> &patterns, const OverlappingWFCOptions &options) {
|
||||
static uint32_t get_ground_pattern_id(const Array2D<T> &input, const Vector<Array2D<T>> &patterns, const OverlappingWFCOptions &options) {
|
||||
// Get the pattern.
|
||||
Array2D<T> 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++) {
|
||||
for (uint32_t i = 0; i < patterns.size(); i++) {
|
||||
if (ground_pattern == patterns[i]) {
|
||||
return i;
|
||||
}
|
||||
@ -92,7 +92,7 @@ private:
|
||||
|
||||
//Return the list of patterns, as well as their probabilities of apparition.
|
||||
static std::pair<Vector<Array2D<T>>, Vector<double>> get_patterns(const Array2D<T> &input, const OverlappingWFCOptions &options) {
|
||||
std::unordered_map<Array2D<T>, unsigned> patterns_id;
|
||||
std::unordered_map<Array2D<T>, uint32_t> patterns_id;
|
||||
Vector<Array2D<T>> patterns;
|
||||
|
||||
// The number of time a pattern is seen in the input image.
|
||||
@ -100,15 +100,15 @@ private:
|
||||
|
||||
Vector<Array2D<T>> symmetries(
|
||||
8, Array2D<T>(options.pattern_size, options.pattern_size));
|
||||
unsigned max_i = options.periodic_input
|
||||
uint32_t max_i = options.periodic_input
|
||||
? input.height
|
||||
: input.height - options.pattern_size + 1;
|
||||
unsigned max_j = options.periodic_input
|
||||
uint32_t max_j = options.periodic_input
|
||||
? input.width
|
||||
: input.width - options.pattern_size + 1;
|
||||
|
||||
for (unsigned i = 0; i < max_i; i++) {
|
||||
for (unsigned j = 0; j < max_j; j++) {
|
||||
for (uint32_t i = 0; i < max_i; i++) {
|
||||
for (uint32_t j = 0; j < max_j; j++) {
|
||||
// Compute the symmetries of every pattern in the image.
|
||||
symmetries[0].data =
|
||||
input
|
||||
@ -124,7 +124,7 @@ private:
|
||||
|
||||
// The number of symmetries in the option class define which symetries
|
||||
// will be used.
|
||||
for (unsigned k = 0; k < options.symmetry; k++) {
|
||||
for (uint32_t k = 0; k < options.symmetry; k++) {
|
||||
auto res = patterns_id.insert(
|
||||
std::make_pair(symmetries[k], patterns.size()));
|
||||
|
||||
@ -145,14 +145,14 @@ private:
|
||||
|
||||
//Return true if the pattern1 is compatible with pattern2 when pattern2 is at a distance (dy,dx) from pattern1.
|
||||
static bool agrees(const Array2D<T> &pattern1, const Array2D<T> &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;
|
||||
unsigned ymax = dy < 0 ? dy + pattern2.height : pattern1.width;
|
||||
uint32_t xmin = dx < 0 ? 0 : dx;
|
||||
uint32_t xmax = dx < 0 ? dx + pattern2.width : pattern1.width;
|
||||
uint32_t ymin = dy < 0 ? 0 : dy;
|
||||
uint32_t ymax = dy < 0 ? dy + pattern2.height : pattern1.width;
|
||||
|
||||
// Iterate on every pixel contained in the intersection of the two pattern.
|
||||
for (unsigned y = ymin; y < ymax; y++) {
|
||||
for (unsigned x = xmin; x < xmax; x++) {
|
||||
for (uint32_t y = ymin; y < ymax; y++) {
|
||||
for (uint32_t x = xmin; x < xmax; x++) {
|
||||
// Check if the color is the same in the two patterns in that pixel.
|
||||
if (pattern1.get(y, x) != pattern2.get(y - dy, x - dx)) {
|
||||
return false;
|
||||
@ -166,13 +166,13 @@ private:
|
||||
// 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 Vector<std::array<Vector<unsigned>, 4>> generate_compatible(const Vector<Array2D<T>> &patterns) {
|
||||
Vector<std::array<Vector<unsigned>, 4>> compatible = Vector<std::array<Vector<unsigned>, 4>>(patterns.size());
|
||||
static Vector<std::array<Vector<uint32_t>, 4>> generate_compatible(const Vector<Array2D<T>> &patterns) {
|
||||
Vector<std::array<Vector<uint32_t>, 4>> compatible = Vector<std::array<Vector<uint32_t>, 4>>(patterns.size());
|
||||
|
||||
// Iterate on every dy, dx, pattern1 and pattern2
|
||||
for (unsigned pattern1 = 0; pattern1 < patterns.size(); pattern1++) {
|
||||
for (unsigned direction = 0; direction < 4; direction++) {
|
||||
for (unsigned pattern2 = 0; pattern2 < patterns.size(); pattern2++) {
|
||||
for (uint32_t pattern1 = 0; pattern1 < patterns.size(); pattern1++) {
|
||||
for (uint32_t direction = 0; direction < 4; direction++) {
|
||||
for (uint32_t pattern2 = 0; pattern2 < patterns.size(); pattern2++) {
|
||||
if (agrees(patterns[pattern1], patterns[pattern2], directions_y[direction], directions_x[direction])) {
|
||||
compatible[pattern1][direction].push_back(pattern2);
|
||||
}
|
||||
@ -184,32 +184,32 @@ private:
|
||||
}
|
||||
|
||||
// Transform a 2D array containing the patterns id to a 2D array containing the pixels.
|
||||
Array2D<T> to_image(const Array2D<unsigned> &output_patterns) const {
|
||||
Array2D<T> to_image(const Array2D<uint32_t> &output_patterns) const {
|
||||
Array2D<T> output = Array2D<T>(options.out_height, options.out_width);
|
||||
|
||||
if (options.periodic_output) {
|
||||
for (unsigned y = 0; y < options.get_wave_height(); y++) {
|
||||
for (unsigned x = 0; x < options.get_wave_width(); x++) {
|
||||
for (uint32_t y = 0; y < options.get_wave_height(); y++) {
|
||||
for (uint32_t x = 0; x < options.get_wave_width(); x++) {
|
||||
output.get(y, x) = patterns[output_patterns.get(y, x)].get(0, 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (unsigned y = 0; y < options.get_wave_height(); y++) {
|
||||
for (unsigned x = 0; x < options.get_wave_width(); x++) {
|
||||
for (uint32_t y = 0; y < options.get_wave_height(); y++) {
|
||||
for (uint32_t x = 0; x < options.get_wave_width(); x++) {
|
||||
output.get(y, x) = patterns[output_patterns.get(y, x)].get(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned y = 0; y < options.get_wave_height(); y++) {
|
||||
for (uint32_t y = 0; y < options.get_wave_height(); y++) {
|
||||
const Array2D<T> &pattern = patterns[output_patterns.get(y, options.get_wave_width() - 1)];
|
||||
for (unsigned dx = 1; dx < options.pattern_size; dx++) {
|
||||
for (uint32_t dx = 1; dx < options.pattern_size; dx++) {
|
||||
output.get(y, options.get_wave_width() - 1 + dx) = pattern.get(0, dx);
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned x = 0; x < options.get_wave_width(); x++) {
|
||||
for (uint32_t x = 0; x < options.get_wave_width(); x++) {
|
||||
const Array2D<T> &pattern = patterns[output_patterns.get(options.get_wave_height() - 1, x)];
|
||||
for (unsigned dy = 1; dy < options.pattern_size; dy++) {
|
||||
for (uint32_t dy = 1; dy < options.pattern_size; dy++) {
|
||||
output.get(options.get_wave_height() - 1 + dy, x) =
|
||||
pattern.get(dy, 0);
|
||||
}
|
||||
@ -217,8 +217,8 @@ private:
|
||||
|
||||
const Array2D<T> &pattern = patterns[output_patterns.get(options.get_wave_height() - 1, options.get_wave_width() - 1)];
|
||||
|
||||
for (unsigned dy = 1; dy < options.pattern_size; dy++) {
|
||||
for (unsigned dx = 1; dx < options.pattern_size; dx++) {
|
||||
for (uint32_t dy = 1; dy < options.pattern_size; dy++) {
|
||||
for (uint32_t dx = 1; dx < options.pattern_size; dx++) {
|
||||
output.get(options.get_wave_height() - 1 + dy, options.get_wave_width() - 1 + dx) = pattern.get(dy, dx);
|
||||
}
|
||||
}
|
||||
@ -227,8 +227,8 @@ private:
|
||||
return output;
|
||||
}
|
||||
|
||||
unsigned get_pattern_id(const Array2D<T> &pattern) {
|
||||
unsigned *pattern_id = std::find(patterns.begin(), patterns.end(), pattern);
|
||||
uint32_t get_pattern_id(const Array2D<T> &pattern) {
|
||||
uint32_t *pattern_id = std::find(patterns.begin(), patterns.end(), pattern);
|
||||
|
||||
if (pattern_id != patterns.end()) {
|
||||
return *pattern_id;
|
||||
@ -239,8 +239,8 @@ private:
|
||||
|
||||
// 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++) {
|
||||
void set_pattern(uint32_t pattern_id, uint32_t i, uint32_t j) {
|
||||
for (uint32_t p = 0; p < patterns.size(); p++) {
|
||||
if (pattern_id != p) {
|
||||
wfc.remove_wave_pattern(i, j, p);
|
||||
}
|
||||
@ -254,7 +254,7 @@ public:
|
||||
// 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<T> &pattern, unsigned i, unsigned j) {
|
||||
bool set_pattern(const Array2D<T> &pattern, uint32_t i, uint32_t j) {
|
||||
auto pattern_id = get_pattern_id(pattern);
|
||||
|
||||
if (pattern_id == std::nullopt || i >= options.get_wave_height() || j >= options.get_wave_width()) {
|
||||
@ -267,7 +267,7 @@ public:
|
||||
|
||||
// Run the WFC algorithm, and return the result if the algorithm succeeded.
|
||||
Array2D<T> run() {
|
||||
Array2D<unsigned> result = wfc.run();
|
||||
Array2D<uint32_t> result = wfc.run();
|
||||
|
||||
if (result.width == 0 && result.height == 0) {
|
||||
return Array2D<T>(0, 0);
|
||||
|
@ -4,14 +4,13 @@
|
||||
void Propagator::init_compatible() {
|
||||
std::array<int, 4> value;
|
||||
// We compute the number of pattern compatible in all directions.
|
||||
for (unsigned y = 0; y < wave_height; y++) {
|
||||
for (unsigned x = 0; x < wave_width; x++) {
|
||||
for (unsigned pattern = 0; pattern < patterns_size; pattern++) {
|
||||
for (uint32_t y = 0; y < wave_height; y++) {
|
||||
for (uint32_t x = 0; x < wave_width; x++) {
|
||||
for (uint32_t pattern = 0; pattern < patterns_size; pattern++) {
|
||||
for (int direction = 0; direction < 4; direction++) {
|
||||
value[direction] =
|
||||
static_cast<unsigned>(propagator_state[pattern][get_opposite_direction(direction)]
|
||||
.size());
|
||||
value[direction] = static_cast<uint32_t>(propagator_state[pattern][get_opposite_direction(direction)].size());
|
||||
}
|
||||
|
||||
compatible.get(y, x, pattern) = value;
|
||||
}
|
||||
}
|
||||
@ -22,12 +21,12 @@ 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.
|
||||
unsigned y1, x1, pattern;
|
||||
uint32_t y1, x1, pattern;
|
||||
std::tie(y1, x1, pattern) = propagating[propagating.size() - 1];
|
||||
propagating.resize(propagating.size() - 1);
|
||||
|
||||
// We propagate the information in all 4 directions.
|
||||
for (unsigned direction = 0; direction < 4; direction++) {
|
||||
for (uint32_t direction = 0; direction < 4; direction++) {
|
||||
// We get the next cell in the direction direction.
|
||||
int dx = directions_x[direction];
|
||||
int dy = directions_y[direction];
|
||||
@ -47,14 +46,14 @@ void Propagator::propagate(Wave &wave) {
|
||||
}
|
||||
|
||||
// The index of the second cell, and the patterns compatible
|
||||
unsigned i2 = x2 + y2 * wave.width;
|
||||
const Vector<unsigned> &patterns = propagator_state[pattern][direction];
|
||||
uint32_t i2 = x2 + y2 * wave.width;
|
||||
const Vector<uint32_t> &patterns = propagator_state[pattern][direction];
|
||||
|
||||
// For every pattern that could be placed in that cell without being in
|
||||
// contradiction with pattern1
|
||||
int size = patterns.size();
|
||||
for (int i = 0; i < size; ++i) {
|
||||
unsigned int pattern = patterns[i];
|
||||
uint32_t pattern = patterns[i];
|
||||
|
||||
// We decrease the number of compatible patterns in the opposite
|
||||
// direction If the pattern was discarded from the wave, the element
|
||||
|
@ -11,22 +11,22 @@ class Wave;
|
||||
|
||||
class Propagator {
|
||||
public:
|
||||
using PropagatorState = Vector<std::array<Vector<unsigned>, 4>>;
|
||||
using PropagatorState = Vector<std::array<Vector<uint32_t>, 4>>;
|
||||
|
||||
private:
|
||||
const uint32_t patterns_size;
|
||||
|
||||
PropagatorState propagator_state;
|
||||
|
||||
const unsigned wave_width;
|
||||
const unsigned wave_height;
|
||||
const uint32_t wave_width;
|
||||
const uint32_t wave_height;
|
||||
|
||||
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.
|
||||
Vector<std::tuple<unsigned, unsigned, unsigned>> propagating;
|
||||
Vector<std::tuple<uint32_t, uint32_t, uint32_t>> 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
|
||||
@ -38,7 +38,7 @@ private:
|
||||
void init_compatible();
|
||||
|
||||
public:
|
||||
Propagator(unsigned wave_height, unsigned wave_width, bool periodic_output,
|
||||
Propagator(uint32_t wave_height, uint32_t wave_width, bool periodic_output,
|
||||
PropagatorState propagator_state) :
|
||||
patterns_size(propagator_state.size()),
|
||||
propagator_state(propagator_state),
|
||||
@ -49,12 +49,12 @@ public:
|
||||
init_compatible();
|
||||
}
|
||||
|
||||
void add_to_propagator(unsigned y, unsigned x, unsigned pattern) {
|
||||
void add_to_propagator(uint32_t y, uint32_t x, uint32_t pattern) {
|
||||
// All the direction are set to 0, since the pattern cannot be set in (y,x).
|
||||
std::array<int, 4> temp = {};
|
||||
compatible.get(y, x, pattern) = temp;
|
||||
|
||||
propagating.push_back(std::tuple<unsigned, unsigned, unsigned>(y, x, pattern));
|
||||
propagating.push_back(std::tuple<uint32_t, uint32_t, uint32_t>(y, x, pattern));
|
||||
}
|
||||
|
||||
void propagate(Wave &wave);
|
||||
|
@ -22,7 +22,7 @@ enum class Symmetry {
|
||||
// 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) {
|
||||
constexpr uint32_t nb_of_possible_orientations(const Symmetry &symmetry) {
|
||||
switch (symmetry) {
|
||||
case Symmetry::X:
|
||||
return 1;
|
||||
@ -46,7 +46,7 @@ struct Tile {
|
||||
|
||||
// Generate the map associating an orientation id to the orientation
|
||||
// id obtained when rotating 90° anticlockwise the tile.
|
||||
static Vector<unsigned> generate_rotation_map(const Symmetry &symmetry) {
|
||||
static Vector<uint32_t> generate_rotation_map(const Symmetry &symmetry) {
|
||||
switch (symmetry) {
|
||||
case Symmetry::X:
|
||||
return { 0 };
|
||||
@ -64,7 +64,7 @@ struct Tile {
|
||||
|
||||
// Generate the map associating an orientation id to the orientation
|
||||
// id obtained when reflecting the tile along the x axis.
|
||||
static Vector<unsigned> generate_reflection_map(const Symmetry &symmetry) {
|
||||
static Vector<uint32_t> generate_reflection_map(const Symmetry &symmetry) {
|
||||
switch (symmetry) {
|
||||
case Symmetry::X:
|
||||
return { 0 };
|
||||
@ -87,12 +87,12 @@ struct Tile {
|
||||
// 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 Vector<Vector<unsigned>> generate_action_map(const Symmetry &symmetry) {
|
||||
Vector<unsigned> rotation_map = generate_rotation_map(symmetry);
|
||||
Vector<unsigned> reflection_map = generate_reflection_map(symmetry);
|
||||
static Vector<Vector<uint32_t>> generate_action_map(const Symmetry &symmetry) {
|
||||
Vector<uint32_t> rotation_map = generate_rotation_map(symmetry);
|
||||
Vector<uint32_t> reflection_map = generate_reflection_map(symmetry);
|
||||
size_t size = rotation_map.size();
|
||||
Vector<Vector<unsigned>> action_map(8,
|
||||
Vector<unsigned>(size));
|
||||
Vector<Vector<uint32_t>> action_map(8,
|
||||
Vector<uint32_t>(size));
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
action_map[0][i] = i;
|
||||
}
|
||||
@ -167,29 +167,29 @@ template <typename T>
|
||||
class TilingWFC {
|
||||
private:
|
||||
Vector<Tile<T>> tiles;
|
||||
Vector<std::pair<unsigned, unsigned>> id_to_oriented_tile;
|
||||
Vector<Vector<unsigned>> oriented_tile_ids;
|
||||
Vector<std::pair<uint32_t, uint32_t>> id_to_oriented_tile;
|
||||
Vector<Vector<uint32_t>> oriented_tile_ids;
|
||||
|
||||
TilingWFCOptions options;
|
||||
|
||||
WFC wfc;
|
||||
|
||||
public:
|
||||
unsigned height;
|
||||
unsigned width;
|
||||
uint32_t height;
|
||||
uint32_t width;
|
||||
|
||||
private:
|
||||
// Generate mapping from id to oriented tiles and vice versa.
|
||||
static std::pair<Vector<std::pair<unsigned, unsigned>>,
|
||||
Vector<Vector<unsigned>>>
|
||||
static std::pair<Vector<std::pair<uint32_t, uint32_t>>,
|
||||
Vector<Vector<uint32_t>>>
|
||||
generate_oriented_tile_ids(const Vector<Tile<T>> &tiles) {
|
||||
Vector<std::pair<unsigned, unsigned>> id_to_oriented_tile;
|
||||
Vector<Vector<unsigned>> oriented_tile_ids;
|
||||
Vector<std::pair<uint32_t, uint32_t>> id_to_oriented_tile;
|
||||
Vector<Vector<uint32_t>> oriented_tile_ids;
|
||||
|
||||
unsigned id = 0;
|
||||
for (unsigned i = 0; i < tiles.size(); i++) {
|
||||
uint32_t id = 0;
|
||||
for (uint32_t i = 0; i < tiles.size(); i++) {
|
||||
oriented_tile_ids.push_back({});
|
||||
for (unsigned j = 0; j < tiles[i].data.size(); j++) {
|
||||
for (uint32_t j = 0; j < tiles[i].data.size(); j++) {
|
||||
id_to_oriented_tile.push_back({ i, j });
|
||||
oriented_tile_ids[i].push_back(id);
|
||||
id++;
|
||||
@ -200,31 +200,31 @@ private:
|
||||
}
|
||||
|
||||
// Generate the propagator which will be used in the wfc algorithm.
|
||||
static Vector<std::array<Vector<unsigned>, 4>> generate_propagator(
|
||||
const Vector<std::tuple<unsigned, unsigned, unsigned, unsigned>> &neighbors,
|
||||
static Vector<std::array<Vector<uint32_t>, 4>> generate_propagator(
|
||||
const Vector<std::tuple<uint32_t, uint32_t, uint32_t, uint32_t>> &neighbors,
|
||||
Vector<Tile<T>> tiles,
|
||||
Vector<std::pair<unsigned, unsigned>> id_to_oriented_tile,
|
||||
Vector<Vector<unsigned>> oriented_tile_ids) {
|
||||
Vector<std::pair<uint32_t, uint32_t>> id_to_oriented_tile,
|
||||
Vector<Vector<uint32_t>> oriented_tile_ids) {
|
||||
|
||||
size_t nb_oriented_tiles = id_to_oriented_tile.size();
|
||||
Vector<std::array<Vector<bool>, 4>> dense_propagator(
|
||||
nb_oriented_tiles, { Vector<bool>(nb_oriented_tiles, false), Vector<bool>(nb_oriented_tiles, false), Vector<bool>(nb_oriented_tiles, false), Vector<bool>(nb_oriented_tiles, false) });
|
||||
|
||||
for (auto neighbor : neighbors) {
|
||||
unsigned tile1 = std::get<0>(neighbor);
|
||||
unsigned orientation1 = std::get<1>(neighbor);
|
||||
unsigned tile2 = std::get<2>(neighbor);
|
||||
unsigned orientation2 = std::get<3>(neighbor);
|
||||
Vector<Vector<unsigned>> action_map1 =
|
||||
uint32_t tile1 = std::get<0>(neighbor);
|
||||
uint32_t orientation1 = std::get<1>(neighbor);
|
||||
uint32_t tile2 = std::get<2>(neighbor);
|
||||
uint32_t orientation2 = std::get<3>(neighbor);
|
||||
Vector<Vector<uint32_t>> action_map1 =
|
||||
Tile<T>::generate_action_map(tiles[tile1].symmetry);
|
||||
Vector<Vector<unsigned>> action_map2 =
|
||||
Vector<Vector<uint32_t>> action_map2 =
|
||||
Tile<T>::generate_action_map(tiles[tile2].symmetry);
|
||||
|
||||
auto add = [&](unsigned action, unsigned direction) {
|
||||
unsigned temp_orientation1 = action_map1[action][orientation1];
|
||||
unsigned temp_orientation2 = action_map2[action][orientation2];
|
||||
unsigned oriented_tile_id1 = oriented_tile_ids[tile1][temp_orientation1];
|
||||
unsigned oriented_tile_id2 = oriented_tile_ids[tile2][temp_orientation2];
|
||||
auto add = [&](uint32_t action, uint32_t direction) {
|
||||
uint32_t temp_orientation1 = action_map1[action][orientation1];
|
||||
uint32_t temp_orientation2 = action_map2[action][orientation2];
|
||||
uint32_t oriented_tile_id1 = oriented_tile_ids[tile1][temp_orientation1];
|
||||
uint32_t oriented_tile_id2 = oriented_tile_ids[tile2][temp_orientation2];
|
||||
dense_propagator[oriented_tile_id1][direction][oriented_tile_id2] = true;
|
||||
direction = get_opposite_direction(direction);
|
||||
dense_propagator[oriented_tile_id2][direction][oriented_tile_id1] = true;
|
||||
@ -240,7 +240,7 @@ private:
|
||||
add(7, 0);
|
||||
}
|
||||
|
||||
Vector<std::array<Vector<unsigned>, 4>> propagator(nb_oriented_tiles);
|
||||
Vector<std::array<Vector<uint32_t>, 4>> propagator(nb_oriented_tiles);
|
||||
|
||||
for (size_t i = 0; i < nb_oriented_tiles; ++i) {
|
||||
for (size_t j = 0; j < nb_oriented_tiles; ++j) {
|
||||
@ -269,16 +269,16 @@ private:
|
||||
}
|
||||
|
||||
// Translate the generic WFC result into the image result
|
||||
Array2D<T> id_to_tiling(Array2D<unsigned> ids) {
|
||||
unsigned size = tiles[0].data[0].height;
|
||||
Array2D<T> id_to_tiling(Array2D<uint32_t> ids) {
|
||||
uint32_t size = tiles[0].data[0].height;
|
||||
Array2D<T> tiling(size * ids.height, size * ids.width);
|
||||
|
||||
for (unsigned i = 0; i < ids.height; i++) {
|
||||
for (unsigned j = 0; j < ids.width; j++) {
|
||||
std::pair<unsigned, unsigned> oriented_tile = id_to_oriented_tile[ids.get(i, j)];
|
||||
for (uint32_t i = 0; i < ids.height; i++) {
|
||||
for (uint32_t j = 0; j < ids.width; j++) {
|
||||
std::pair<uint32_t, uint32_t> oriented_tile = id_to_oriented_tile[ids.get(i, j)];
|
||||
|
||||
for (unsigned y = 0; y < size; y++) {
|
||||
for (unsigned x = 0; x < size; x++) {
|
||||
for (uint32_t y = 0; y < size; y++) {
|
||||
for (uint32_t x = 0; x < size; x++) {
|
||||
tiling.get(i * size + y, j * size + x) = tiles[oriented_tile.first].data[oriented_tile.second].get(y, x);
|
||||
}
|
||||
}
|
||||
@ -288,8 +288,8 @@ private:
|
||||
return tiling;
|
||||
}
|
||||
|
||||
void set_tile(unsigned tile_id, unsigned i, unsigned j) {
|
||||
for (unsigned p = 0; p < id_to_oriented_tile.size(); p++) {
|
||||
void set_tile(uint32_t tile_id, uint32_t i, uint32_t j) {
|
||||
for (uint32_t p = 0; p < id_to_oriented_tile.size(); p++) {
|
||||
if (tile_id != p) {
|
||||
wfc.remove_wave_pattern(i, j, p);
|
||||
}
|
||||
@ -300,9 +300,9 @@ public:
|
||||
// Construct the TilingWFC class to generate a tiled image.
|
||||
TilingWFC(
|
||||
const Vector<Tile<T>> &tiles,
|
||||
const Vector<std::tuple<unsigned, unsigned, unsigned, unsigned>>
|
||||
const Vector<std::tuple<uint32_t, uint32_t, uint32_t, uint32_t>>
|
||||
&neighbors,
|
||||
const unsigned height, const unsigned width,
|
||||
const uint32_t height, const uint32_t width,
|
||||
const TilingWFCOptions &options, int seed) :
|
||||
tiles(tiles),
|
||||
id_to_oriented_tile(generate_oriented_tile_ids(tiles).first),
|
||||
@ -318,19 +318,19 @@ public:
|
||||
// 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) {
|
||||
bool set_tile(uint32_t tile_id, uint32_t orientation, uint32_t i, uint32_t j) {
|
||||
if (tile_id >= oriented_tile_ids.size() || orientation >= oriented_tile_ids[tile_id].size() || i >= height || j >= width) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned oriented_tile_id = oriented_tile_ids[tile_id][orientation];
|
||||
uint32_t oriented_tile_id = oriented_tile_ids[tile_id][orientation];
|
||||
set_tile(oriented_tile_id, i, j);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Run the tiling wfc and return the result if the algorithm succeeded
|
||||
Array2D<T> run() {
|
||||
Array2D<unsigned> a = wfc.run();
|
||||
Array2D<uint32_t> a = wfc.run();
|
||||
|
||||
if (a.width == 0 && a.height == 0) {
|
||||
return Array2D<T>(0, 0);
|
||||
|
@ -8,7 +8,7 @@ namespace {
|
||||
Vector<double> get_plogp(const Vector<double> &distribution) {
|
||||
Vector<double> plogp;
|
||||
|
||||
for (unsigned i = 0; i < distribution.size(); i++) {
|
||||
for (uint32_t i = 0; i < distribution.size(); i++) {
|
||||
plogp.push_back(distribution[i] * log(distribution[i]));
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ Vector<double> get_plogp(const Vector<double> &distribution) {
|
||||
double get_min_abs_half(const Vector<double> &v) {
|
||||
double min_abs_half = std::numeric_limits<double>::infinity();
|
||||
|
||||
for (unsigned i = 0; i < v.size(); i++) {
|
||||
for (uint32_t i = 0; i < v.size(); i++) {
|
||||
min_abs_half = std::min(min_abs_half, std::abs(v[i] / 2.0));
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ double get_min_abs_half(const Vector<double> &v) {
|
||||
|
||||
} // namespace
|
||||
|
||||
Wave::Wave(unsigned height, unsigned width,
|
||||
Wave::Wave(uint32_t height, uint32_t width,
|
||||
const Vector<double> &patterns_frequencies) :
|
||||
patterns_frequencies(patterns_frequencies),
|
||||
plogp_patterns_frequencies(get_plogp(patterns_frequencies)),
|
||||
@ -44,7 +44,7 @@ Wave::Wave(unsigned height, unsigned width,
|
||||
double base_entropy = 0;
|
||||
double base_s = 0;
|
||||
|
||||
for (unsigned i = 0; i < nb_patterns; i++) {
|
||||
for (uint32_t i = 0; i < nb_patterns; i++) {
|
||||
base_entropy += plogp_patterns_frequencies[i];
|
||||
base_s += patterns_frequencies[i];
|
||||
}
|
||||
@ -62,13 +62,13 @@ Wave::Wave(unsigned height, unsigned width,
|
||||
memoisation.log_sum.fill(log_base_s);
|
||||
|
||||
memoisation.nb_patterns.resize(width * height);
|
||||
memoisation.nb_patterns.fill(static_cast<unsigned>(nb_patterns));
|
||||
memoisation.nb_patterns.fill(static_cast<uint32_t>(nb_patterns));
|
||||
|
||||
memoisation.entropy.resize(width * height);
|
||||
memoisation.entropy.fill(entropy_base);
|
||||
}
|
||||
|
||||
void Wave::set(unsigned index, unsigned pattern, bool value) {
|
||||
void Wave::set(uint32_t index, uint32_t pattern, bool value) {
|
||||
bool old_value = data.get(index, pattern);
|
||||
|
||||
// If the value isn't changed, nothing needs to be done.
|
||||
@ -101,7 +101,7 @@ int Wave::get_min_entropy(std::minstd_rand &gen) const {
|
||||
double min = std::numeric_limits<double>::infinity();
|
||||
int argmin = -1;
|
||||
|
||||
for (unsigned i = 0; i < size; i++) {
|
||||
for (uint32_t i = 0; i < size; i++) {
|
||||
// If the cell is decided, we do not compute the entropy (which is equal
|
||||
// to 0).
|
||||
double nb_patterns_local = memoisation.nb_patterns[i];
|
||||
|
@ -13,7 +13,7 @@ struct EntropyMemoisation {
|
||||
Vector<double> plogp_sum; // The sum of p'(pattern)// log(p'(pattern)).
|
||||
Vector<double> sum; // The sum of p'(pattern).
|
||||
Vector<double> log_sum; // The log of sum.
|
||||
Vector<unsigned> nb_patterns; // The number of patterns present
|
||||
Vector<uint32_t> nb_patterns; // The number of patterns present
|
||||
Vector<double> entropy; // The entropy of the cell.
|
||||
};
|
||||
|
||||
@ -45,28 +45,28 @@ private:
|
||||
|
||||
public:
|
||||
// The size of the wave.
|
||||
const unsigned width;
|
||||
const unsigned height;
|
||||
const unsigned size;
|
||||
const uint32_t width;
|
||||
const uint32_t height;
|
||||
const uint32_t size;
|
||||
|
||||
// Initialize the wave with every cell being able to have every pattern.
|
||||
Wave(unsigned height, unsigned width, const Vector<double> &patterns_frequencies);
|
||||
Wave(uint32_t height, uint32_t width, const Vector<double> &patterns_frequencies);
|
||||
|
||||
// Return true if pattern can be placed in cell index.
|
||||
bool get(unsigned index, unsigned pattern) const {
|
||||
bool get(uint32_t index, uint32_t 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 {
|
||||
bool get(uint32_t i, uint32_t j, uint32_t pattern) const {
|
||||
return get(i * width + j, pattern);
|
||||
}
|
||||
|
||||
// Set the value of pattern in cell index.
|
||||
void set(unsigned index, unsigned pattern, bool value);
|
||||
void set(uint32_t index, uint32_t pattern, bool value);
|
||||
|
||||
// Set the value of pattern in cell (i,j).
|
||||
void set(unsigned i, unsigned j, unsigned pattern, bool value) {
|
||||
void set(uint32_t i, uint32_t j, uint32_t pattern, bool value) {
|
||||
set(i * width + j, pattern, value);
|
||||
}
|
||||
|
||||
|
@ -21,11 +21,11 @@ Vector<double> &normalize(Vector<double> &v) {
|
||||
}
|
||||
} //namespace
|
||||
|
||||
Array2D<unsigned> WFC::wave_to_output() const {
|
||||
Array2D<unsigned> output_patterns(wave.height, wave.width);
|
||||
Array2D<uint32_t> WFC::wave_to_output() const {
|
||||
Array2D<uint32_t> output_patterns(wave.height, wave.width);
|
||||
|
||||
for (unsigned i = 0; i < wave.size; i++) {
|
||||
for (unsigned k = 0; k < nb_patterns; k++) {
|
||||
for (uint32_t i = 0; i < wave.size; i++) {
|
||||
for (uint32_t k = 0; k < nb_patterns; k++) {
|
||||
if (wave.get(i, k)) {
|
||||
output_patterns.data.write[i] = k;
|
||||
}
|
||||
@ -36,18 +36,18 @@ Array2D<unsigned> WFC::wave_to_output() const {
|
||||
|
||||
WFC::WFC(bool periodic_output, int seed,
|
||||
Vector<double> patterns_frequencies,
|
||||
Propagator::PropagatorState propagator, unsigned wave_height,
|
||||
unsigned wave_width) :
|
||||
Propagator::PropagatorState propagator, uint32_t wave_height,
|
||||
uint32_t 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) {}
|
||||
|
||||
Array2D<unsigned> WFC::run() {
|
||||
Array2D<uint32_t> WFC::run() {
|
||||
while (true) {
|
||||
// Define the value of an undefined cell.
|
||||
ObserveStatus result = observe();
|
||||
|
||||
// Check if the algorithm has terminated.
|
||||
if (result == failure) {
|
||||
return Array2D<unsigned>(0, 0);
|
||||
return Array2D<uint32_t>(0, 0);
|
||||
} else if (result == success) {
|
||||
return wave_to_output();
|
||||
}
|
||||
@ -75,7 +75,7 @@ WFC::ObserveStatus WFC::observe() {
|
||||
|
||||
// Choose an element according to the pattern distribution
|
||||
double s = 0;
|
||||
for (unsigned k = 0; k < nb_patterns; k++) {
|
||||
for (uint32_t k = 0; k < nb_patterns; k++) {
|
||||
s += wave.get(argmin, k) ? patterns_frequencies[k] : 0;
|
||||
}
|
||||
|
||||
@ -83,7 +83,7 @@ WFC::ObserveStatus WFC::observe() {
|
||||
double random_value = dis(gen);
|
||||
size_t chosen_value = nb_patterns - 1;
|
||||
|
||||
for (unsigned k = 0; k < nb_patterns; k++) {
|
||||
for (uint32_t k = 0; k < nb_patterns; k++) {
|
||||
random_value -= wave.get(argmin, k) ? patterns_frequencies[k] : 0;
|
||||
if (random_value <= 0) {
|
||||
chosen_value = k;
|
||||
@ -92,7 +92,7 @@ WFC::ObserveStatus WFC::observe() {
|
||||
}
|
||||
|
||||
// And define the cell with the pattern.
|
||||
for (unsigned k = 0; k < nb_patterns; k++) {
|
||||
for (uint32_t k = 0; k < nb_patterns; k++) {
|
||||
if (wave.get(argmin, k) != (k == chosen_value)) {
|
||||
propagator.add_to_propagator(argmin / wave.width, argmin % wave.width, k);
|
||||
wave.set(argmin, k, false);
|
||||
|
@ -28,16 +28,16 @@ private:
|
||||
// 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<unsigned> wave_to_output() const;
|
||||
Array2D<uint32_t> wave_to_output() const;
|
||||
|
||||
public:
|
||||
// Basic constructor initializing the algorithm.
|
||||
WFC(bool periodic_output, int seed, Vector<double> patterns_frequencies,
|
||||
Propagator::PropagatorState propagator, unsigned wave_height,
|
||||
unsigned wave_width);
|
||||
Propagator::PropagatorState propagator, uint32_t wave_height,
|
||||
uint32_t wave_width);
|
||||
|
||||
// Run the algorithm, and return a result if it succeeded.
|
||||
Array2D<unsigned> run();
|
||||
Array2D<uint32_t> run();
|
||||
|
||||
// Return value of observe.
|
||||
enum ObserveStatus {
|
||||
@ -53,7 +53,7 @@ public:
|
||||
void propagate() { propagator.propagate(wave); }
|
||||
|
||||
// Remove pattern from cell (i,j).
|
||||
void remove_wave_pattern(unsigned i, unsigned j, unsigned pattern) {
|
||||
void remove_wave_pattern(uint32_t i, uint32_t j, uint32_t pattern) {
|
||||
if (wave.get(i, j, pattern)) {
|
||||
wave.set(i, j, pattern, false);
|
||||
propagator.add_to_propagator(i, j, pattern);
|
||||
|
Loading…
Reference in New Issue
Block a user