1
0
mirror of https://github.com/JustinSDK/dotSCAD.git synced 2025-08-10 16:54:23 +02:00

add maze_regular_polygon_generator

This commit is contained in:
Justin Lin
2019-09-01 11:03:23 +08:00
parent 355d78da86
commit cc6b19984b

View File

@@ -0,0 +1,237 @@
include <line2d.scad>;
include <arc.scad>;
include <hollow_out.scad>;
radius_of_circle_wrapper = 15;
wall_thickness = 1;
wall_height = 1;
cblocks = 12;
levels = 3;
sides = 6; // [3:24]
bottom = "NO"; // [YES,NO]
// give a [x, y] point and length. draw a line in the x direction
module x_line(point, length, thickness = 1) {
line2d(point, point + [0, length], width = thickness);
}
/*
* constants, for clearness
*
*/
// random directions, for picking up a direction to visit the next block
function PERMUTATION_OF_FOUR() = [
[1, 2, 3, 4],
[1, 2, 4, 3],
[1, 3, 2, 4],
[1, 3, 4, 2],
[1, 4, 2, 3],
[1, 4, 3, 2],
[2, 1, 3, 4],
[2, 1, 4, 3],
[2, 3, 1, 4],
[2, 3, 4, 1],
[2, 4, 1, 3],
[2, 4, 3, 1],
[3, 1, 2, 4],
[3, 1, 4, 2],
[3, 2, 1, 4],
[3, 2, 4, 1],
[3, 4, 1, 2],
[3, 4, 2, 1],
[4, 1, 2, 3],
[4, 1, 3, 2],
[4, 2, 1, 3],
[4, 2, 3, 1],
[4, 3, 1, 2],
[4, 3, 2, 1]
];
function NO_WALL() = 0;
function UP_WALL() = 1;
function RIGHT_WALL() = 2;
function UP_RIGHT_WALL() = 3;
function NOT_VISITED() = 0;
function VISITED() = 1;
/*
* utilities functions
*
*/
// comare the equality of [x1, y1] and [x2, y2]
function cord_equals(cord1, cord2) = cord1 == cord2;
// is the point visited?
function not_visited(cord, vs, index = 0) =
index == len(vs) ? true :
(cord_equals([vs[index][0], vs[index][1]], cord) && vs[index][2] == 1 ? false :
not_visited(cord, vs, index + 1));
// pick a direction randomly
function rand_dirs() =
PERMUTATION_OF_FOUR()[round(rands(0, 24, 1)[0])];
// replace v1 in the vector with v2
function replace(v1, v2, vs) =
[for(i = [0:len(vs) - 1]) vs[i] == v1 ? v2 : vs[i]];
/*
* functions for generating a maze vector
*
*/
// initialize a maze
function init_maze(rows, columns) =
[
for(c = [1 : columns])
for(r = [1 : rows])
[c, r, 0, UP_RIGHT_WALL()]
];
// find a vector in the maze vector
function find(i, j, maze_vector, index = 0) =
index == len(maze_vector) ? [] : (
cord_equals([i, j], [maze_vector[index][0], maze_vector[index][1]]) ? maze_vector[index] : find(i, j, maze_vector, index + 1)
);
////
// NO_WALL = 0;
// UP_WALL = 1;
// RIGHT_WALL = 2;
// UP_RIGHT_WALL = 3;
function delete_right_wall(original_block) =
original_block == NO_WALL() || original_block == RIGHT_WALL() ? NO_WALL() : UP_WALL();
function delete_up_wall(original_block) =
(original_block == NO_WALL() || original_block == UP_WALL()) ? NO_WALL() : RIGHT_WALL();
function delete_right_wall_of(vs, is_visited, maze_vector) =
replace(vs, [vs[0], vs[1] , is_visited, delete_right_wall(vs[3])] ,maze_vector);
function delete_up_wall_of(vs, is_visited, maze_vector) =
replace(vs, [vs[0], vs[1] , is_visited, delete_up_wall(vs[3])] ,maze_vector);
function go_right(i, j, rows, columns, maze_vector) =
go_maze(i + 1, j, rows, columns, delete_right_wall_of(find(i, j, maze_vector), VISITED(), maze_vector));
function go_up(i, j, rows, columns, maze_vector) =
go_maze(i, j - 1, rows, columns, delete_up_wall_of(find(i, j, maze_vector), VISITED(), maze_vector));
function visit(v, maze_vector) =
replace(v, [v[0], v[1], VISITED(), v[3]], maze_vector);
function go_left(i, j, rows, columns, maze_vector) =
go_maze(i - 1, j, rows, columns, delete_right_wall_of(find(i - 1, j, maze_vector), NOT_VISITED(), maze_vector));
function go_down(i, j, rows, columns, maze_vector) =
go_maze(i, j + 1, rows, columns, delete_up_wall_of(find(i, j + 1, maze_vector), NOT_VISITED(), maze_vector));
function go_maze(i, j, rows, columns, maze_vector) =
look_around(i, j, rand_dirs(), rows, columns, visit(find(i, j, maze_vector), maze_vector));
function look_around(i, j, dirs, rows, columns, maze_vector, index = 0) =
index == 4 ? maze_vector :
look_around(
i, j, dirs,
rows, columns,
build_wall(i, j, dirs[index], rows, columns, maze_vector),
index + 1
);
function build_wall(i, j, n, rows, columns, maze_vector) =
n == 1 && i != columns && not_visited([i + 1, j], maze_vector) ? go_right(i, j, rows, columns, maze_vector) : (
n == 2 && j != 1 && not_visited([i, j - 1], maze_vector) ? go_up(i, j, rows, columns, maze_vector) : (
n == 3 && i != 1 && not_visited([i - 1, j], maze_vector) ? go_left(i, j,rows, columns, maze_vector) : (
n == 4 && j != rows && not_visited([i, j + 1], maze_vector) ? go_down(i, j, rows, columns, maze_vector) : maze_vector
)
)
);
module ring_regular_polygon_sector(radius, angle, thickness, width, sides) {
intersection() {
arc(
radius = radius - 0.1,
angle = [0, 360],
width = thickness + 0.2,
width_mode = "LINE_OUTWARD",
$fn = sides
);
rotate([0, 0, angle]) x_line([0, 0], radius * 3, width);
}
}
module regular_polygon_to_polygon_wall(radius, length, angle, thickness, sides) {
intersection() {
hollow_out(shell_thickness = length)
circle(r = radius + length, $fn = sides);
rotate([0, 0, angle])
x_line([0, 0], (radius + length) * 2, thickness);
}
}
module regular_polygon_maze(radius, cblocks, levels, thickness = 1, sides) {
full_circle_angle = 360;
arc_angle = full_circle_angle / cblocks;
r = radius / (levels + 1);
maze = go_maze(1, 1, cblocks, levels, replace([levels, cblocks - 1, 0, UP_RIGHT_WALL()], [levels, cblocks - 1, 0, UP_WALL()], init_maze(cblocks, levels)));
difference() {
union() {
for(i = [1 : levels + 1]) {
arc(
radius = r * i,
angle = [0, 360],
width = thickness,
width_mode = "LINE_OUTWARD",
$fn = sides
);
}
for(i = [0:len(maze) - 1]) {
cord = maze[i];
cr = cord[0];
cc = cord[1] - 1;
v = cord[3];
angle = cc * arc_angle;
if(v == 1 || v == 3) {
regular_polygon_to_polygon_wall(r * cr, r, cc * arc_angle , thickness, sides);
}
}
}
union() {
// maze entry
ring_regular_polygon_sector(r, arc_angle / 1.975 , thickness, r / 3, sides);
// road to the next level
for(i = [0:len(maze) - 1]) {
cord = maze[i];
cr = cord[0];
cc = cord[1] - 1;
v = cord[3];
if(v == 0 || v == 1) {
ring_regular_polygon_sector(r * (cr + 1), (cc + 0.5) * arc_angle , thickness, r / 3 , sides);
}
}
}
}
}
linear_extrude(wall_height)
regular_polygon_maze(radius_of_circle_wrapper, cblocks, levels, wall_thickness, sides);
if(bottom == "YES") {
linear_extrude(wall_height / 2)
offset(delta = wall_thickness)
circle(radius_of_circle_wrapper, $fn = sides);
}