Added repeat to turtle. Added centroid to geometry.scad.

This commit is contained in:
Adrian Mariano 2019-07-15 20:14:29 -04:00
parent 81fd73588f
commit a71868431b
2 changed files with 47 additions and 11 deletions

View file

@ -385,6 +385,18 @@ function polygon_area(vertices) =
0.5*sum([for(i=[0:len(vertices)-1]) det2(select(vertices,i,i+1))]);
// Function: centroid()
// Usage:
// centroid(vertices)
// Description:
// Given a simple polygon, returns the coordinates of the polygon's centroid.
// If the polygon is self-intersecting, the results are undefined.
function centroid(vertices) =
sum([for(i=[0:len(vertices)-1])
let(segment=select(vertices,i,i+1))
det2(segment)*sum(segment)]) / 6 / polygon_area(vertices);
// Function: assemble_path_fragments()
// Usage:
// assemble_path_fragments(subpaths);

View file

@ -1,3 +1,4 @@
include<BOSL2/std.scad>
//////////////////////////////////////////////////////////////////////
// LibFile: shapes2d.scad
// Common useful 2D shapes.
@ -568,11 +569,13 @@ module supershape(step=0.5,m1=4,m2=undef,n1,n2=undef,n3=undef,a=1,b=undef, r=und
// - "length", length: Change the turtle move distance to `length`
// - "scale", factor: Multiply turtle move distance by `factor`
// - "addlength", length: Add `length` to the turtle move distance
// - "repeat", count, comands: Repeats a list of commands `count` times.
//
// Arguments:
// commands = list of turtle commands
// state = starting turtle state (from previous call) or starting point. Default: start at the origin
// full_state = if true return the full turtle state for continuing the path in subsequent turtle calls. Default: false
// repeat = number of times to repeat the command list. Default: 1
//
// Example(2D): Simple rectangle
// path = turtle(["xmove",3, "ymove", "xmove",-3, "ymove",-1]);
@ -580,8 +583,14 @@ module supershape(step=0.5,m1=4,m2=undef,n1,n2=undef,n3=undef,a=1,b=undef, r=und
// Example(2D): Pentagon
// path=turtle(["angle",360/5,"move","turn","move","turn","move","turn","move"]);
// stroke(path,width=.1,closed=true);
// Example(2D): Pentagon using the repeat argument
// path=turtle(["move","turn",360/5],repeat=5);
// stroke(path,width=.1,closed=true);
// Example(2D): Pentagon using the repeat turtle command, setting the turn angle
// path=turtle(["angle",360/5,"repeat",5,["move","turn"]]);
// stroke(path,width=.1,closed=true);
// Example(2D): Pentagram
// path = turtle(flatten(replist(["move","left",144],10)));
// path = turtle(["move","left",144], repeat=10);
// stroke(path,width=.05);
// Example(2D): Sawtooth path
// path = turtle([
@ -611,16 +620,16 @@ module supershape(step=0.5,m1=4,m2=undef,n1,n2=undef,n3=undef,a=1,b=undef, r=und
// ]);
// stroke(path, width=.1);
// Example(2DMed): square spiral
// path = turtle(flatten(replist(["move","left","addlength",1],50)));
// path = turtle(["move","left","addlength",1],repeat=50);
// stroke(path,width=.2);
// Example(2DMed): pentagonal spiral
// path = turtle(concat(["angle",360/5],flatten(replist(["move","left","addlength",1],50))));
// path = turtle(["move","left",360/5,"addlength",1],repeat=50);
// stroke(path,width=.2);
// Example(2DMed): yet another spiral
// Example(2DMed): yet another spiral, without using `repeat`
// path = turtle(concat(["angle",71],flatten(replist(["move","left","addlength",1],50))));
// stroke(path,width=.2);
// Example(2DMed): The previous spiral grows linearly and eventually intersects itself. This one grows geometrically and does not.
// path = turtle(concat(["angle",71],flatten(replist(["move","left","scale",1.05],50))));
// path = turtle(["move","left",71,"scale",1.05],repeat=50);
// stroke(path,width=.05);
// Example(2D): Koch Snowflake
// function koch_unit(depth) =
@ -634,24 +643,39 @@ module supershape(step=0.5,m1=4,m2=undef,n1,n2=undef,n3=undef,a=1,b=undef, r=und
// ["right"],
// koch_unit(depth-1)
// );
// koch=concat(["angle",60],flatten(replist(concat(koch_unit(3),["left","left"]),3)));
// koch=concat(["angle",60,"repeat",3],[concat(koch_unit(3),["left","left"])]);
// polygon(turtle(koch));
function turtle(commands, state=[[[0,0]],[1,0],90], full_state=false) =
function turtle(commands, state=[[[0,0]],[1,0],90], full_state=false, repeat=1) =
let( state = is_vector(state) ? [[state],[1,0],90] : state )
_turtle(commands,state,full_state);
repeat == 1 ? _turtle(commands,state,full_state)
: _turtle_repeat(commands, state, full_state, repeat);
function _turtle_repeat(commands, state, full_state, repeat) =
repeat==1 ? _turtle(commands,state,full_state)
: _turtle_repeat(commands, _turtle(commands, state, true), full_state, repeat-1);
function _turtle_command_len(commands, index) =
commands[index] == "repeat" ? 3 : // Repeat command requires 2 args
is_string(commands[index+1]) ? 1 // If 2nd item is a string it's must be a new command
: 2; // Otherwise we have command and arg
function _turtle(commands, state, full_state, index=0) =
index < len(commands) ?
_turtle(commands,
turtle_command(commands[index],commands[index+1],state,index),
_turtle_command(commands[index],commands[index+1],commands[index+2],state,index),
full_state,
index+(!is_string(commands[index+1])?2:1)
index+_turtle_command_len(commands,index)
) :
( full_state ? state : state[0] );
// Turtle state: state = [path, step_vector, default angle]
function turtle_command(command, parm, state, index) =
function _turtle_command(command, parm, parm2, state, index) =
command == "repeat" ? assert(is_num(parm),str("\"repeat\" command requires a numeric parameter at index ",index))
assert(is_list(parm2),str("\"repeat\" command requires a command list parameter at index ",index))
_turtle_repeat(parm2, state, true, parm)
:
let(
path = 0,
step=1,