License ======= This code is in the public domain. Use, modify, redistribute with or without modification, or license it as you see fit. Manifest ======== Files in this package are: readme.txt This file sample.dat Some sample Octave data, a 100x100 matrix tk_interp.cc C++ source for a dynamically loaded Octave module Contains routines for using BLT/VTK with Octave tk_matrix.tcl Example Tcl/Tk GUI which uses BLT/VTK with Octave tk_matrix Executable script that runs Octave and loads the GUI from tk_matrix.tcl Makefile The Makefile for tk_interp.cc rainbow.m A colormap function tk_*.m Various user interaction dialogs Compiling Octave with tk_interp.cc ================================== In order to use tk_interp, you may need to relink the Octave binary with pthreads. 1) Untar/gz the octave source to /someplace/octave 2) Change directory to /someplace/octave and run ./configure 4) Edit /someplace/octave/Makeconf, changing LIBS = ... to LIBS = ... -lpthread or maybe LIBS = ... -lpthreads 5) Change directory to /someplace/octave and run 'make' and optionally run 'make install' afterwards. After installation (which by default is in /usr/local/bin), rename octave to octave-pthreads and mkoctfile to mkoctfile-pthreads Creating tk_interp.oct ====================== After relinking a custom version of Octave with pthreads, you'll need to create tk_interp.oct. Modify Makefile in the tk_octave directory to reference the appropriate mkoctfile for your custom version of Octave, and comment out TCL_OPTS=, BLT_OPTS= or VTK_OPTS= as appropriate. Type make and it should create tk_interp.oct for you. Note that to use BLT and VTK, you will need to link with code distributed under four different licenses: 1) Octave uses a GPL license. 2) Tcl/Tk uses a BSD-style license without advertising clause, which is said to be GPL compatible. 3) BLT uses a BSD-style license with advertising clause, which is said to be GPL incompatible. 4) VTK uses a BSD-style license without advertising clause, but with a restriction against redistributing with modifications. The FSF considers linking as equivalent to modification. Since Octave is GPL, this would mean that all parts of the program have to be compatible since they won't work unless they are linked. Since this interpretation of the GPL has not yet been tested in any court, use your own judgement. Some simple tests ================= Is it alive? $ octave-pthreads tk_interp tk_cmd('toplevel .msg') tk_cmd('button .msg.hello -text "Hello, world!" -command {destroy .msg}') tk_cmd('pack .msg.hello') Can you get data from it? tk_cmd('toplevel .data'); tk_cmd(sprintf('set value %f', pi)); tk_cmd('entry .data.entry -textvariable value'); tk_cmd('pack .data.entry'); tk_cmd('bind .data.entry {destroy .data}'); tk_cmd('tkwait window .data'); mypi = eval([tk_cmd('set value'), ";"]) Try one of the built-in dialogs tk_message("Hello, world!"); Running the BLT/VTK example =========================== In the tk_octave directory you should now be able to run the main example. This requires BLT, and can use TkTable and VTK if you have them. The tk_matrix script needs to know the location of your custom version of octave. If it is not in /usr/local/bin/octave-pthreads, change the top line of the script as appropriate, then type: $ ./tk_matrix If you get the message that oct_mtov is not a proper command, then you haven't specified OPTS = $(BLT_OPTS) in the Makefile. The example lets you view a 2D matrix of octave data as an image. Click with the middle button to look at the X-Y cross sections at that point. Click with the left button, move, and click with the left button to zoom into a region of the matrix. Click with the right button to return to the full image. Click the "Table" button to view the data in a spreadsheet. You can type octave commands directly into the command window. E.g., logsample = log(1+sample); You can view a different matrix by typing its name into the matrix name window. Assuming you have defined logsample as above, then enter "logsample" into the window and press return. How it works ============ tk_interp.cc defines the following new commands in octave: window_name = tk_interp() starts the tcl interpreter result = tk_cmd() sends a tcl command to the tcl interpreter tk_loop() waits on the tcl interpreter, processing callbacks as needed tk_end() ends the tcl interpreter tk_interp.cc defines the following new commands in tcl: oct_cmd command sends a callback to the octave interpreter. All arguments are glued together as one long command string. oct_matrix name [exists|rows|cols|columns|min|max] grabs info about a matrix from octave oct_matrix name [elem|element] i j grabs name(i,j) from octave oct_string exist grabs info about a string from octave oct_string name grabs name as a string from octave oct_mtov name vector x y sizex sizey grabs name(x:x+sizex,y:y+sizey) from octave and places it into a BLT vector. oct_mtovtk name VTKname grabs a matrix from octave and places it into a VTK data structure oct_quit ends the Octave interpreter Note that if name starts with global::, it searches the global symbol table, if name starts with top::, it searchs the top level symbol table. If name starts with current::, it searches the current symbol table. The default is to search the top level symbol table. WARNING!!! There are concurrency issues to sort out which can be especially severe with current::, so use with caution. tk_interp also defines a new image format: image create photo tclimage defines a new variable tclimage which will contain a photo tclimage configure -data "name" like imagesc, scales the image according to the current colormap This requires the following octave declaration before it will work: global __current_color_map__ = gray(64); Both name and __current_color_map__ are variables in the top level symbol table. tclimage configure -data "name -colormap map" like imagesc, scales the image according to the colormap map Both name and map are octave variables in the top level symbol table tclimage configure -data "name -indexed" like image, doesn't scale the image, but assumes that it's values are are 1-origin indices into the colormap Projects ======== Modify tk_matrix.tcl so that you can enter either "z" or "x y z", and update the x and y axis limits appropriately. Also give the programmer control over x, y and z axis labels and matrix title. Implement variable notification so that when the value changes in octave, the tcl matrix gets redrawn. Define a widget type in octave along with packing commands so that the user interface can be implemented entirely in Octave. Sort out concurrency issues. Currently the tcl thread is looking at the octave variables while octave is running in a separate thread. To see how much of a problem this is in practice, enter "sample" as the tk_matrix name (and press return), then type the following octave command: for i=1:rows(sample), for j=1:columns(sample), sample(i,j)=log(1+sample(i,j)); end; end; While that command is executing, click on the matrix name entry box and press return. You will see the matrix slowly change from linear to log scale. On my machine, this doesn't crash. These are a couple of real race conditions underlying which could lead to a seg_fault, but the window is very small (not much wider than the amount of time it takes to copy the octave_value reference and update its reference count. In practice, the octave main loop is going to be sitting in tk_cmd or tk_loop during almost all GUI interaction, so the issue will never come up, but you will have to think carefully about what you put in your tk_cmd and oct_cmd commands to be sure. See SAFE_VAR in tk_interp.cc.