Swarm
Screen Saver
There are
chasing bees and one bee trying to escape from the average location of the
chasing bees. All the bees own a property mass and a property friction.
The friction is a force which is linearly proportional to the speed and directed
into the opposite directon than the speed vector. As you know, a mass is a
resistance against a change of speed (F = m*a, a = dv/dt, F: Force, m: Mass, a:
acceleration, v: speed, t: time) and a friction is a resistance against a speed
(F = k*v, F: Force, k: friction per speed, v: speed). Thus the friction value
together with the accelerating force determines the maximal speed a bee can
achieve (Vmax = F/k). The mass determines, how fast this speed can be achieved.
One pixel on the screen matches 1m. The force accelerating the chasers is
always directed to the location of the escaping bee and has always the value
1N. The force which is accelerating the escaping bee is directed so, to get
away from the average location of the chasing bees. The value of this force
does change between min-force and max-force. Min-force is
used as long as the distance between the location of the escaping bee and the
average location of the chasing bees is larger than low-radius. In case
of this distance becomes smaller than low-radius, max-force will be used
until the distance is larger than high-radius. The escaping bee is not
able to leave the screen. The value of Border-Repulsion determines the
repulsion of the escaping bee from the limits of the screen. In case of Border-Repulsion
is 1.0, the bee will be reflected with the same speed. In case of this value is
zero, the matching component of the speed vector of the escaping bee will be
zero after having touched the screen border. The value of timer
determines the intervall between two screen updates in ms. Before an update Number-Of-Steps
steps will be calculated, each step with a time intervall of timer
divided by Number-Of-Steps.
This version
of the screen saver contains the following changes compared to the previous version:
1. I´ve used
my German-English dictionary but again no spell checker.
2. For storage
of initialization data the registry is used instead of an .ini file.
Thus, every
user will have his own initialization data, which cannot be messed up by
another user.
3. In case of
color-palette animation is available, it will be used. The last version was
published without color-palette animation. The result were step-wise
color-changes (on 256 and 16 Color resolutions) only using the colors available
instead of floating color-changes.
4. A better
mathematical method is used resulting in higher accuracy.
The
mathematical model used is a System of nonlinear differential equations:
m*a + k*v = F
a + k/m*v =
F/m
with
v = dx/dt
a = dv/dt
There are two
differential equations for every bee -- one for every dimension -- the bees
live in a two dimensional space (x, y). The system is nonlinear, since the
accelerating force for e.g. the chasing bees is calculated like that:
Fx = (Xescape
- Xchase)/sqrt(sqr(Xescape - Xchase) + sqr(Yescape - Ychase))
Fy = (Yescape
- Ychase)/sqrt(sqr(Xescape - Xchase) + sqr(Yescape - Ychase))
For the
escaping bee the force is calculated like that:
Fx = (Xescape
- Xchase)/sqrt(sqr(Xescape - Xchase) + sqr(Yescape - Ychase))*F
Fy = (Yescape
- Ychase)/sqrt(sqr(Xescape - Xchase) + sqr(Yescape - Ychase))*F
with F equal min.
Force or equal max. Force (see rule described above).
This system
may be simplified, by asuming stepwise constant values for F. This
simplification results in a set of independend linear differential equations.
The last
version was using the Trapez-Rule to integrate the step-wise linear
differential equation.
I remembered
that there is no need to solve a linear differential equation by using a
numerical integration method like the trapez rule, but that there is a
analytical solution:
x(t) =
C1*exp(-k/m*t) + F/k*t + C2
with:
x(t = 0) = C1
+ C2
v(t = 0) =
dx/dt(0) = -k/m*C1 + F/k
Since time is
relative (grin) there is no need to use an absolute time in this system, but it
is possible to reset the time before every timestep to zero and to determine C1
and C2 by using the current x and v. Thus there is no need to calculate
exp(...) at every timestep, since the argument in the exp() function will
always be equal to -k/m*h with h equal the step-lenght.
This approach
does not require more operations for one step than the trapez rule. The
advantage is, that a system with a very small mass (the bees may accelerate
very fast) will be solved accurate. Using the trapez rule (and even worse using
forward euler rule, which I've used in the very first non-published version)
the speed calculated may be higher than the maximum speed possible, determined
by the friction and force.
But there is
still a need to use a step-lenght which is as small as possible (Number Of
Steps as high as possible) to make the force to be updated as often as
possible.
About programming:
I've used C++
with exception handling. You may easily check this by removing the write
permissions of the matching registry entry
(\HKEY_CURRENT_USER\Software\Peter_Foelsche\swarm\1.1) and trying to use the OK
button in the setup-dialog-box.
There are no
global variables, despite there is no need to not use global variables, which
would even make the code faster.
Storing into
registry is done using my persistent object technology. This technology is
heavily using C++-Exception-Handling. This technology may be used to write/read
to/from somewhere, including common files, named pipes, TCP/IP sockets, .ini
files, registry. Thus it may also be used to do IPC.
This is
realized by using -- to use a catch word -- plug&play, a programmer would
say: interface definition using abstract base classes.
Only one
method must be written to make objects of a class persistent. This method is a
constructor and this constructor is used for writing and reading. Thus there is
no need to use a void constructor and to initialize the object later in a
method (which is kind of C-Programming). There is also no problem in case of
storing or restoring of an object fails.
Storing/Restoring
may be done via defineable serialization methods for simple types (integers,
char, double, ...). This serialization methods realize machine-independency or
translation from/into human readable strings e.g. for storage into .ini files.
A persistent class may than be used without any need for changes with any
storage object to store binary or human reable into files or registry or for
IPC.
My coding
style has heavily changed since I started using C++-Exception-Handling, 2 or 3
years ago using Borland C++ v1.5 for OS/2 2.0. Usually the exception classes
provided in the standard C++ library do not fullfill my requirements. This
additional requirements are: An exception object must be able to contain a
pointer to another exception object. An exception object must be able to create
a copy of itself on the freestore. Thus an exception object may in fact be the
head of a chain of exception objects. This is what I understand is hierarchicle
exception handling. There should not just an object be thrown, telling the
caller of the code that the write() system call has failed because of BADF, but
the user should see some more explanation made by catching an exception object
and rethrowing a new one which contains a pointer to a copy of the catched one
to explain the context of the catched exception object. This may also be
realized in base-class/member-class relations -- obviously not by
catching/rethrowing, since you cannot put a call to a base-class/member-class
constructor into a try-catch-block.
Peter Foelsche