vulcan_

Hello There Animation by Jordan Brown

Jul 31st, 2025 (edited)
295
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
JavaScript 6.29 KB | Source Code | 0 0
  1. /*
  2.  This script was presented by Jordan Brown in the OpenSCAD
  3.  forum to illustrate how an object could be used to control
  4.  an animation
  5.  
  6.  Demonstration animation.
  7.  The animation was built to run with animation parameters
  8.  set to FPS=10 and steps=100.
  9.  */
  10.  
  11. v = version();
  12. //echo( _v.x, _v.y, _v.z );
  13. assert( _v.x== 2025 && _v.y>=7 && _v.z >= 11 );
  14.  
  15. //Remember that this requires 2025.07.11. Zoom as desired.
  16.  
  17. // Best view is looking straight down at the origin.
  18. $vpr = [0,0,0];
  19. $vpt = [0,0,0];
  20.  
  21. /*
  22.  This vector is a description of everything that happens
  23.  during the animation. You want a wide window to read it.
  24.  The only thing that's defined is "t", the timestamp for that
  25.  particular entry. The rest are up to your program.
  26.  For this animation:
  27.   pos1, pos2: the {red, green} stick man's position
  28.   arm1, arm2: the {red, green} stick man's arm angle
  29.   says1, says2: what the {red, green} stick man is saying
  30.  */
  31. timeline = [
  32. object(t=0, pos1=[-50,0,0],
  33.               arm1=-30, says1="",
  34.               pos2=[50,0],  arm2=-30, says2=""),
  35. object(t=2.5, arm1=-30 ),
  36. object(t=3,   arm1=50,  says1="Hey, George!"  ),
  37. object(t=3.5, arm1=-30 ),
  38. object(t=5,             says1="" ),
  39. object(t=5.5,               arm2=-30 ),
  40. object(t=6,                 arm2=50, says2="Hey, Fred!" ),
  41. object(t=6.5,               arm2=-30 ),
  42. object(t=7,                     says2="" ),
  43. object(t=12, pos1=[-5,0,0],  pos2=[5,0] ),
  44. object(t=13,            says1="Can I go past?" ),
  45. object(t=14,            says1="" ),
  46. object(t=15,                    says2="Sorry, no." ),
  47. object(t=16,                    says2="" ),
  48. object(t=17,            says1="I hate living on a number line!" ),
  49. object(t=19,            says1="" ),
  50. object(t=19.5,                  says2="Me too!"  ),
  51. object(t=20.5,                  says2="" ),
  52. object(t=22, pos1=[-5,0,0],
  53.                             arm2=-30,
  54.                         says1="", pos2=[5,0],
  55.                             arm2=-30,
  56.                                 says2="" ),
  57. ];
  58.  
  59. // Now, create the current frame of the animation.
  60.  
  61. // Get the current values of all of the timeline columns.
  62. a = animate(timeline);
  63. /* Using those values,
  64.    create the model at this moment.
  65.    There are two stick men.
  66.  */
  67. translate(a.pos1) {
  68.     color("red")
  69.         stickman(a.says1, a.arm1);
  70.     }
  71. translate(a.pos2) {
  72.     color("green")
  73.         stickman(a.says2, a.arm2);
  74.     }
  75.  
  76. // Create a stick man, holding his arms at the specified angle and saying what's specified.
  77. module stickman(says, arm) {
  78.     square([1,8], center=true);
  79.     translate([0,5])
  80.         circle(2);
  81.     translate([0,2])
  82.         rotate(arm)
  83.             translate([0,-0.5])
  84.                 square([4,1]);
  85.     translate([0,2])
  86.         rotate(180-arm)
  87.             translate([0,-0.5])
  88.                 square([4,1]);
  89.     translate([0,-4])
  90.         rotate(200)
  91.             translate([-0.5,0])
  92.                 square([1,5]);
  93.     translate([0,-4])
  94.         rotate(160)
  95.             translate([-0.5,0])
  96.                 square([1,5]);
  97.     translate([0, 8])
  98.         text(says, halign="center", valign="baseline", size=3);
  99.     }
  100.  
  101. // The rest is generic support for using a timeline like that.
  102.  
  103. // Extract one column from an animation timeline, extracting only
  104. // those entries where that column is present.
  105. function animate_extract(list, key) = [
  106.     for (e = list)
  107.         if( !is_undef(e[key]) ) [ e.t, e[key] ]
  108.     ];
  109.  
  110. // Get the duration of the timeline, the timestamp of the
  111. // last entry in the timeline.
  112. function animate_duration(list) = list[len(list)-1].t;
  113.  
  114. // Given $t, a timeline and a key, interpolate the current value
  115. // of the key.
  116. function animate_interpolate(list, key) =
  117.     xlookup(
  118.         $t * animate_duration(list),
  119.         animate_extract(list, key)
  120.         );
  121.  
  122. // Get a list of all keys used in the timeline.
  123. function animate_keys(list) =
  124.     let( o = object(
  125.             [
  126.             for (e = list)
  127.                 for (k = e) [ k, true ]
  128.             ]
  129.             )
  130.         )
  131.     [ for (k = o) k ];
  132.  
  133. // Given $t and a timeline, return an aggregated object with the
  134. // current values of all of the columns of the timeline.
  135. function animate(timeline) =
  136.     let(keys = animate_keys(timeline))
  137.     object(
  138.         [
  139.         for (k = keys)
  140.             [ k, animate_interpolate(timeline, k) ]
  141.         ]
  142.         );
  143.  
  144. // lookup() on steroids. Given a value and a lookup-like list,
  145. // do the lookup and interpolation that lookup() does... but have
  146. // it also work for strings, booleans, and identical-length lists
  147. // of numbers.
  148. function xlookup(val, list) =
  149.     is_num(list[0][1])      ? lookup(val, list)
  150.     : is_string(list[0][1]) ? lookup_string(val, list)
  151.     : is_bool(list[0][1])   ? lookup_bool(  val, list)
  152.     : is_list(list[0][1])   ? lookup_list(  val, list)
  153.     : assert(false, "don't know how to lookup that type")
  154.     ;
  155.  
  156. // Given a value and a lookup list, return the index of the entry
  157. // before (or matching) the value.
  158. function lookup_prev(val, list) =
  159.     let (tmp = [ for (i = [0:1:len(list)-1])
  160.         [ list[i][0], i ] ]
  161.         )
  162.     floor(lookup(val, tmp))
  163.     ;
  164.  
  165. //Given a value and a lookup list, return the index of the entry
  166. // after (or matching) the value.
  167. function lookup_next(val, list) =
  168.     let (tmp = [ for (i = [0:1:len(list)-1])
  169.         [ list[i][0], i ] ]
  170.         )
  171.     ceil(lookup(val, tmp))
  172.     ;
  173.  
  174. // Given a value and a lookup list containing strings, return the
  175. // string before (or matching) the value.
  176. function lookup_string(val, list) =
  177.     list[lookup_prev(val, list)][1]
  178.     ;
  179.  
  180. // Given a value and a lookup list containing booleans, return the
  181. // boolean before (or matching) the value.
  182. function lookup_bool(val, list) =
  183.     list[lookup_prev(val, list)][1]
  184.     ;
  185.  
  186. // Given a value and a lookup list containing same-length lists of
  187. // numbers, interpolate values for the list. Note that because
  188. // lookup_prev() and lookup_next() return the same entry on an exact
  189. // match, and that leads to 0*0/0, that case has to be handled
  190. // specially.
  191. function lookup_list(val, list) =
  192.     let(
  193.         p = lookup_prev(val, list),
  194.         n = lookup_next(val, list)
  195.         )
  196.     p == n ?
  197.         list[p][1]
  198.     :   list[p][1] +
  199.             (list[n][1]-list[p][1]) *
  200.             (val - list[p][0]) / (list[n][0] - list[p][0])
  201.     ;
  202.  
Tags: OpenSCAD
Advertisement
Add Comment
Please, Sign In to add comment