Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- This script was presented by Jordan Brown in the OpenSCAD
- forum to illustrate how an object could be used to control
- an animation
- Demonstration animation.
- The animation was built to run with animation parameters
- set to FPS=10 and steps=100.
- */
- v = version();
- //echo( _v.x, _v.y, _v.z );
- assert( _v.x== 2025 && _v.y>=7 && _v.z >= 11 );
- //Remember that this requires 2025.07.11. Zoom as desired.
- // Best view is looking straight down at the origin.
- $vpr = [0,0,0];
- $vpt = [0,0,0];
- /*
- This vector is a description of everything that happens
- during the animation. You want a wide window to read it.
- The only thing that's defined is "t", the timestamp for that
- particular entry. The rest are up to your program.
- For this animation:
- pos1, pos2: the {red, green} stick man's position
- arm1, arm2: the {red, green} stick man's arm angle
- says1, says2: what the {red, green} stick man is saying
- */
- timeline = [
- object(t=0, pos1=[-50,0,0],
- arm1=-30, says1="",
- pos2=[50,0], arm2=-30, says2=""),
- object(t=2.5, arm1=-30 ),
- object(t=3, arm1=50, says1="Hey, George!" ),
- object(t=3.5, arm1=-30 ),
- object(t=5, says1="" ),
- object(t=5.5, arm2=-30 ),
- object(t=6, arm2=50, says2="Hey, Fred!" ),
- object(t=6.5, arm2=-30 ),
- object(t=7, says2="" ),
- object(t=12, pos1=[-5,0,0], pos2=[5,0] ),
- object(t=13, says1="Can I go past?" ),
- object(t=14, says1="" ),
- object(t=15, says2="Sorry, no." ),
- object(t=16, says2="" ),
- object(t=17, says1="I hate living on a number line!" ),
- object(t=19, says1="" ),
- object(t=19.5, says2="Me too!" ),
- object(t=20.5, says2="" ),
- object(t=22, pos1=[-5,0,0],
- arm2=-30,
- says1="", pos2=[5,0],
- arm2=-30,
- says2="" ),
- ];
- // Now, create the current frame of the animation.
- // Get the current values of all of the timeline columns.
- a = animate(timeline);
- /* Using those values,
- create the model at this moment.
- There are two stick men.
- */
- translate(a.pos1) {
- color("red")
- stickman(a.says1, a.arm1);
- }
- translate(a.pos2) {
- color("green")
- stickman(a.says2, a.arm2);
- }
- // Create a stick man, holding his arms at the specified angle and saying what's specified.
- module stickman(says, arm) {
- square([1,8], center=true);
- translate([0,5])
- circle(2);
- translate([0,2])
- rotate(arm)
- translate([0,-0.5])
- square([4,1]);
- translate([0,2])
- rotate(180-arm)
- translate([0,-0.5])
- square([4,1]);
- translate([0,-4])
- rotate(200)
- translate([-0.5,0])
- square([1,5]);
- translate([0,-4])
- rotate(160)
- translate([-0.5,0])
- square([1,5]);
- translate([0, 8])
- text(says, halign="center", valign="baseline", size=3);
- }
- // The rest is generic support for using a timeline like that.
- // Extract one column from an animation timeline, extracting only
- // those entries where that column is present.
- function animate_extract(list, key) = [
- for (e = list)
- if( !is_undef(e[key]) ) [ e.t, e[key] ]
- ];
- // Get the duration of the timeline, the timestamp of the
- // last entry in the timeline.
- function animate_duration(list) = list[len(list)-1].t;
- // Given $t, a timeline and a key, interpolate the current value
- // of the key.
- function animate_interpolate(list, key) =
- xlookup(
- $t * animate_duration(list),
- animate_extract(list, key)
- );
- // Get a list of all keys used in the timeline.
- function animate_keys(list) =
- let( o = object(
- [
- for (e = list)
- for (k = e) [ k, true ]
- ]
- )
- )
- [ for (k = o) k ];
- // Given $t and a timeline, return an aggregated object with the
- // current values of all of the columns of the timeline.
- function animate(timeline) =
- let(keys = animate_keys(timeline))
- object(
- [
- for (k = keys)
- [ k, animate_interpolate(timeline, k) ]
- ]
- );
- // lookup() on steroids. Given a value and a lookup-like list,
- // do the lookup and interpolation that lookup() does... but have
- // it also work for strings, booleans, and identical-length lists
- // of numbers.
- function xlookup(val, list) =
- is_num(list[0][1]) ? lookup(val, list)
- : is_string(list[0][1]) ? lookup_string(val, list)
- : is_bool(list[0][1]) ? lookup_bool( val, list)
- : is_list(list[0][1]) ? lookup_list( val, list)
- : assert(false, "don't know how to lookup that type")
- ;
- // Given a value and a lookup list, return the index of the entry
- // before (or matching) the value.
- function lookup_prev(val, list) =
- let (tmp = [ for (i = [0:1:len(list)-1])
- [ list[i][0], i ] ]
- )
- floor(lookup(val, tmp))
- ;
- //Given a value and a lookup list, return the index of the entry
- // after (or matching) the value.
- function lookup_next(val, list) =
- let (tmp = [ for (i = [0:1:len(list)-1])
- [ list[i][0], i ] ]
- )
- ceil(lookup(val, tmp))
- ;
- // Given a value and a lookup list containing strings, return the
- // string before (or matching) the value.
- function lookup_string(val, list) =
- list[lookup_prev(val, list)][1]
- ;
- // Given a value and a lookup list containing booleans, return the
- // boolean before (or matching) the value.
- function lookup_bool(val, list) =
- list[lookup_prev(val, list)][1]
- ;
- // Given a value and a lookup list containing same-length lists of
- // numbers, interpolate values for the list. Note that because
- // lookup_prev() and lookup_next() return the same entry on an exact
- // match, and that leads to 0*0/0, that case has to be handled
- // specially.
- function lookup_list(val, list) =
- let(
- p = lookup_prev(val, list),
- n = lookup_next(val, list)
- )
- p == n ?
- list[p][1]
- : list[p][1] +
- (list[n][1]-list[p][1]) *
- (val - list[p][0]) / (list[n][0] - list[p][0])
- ;
Advertisement
Add Comment
Please, Sign In to add comment