mirror of
https://github.com/JustinSDK/dotSCAD.git
synced 2025-08-08 15:56:42 +02:00
optimization
This commit is contained in:
@@ -55,7 +55,7 @@ function get_state_weight(weights, state) = weights[search([state], weights)[0]]
|
|||||||
|
|
||||||
function wf_collapse(wf, x, y, weights) =
|
function wf_collapse(wf, x, y, weights) =
|
||||||
let(
|
let(
|
||||||
states = wf_eigenstates_at(wf, x, y),
|
states = wf_eigenstates(wf)[y][x],
|
||||||
threshold = rand() * sum(weights)
|
threshold = rand() * sum(weights)
|
||||||
)
|
)
|
||||||
_wf_collapse(wf, x, y, states, weights, len(states), threshold);
|
_wf_collapse(wf, x, y, states, weights, len(states), threshold);
|
||||||
@@ -71,7 +71,7 @@ function _wf_collapse(wf, x, y, states, weights, leng, threshold, i = 0) =
|
|||||||
function wf_entropy_weights(wf, x, y) =
|
function wf_entropy_weights(wf, x, y) =
|
||||||
let(
|
let(
|
||||||
all_weights = wf_weights(wf),
|
all_weights = wf_weights(wf),
|
||||||
weights = [for(state = wf_eigenstates_at(wf, x, y)) get_state_weight(all_weights, state)],
|
weights = [for(state = wf_eigenstates(wf)[y][x]) get_state_weight(all_weights, state)],
|
||||||
sumOfWeights = sum(weights),
|
sumOfWeights = sum(weights),
|
||||||
sumOfWeightLogWeights = sum([for(w = weights) w * ln(w)])
|
sumOfWeightLogWeights = sum([for(w = weights) w * ln(w)])
|
||||||
)
|
)
|
||||||
@@ -87,14 +87,13 @@ function _replaceStatesAt(wf, x, y, states) =
|
|||||||
|
|
||||||
function wf_not_collapsed_coords(wf, notCollaspedCoords) =
|
function wf_not_collapsed_coords(wf, notCollaspedCoords) =
|
||||||
is_undef(notCollaspedCoords) ?
|
is_undef(notCollaspedCoords) ?
|
||||||
let(rx = [0:wf_width(wf) - 1])
|
|
||||||
[
|
[
|
||||||
for(y = [0:wf_height(wf) - 1], x = rx)
|
for(y = [0:wf_height(wf) - 1], x = [0:wf_width(wf) - 1])
|
||||||
if(len(wf_eigenstates_at(wf, x, y)) != 1) [x, y]
|
if(len(wf_eigenstates(wf)[y][x]) != 1) [x, y]
|
||||||
] :
|
] :
|
||||||
[
|
[
|
||||||
for(coord = notCollaspedCoords)
|
for(coord = notCollaspedCoords)
|
||||||
if(len(wf_eigenstates_at(wf, coord.x, coord.y)) != 1) coord
|
if(len(wf_eigenstates(wf)[coord.y][coord.x]) != 1) coord
|
||||||
];
|
];
|
||||||
|
|
||||||
function wf_coord_weights_min_entropy(wf, notCollaspedCoords) =
|
function wf_coord_weights_min_entropy(wf, notCollaspedCoords) =
|
||||||
@@ -104,8 +103,11 @@ function wf_coord_weights_min_entropy(wf, notCollaspedCoords) =
|
|||||||
let(x = coord.x, y = coord.y)
|
let(x = coord.x, y = coord.y)
|
||||||
[x, y, wf_entropy_weights(wf, x, y)]
|
[x, y, wf_entropy_weights(wf, x, y)]
|
||||||
],
|
],
|
||||||
m = coord_entropy_weights_lt[0],
|
min_coord_entropy_weights = _coord_entropy_weights(
|
||||||
min_coord_entropy_weights = _coord_entropy_weights(coord_entropy_weights_lt, len(coord_entropy_weights_lt), m)
|
coord_entropy_weights_lt,
|
||||||
|
len(coord_entropy_weights_lt),
|
||||||
|
coord_entropy_weights_lt[0]
|
||||||
|
)
|
||||||
)
|
)
|
||||||
[min_coord_entropy_weights.x, min_coord_entropy_weights.y, min_coord_entropy_weights[2][1]];
|
[min_coord_entropy_weights.x, min_coord_entropy_weights.y, min_coord_entropy_weights[2][1]];
|
||||||
|
|
||||||
@@ -122,10 +124,10 @@ function _coord_entropy_weights(coord_entropy_weights_lt, leng, m, i = 1) =
|
|||||||
- tilemap_wf(tm)
|
- tilemap_wf(tm)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function tilemap(width, height, sample) = [
|
function tilemap(width, height, sample, nbr_dirs) = [
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
compatibilities_of_tiles(sample),
|
compatibilities_of_tiles(sample, nbr_dirs),
|
||||||
wave_function(width, height, weights_of_tiles(sample))
|
wave_function(width, height, weights_of_tiles(sample))
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -134,66 +136,60 @@ function tilemap_height(tm) = tm[1];
|
|||||||
function tilemap_compatibilities(tm) = tm[2];
|
function tilemap_compatibilities(tm) = tm[2];
|
||||||
function tilemap_wf(tm) = tm[3];
|
function tilemap_wf(tm) = tm[3];
|
||||||
|
|
||||||
function propagate(w, h, compatibilities, wf, x, y) =
|
function propagate(nbr_dirs, compatibilities, wf, coord) =
|
||||||
_propagate(
|
_propagate(
|
||||||
w,
|
nbr_dirs,
|
||||||
h,
|
|
||||||
compatibilities,
|
compatibilities,
|
||||||
wf,
|
[wf, create_stack(coord)]
|
||||||
create_stack([x, y])
|
|
||||||
);
|
);
|
||||||
|
|
||||||
function _propagate(w, h, compatibilities, wf, stack) =
|
function _propagate(nbr_dirs, compatibilities, wf_stack) =
|
||||||
|
let(wf = wf_stack[0], stack = wf_stack[1])
|
||||||
stack == [] ? wf :
|
stack == [] ? wf :
|
||||||
let(
|
let(
|
||||||
current_coord = stack[0],
|
current_coord = stack[0],
|
||||||
cs = stack[1],
|
|
||||||
cx = current_coord.x,
|
cx = current_coord.x,
|
||||||
cy = current_coord.y,
|
cy = current_coord.y,
|
||||||
current_tiles = wf_eigenstates_at(wf, cx, cy),
|
current_tiles = wf_eigenstates(wf)[cy][cx],
|
||||||
dirs = neighbor_dirs(cx, cy, w, h),
|
dirs = nbr_dirs[cy][cx],
|
||||||
wf_stack = _doDirs(compatibilities, wf, cs, cx, cy, current_tiles, dirs, len(dirs))
|
nx_wf_stack = _doDirs(compatibilities, [wf, stack[1]], current_coord, current_tiles, dirs, len(dirs))
|
||||||
)
|
)
|
||||||
_propagate(w, h, compatibilities, wf_stack[0], wf_stack[1]);
|
_propagate(nbr_dirs, compatibilities, nx_wf_stack);
|
||||||
|
|
||||||
function _doDirs(compatibilities, wf, stack, cx, cy, current_tiles, dirs, leng, i = 0) =
|
contradiction_msg = "A contradiction happens. Tiles have all been ruled out by your previous choices. Please try again.";
|
||||||
i == leng ? [wf, stack] :
|
function _doDirs(compatibilities, wf_stack, current_coord, current_tiles, dirs, leng, i = 0) =
|
||||||
|
i == leng ? wf_stack :
|
||||||
let(
|
let(
|
||||||
dir = dirs[i],
|
dir = dirs[i],
|
||||||
nbrx = cx + dir[0],
|
nbr = dir + current_coord,
|
||||||
nbry = cy + dir[1],
|
nbr_tiles = wf_eigenstates(wf_stack[0])[nbr.y][nbr.x],
|
||||||
nbr_tiles = wf_eigenstates_at(wf, nbrx, nbry),
|
|
||||||
compatible_nbr_tiles = [
|
compatible_nbr_tiles = [
|
||||||
for(nbr_tile = nbr_tiles)
|
for(nbr_tile = nbr_tiles)
|
||||||
if(compatible_nbr_tile(compatibilities, current_tiles, nbr_tile, dir)) nbr_tile
|
if(compatible_nbr_tile(compatibilities, current_tiles, nbr_tile, dir)) nbr_tile
|
||||||
],
|
],
|
||||||
leng_compatible_nbr_tiles = len(compatible_nbr_tiles),
|
leng_compatible_nbr_tiles = len(compatible_nbr_tiles),
|
||||||
|
|
||||||
wf_stack =
|
mx_wf_stack =
|
||||||
assert(leng_compatible_nbr_tiles > 0,
|
assert(leng_compatible_nbr_tiles > 0, contradiction_msg)
|
||||||
str("(", nbrx, ", ", nbry, ")",
|
|
||||||
" reaches a contradiction. Tiles have all been ruled out by your previous choices. Please try again."))
|
|
||||||
|
|
||||||
leng_compatible_nbr_tiles == len(nbr_tiles) ?
|
leng_compatible_nbr_tiles == len(nbr_tiles) ?
|
||||||
[wf, stack]
|
wf_stack
|
||||||
:
|
:
|
||||||
[
|
[
|
||||||
_replaceStatesAt(wf, nbrx, nbry, compatible_nbr_tiles),
|
_replaceStatesAt(wf_stack[0], nbr.x, nbr.y, compatible_nbr_tiles),
|
||||||
stack_push(stack, [nbrx, nbry])
|
stack_push(wf_stack[1], nbr)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
_doDirs(compatibilities, wf_stack[0], wf_stack[1], cx, cy, current_tiles, dirs, leng, i + 1);
|
_doDirs(compatibilities, mx_wf_stack, current_coord, current_tiles, dirs, leng, i + 1);
|
||||||
|
|
||||||
function generate(w, h, compatibilities, wf, notCollaspedCoords) =
|
function generate(nbr_dirs, compatibilities, wf, notCollaspedCoords) =
|
||||||
len(notCollaspedCoords) == 0 ? collapsed_tiles(wf) :
|
len(notCollaspedCoords) == 0 ? collapsed_tiles(wf) :
|
||||||
let(
|
let(
|
||||||
coord_weights = wf_coord_weights_min_entropy(wf, notCollaspedCoords),
|
coord_weights = wf_coord_weights_min_entropy(wf, notCollaspedCoords),
|
||||||
x = coord_weights.x,
|
|
||||||
y = coord_weights.y,
|
|
||||||
weights = coord_weights[2],
|
weights = coord_weights[2],
|
||||||
nwf = propagate(w, h, compatibilities, wf_collapse(wf, x, y, weights), x, y)
|
nwf = propagate(nbr_dirs, compatibilities, wf_collapse(wf, coord_weights.x, coord_weights.y, weights), coord_weights)
|
||||||
)
|
)
|
||||||
generate(w, h, compatibilities, nwf, wf_not_collapsed_coords(nwf));
|
generate(nbr_dirs, compatibilities, nwf, wf_not_collapsed_coords(nwf));
|
||||||
|
|
||||||
function neighbor_dirs(x, y, width, height) = [
|
function neighbor_dirs(x, y, width, height) = [
|
||||||
if(x > 0) [-1, 0], // left
|
if(x > 0) [-1, 0], // left
|
||||||
@@ -202,11 +198,11 @@ function neighbor_dirs(x, y, width, height) = [
|
|||||||
if(y < height - 1) [ 0, 1] // bottom
|
if(y < height - 1) [ 0, 1] // bottom
|
||||||
];
|
];
|
||||||
|
|
||||||
function neighbor_compatibilities(sample, x, y, width, height) =
|
function neighbor_compatibilities(sample, x, y, nbr_dirs) =
|
||||||
let(me = sample[y][x])
|
let(me = sample[y][x])
|
||||||
[for(dir = neighbor_dirs(x, y, width, height)) [me, sample[y + dir[1]][x + dir[0]], dir]];
|
[for(dir = nbr_dirs[y][x]) [me, sample[y + dir.y][x + dir.x], dir]];
|
||||||
|
|
||||||
function compatibilities_of_tiles(sample) =
|
function compatibilities_of_tiles(sample, nbr_dirs) =
|
||||||
let(
|
let(
|
||||||
width = len(sample[0]),
|
width = len(sample[0]),
|
||||||
height = len(sample),
|
height = len(sample),
|
||||||
@@ -214,7 +210,7 @@ function compatibilities_of_tiles(sample) =
|
|||||||
)
|
)
|
||||||
hashset_elems(hashset([
|
hashset_elems(hashset([
|
||||||
for(y = [0:height - 1], x = rx)
|
for(y = [0:height - 1], x = rx)
|
||||||
each neighbor_compatibilities(sample, x, y, width, height)
|
each neighbor_compatibilities(sample, x, y, nbr_dirs)
|
||||||
], number_of_buckets = width * height));
|
], number_of_buckets = width * height));
|
||||||
|
|
||||||
function collapsed_tiles(wf) =
|
function collapsed_tiles(wf) =
|
||||||
@@ -225,7 +221,8 @@ function collapsed_tiles(wf) =
|
|||||||
)
|
)
|
||||||
[
|
[
|
||||||
for(y = [0:wf_h - 1])
|
for(y = [0:wf_h - 1])
|
||||||
[for(x = rx) wf_eigenstates_at(wf, x, y)[0]]
|
let(wfy = wf_eigenstates(wf)[y])
|
||||||
|
[for(x = rx) wfy[x][0]]
|
||||||
];
|
];
|
||||||
|
|
||||||
function compatible_nbr_tile(compatibilities, current_tiles, nbr_tile, dir) =
|
function compatible_nbr_tile(compatibilities, current_tiles, nbr_tile, dir) =
|
||||||
|
@@ -4,28 +4,30 @@ use <../util/rand.scad>;
|
|||||||
// An implementation of [Wave Function Collapse](https://github.com/mxgmn/WaveFunctionCollapse)
|
// An implementation of [Wave Function Collapse](https://github.com/mxgmn/WaveFunctionCollapse)
|
||||||
function tile_wfc(size, sample) =
|
function tile_wfc(size, sample) =
|
||||||
let(
|
let(
|
||||||
tm = tilemap(size[0], size[1], sample),
|
w = size.x,
|
||||||
|
h = size.y,
|
||||||
|
nbr_dirs = [
|
||||||
|
for(y = [0:h - 1])
|
||||||
|
[for(x = [0:w - 1]) neighbor_dirs(x, y, w, h)]
|
||||||
|
],
|
||||||
|
tm = tilemap(w, h, sample, nbr_dirs),
|
||||||
// random start
|
// random start
|
||||||
x = floor(rand(size[0] * 0.25, size[0] * 0.75)),
|
x = floor(rand(w * 0.25, w * 0.75)),
|
||||||
y = floor(rand(size[1] * 0.25, size[1] * 0.75)),
|
y = floor(rand(h * 0.25, h * 0.75)),
|
||||||
w = tilemap_width(tm),
|
|
||||||
h = tilemap_height(tm),
|
|
||||||
compatibilities = tilemap_compatibilities(tm),
|
compatibilities = tilemap_compatibilities(tm),
|
||||||
wf = tilemap_wf(tm),
|
wf = tilemap_wf(tm),
|
||||||
all_weights = wf_weights(wf),
|
all_weights = wf_weights(wf),
|
||||||
states = wf_eigenstates_at(wf, x, y),
|
states = wf_eigenstates_at(wf, x, y),
|
||||||
weights = [for(state = states) get_state_weight(all_weights, state)],
|
weights = [for(state = states) get_state_weight(all_weights, state)],
|
||||||
first_collasped_propagated = propagate(
|
first_collasped_propagated = propagate(
|
||||||
w,
|
nbr_dirs,
|
||||||
h,
|
|
||||||
compatibilities,
|
compatibilities,
|
||||||
wf_collapse(wf, x, y, weights),
|
wf_collapse(wf, x, y, weights),
|
||||||
x,
|
[x, y]
|
||||||
y
|
|
||||||
),
|
),
|
||||||
notCollapsedCoords = wf_not_collapsed_coords(first_collasped_propagated)
|
notCollapsedCoords = wf_not_collapsed_coords(first_collasped_propagated)
|
||||||
)
|
)
|
||||||
generate(w, h, compatibilities, first_collasped_propagated, notCollapsedCoords);
|
generate(nbr_dirs, compatibilities, first_collasped_propagated, notCollapsedCoords);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user