\ 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