mirror of
https://github.com/JustinSDK/dotSCAD.git
synced 2025-08-17 20:11:50 +02:00
add mz_cube
This commit is contained in:
24
src/experimental/_impl/_mz_cube_comm.scad
Normal file
24
src/experimental/_impl/_mz_cube_comm.scad
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// NO_WALL = 0;
|
||||||
|
// Y_WALL = 1;
|
||||||
|
// X_WALL = 2;
|
||||||
|
// Y_X_WALL = 3;
|
||||||
|
// Z_WALL = 4;
|
||||||
|
// Z_Y_WALL = 5;
|
||||||
|
// Z_X_WALL = 6;
|
||||||
|
// Z_Y_X_WALL = 7;
|
||||||
|
// MASK = 8;
|
||||||
|
|
||||||
|
function no_wall(cell) = get_type(cell) == 0;
|
||||||
|
function y_wall(cell) = get_type(cell) == 1;
|
||||||
|
function x_wall(cell) = get_type(cell) == 2;
|
||||||
|
function y_x_wall(cell) = get_type(cell) == 3;
|
||||||
|
function z_wall(cell) = get_type(cell) == 4;
|
||||||
|
function z_y_wall(cell) = get_type(cell) == 5;
|
||||||
|
function z_x_wall(cell) = get_type(cell) == 6;
|
||||||
|
function z_y_x_wall(cell) = get_type(cell) == 7;
|
||||||
|
|
||||||
|
function cell(x, y, z, type, visited) = [x, y, z, type, visited];
|
||||||
|
function get_x(cell) = cell.x;
|
||||||
|
function get_y(cell) = cell.y;
|
||||||
|
function get_z(cell) = cell.z;
|
||||||
|
function get_type(cell) = cell[3];
|
180
src/experimental/_impl/_mz_cube_impl.scad
Normal file
180
src/experimental/_impl/_mz_cube_impl.scad
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
use <_mz_cube_comm.scad>;
|
||||||
|
use <../../util/shuffle.scad>;
|
||||||
|
|
||||||
|
function update(cells, cell) =
|
||||||
|
let(
|
||||||
|
x = cell.x,
|
||||||
|
y = cell.y,
|
||||||
|
z = cell.z,
|
||||||
|
rowY = [for(c = cells[z][y]) if(c.x == x) cell else c],
|
||||||
|
layerZ = [
|
||||||
|
for(r = [0:len(cells[z]) - 1])
|
||||||
|
if(r == y) rowY
|
||||||
|
else cells[z][r]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
[
|
||||||
|
for(layer = [0:len(cells) - 1])
|
||||||
|
if(layer == z) layerZ
|
||||||
|
else cells[layer]
|
||||||
|
];
|
||||||
|
|
||||||
|
// is (x, y) visited?
|
||||||
|
function visited(x, y, z, cells) = cells[z][y][x][4];
|
||||||
|
|
||||||
|
// is (x, y) visitable?
|
||||||
|
function visitable(x, y, z, cells, layers, rows, columns) =
|
||||||
|
z >= 0 && z < layers && // z bound
|
||||||
|
y >= 0 && y < rows && // y bound
|
||||||
|
x >= 0 && x < columns && // x bound
|
||||||
|
!visited(x, y, z, cells); // unvisited
|
||||||
|
|
||||||
|
// setting (x, y) as being visited
|
||||||
|
function set_visited(x, y, z, cells) = update(cells, [x, y, z, get_type(cells[z][y][x]), true]);
|
||||||
|
|
||||||
|
// 0(right), 1(top), 2(left), 3(bottom), 4(up), 5(down)
|
||||||
|
function rand_dirs(c, seed) =
|
||||||
|
let(dirs = [0, 1, 2, 3, 4, 5])
|
||||||
|
is_undef(seed) ? shuffle(dirs) : shuffle(dirs, c + seed);
|
||||||
|
|
||||||
|
// get x value by dir
|
||||||
|
_next_x_table = [1, 0, -1, 0, 0, 0];
|
||||||
|
function next_x(x, dir, columns, wrapping) =
|
||||||
|
let(nx = x + _next_x_table[dir])
|
||||||
|
wrapping ? (nx + columns) % columns : nx;
|
||||||
|
|
||||||
|
// get y value by dir
|
||||||
|
_next_y_table = [0, 1, 0, -1, 0, 0];
|
||||||
|
function next_y(y, dir, rows, wrapping) =
|
||||||
|
let(ny = y + _next_y_table[dir])
|
||||||
|
wrapping ? (ny + rows) % rows : ny;
|
||||||
|
|
||||||
|
// get z value by dir
|
||||||
|
_next_z_table = [0, 0, 0, 0, 1, -1];
|
||||||
|
function next_z(z, dir, layers, wrapping) =
|
||||||
|
let(nz = z + _next_z_table[dir])
|
||||||
|
wrapping ? (nz + layers) % layers : nz;
|
||||||
|
|
||||||
|
// go right and carve the right wall
|
||||||
|
function carve_right(x, y, z, cells) =
|
||||||
|
let(cell = cells[z][y][x])
|
||||||
|
update(
|
||||||
|
cells,
|
||||||
|
z_y_x_wall(cell) ? [x, y, z, 5, true] :
|
||||||
|
z_x_wall(cell) ? [x, y, z, 4, true] :
|
||||||
|
y_x_wall(cell) ? [x, y, z, 1, true] : [x, y, z, 0, true]
|
||||||
|
);
|
||||||
|
|
||||||
|
// go top and carve the top wall
|
||||||
|
function carve_top(x, y, z, cells) =
|
||||||
|
let(cell = cells[z][y][x])
|
||||||
|
update(
|
||||||
|
cells,
|
||||||
|
z_y_x_wall(cell) ? [x, y, z, 6, true] :
|
||||||
|
z_y_wall(cell) ? [x, y, z, 4, true] :
|
||||||
|
y_x_wall(cell) ? [x, y, z, 2, true] : [x, y, z, 0, true]
|
||||||
|
);
|
||||||
|
|
||||||
|
// go up and carve the up wall
|
||||||
|
function carve_up(x, y, z, cells) =
|
||||||
|
let(cell = cells[z][y][x])
|
||||||
|
update(
|
||||||
|
cells,
|
||||||
|
z_y_x_wall(cell) ? [x, y, z, 3, true] :
|
||||||
|
z_y_wall(cell) ? [x, y, z, 1, true] :
|
||||||
|
z_x_wall(cell) ? [x, y, z, 6, true] : [x, y, z, 0, true]
|
||||||
|
);
|
||||||
|
|
||||||
|
// go left and carve the right wall of the left cell
|
||||||
|
function carve_left(x, y, z, cells, columns) =
|
||||||
|
let(
|
||||||
|
x_minus_one = x - 1,
|
||||||
|
nx = x_minus_one < 0 ? x_minus_one + columns : x_minus_one
|
||||||
|
)
|
||||||
|
update(
|
||||||
|
cells,
|
||||||
|
[nx, y, z, 5, false]
|
||||||
|
);
|
||||||
|
|
||||||
|
// go bottom and carve the top wall of the bottom cell
|
||||||
|
function carve_bottom(x, y, z, cells, rows) =
|
||||||
|
let(
|
||||||
|
y_minus_one = y - 1,
|
||||||
|
ny = y_minus_one < 0 ? y_minus_one + rows : y_minus_one
|
||||||
|
)
|
||||||
|
update(
|
||||||
|
cells,
|
||||||
|
[x, ny, z, 6, false]
|
||||||
|
);
|
||||||
|
|
||||||
|
// go down and carve the up wall of the down cell
|
||||||
|
function carve_down(x, y, z, cells, layers) =
|
||||||
|
let(
|
||||||
|
z_minus_one = z - 1,
|
||||||
|
nz = z_minus_one < 0 ? z_minus_one + layers : z_minus_one
|
||||||
|
)
|
||||||
|
update(
|
||||||
|
cells,
|
||||||
|
[x, y, nz, 3, false]
|
||||||
|
);
|
||||||
|
|
||||||
|
// 0(right), 1(top), 2(left), 3(bottom), 4(up), 5(down)
|
||||||
|
function carve(dir, x, y, z, cells, layers, rows, columns) =
|
||||||
|
dir == 0 ? carve_right(x, y, z, cells) :
|
||||||
|
dir == 1 ? carve_top(x, y, z, cells) :
|
||||||
|
dir == 2 ? carve_left(x, y, z, cells, columns) :
|
||||||
|
dir == 3 ? carve_bottom(x, y, z, cells, rows) :
|
||||||
|
dir == 4 ? carve_up(x, y, z, cells) :
|
||||||
|
/*dir 5*/ carve_down(x, y, z, cells, layers);
|
||||||
|
|
||||||
|
// find out visitable dirs from (x, y)
|
||||||
|
function visitable_dirs(r_dirs, x, y, z, cells, layers, rows, columns, x_wrapping, y_wrapping, z_wrapping) = [
|
||||||
|
for(dir = r_dirs)
|
||||||
|
if(
|
||||||
|
visitable(
|
||||||
|
next_x(x, dir, columns, x_wrapping),
|
||||||
|
next_y(y, dir, rows, y_wrapping),
|
||||||
|
next_z(z, dir, layers, z_wrapping),
|
||||||
|
cells, layers, rows, columns
|
||||||
|
)
|
||||||
|
)
|
||||||
|
dir
|
||||||
|
];
|
||||||
|
|
||||||
|
// go maze from (x, y, z)
|
||||||
|
function go_maze(x, y, z, cells, layers, rows, columns, x_wrapping = false, y_wrapping = false, z_wrapping = false, seed) =
|
||||||
|
let(
|
||||||
|
r_dirs = rand_dirs(x + y * columns + z * rows * columns, seed),
|
||||||
|
v_dirs = visitable_dirs(r_dirs, x, y, z, cells, layers, rows, columns, x_wrapping, y_wrapping, z_wrapping),
|
||||||
|
nx_cells0 = set_visited(x, y, z, cells),
|
||||||
|
leng_v_dirs = len(v_dirs)
|
||||||
|
)
|
||||||
|
// have visitable dirs?
|
||||||
|
leng_v_dirs == 0 ? nx_cells0 : // road closed
|
||||||
|
// try four directions
|
||||||
|
let(nxcells1 = next_cells(x, y, z, v_dirs[0], nx_cells0, layers, rows, columns, x_wrapping, y_wrapping, z_wrapping, seed))
|
||||||
|
leng_v_dirs == 1 ? nxcells1 :
|
||||||
|
let(nxcells2 = next_cells(x, y, z, v_dirs[1], nxcells1, layers, rows, columns, x_wrapping, y_wrapping, z_wrapping, seed))
|
||||||
|
leng_v_dirs == 2 ? nxcells2 :
|
||||||
|
let(nxcells3 = next_cells(x, y, z, v_dirs[2], nxcells2, layers, rows, columns, x_wrapping, y_wrapping, z_wrapping, seed))
|
||||||
|
leng_v_dirs == 3 ? nxcells3 :
|
||||||
|
let(nxcells4 = next_cells(x, y, z, v_dirs[3], nxcells3, layers, rows, columns, x_wrapping, y_wrapping, z_wrapping, seed))
|
||||||
|
leng_v_dirs == 4 ? nxcells4 :
|
||||||
|
let(nxcells5 = next_cells(x, y, z, v_dirs[4], nxcells4, layers, rows, columns, x_wrapping, y_wrapping, z_wrapping, seed))
|
||||||
|
leng_v_dirs == 5 ? nxcells5 : next_cells(x, y, v_dirs[5], nxcells5, layers, rows, columns, x_wrapping, y_wrapping, z_wrapping, seed);
|
||||||
|
|
||||||
|
function next_cells(x, y, z, dir, cells, layers, rows, columns, x_wrapping, y_wrapping, z_wrapping, seed) =
|
||||||
|
let(
|
||||||
|
nx = next_x(x, dir, columns, x_wrapping),
|
||||||
|
ny = next_y(y, dir, rows, y_wrapping),
|
||||||
|
nz = next_z(z, dir, layers, z_wrapping)
|
||||||
|
)
|
||||||
|
!visitable(nx, ny, nz, cells, layers, rows, columns) ? // is the dir visitable?
|
||||||
|
cells : // road closed so return cells directly
|
||||||
|
go_maze( // try the cell
|
||||||
|
nx, ny, nz,
|
||||||
|
carve(dir, x, y, z, cells, layers, rows, columns),
|
||||||
|
layers, rows, columns,
|
||||||
|
x_wrapping, y_wrapping, z_wrapping,
|
||||||
|
seed
|
||||||
|
);
|
47
src/experimental/_impl/_mz_cube_initialize.scad
Normal file
47
src/experimental/_impl/_mz_cube_initialize.scad
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
use <_mz_cube_comm.scad>;
|
||||||
|
|
||||||
|
// create a starting maze for being visited later.
|
||||||
|
function _lrc_maze(layers, rows, columns) =
|
||||||
|
[
|
||||||
|
for(z = [0:layers - 1])
|
||||||
|
[
|
||||||
|
for(y = [0:rows - 1])
|
||||||
|
[
|
||||||
|
for(x = [0:columns - 1])
|
||||||
|
cell(
|
||||||
|
x, y, z,
|
||||||
|
// all cells have up/top/right walls
|
||||||
|
7,
|
||||||
|
// unvisited
|
||||||
|
false
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
function _mz_mask(mask) =
|
||||||
|
let(
|
||||||
|
layers = len(mask),
|
||||||
|
rows = len(mask[0]),
|
||||||
|
columns = len(mask[0][1])
|
||||||
|
)
|
||||||
|
[
|
||||||
|
for(z = [0:layers - 1]) [
|
||||||
|
for(y = [0:rows - 1]) [
|
||||||
|
for(x = [0:columns - 1])
|
||||||
|
mask[layers - z - 1][rows - y - 1][x] == 0 ?
|
||||||
|
cell(
|
||||||
|
x, y, z,
|
||||||
|
8, // mask
|
||||||
|
true // visited
|
||||||
|
)
|
||||||
|
:
|
||||||
|
cell(
|
||||||
|
x, y, z,
|
||||||
|
// all cells have up/top/right walls
|
||||||
|
7, // unvisited
|
||||||
|
false
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
107
src/experimental/mz_cube.scad
Normal file
107
src/experimental/mz_cube.scad
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
/**
|
||||||
|
* mz_cube.scad
|
||||||
|
*
|
||||||
|
* @copyright Justin Lin, 2020
|
||||||
|
* @license https://opensource.org/licenses/lgpl-3.0.html
|
||||||
|
*
|
||||||
|
* @see https://openhome.cc/eGossip/OpenSCAD/lib3x-mz_cube.html
|
||||||
|
*
|
||||||
|
**/
|
||||||
|
|
||||||
|
use <_impl/_mz_cube_impl.scad>;
|
||||||
|
use <mz_cube_initialize.scad>;
|
||||||
|
|
||||||
|
function mz_cube(layers, rows, columns, start = [0, 0, 0], init_cells, x_wrapping = false, y_wrapping = false, z_wrapping = false, seed) =
|
||||||
|
let(
|
||||||
|
init_undef = is_undef(init_cells),
|
||||||
|
mz = init_undef ? mz_cube_initialize(layers, rows, columns) : init_cells
|
||||||
|
)
|
||||||
|
go_maze(
|
||||||
|
start.x,
|
||||||
|
start.y,
|
||||||
|
start.z,
|
||||||
|
mz,
|
||||||
|
len(mz),
|
||||||
|
len(mz[0]),
|
||||||
|
len(mz[0][0]),
|
||||||
|
x_wrapping,
|
||||||
|
y_wrapping,
|
||||||
|
z_wrapping,
|
||||||
|
seed
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
use <experimental/mz_cube.scad>;
|
||||||
|
use <experimental/mz_cube_get.scad>;
|
||||||
|
use <util/has.scad>;
|
||||||
|
|
||||||
|
layers = 3;
|
||||||
|
rows = 4;
|
||||||
|
columns = 5;
|
||||||
|
cell_width = 5;
|
||||||
|
wall_thickness = 3;
|
||||||
|
|
||||||
|
cells = mz_cube(layers, rows, columns);
|
||||||
|
|
||||||
|
difference() {
|
||||||
|
translate([wall_thickness, wall_thickness, wall_thickness] * 0.95 / -2)
|
||||||
|
cube([
|
||||||
|
columns * cell_width + wall_thickness * .95,
|
||||||
|
rows * cell_width + wall_thickness * .95,
|
||||||
|
layers * cell_width + wall_thickness * .95
|
||||||
|
]);
|
||||||
|
|
||||||
|
union() {
|
||||||
|
for(layer = cells, row = layer, cell = row) {
|
||||||
|
x = mz_cube_get(cell, "x");
|
||||||
|
y = mz_cube_get(cell, "y");
|
||||||
|
z = mz_cube_get(cell, "z");
|
||||||
|
type = mz_cube_get(cell, "t");
|
||||||
|
|
||||||
|
translate([x, y, z] * cell_width) {
|
||||||
|
if(has(["Z_WALL", "Z_Y_WALL", "Z_X_WALL", "Z_Y_X_WALL"], type)) {
|
||||||
|
translate([0, 0, cell_width])
|
||||||
|
cell_wall(cell_width, wall_thickness);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(has(["Y_WALL", "Y_X_WALL", "Z_Y_WALL", "Z_Y_X_WALL"], type)) {
|
||||||
|
translate([0, cell_width, 0])
|
||||||
|
rotate([90, 0, 0])
|
||||||
|
cell_wall(cell_width, wall_thickness);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(has(["X_WALL", "Y_X_WALL", "Z_X_WALL", "Z_Y_X_WALL"], type)) {
|
||||||
|
translate([cell_width, 0, 0])
|
||||||
|
rotate([0, -90, 0])
|
||||||
|
cell_wall(cell_width, wall_thickness);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
translate([-wall_thickness / 2, -wall_thickness / 2, -wall_thickness / 2])
|
||||||
|
cube([cell_width * columns + wall_thickness, cell_width * rows + wall_thickness, wall_thickness]);
|
||||||
|
|
||||||
|
translate([-wall_thickness / 2, -wall_thickness / 2, -wall_thickness / 2])
|
||||||
|
cube([wall_thickness, cell_width * rows + wall_thickness, cell_width * layers + wall_thickness]);
|
||||||
|
|
||||||
|
translate([-wall_thickness / 2, -wall_thickness / 2, -wall_thickness / 2])
|
||||||
|
cube([cell_width * columns + wall_thickness, wall_thickness, cell_width * layers + wall_thickness]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module cell_wall(cell_width, wall_thickness) {
|
||||||
|
hull() {
|
||||||
|
cube(wall_thickness, center = true);
|
||||||
|
|
||||||
|
translate([cell_width, 0])
|
||||||
|
cube(wall_thickness, center = true);
|
||||||
|
|
||||||
|
translate([cell_width, cell_width])
|
||||||
|
cube(wall_thickness, center = true);
|
||||||
|
|
||||||
|
translate([0, cell_width])
|
||||||
|
cube(wall_thickness, center = true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
20
src/experimental/mz_cube_get.scad
Normal file
20
src/experimental/mz_cube_get.scad
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// NO_WALL = 0;
|
||||||
|
// Y_WALL = 1;
|
||||||
|
// X_WALL = 2;
|
||||||
|
// Y_X_WALL = 3;
|
||||||
|
// Z_WALL = 4;
|
||||||
|
// Z_Y_WALL = 5;
|
||||||
|
// Z_X_WALL = 6;
|
||||||
|
// Z_Y_X_WALL = 7;
|
||||||
|
// MASK = 8;
|
||||||
|
|
||||||
|
function mz_cube_get(cell, query) =
|
||||||
|
let(
|
||||||
|
i = search(query, [
|
||||||
|
["x", 0],
|
||||||
|
["y", 1],
|
||||||
|
["z", 2],
|
||||||
|
["t", 3]
|
||||||
|
])[0]
|
||||||
|
)
|
||||||
|
i != 3 ? cell[i] : ["NO_WALL", "Y_WALL", "X_WALL", "Y_X_WALL", "Z_WALL", "Z_Y_WALL", "Z_X_WALL", "Z_Y_X_WALL", "MASK"][cell[i]];
|
4
src/experimental/mz_cube_initialize.scad
Normal file
4
src/experimental/mz_cube_initialize.scad
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
use <_impl/_mz_cube_initialize.scad>;
|
||||||
|
|
||||||
|
function mz_cube_initialize(layers, rows, columns, mask) =
|
||||||
|
is_undef(mask) ? _lrc_maze(layers, rows, columns) : _mz_mask(mask);
|
Reference in New Issue
Block a user