Version 7 of Vector rotations with Bwise

Updated 2004-03-25 08:40:05

by Theo Verelst

A common thing in math and science is the rotation of a vector over an angle, as most with a math basis knowledge will know, a matrix can be used for the purpose of performing the rotation on a vector.

A rotation matrix is even a very well formed matrix in general with normally excellent invertability and eigenvalue computability.

It is not hard to make a orthogonal and even orthonomal basis for both the column and row space of a 2 dimensional matrix, and we can do so symbolically with simple geometic functions with a single rotation angle as a parameter for each of the 2x2 matrix elements which determines the rotation the matrix performs when multiplied to a vector.

Clear application is computer graphics, but other computations, for instance where complex numbers are used such as in electronics or other solutions of differential equations, also can become more insightfull by clear (simple) vector representations.

Bwise is about BlockWise programming, and also about Tk canvasses with interactions and graphical feedback, so this is a nice example.

In tcl, without using anything specifically from the Bwise package, except I used the function window, and will use the 'create block' facility of it, the rotation of a 2 dimensional (2 real components obviously quantized to some computer number resolution) vector can be performed by:

 proc vec2rot { x y a } {
   set     rotor.out [ expr cos($a) *$x  - sin($a) *$y ]
   lappend rotor.out [ expr sin($a) *$x  + cos($a) *$y ]
 }

When this procedure is defined, procs_window from bwise can be used to blockify our procedure. First, refresh the list of procs, then double click vec2rot, and then press the ' block' button on the bottom. First, a block on the canvas will be generated with name 'vec2rot'. When pressed again, serial numbers are added to the name, based on the highest appearing serial number on the canvas thus far. I double clicked and 'del sel' (deleted) the first instance of the block after clicking into existence two more, so I have vec2rot1 and vec2rot2 .

The procedure, like any, has only one return value, which is a list.

So we define for the sake of the Bwise canvas we have in mind a seperate block, which splits a 2-long list into elements for to two output pins. We use the newproc bwise proc to generate a 2 output block, possibly using the pro_args functions, which automatically puts arguments in place for the newproc, which gets default arguments except for name and output names x and y.

   pro_args  newproc {{name {sep1}}  {out {x y}}}

Gives:

   newproc {} sep1 in {x y}

Either using eval on the pro_args or simply issuing the newproc command a seperator block is created which is given list-split block function code, and connected to the ouput of the rotation block by either command or UI:

   set sep1.bfunc {set sep1.x [lindex ${sep1.in} 0] ; set sep1.y [lindex ${sep1.in} 1] }

http://82.168.209.239/Wiki/rotor1.jpg

The above Bwise representation was made by doing the above twice to create two rotator blocks and list splitters, and by connecting the blocks up and dragging them in place.

Lets define PI, and see if we can make the block sequence work for us by feeding it a vector, specifying angle, activating the block chain, and inspecting the results at the output pins.

   set pi [expr 2.0*acos(0)]

The input vector can be set, for instance to (1,0) by editing the fields in the vec2rot1 blocks' data window, called up by right clicking on the block and selecting 'Data'. After also entering an angle, for instance 0 (rad), and also entering an angle in the vec2rot2's data window, we can apply 'Funprop' (short for functional propagate, which makes all blocks 'fire' which at some point in the process have all their input pins fed with new data over a connection) to run the whole sequence, which results in the following:

http://82.168.209.239/Wiki/rotor2.jpg

Does that add up? Easily. Graphical inspection makes clear we have entered x1 basis vector into our computation, and requested two 0 rotations of rotations matrix/vector multiplication blocks, and we see at the overall output at sep2 that we get the same vector as x1 as a result. Now lets add some rotation to the chain, for instance a 180 degree rotation in the first block by entering the (numerical) value of PI into the field:

   set vec2rot1.a $pi     
   # 3.14159265359

which after issueing

   net_funprop vec2rot1

To 'run' the network again results in an output vector of (-1.0 -2.06823111155e-13) which is very close to the vector (-1,0) which is indeed -x1 , the half circle rotated input vector.

We may also want to check how we can rotate followed by inverse rotate