Moving dots

Arjen Markus (3 June 2003) During the 4th European Tclers' Meeting, several of us came to speak about applying my idea of Programmed story telling to make a tool for children to learn how to program. Richard Suchenwirth suggested using a puppy that you give commands to. Charming an idea as this is, I thought of a simpler approach first (doing the graphics and building in the social behaviour takes some effort, and I am one for fast results nowadays :). Why not define a set of commands for points or dots chasing each other? With a few commands you get interesting curves.

In the example below:

• A follows a straight line and B follows A at a right angle
• C1 to C4 start off at a square and follow each other to give a spiralling motion

Technical notes:

• If you have a dot with an autonomous movement, the speed may influence the resulting curve for a following dot.
• The speed at which dots follow each other is proportional to their distance. This makes the differential equations that are being solved linear. A variation would be to make the speed constant and have only the direction depend on the vector between the two dots.
• There is no error checking (fast results, remember?).

# movedots.tcl --
#    Define moving dots that can trace each other
#

package require Tk

# dot --
#    Define a dot (give it a name)
# Arguments:
#    name     Name of the dot (new command)
#    x        X-coordinate at start
#    y        Y-coordinate at start
#    colour   Colour of the line to draw
# Result:
#    None
# Side effect:
#    Command "name" will be created
#
proc dot {name x y colour} {
variable all_dots
variable dot_prop

lappend all_dots \$name
set dot_prop(\$name,x)      \$x
set dot_prop(\$name,y)      \$y
set dot_prop(\$name,colour) \$colour

interp alias {} \$name {} DotImpl \$name
}

# DotImpl --
#    Handle the commands for a dot (motion etc.)
# Arguments:
#    name     Name of the dot
#    subcomm  Subcommand
#    args     Any arguments
# Result:
#    None
# Side effect:
#    Whatever the subcommand means
#
proc DotImpl {name subcomm args} {
variable all_dots
variable dot_prop

switch -- \$subcomm {
"moves"   { set dot_prop(\$name,movex) [lindex \$args 0]
set dot_prop(\$name,movey) [lindex \$args 1]
set dot_prop(\$name,move)  "move"
}
"follows" { set dot_prop(\$name,follows) [lindex \$args 0]
set dot_prop(\$name,move) "follows"
set dot_prop(\$name,angle) 0.0
if { [llength \$args] == 3 } {
set dot_prop(\$name,angle) [expr {[lindex \$args 2]/180.0*3.1415926}]
}
}
"draw"    { DotDraw \$name }
"update"  { set dot_prop(\$name,x) \$dot_prop(\$name,xn)
set dot_prop(\$name,y) \$dot_prop(\$name,yn)
}
default   { # Ingnore }
}
}

# DotDraw --
#    Draw the (new) position of the dot
# Arguments:
#    name     Name of the dot (new command)
# Result:
#    None
# Side effect:
#    Line segment drawn, position updated
#
proc DotDraw {name} {
variable all_dots
variable dot_prop
variable t
variable dt

if { \$dot_prop(\$name,move) == "move" } {
set x [expr \$dot_prop(\$name,movex)]
set y [expr \$dot_prop(\$name,movey)]
} else {
set target \$dot_prop(\$name,follows)
set angle  \$dot_prop(\$name,angle)
set x      \$dot_prop(\$name,x)
set y      \$dot_prop(\$name,y) ;# Updates should be delayed!
set tx     \$dot_prop(\$target,x)
set ty     \$dot_prop(\$target,y)
set vx     [expr {\$tx-\$x}]
set vy     [expr {\$ty-\$y}]
set dx     [expr {\$dt*(cos(\$angle)*\$vx-sin(\$angle)*\$vy)}]
set dy     [expr {\$dt*(sin(\$angle)*\$vx+cos(\$angle)*\$vy)}]
set x      [expr {\$x+\$dx}]
set y      [expr {\$y+\$dy}]
}

# Updates should be delayed!!

.c create line \$dot_prop(\$name,x) \$dot_prop(\$name,y) \$x \$y -fill \$dot_prop(\$name,colour)
set dot_prop(\$name,xn) \$x
set dot_prop(\$name,yn) \$y
}

# main --
#    Main code:
#    - Create the canvas
#    - Define some dots
#    - Draw the tracks they produce
#

canvas .c -background white -width 500 -height 500
pack   .c -fill both

set t       0
set dt      0.02
set nosteps 1000

#dot A 450.0 250.0 blue
#dot B 470.0 250.0 green
#A moves {250.0+200.0*cos(\$t)} {250.0+200.0*sin(\$t)}

dot A 0.0 200.0 blue
dot B 0.0 230.0 green

A moves {30*\$t} 200.0
B follows A -angle -90

dot C1 400.0   0.0 blue
dot C2 400.0 400.0 green
dot C3   0.0 400.0 red
dot C4   0.0   0.0 magenta

C1 follows C2 -angle -10
C2 follows C3 -angle -10
C3 follows C4 -angle -10
C4 follows C1 -angle -10

for { set i 0 } { \$i < \$nosteps } { incr i } {
foreach dot \$all_dots {
\$dot draw
}
foreach dot \$all_dots {
\$dot update
}
set t [expr {\$t+\$dt}]
}

Theo Verelst Well well, contractive difference equations, it would be good to take the accompanying differential equations, which for as it seems here limited order linear problems (oops, maybe I didn't see right, is the distance linear?) would seems solvable. Maybe even automatically. I remember a big book with diff. eq. that definitely contained images of this kind.

 Category Example