\ ob.particle \ \ hp_particle \ class of elmnts that simulates a zero dimmensional body that can have \ forces acted on it. part of the collection of software componenets: \ "henri poincare." \ \ description of methods: \ \ NEW: ( n -- , allocate memory for n dimensions ) \ \ OPEN: ( -- , called internally by space object ) \ CLOSE: ( -- , called internally by space object ) \ \ GET.TYPE: ( -- id , type of particle ) \ \ PUT.MASS: ( mass -- ) \ GET.MASS: ( -- mass ) \ \ PUT.ENABLE: ( flag dim# -- , enable or disable one dimension ) \ GET.ENABLE: ( dim# -- flag , get enable status of dimension ) \ \ PUT.RANGE: ( min range dim# -- , set spacial range per dimension ) \ GET.RANGE: ( dim# -- min range , get spacial range of dimension ) \ \ PUT.WRAP: ( flag dim# -- , set to toroid space if true ) \ GET.WRAP: ( dim# -- flag , get wrap status of dimension ) \ \ PUT.ACTIVE.ELM: ( elm# -- , set element to be passed to instrument ) \ GET.ACTIVE.ELM: ( -- elm# , retrieve element for instrument ) \ \ PUT.INSTRUMENT: ( instr -- , assign instrument to particle ) \ GET.INSTRUMENT: ( -- instr , get instrument address ) \ \ PREFAB: ( -- , allocates space for data and creates instrument ) \ \ UPDATE: ( -- , update position etc based on new force value ) \ REFRESH: ( -- , "plays" instrument ) \ \ FREEZE: ( -- , stop the particle's motion etc ) \ \ data (position, etc) are stored and can be retrieved using the methods \ of the superclass (ob.elmnts). Data selectors (particle_position etc) \ have been defined for this purpose. Alternatively, equivalent methods \ of the put: and get: (put.position: get.position: etc), and the ed.to: \ and ed.at: methods (pd.to: pd.at: etc) have are have been defined. \ \ based on ideas presented by Joel Ryan. \ \ Code: Han-earl Park \ Copyright 2000 Buster & Friends C-ALTO Labs \ (Den haag, December 1997 - \ (Valencia, October 1998 - \ (Southampton, May 2000 - \ \ MOD: HeP 12/11/97 Started project creating a simple two dimensional puck. \ MOD: HeP 10/11/98 Make the puck multi dimensional. \ complete redesign of object classes. \ MOD: HeP 10/15/98 Change name of the collective software components \ to "forces in motion". \ MOD: HeP 10/24/98 Yet another redesign of the components with the addtion \ of the space class which does all the calculation. \ thus, the puck classes no longer hold any "intelligence." \ thanks to mark trayle for suggesting this arrangement. \ MOD: HeP 10/29/98 Redesigned so that the force class acts as a pluggin to \ the space class. Thus the scheduling intelligence is \ kept part of ob.space, but the forces are polled from \ the force objects. \ MOD: HeP 10/30/98 Move all the dimension enabling from the space class. \ add instrument stuff. \ MOD: HeP 11/04/98 Renamed ob.puck as ob.particle. \ MOD: HeP 11/17/98 The methods put.enable: and get.enable: now work like the \ old put.enable.dim and get.enable.dim: To enable or \ disable all dimensions, pass -1 as the dimension number. \ MOD: HeP 11/18/98 Made the xxx.get: and xxx.put: methods equivalent of \ the standard get: and put: methods of the ob.elmnts class. \ Add corresponding xxd.at: and xxd.to: methods. \ MOD: HeP 11/20/98 Got rid of the instance varaible iv-part-glob-enabled? \ MOD: HeP 11/29/98 Add prefab: method. \ moved the put.wrap: get.wrap: and put.size: get.size: \ methods from the space class. \ MOD: HeP 12/10/98 Add a few instance objects and in the process make the \ distiction between "dynamic" (force, position, etc) and \ "static" (mass, etc) properties of the particle. \ MOD: HeP 03/24/99 Temp fix: Clip the force value to the range of mass... \ MOD: HeP 07/27/99 Change name of components to "henri poincare" \ MOD: HeP 11/16/99 Rename (UPDATE): as REFRESH: \ Standardize methods: OPEN: CLOSE: DEFAULT: UNPDATE: \ REFRESH: and PREFAB: \ However, RESET: still follows the ob.elmnts model. \ MOD: HeP 04/08/00 Change the selectors' prefix from "particle_" to "hp_". \ Update some of the general comments. \ MOD: HeP 02-26-02 Fixed bug with PD.AT: and related methods. \ \ ToDo: Modify particle to have "volume" and incorporates collision. \ ToDo: RANDOMIZE: uses gaussian for position and velocity. include? task-hp_util myt:hp_util anew task-hp_particle \ data selectors \ 00 constant particle_force \ 01 constant particle_position \ 02 constant particle_velocity \ 03 constant particle_dvelocity 00 constant hp_force 01 constant hp_position 02 constant hp_velocity 03 constant hp_dvelocity method GET.TYPE: method #PROPERTIES: method PUT.ACTIVE.ELM: method GET.ACTIVE.ELM: method REFRESH: method PUT.MASS: method GET.MASS: method PUT.RADIUS: method GET.RADIUS: method PUT.WRAP: method GET.WRAP: method PUT.RANGE: method GET.RANGE: method PUT.POSITION: method GET.POSITION: method PUT.VELOCITY: method GET.VELOCITY: method PUT.FORCE: method GET.FORCE: method PUT.DVELOCITY: method GET.DVELOCITY: method PD.TO: method PD.AT: method VD.TO: method VD.AT: method FD.TO: method FD.AT: method DVD.TO: method DVD.AT: method GET.|V|: method GET.|F|: method GET.|DV|: method FREEZE: method RANDOMIZE: method PRINT.DATA: :class OB.PARTICLE iv-prtcl-mass 0 iv=> iv-prtcl-radius \ 17 iv=> iv-prtcl-vel-max \ hp_position iv=> iv-prtcl-active-elm \ self reset: [] ;m :m INIT: ( -- ) init: super self default: [] ;m \ memory allocation \ \ subclasses may add to the number of elements used for internal storage \ by overiding the #properties: method as follows: \ \ :m #PROPERTIES: ( -- elm# ) \ #properties: super #additional_elements + \ ;m \ \ the new: method will automatically pick these up. :m #PROPERTIES: ( -- elm# , number of elements for data storage ) 4 ;m :m NEW: ( #dim -- , number of springs and dimensions ) self #properties: [] over new: super \ dup new: iv-prtcl-enabled? dup new: iv-prtcl-wrap? dup new: iv-prtcl-min dup new: iv-prtcl-max new: iv-prtcl-range \ self reset: [] ;m :m FREE: ( -- ) free: super \ free: iv-prtcl-enabled? free: iv-prtcl-wrap? free: iv-prtcl-min free: iv-prtcl-max free: iv-prtcl-range \ iv-prtcl-instr IF iv-prtcl-instr close: [] THEN ;m \ instrument :m PUT.INSTRUMENT: ( instr -- ) iv=> iv-prtcl-instr ;m :m GET.INSTRUMENT: ( -- instr ) iv-prtcl-instr ;m :m PUT.ACTIVE.ELM: ( elm# -- , element to be passed to instrument ) iv=> iv-prtcl-active-elm ;m :m GET.ACTIVE.ELM: ( -- elm# ) iv-prtcl-active-elm ;m \ internal methods called by the space class :m OPEN: ( -- ) iv-prtcl-instr IF iv-prtcl-instr open: [] THEN ;m :m CLOSE: ( -- ) iv-prtcl-instr IF iv-prtcl-instr close: [] THEN ;m \ enable or disable puck :m PUT.ENABLE: ( flag dim# -- , enable or disable one dimension ) dup 0< IF drop fill: iv-prtcl-enabled? ELSE to: iv-prtcl-enabled? THEN ;m :m GET.ENABLE: ( dim# -- flag , get enable status of dimension ) at: iv-prtcl-enabled? ;m \ spacial range of particle :m PUT.RANGE: ( min range dim# -- , set spacial range of dimension ) dup 0< IF drop 2dup fill: iv-prtcl-range fill: iv-prtcl-min + fill: iv-prtcl-max ELSE 3dup tuck to: iv-prtcl-range to: iv-prtcl-min -rot + swap to: iv-prtcl-max THEN ;m :m GET.RANGE: ( dim# -- min range , get range of dimension ) dup at: iv-prtcl-min swap at: iv-prtcl-range ;m \ toroid space? :m PUT.WRAP: ( flag dim# -- , set dimension to toroid shape if true ) dup 0< IF drop fill: iv-prtcl-wrap? ELSE to: iv-prtcl-wrap? THEN ;m :m GET.WRAP: ( dim# -- flag , get wrap status of dimension ) at: iv-prtcl-wrap? ;m \ "mass" :m PUT.MASS: ( mass -- ) iv=> iv-prtcl-mass ;m :m GET.MASS: ( -- mass ) iv-prtcl-mass ;m \ "volume" :m PUT.RADIUS: ( r -- ) iv=> iv-prtcl-radius ;m :m GET.RADIUS: ( -- r ) iv-prtcl-radius ;m \ set position, velocity and force \ \ these methods are similar to ob.elmnt's put: and get: methods, and are \ really just defined for convinience since you can still use put: or get: \ with the appropriate selector. :m PUT.POSITION: ( x y z... -- , assign position of puck ) hp_position put: self ;m :m PUT.VELOCITY: ( vx vy vz... -- , assign velocity ) hp_velocity put: self ;m :m PUT.FORCE: ( fx fy fz... -- , assign force ) hp_force put: self ;m :m PUT.DVELOCITY: ( Ævx Ævy Ævz... -- , assign acceleration ) hp_dvelocity put: self ;m :m GET.POSITION: ( -- x y z... , retrieve position of puck ) hp_position get: self ;m :m GET.VELOCITY: ( -- vx vy vz... , retrieve velocity ) hp_velocity get: self ;m :m GET.FORCE: ( -- fx fy fz... , retrieve force ) hp_force get: self ;m :m GET.DVELOCITY: ( -- Ævx Ævy Ævz... , retrieve acceleration ) hp_dvelocity get: self ;m \ assign values per dimension \ \ these are the equivalent of ob.elmnt's ed.at: and ed.to: methods, which \ can still be used with the appropriate selectors. :m PD.TO: ( pos dim# -- , assign a coord to dimension ) hp_position swap ed.to: self ;m :m VD.TO: ( vel dim# -- , assign a velocity component ) hp_velocity swap ed.to: self ;m :m FD.TO: ( force dim# -- , assign a force component ) hp_force swap ed.to: self ;m :m DVD.TO: ( Æv dim# -- , assign acceleration component ) hp_dvelocity swap ed.to: self ;m :m PD.AT: ( dim# -- pos , coordinate of the given dimension ) hp_position swap ed.at: self ;m :m VD.AT: ( dim# -- vel , retrieve velocity component ) hp_velocity swap ed.at: self ;m :m FD.AT: ( dim# -- force , retrieve a force component ) hp_force swap ed.at: self ;m :m DVD.AT: ( dim# -- Æv , retrieve acceleration component ) hp_dvelocity swap ed.at: self ;m \ retrieve non-vectored values :m GET.|V|: ( -- |v| , speed of particle ) dimension: self #dimensions! hp_velocity get: self vec->abs ;m :m GET.|F|: ( -- |f| , absolute force value ) dimension: self #dimensions! hp_force get: self vec->abs ;m :m GET.|DV|: ( -- |Æv| , absolute acelleration ) dimension: self #dimensions! hp_dvelocity get: self vec->abs ;m \ zero motion of the particle :m FREEZE: ( -- , sets force velocity and acceleration to zero ) dimension: self \ dup 0 DO 0 LOOP hp_force put: self dup 0 DO 0 LOOP hp_velocity put: self 0 DO 0 LOOP hp_dvelocity put: self ;m \ update data based on force value :m REFRESH: ( -- ) iv-prtcl-instr dup IF iv-prtcl-active-elm dup 0> IF self rot element.on: [] ( elm# addr instr -- ) ELSE 2drop THEN ELSE drop THEN ;m :m UPDATE: ( -- , update position etc based on new force ) dimension: self 0 DO \ \ calculate acceleration... hp_force i ed.at: self \ -- f iv-prtcl-mass negate iv-prtcl-mass clipto iv-prtcl-mass / \ -- Æv dup \ -- Æv Æv hp_dvelocity i ed.to: self \ -- Æv \ \ update velocity... hp_velocity i ed.at: self + \ -- v dup \ -- v v hp_velocity i ed.to: self \ -- v \ \ update position... iv-prtcl-vel-max negate iv-prtcl-vel-max clipto \ -- v' hp_position i ed.at: self + \ -- p \ dup i at: iv-prtcl-min i at: iv-prtcl-max within? NOT IF i at: iv-prtcl-wrap? IF \ wrap to other side... dup i at: iv-prtcl-min < IF i at: iv-prtcl-max - i at: iv-prtcl-range mod i at: iv-prtcl-max + ELSE i at: iv-prtcl-min - i at: iv-prtcl-range mod i at: iv-prtcl-min + THEN ELSE \ bounce off edge... dup i at: iv-prtcl-min < IF i at: iv-prtcl-min - negate i at: iv-prtcl-min + ELSE i at: iv-prtcl-max - negate i at: iv-prtcl-max + THEN hp_velocity i ed.at: self negate hp_velocity i ed.to: self THEN THEN hp_position i ed.to: self ( -- ) LOOP \ self REFRESH: [] \ late bound! ;m \ print data and stats :m PRINT.DATA: ( -- , print data in array ) space ." force #0" hp_force self print.element: [] cr space ." position #1" hp_position self print.element: [] cr space ." velocity #2" hp_velocity self print.element: [] cr space ." dvelocity #3" hp_dvelocity self print.element: [] cr ;m :m PRINT.STATS: ( -- , print non dimension specific data ) ." Active elm# =" iv-prtcl-active-elm 4 .r cr ." Mass =" iv-prtcl-mass 4 .r cr ." Instrument = " iv-prtcl-instr ob.name cr ;m :m PRINT: ( -- ) cr name: self cr ." Element # \ Dim#" dimension: self dup IF 0 1 .r 1 DO i 8 .r LOOP cr ELSE drop THEN \ many: self IF self print.data: [] ?pause ELSE ." No Data!!" cr THEN self print.stats: [] ;m :m RANDOMIZE: ( -- , randomize position and initial velocity ) dimension: self 0 DO i at: iv-prtcl-range choose i at: iv-prtcl-min + LOOP hp_position put: self \ dimension: self 0 DO 1 choose+/- LOOP hp_velocity put: self ;m :m PREFAB: ( -- ) free: self 3 new: self instantiate ob.midi.instrument put.instrument: self ;m ;class