> MultiSlice Programmer Documentation
[MultiSlice API]
MultiSlice is designed in order to shield programmers from the X/MOTIF
code, which can often prove
to be extremely difficult to program in. It is also designed to provide
programmers with the ability to
manipulate large 3D data-sets without resorting to falling back on
X/MOTIF. In addition, the MultiSlice
API allows the programmer access to raw X/MOTIF if necessary, observing
only minimal precautions.
Some of the commonly used variables in MultiSlice are also self-correcting,
i.e. a programmer writes
a routine which corrupts one or more variables, they can be self-corrected
without the program
crashing. (Note that, however, self-correction is limited and is not
an excuse to write buggy code !!)
Self correction is mainly utilized in order to prevent large data-sets
from memory leaks, a rather
annoying bug in the X-Windows system that often causes programs
to crash over time due to
corruption of memory areas. Although memory leaks have not been experienced
in the current version,
which can handle upto twenty images (512 X 512) without any problems,
future extensions which may
support true OpenGL-based 3D images with more images open (current
version has been tested
with 40 images with no problems, although the facility was later removed
due to a large amount
of swap file accesses), may suffer from memory leaks. You may refer
to a technical paper on how
to minimize the effects of memory leaks if you need to by clicking
here.
How do I install MultiSlice on my system ?
As a programmer/administrator installing MultiSlice is relatively uncomplicated. Simply download the file slice and run it if you have Irix 5.3 and a MIPS R4400. Alternatively, download the first slice file, un-gzip it (gzip *.gz) and un-tar it (tar xvf filename.tar). After that, simply run a make -u and strip slice. Copy the slice file generated to whichever directory you want the users to work in, and copy the *.raw and *.study files to the same directory. Also copy and customize the two shell scripts (wwwhelpmoi and qpr) to your particular configuration. Thses are simple, uncomplicated scripts and should not cause any problems.
User reports crashes/bugs and other problems
If users complain of any crashes on start-up, please check your
X-Windows configuration. You must have X11R6 or later, as well as Motif
1.2. On most older Sun systems, OpenWindows will not support full X11R6
functionality. You must have Motif and an X11R6 compatible windowing system.
If MultiSlice starts and quits immediately reporting that it cannot open
file `slicetempyhsTN', it would indicate that the user running it does
not have write-access to the current directory. Note that MultiSlice is
extremely file-intensive and requires full access (read/write and modify)
to the current directory. If MultiSlice quits during a working session
with the message `cannot open xyz.raw' check that the file is [a] readable
and [b] present in the path indicated and that path is also readable/writable.
If the user accidentally leaves MultiSlice running overnight, and complains
that MultiSlice quit with the message `Possible system timeout', this will
not be a bug. MultiSlice has an automatic timeout after 8.30 hrs of inactivity.
This is to prevent CPU cycles being wasted and to prevent a possible system
lockout due to a crash in the X kernel (if it ever occurs) or a session
left running in the background if the shell it runs under is destroyed
(a rather common occurance in most systems). Note that in all these errors
all user-processed functions are still saved to disk. Simply load all the
slicetempyhsT* files and save the ones needed to be saved under different
filenames. Also note that MultiSlice will, by default, save everything
even in the event of a fatal crash (unlikely, since it has been tested
extensively). In extreme circumstances, only the last file processed could
be affected since MultiSlice opens and closes only one file at a time (although,
very rapidly).
MultiSlice System performance and timings ?
MultiSlice compares on a roughly equal basis with the old Slice
program in terms of timing and performance. The overhead that the old program
generated when reading and writing to and from the screen (XPutPixel/XGetPixel)
is offset by the fact that MultiSlice loads a file in the background and
creates the pixmap and window system necessary. In comparative performance
timings :-
Region Growing (single image) Old Slice: 2.22s
MultiSlice: 3.05s
Image Growing (single image) Old Slice:
7.55s MultiSlice: 6.71s
Note that these timings are +/- 0.2s. System loading was 52 processes
(+2 slice & MultiSlice), roughly average for an SGI Indy, images loaded
were identical and points chosen on the image were within 10% of each other.
Each had one image loaded and was given 15s to settle down (and for the
multitasker to execute in MultiSlice). Timings were not made electronically,
but with a stopwatch, since the old slice had no multitasking capability
or any form of self-timing capability. Timings are roughly equal for both
cases. Note that MultiSlice will normally be a lot faster due to it's multiple
image processing capability. The time taken for the user to load a file
in the old slice and run the process each time will be significantly slower
than the time taken to do a 3D image processing function. As a rough estimate
for complete timings,
Region growing (ten images) Old Slice: 1min
54s MultiSlice: 58.23s
Image growing (ten images) Old Slice:
2min 86.8s MultiSlice: 1min 9.34s
Note that these timings include the time taken for the user to load
a file in the old slice, and the user to select and load a selection of
images in MultiSlice. Since human interaction is included, timings may
very from person to person. Alos note that the significant disadvantage
of the old slice was that each image had to be loaded one at a time and
processing was also one at a time, which is not the case in MultiSlice.
Timings, as before, are comparable (excluding the roughly 1 minute for
user interaction in the old slice environment).
How does memory get consumed and swap space used as the program runs ?
Following is the dump of a memory/swapfile allocation as the program processes 10 images and does a 3D region growing algorithm on the images, followed by a load of 10 more images and a de-allocation of one of the images loaded.
Swap space allocated and memory mapped (MultiSlice, 48 Meg. RAM, MIPS R4400, IP22) Cooley% swap -s total: 3.08m allocated + 156.07m add'l reserved = 159.15m bytes used, 126.35m bytes available Cooley% ..completed. Changed temporary file extensions..to Y. swap -s total: 3.08m allocated + 157.12m add'l reserved = 160.20m bytes used, 125.30m bytes available Cooley% swap -s total: 3.08m allocated + 157.12m add'l reserved = 160.21m bytes used, 125.30m bytes available Cooley% swap -s total: 3.08m allocated + 157.35m add'l reserved = 160.43m bytes used, 125.07m bytes available Cooley% swap -s total: 3.08m allocated + 157.35m add'l reserved = 160.43m bytes used, 125.07m bytes available Cooley% swap -s total: 3.14m allocated + 162.18m add'l reserved = 165.31m bytes used, 120.19m bytes available Cooley% swap -s total: 5.11m allocated + 163.28m add'l reserved = 168.39m bytes used, 117.12m bytes available Cooley% swap -s total: 8.63m allocated + 164.23m add'l reserved = 172.87m bytes used, 112.64m bytes available Cooley% swap -s total: 7.81m allocated + 167.39m add'l reserved = 175.20m bytes used, 110.30m bytes available Cooley% swap -s total: 10.06m allocated + 165.38m add'l reserved = 175.44m bytes used, 110.06m bytes available Cooley% swap -s total: 9.96m allocated + 165.73m add'l reserved = 175.69m bytes used, 109.81m bytes available Cooley% swap -s total: 9.80m allocated + 165.64m add'l reserved = 175.43m bytes used, 110.07m bytes available Cooley% swap -s total: 9.61m allocated + 165.57m add'l reserved = 175.18m bytes used, 110.32m bytes available Cooley% swap -s total: 9.16m allocated + 166.03m add'l reserved = 175.19m bytes used, 110.31m bytes available Cooley% Normal program termination ... Run Time : 110 seconds --------------------------MultiSlice RTP---------------------------- [1] Done slice Cooley% swap -s total: 7.62m allocated + 142.24m add'l reserved = 149.86m bytes used, 135.65m bytes available Cooley% swap -s total: 7.62m allocated + 142.24m add'l reserved = 149.86m bytes used, 135.65m bytes availableAs can be seen, the memory requirements increase rapidly when loading and processing, before reducing slightly when a file is de-allocated, and then dropping sharply when the program quits.
What do I need to program in MultiSlice ?
In order to program in MultiSlice you need to have :-
(i) A Silicon Graphics Indy (MIPS R4400-132MHz) or higher with at least
48 megabytes of RAM
and 120 megabytes of free disk space. In addition,
the swap file should be at least 100 megabytes.
(ii) A decent C compiler (the default one included with the machine
should suffice).
(iii) X11R6 and Motif 1.2 or higher.
(iv) Irix version 5.3 or higher.
In addition, you need to have a reasonable knowledge of C. You don't
need to know anything about
X/MOTIF, K&R C, C++ or anything else. If you know how to manipulate
files (load, save etc.) and
have a basic knowledge of arrays, you can write a reasonably good function
in MultiSlice that can
manipulate upto 10 files and do a large number of image handling/manipulation
operations in 3D
or 2D, display the results, give the user an option to maximise/minimise
the output, all without writing
more than a single line of X/MOTIF code (the single
line is simply to attach your function to the menu
system).
All MultiSlice functions are grouped into four groups, which are a definition
of the difficulty level and
knowledge required by the programmer. Any good C programmer can easily
write a Group I or II
program without any difficulty. However, groups III and IV require
extensive knowledge of the
X/MOTIF system. It is recommended that you start writing a Group I
or II function before extending
it to a Group III or IV after you gain familiarity with the system.
Note that self-correction is NOT
provided for Group III or IV programs to a large extent. A bug/error
in these functions will crash the
system completely, possibly without any form of recovery or protection
for the files loaded.
What are Groups ?
Groups are simply a category of functions, similar to a security level.
The number of variables imported
and the type indicates the level of a group. Groups are defined as
follows :-
Group | Description of Group |
I | This group defines the base level. Functions operate in psuedo-3D (i.e. the function can handle upto 10 files, display upto 10 outputs, and process the images without any user input) and require practically no knowledge of X/MOTIF. These can be simply put together by using the checklist described below and require the least programmer knowledge. This is a good level to start out with, in order to build confidence and learn a little about the API itself, without the need for extensive debugging or extensive knowledge of the X-Windows system. |
II | This group is at a slightly higher level. It allows the function to display a simple check box or other form of user input, with a little knowledge of X/MOTIF and keeps some of the security checks and functionality of Group I in place. In addition, it allows access to the real-time clock, allowing the functions to run in real-time with self-timing mechanisms. It also allows background processing if required, along with screen drawing capability. It does not come with an extensive checklist, so when building functions in this group, proceed with some degree of caution. |
III | This group does not come with any sort of self-correction. It does not come with any help or a checklist and has very little documentation. It will allow you to work in full 3D, use the OpenGL API to display images if necessary and allows access to most variables. When using this group and sub-functions, beware of memory leaks with large data sets. In addition be aware of the differences in color maps between the standard color map and a full OpenGL color map. This group has not been implemented fully, although a degree of support has been built in. The background display routine allows only 2D images to be represented and has to be extended to support OpenGL. You MUST be able to program in Group IV when attempting the full usage of this group. |
IV | System Group. This group comes with a degree of documentation, most of which is contained within the program code. All system functions are accessible from this group. You can manipulate any number of files in any way, extend the number of files loaded, change the background routines, alter the user interface and do anything to the program's functionality. There is NO self-correction, any routines which belong to Group IV will crash the program easily. Use all required caution and do extensive and thorough testing for extended periods. There is very little chance of self-recovery. |
Variables ?
MultiSlice uses the manipulation of variables to determine the level
of a program. There are a lot of
variables in MultiSlice, out of which only a fraction are usually imported
into a function (usually not
more than 2 (one of which is an int and the other a char) for a filter,
for example). The following
is a complete listing of all the external variables in MultiSlice :-
Variable Names | Type | [F]lag/[D]ata | Group Level | Reference |
fg,bg | unsigned long | D | II | foreground & background black and white pixel colors. |
time | int | D | II | Time (in seconds) since start of program execution. |
curfile | int | D | I | Current file number
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Checklists are a fast way of implementing a Group I and most of a Group
II function.
Similar to a template in a word processor, simply follow the checklist
to implement a
simple functions. For more extensive functions, you will need implement
the code by
yourself by building on the checklists.
Checklist - Standard function checklist (1 input file, 1 output file) - Group I
This checklist will foxus on writing a single input and single output function called from the menu of MultiSlice RTP. It will be structured in several parts as follows.
1. Change to your MultiSlice directory.
2. Create a new file called myfunc.c
3. Add the file to the Makefile.
4. Open myfunc.c in a text editor.
5. Create the function, calling it newfunc (say) :-
void newfunc_callback(Widget w, XtPointer client_data,
XmAnyCallbackStruct *call_data)
{
}
6. Note that the _callback denotes a function called back from the
menu.
7. Proceed by declaring local variables in the { } of newfunc()
e.g.
Arg al[10];
int ac;
int current;
FILE *p_file;
int i;
int a,b;
8. Now initialise the temporary I/O arrays as follows :-
for (a=0;a<512;a++){for (b=0;b<512;b++) {
array1[a][b]=0; array2[a][b]=0; }}
9. Run the normal status check on the system by inserting your code
inside the if statement.
if (yhs_files_open >=1 && yhs_files_open
< 20 && yhs_filename[0] >= 1)
{
yourcodehere();
}
10.The lines above simply check that files are loaded & selected
properly.
11. Open your input filename as follows :-
if((p_file = fopen(yhs_filename1,"r")) == NULL)
{
fprintf(stderr, "Cannot
open: %s\n",yhs_filename1);
exit(1);
}
12. Now read it in & close the file.
for (a=0;a<512;a++){
for (b=0;b<512;b++)
{ array1[a][b]=getc(p_file); }}
fclose(p_file);
13. Type your code in place now. Note that all values of the file are
in array1, so your code will generate output into array2.
14. Output your code to the relevant file by writing to array2.
strcpy(tempfileold,tempfilenew);
/* copy the new filename to the old file i.e. save
the old file */
strcat(tempfilenew,addcharac);
/* new free temp file */
if((p_file = fopen(tempfileold,"w")) == NULL)
{
fprintf(stderr, "Cannot
open: %s - Temporary file for writing.\n",tempfileold);
exit(1);
}
for (a=0;a<512;a++){
for (b=0;b<512;b++)
{ putc(array2[a][b],p_file); }}
fclose(p_file);
15. All the values are saved. Now unlock the background file loader.
run_once=0;
file_loader=1;
file_yhs=tempfileold;
16. And end your function at this stage.
}
}
17. Now, your function should be working and integrated into MultiSlice.
Ensure that your have imported run_once,file_loader,file_yhs, yhs_filename[0]
and yhs_files_open as external variables at the start of your file. Also
import any libraries used (e.g. math.h) at the start of your file.
18. Your function has now been created, but not yet linked to the menu.
Open the file menu.c, and type the following :-
void create_my_menu(Widget parent)
{
19. The above statement creates a new menu. Declare the widgets for
it as follows :-
Widget my_menu_pane, my_menu_button, my_button;
20. Create the menu pane for the menu ..
my_menu_pane = XmCreatePulldownMenu(parent, "MyFunc
", NULL, 0);
21. Populate the menu pane ..
my_button = XmCreatePushButton(my_menu_pane, "My
first function",
NULL, 0);
XtManageChild(my_button);
22. Add the callback..
XtAddCallback(my_button, XmNactivateCallback,
(XtCallbackProc) newfunc_callback, (XtPointer) NULL);
23. Tidy up the procedure..
argcount = 0;
XtSetArg(args[argcount], XmNsubMenuId, my_menu_pane);
argcount++;
my_menu_button = XmCreateCascadeButton(parent, "MyMenu
", args,
argcount);
XtManageChild(my_menu_button);
}
24. Note that although several statements of X/MOTIF code are stated
above, only one line are relevant to include your function to an existing
menu (which is the usual case). Simply type the following line into your
code if you do not wish to create a new menu and pane on the menu bar of
MultiSlice RTP :-
XtAddCallback( XtManageChild(XmCreatePushButton(existing_menu_pane,
"My first function", NULL, 0)), XmNactivateCallback, (XtCallbackProc) newfunc_callback,
(XtPointer) NULL);
Substitute existing_menu_pane with the name of the correct pane. there is no need to declare any Widgets and no need to create a seperate menu, unless required. Omit steps 18-23 if using this procedure.
Hence, only a single line of X/MOTIF code is required for implementing functions in MultiSlice RTP.
Checklist - Basic Group II function checklist (1 user input, 2 input, 1 output)
1. Using the Group 1 checklist, implement your function. Add the following
in order to create user interaction with a dialog box, as follows.
2. Create the dialog-creation function.
void create_my_dialog(Widget parent) {
3. Declare variables used.
XmString message;
Widget temp_widget = parent;
4. Ensure the parent of the dialog is a shell widget.
while ( !XtIsShell(temp_widget) ) {
temp_widget = XtParent(temp_widget);
}
5. Create the message.
message = XmStringLtoRCreate(MY_MESSAGE, XmSTRING_DEFAULT_CHARSET);
6. Create the dialog.
argcount = 0;
XtSetArg(args[argcount], XmNmessageString, message); argcount++;
my_dialog = XmCreateQuestionDialog(temp_widget, "What do you
want to input",
args, argcount);
7. Add the actions to the buttons.
XtAddCallback(my_dialog, XmNokCallback,
(XtCallbackProc) ok_button_callback, (XtPointer) NULL);
XtAddCallback(my_dialog, XmNcancelCallback,
(XtCallbackProc) cancel_button_callback, (XtPointer) NULL);
8. Cleanup the strings.
XmStringFree(message);
}
9. Create the activation function.
void activate_my_dialog(Widget w, XtPointer client_data,
XmAnyCallbackStruct *call_data) {
selection = MYSELECT;
action = SELECT;
refresh_action();
XtManageChild(my_dialog);
}
10. create the de-activation function
void deactivate_my_dialog(void) {
/* null - no actions at present dialog is auto unmanaged */
/* whenever any of its buttons are pressed.
*/
}
11. Create the callback functions.
static void ok_button_callback(Widget w, XtPointer client_data,
XmAnyCallbackStruct *call_data) {
my_code_here();
}
static void cancel_button_callback(Widget w, XtPointer client_data,
XmAnyCallbackStruct *call_data) {
deactivate_exit_dialog();
}
12. That completes the user interaction. Simply add the create_dialog
and activate_dialog functions to the menu file as shown previously and
run your function.
Checklist - Standard conversion checklist (convert a filter from
the old slice to MultiSlice) - Group I
The best way to demonstrate standard procedure to convert a filter
is to simply take an existing filter function and simply demonstrate the
mechanism for converting it on a line-by-line basis. In this case we consider
a gaussian-type filter with a few enhancements and user input of a single
value. The conversion procedure on a line-by-line basis is as follows :-
#define f6 6
#define f7 7
#define SIGMA_MESSAGE "Enter sigma value (0.5-20):"
#define SIGMAVALUE "Introduce sigma value"
typedef float matrix[IMAGE_WIDTH][IMAGE_HEIGHT];
extern Widget main_window;
extern Cursor theCursor;
/* Extern variables */
extern char *action;
1. Import extra variables to support your function.
extern int yhs_files_open;
extern int yhs_filename[21];
extern int selection;
extern Widget draw_1,draw_2;
extern GC image_gc_2;
extern Pixmap thePixmap_2;
extern XImage *theXImage_1;
extern XImage *theXImage_2;
extern int file_not_loaded;
extern unsigned long fg, bg;
extern void refresh_action(void);
extern int figure;
extern int array1[512][512];
extern int array2[512][512];
extern int running;
extern char *yhs_filename1;
int filter;
float top;
/* Variables for setting resources */
static Arg args[MAXARGS];
static Cardinal argcount;
static Widget sigma_dialog = (Widget) NULL;
/* Procedures to apply the convolution operation */
static void convo_vectorx(matrix m, float *mask, int len,
float *max, float *min, float resul[][IMAGE_HEIGHT]);
static void convo_vectory(matrix m, float *mask, int len, float *max,
float *min, float resul[][IMAGE_HEIGHT]);
static void convolution (matrix m, float y[SIZE2][SIZE2],int length,
float *max, float *min, float resul[][IMAGE_HEIGHT]);
extern void watershed_callback(Widget w, XtPointer client_data,
XmAnyCallbackStruct *call_data);
/* Procedures to get the masks */
void get_gaussian(float s, float *y, int *len);
void get_derigaussian(float s, float *y, int *len);
void get_2derigaussian(float s, float *y, int *len);
/*Gaussian Filter*/
void create_sigma_dialog(Widget parent);
void activate_gaussian_dialog(Widget w, XtPointer client_data,
XmAnyCallbackStruct *call_data);
void deactivate_sigma_dialog(void);
void ok_sigmabutton_callback(Widget w, XtPointer client_data,
XmSelectionBoxCallbackStruct *call_data);
void cancel_sigmabutton_callback(Widget w, XtPointer client_data,
XmSelectionBoxCallbackStruct *call_data);
void gaussian_filter(float sigma);
/* Derivative Gaussian Filter */
void activate_dgaussian_dialog(Widget w, XtPointer client_data,
XmAnyCallbackStruct *call_data);
void dgaussian_filter(float sigma);
/* Second derivative of Gaussian filter */
void activate_d2gaussian_dialog(Widget w, XtPointer client_data,
XmAnyCallbackStruct *call_data);
void d2gaussian_filter(float sigma);
/* DEFINITION OF GAUSSIAN FUNCTIONS */
/* Procedure to create de dialog. */
void create_sigma_dialog(Widget parent){
XmString message;
Widget temp_widget = parent;
/* Ensure the parent of the dialog is a shell widget */
while ( !XtIsShell(temp_widget) ) {
temp_widget = XtParent(temp_widget);
}
message = XmStringLtoRCreate(SIGMA_MESSAGE, XmSTRING_DEFAULT_CHARSET);
argcount = 0;
XtSetArg(args[argcount], XmNselectionLabelString, message);
argcount++;
sigma_dialog = XmCreatePromptDialog(temp_widget, "gaussian dialog",
args, argcount);
/* Remove the help button from the dialog */
temp_widget = XmSelectionBoxGetChild(sigma_dialog, XmDIALOG_HELP_BUTTON);
XtUnmanageChild(temp_widget);
/* Add the actions to the buttons */
XtAddCallback(sigma_dialog, XmNokCallback,
(XtCallbackProc) ok_sigmabutton_callback, (XtPointer) NULL);
XtAddCallback(sigma_dialog, XmNcancelCallback,
(XtCallbackProc) cancel_sigmabutton_callback, (XtPointer) NULL);
XmStringFree(message);
}/*end create_sigma_dialog*/
/* Procedure to activate the gaussian dialog. */
void activate_gaussian_dialog(Widget w, XtPointer client_data,
XmAnyCallbackStruct *call_data){
if (file_not_loaded) return;
selection = GAUSSIAN;
filter = f1;
action = SIGMAVALUE;
refresh_action();
XtManageChild(sigma_dialog);
}
/* Procedure to deactivate gaussian dialog. */
void deactivate_sigma_dialog(void){
/* null - no actions at present dialog is auto unmanaged
whenever any of its buttons are pressed.
*/
}
/* Procedure associated with the ok button. */
void ok_sigmabutton_callback(Widget w, XtPointer client_data,
XmSelectionBoxCallbackStruct *call_data){
float sigma;
char *value;
/* Get sigma value from user's selection */
XmStringGetLtoR(call_data->value, XmSTRING_DEFAULT_CHARSET,
&value);
sigma = atof(value);
if ( atoi(value) < 0.5 || atoi(value) > 20 )
XBell(XtDisplay(w),100);
else
switch (filter) {
case f1: gaussian_filter(sigma); break;
case f2: dgaussian_filter(sigma); break;
case f3: d2gaussian_filter(sigma); break;
case f4: dgaux_gauy_filter(sigma); break;
case f5: dgauy_gaux_filter(sigma); break;
case f6: total_gradient_filter(sigma); break;
case f7: gradient_x_y_filter(sigma); break;
default: break;
}
action=SELECT;
refresh_action();
}
/* Procedure associated with the cancel button. */
void cancel_sigmabutton_callback(Widget w, XtPointer client_data,
XmSelectionBoxCallbackStruct *call_data){
action=SELECT;
refresh_action();
deactivate_sigma_dialog();
}
/* Procedure that aply a gaussian matrix filter to the image */
void gaussian_filter(float sigma){
int i,j,start,length_gaussian,lon;
float value, rmax,rmin,rng, mask_gaussian[SIZE2][SIZE2];
float gaussian[SIZE1];
matrix m,resul;
2. Delete the following lines of code :-
start_delete
/* Fill in the image with background color */
for(i=0; i<IMAGE_WIDTH; i++)
for(j=0; j<IMAGE_HEIGHT; j++)
XPutPixel(theXImage_2,i,j,bg);
/* Clear the drawing window so the image is displayed again */
XClearArea(XtDisplay(draw_1),XtWindow(draw_2),0,0,0,0,True);
/* Associate the watch cursor with the main window */
XDefineCursor(XtDisplay(draw_1), XtWindow(main_window), theCursor);
/* Flush the request buffer and wait for all events */
/* and errors to be processed by the server.
*/
XSync(XtDisplay(draw_1), False);
end_delete
/* Storing the matrix we want to process in m */
for(i=0;i<IMAGE_WIDTH;i++)
for(j=0;j<IMAGE_HEIGHT;j++)
m[i][j]= XGetPixel(theXImage_1,i,j);
3. Replace the above line as :-
m[i][j]= array1[i][j];
get_gaussian(sigma, gaussian, &length_gaussian);
fprintf(stderr,"la long es %i \n",length_gaussian);
/* Only the values higher than 0.01 are desirable */
start=0;
value=pow(gaussian[0],2);
while (value<0.01){
start += 1;
value = pow(gaussian[start],2);
}
for(i=start;i<=length_gaussian-start;i++)
for(j=start;j<=length_gaussian-start;j++){
mask_gaussian[i-start][j-start]= gaussian[i]*gaussian[j];
fprintf(stderr,"la
%i,%i es %f \n",i-start,j-start,
mask_gaussian[i-start][j-start]);
}
length_gaussian = length_gaussian - (2*start);
fprintf(stderr,"la long es %i \n",length_gaussian);
convolution(m, mask_gaussian, length_gaussian, &rmax, &rmin, resul);
rng = (float) (rmax - rmin);
lon = length_gaussian/2;
/* Now compute the convolution, scaling. */
for (i=lon; i<IMAGE_WIDTH-lon; i++)
for (j=lon; j<IMAGE_HEIGHT-lon; j++)
XPutPixel(theXImage_2,i,j,
(unsigned long) (((float)(resul[i][j]-rmin)/rng)*255.0));
4. Replace the above line by :-
array2[i][j]= (unsigned long) (((float)(resul[i][j]-rmin)/rng)*255.0));
5. Delete the following lines :-
/* Copy image into pixmap. */
XPutImage(XtDisplay(draw_2), thePixmap_2,image_gc_2, theXImage_2,
0, 0, 0, 0, theXImage_2->width, theXImage_2->height);
/* Disassociate the watch cursor from the main window */
XUndefineCursor(XtDisplay(draw_1), XtWindow(main_window));
/* Clear the drawing window so the image is displayed again */
XClearArea(XtDisplay(draw_2),XtWindow(draw_2),0,0,0,0,True);
6. Add the saving to disk code and loading from disk code as defined
in the first checklist.
}
7. Save and exit. The function should operate normally as required. Six steps to simply convert an old Slice function to MultiSlice RTP. Note that these steps can be automated to a certain degree by using a simple search and replace. It would not normally require more than 15 minutes to convert the average filter to MultiSlice, after sufficient practice at cutting and pasting relevant sections of code into the proper positions and deleting the old Slice code.
Checklist - Basic Group II conversion checklist (convert a screen drawer from old slice to MultiSlice)
A screen drawer, or a function which writes to the screen explicitly in the old Slice is often relatively difficult to convert. However, MultiSlice does support screen drawing, although indirectly since it must maintain it's screen-independence. Note that all functions on the old Slice can be converted to MultiSlice with sufficient knowledge and experience. It is simply a case of experience in programming at a slightly higher level. It is always possible to convert a screen drawer or any other function in the old Slice without writing a Group IV function. This will be shown by converting a XOR-buffer based real-time Zooming function to MultiSlice RTP. This type of function is usually the most difficult to convert since it explicitly writes to the screen image 1 with an XOR mask, takes user input from the screen, writes back to the screen image 2 and runs in real-time.
1. TRANSLATE. This is the most common programming error encountered
while converting functions. Slice operates on the screen, MultiSlice does
NOT operate on the screen. Therefore, slice uses a slightly obscure screen
based co-ordinate system that moves the origin (0,0) to the TOP LEFT HAND
corner. MultiSlice uses the usual origin at the bottom left hand corner.
Reverse all mouse input by using a third variable z as follows :-
z=x;
x=y;
y=z;
This simple code eliminates the most common errors while translating
such code.
We can now proceed to the actual code itself :-
/* Create the zoom level prompt dialog for the zoom button in
the tools menu */
void create_zoom_dialog(Widget parent)
{
XmString message;
Widget temp_widget = parent;
/* Ensure the parent of the dialog is a shell widget
*/
while ( !XtIsShell(temp_widget) ) {
temp_widget = XtParent(temp_widget);
}
message = XmStringLtoRCreate(ZOOM_MESSAGE, XmSTRING_DEFAULT_CHARSET);
argcount = 0;
XtSetArg(args[argcount], XmNselectionLabelString,
message); argcount++;
zoom_dialog = XmCreatePromptDialog(temp_widget,
"zoom dialog",
args, argcount);
/* Remove the help button from the dialog */
temp_widget = XmSelectionBoxGetChild(zoom_dialog,
XmDIALOG_HELP_BUTTON);
XtUnmanageChild(temp_widget);
/* Add the actions to the buttons */
XtAddCallback(zoom_dialog, XmNokCallback,
(XtCallbackProc) ok_button_callback, (XtPointer) NULL);
XmStringFree(message);
}
/*-----------------------------------------------------------------------------*/
/* a c t i v a t e _ z o o m _ d i a l o g
*/
/*-----------------------------------------------------------------------------*/
void activate_zoom_dialog(Widget w, XtPointer client_data,
XmAnyCallbackStruct *call_data)
{
selection = ZOOM;
action = CLICK;
refresh_action();
XtManageChild(zoom_dialog);
}
/*-----------------------------------------------------------------------------*/
/* o k _ b u t t o n _ c a l l b a c k
*/
/*
*/
/* Callback for the "OK" button
*/
/*----------------------------------------------------------------------------*/
static void ok_button_callback(Widget w, XtPointer client_data,
XmSelectionBoxCallbackStruct *call_data)
{
int t;
char *zoom;
FILE *p_file;
int a,b;
/* Get threshold value from user's selection */
XmStringGetLtoR(call_data->value, XmSTRING_DEFAULT_CHARSET,
&zoom);
2. Insert a check to ensure that the file operate on is at it's maximum
size and not a thumbnail with this simple if statement :-
if(squash[curfile] != 1)
{
t = atoi(zoom);
3. Check the user input values to ensure the user does not input a false value.
if (!(t>0 && t<=50) ) XBell(XtDisplay(w),100);
else {
4. Insert the usual load file code as defined in the first checklist.
if((p_file = fopen(yhs_filename1,"r")) == NULL)
{
fprintf(stderr, "Cannot
open: %s\n",yhs_filename1);
exit(1);
}
for (a=0;a<512;a++){
for (b=0;b<512;b++)
{ array1[a][b]=getc(p_file); array2[a][b]=0; }}
fclose(p_file);
/*Set the scale zooming*/
zoom_level = t;
/* Prepare the widgets to be able to receive the corret events
*/
prepare_handlers(ZOOM);
/* Get the correct scale settings */
old_offset_x = offset_x;
old_offset_y = offset_y;
offset_x = 512/zoom_level;
offset_y = 512/zoom_level;
}
}
}
/*----------------------------------------------------------------------
*/
/* s t a r t _ z o o m
*/
/*----------------------------------------------------------------------
*/
void start_zoom(Widget w, XtPointer client_data, XEvent *event)
{
int i, j, color, x1, y1,z;
int a,b;
FILE *p_file;
5. This is where the translation should be inserted.
z=y;
y=x;
x=z;
if (event->xbutton.button != Button3) return;
remove_event_handlers(ZOOM);
/* Fill in the image with zoomed partition */
for(x1=x; x1<(x+offset_x); x1++)
for(y1=y; y1<(y+offset_y); y1++) {
color = array1[x1][y1];
for(i=0; i<zoom_level; i++)
for(j=0; j<zoom_level; j++) {
array2[((x1-x)*zoom_level)+i][((y1-y)*zoom_level)+j]=color;
};
}
fprintf(stderr,"\nZooming : x1=%d y1=%d x=%d y=%d offset_x=%d
offset_y=%d\n",x1,y1,x,y,offset_x,offset_y);
6. Delete or comment out the old Slice code.
/* Flush the request buffer and wait for all events
*/
/* and errors to be processed by the server.
*/
/* XSync(XtDisplay(w), False); */
7. Insert the new file saving code as shown in the first checklist.
strcpy(tempfileold,tempfilenew);
/* copy the new filename to the old file i.e. save
the old file */
strcat(tempfilenew,addcharac);
/* new free temp file */
if((p_file = fopen(tempfileold,"w")) == NULL)
{
fprintf(stderr, "Cannot
open: %s - Temporary file for writing.\n",tempfileold);
exit(1);
}
for (a=0;a<512;a++){
for (b=0;b<512;b++)
{ putc(array2[a][b],p_file); }}
fclose(p_file);
8. Insert the background code as required.
run_once=0;
file_loader=1;
file_yhs=tempfileold;
}
/*----------------------------------------------------------------------
*/
/* m o v e _ z o o m
*/
/*----------------------------------------------------------------------
*/
void move_zoom(Widget w, XtPointer data, XEvent *p_event)
{
x = p_event->xbutton.x;
y = p_event->xbutton.y;
/* If rectangle on screen, redraw it again using
XOR mask to remove it */
if (rectangle_on_screen)
9. Note the changes made. view[curfile] should be substituted for Image1. Note the extra XOR mask functionality in MultiSlice to smooth the transition by providing a dynamic XOR mask for every file loaded.
XDrawRectangle(XtDisplay(view[curfile]),XtWindow(view[curfile]),
ysxorGC[curfile],old_x,old_y, old_offset_x, old_offset_y);
/*The rectangle can't be moved outside the display
window */
if ( x>( IMAGE_WIDTH-offset_x) ) x=(IMAGE_WIDTH-offset_x);
if ( y>(IMAGE_HEIGHT-offset_y) ) y=(IMAGE_HEIGHT-offset_y);
/* Draw the rectangle in the new position in screen */
10. As before, replace all the old Image1 code with the new view[curfile] and XOR GC mask.
XDrawRectangle(XtDisplay(view[curfile]), XtWindow(view[curfile]),
ysxorGC[curfile],
x, y, offset_x, offset_y);
/* Save values for the next updating rectangle */
old_x = x;
old_y = y;
old_offset_x = offset_x;
old_offset_y = offset_y;
rectangle_on_screen=True;
}
/*----------------------------------------------------------------------
*/
/* h a n d l e _ z o o m _ e x p o s e
*/
/*----------------------------------------------------------------------
*/
void handle_zoom_expose (Widget w, XtPointer client_data,
XmAnyCallbackStruct *call_data)
{
/* If an expose event has happen in draw_1 widget,
the rectangle has */
/* been deleted so set correct value to the variable
*/
rectangle_on_screen=False;
}
void create_zoom_dialog(Widget parent);
void activate_zoom_dialog(Widget w, XtPointer client_data,
XmAnyCallbackStruct *call_data);
static void ok_button_callback(Widget w, XtPointer client_data,
XmSelectionBoxCallbackStruct *call_data);
void start_zoom(Widget w, XtPointer client_data, XEvent *event);
void move_zoom(Widget w, XtPointer data, XEvent *p_event);
extern void prepare_handlers (int sel);
/* Function definition */
/*----------------------------------------------------------------------------*/
/* c r e a t e _ z o o m _ d i a l o g
*/
/* */
/* Create the zoom level prompt dialog for the zoom button in
the tools menu */
/*----------------------------------------------------------------------------*/
void create_zoom_dialog(Widget parent)
{
XmString message;
Widget temp_widget = parent;
/* Ensure the parent of the dialog is a shell widget
*/
while ( !XtIsShell(temp_widget) ) {
temp_widget = XtParent(temp_widget);
}
message = XmStringLtoRCreate(ZOOM_MESSAGE, XmSTRING_DEFAULT_CHARSET);
argcount = 0;
XtSetArg(args[argcount], XmNselectionLabelString,
message); argcount++;
zoom_dialog = XmCreatePromptDialog(temp_widget,
"zoom dialog",
args, argcount);
/* Remove the help button from the dialog */
temp_widget = XmSelectionBoxGetChild(zoom_dialog,
XmDIALOG_HELP_BUTTON);
XtUnmanageChild(temp_widget);
/* Add the actions to the buttons */
XtAddCallback(zoom_dialog, XmNokCallback,
(XtCallbackProc) ok_button_callback, (XtPointer) NULL);
XmStringFree(message);
}
/*-------------------------------------------------------------------------*/
/* a c t i v a t e _ z o o m _ d i a l o g
*/
/*------------------------------------------------------------------------*/
void activate_zoom_dialog(Widget w, XtPointer client_data,
XmAnyCallbackStruct *call_data)
{
selection = ZOOM;
action = CLICK;
refresh_action();
XtManageChild(zoom_dialog);
}
/*------------------------------------------------------------------------*/
/* o k _ b u t t o n _ c a l l b a c k
*/
/*
*/
/* Callback for the "OK" button
*/
/*-----------------------------------------------------------------------*/
static void ok_button_callback(Widget w, XtPointer client_data,
XmSelectionBoxCallbackStruct *call_data)
{
int t;
char *zoom;
/* Get threshold value from user's selection */
XmStringGetLtoR(call_data->value, XmSTRING_DEFAULT_CHARSET,
&zoom);
t = atoi(zoom);
if (!(t>=0 && t<=50) ) XBell(XtDisplay(w),100);
else {
zoom_level = t;
prepare_handlers(ZOOM);
old_offset_x = offset_x;
old_offset_y = offset_y;
offset_x = IMAGE_WIDTH/zoom_level;
offset_y = IMAGE_HEIGHT/zoom_level;
}
}
/*----------------------------------------------------------------------*/
/* s t a r t _ z o o m
*/
/*----------------------------------------------------------------------*/
void start_zoom(Widget w, XtPointer client_data, XEvent *event)
{
int i, j, color, x1, y1;
if (event->xbutton.button != Button3) return;
11. Delete the following code :-
start_delete
/* Fill in the image with background color */
for(x1=x; x1<(x+offset_x); x1++)
for(y1=y; y1<(y+offset_y); y1++) {
color = XGetPixel(theXImage_1,x1,y1);
for(i=0; i<zoom_level; i++)
for(j=0; j<zoom_level; j++) {
XPutPixel(theXImage_2,
((x1-x)*zoom_level)+i,
((y1-y)*zoom_level)+j,color);
};
};
end_delete
12. Replace XPutPixel(theXImage_2 with array2 as shown in the first
conversion checklist.
/* Contorno de la Imagen a negro */
for(i=0; i<IMAGE_WIDTH; i++)
for(j=0; j< IMAGE_HEIGHT; j++) {
XPutPixel(theXImage_2,i,0,0);
XPutPixel(theXImage_2,i,1,0);
XPutPixel(theXImage_2,i,511,0);
XPutPixel(theXImage_2,0,j,0);
XPutPixel(theXImage_2,1,j,0);
XPutPixel(theXImage_2,511,j,0);
};
13. Simply delete the rest.
/* Flush the request buffer and wait for all events
*/
/* and errors to be processed by the server.
*/
XSync(XtDisplay(w), False);
/* Copy image into pixmap */
XPutImage(XtDisplay(draw_2), thePixmap_2, image_gc_2,
theXImage_2,
0, 0, 0, 0, theXImage_2->width, theXImage_2->height);
/* Clear the drawing window so the image is displayed
again */
XClearArea(XtDisplay(draw_1),XtWindow(draw_2),0,0,0,0,True);
}
14. The function is now completely converted. Test it throughly before
releasing it, as with every other function.
Checklist - Simple Group III+ command line function processor checklist (Execute fn from the command-line)
This is a very simple checklist for implementing a Group III+ command line function. Note that although it does not use any Group IV functions, the simple fact of it running in unprotected, critical sections of the program ensure that it's rating is at least a Group III and it should be tested as a Group III or IV function.
1. Edit the file command_slice.c
2. Add the following code to the file :-
if(strcmp("-myfunc", argv[i])
== 0)
{
my_code_here();
}
3. Note that all file loading operations and background processor operations
are available despite the fact the background processor is not yet executing.
This is due to the processor execution immediately after the command line
processing has been completed.
Include the following to load a file :-
run_once=0;
file_load=1;
4. Test the function throughly with other command line functions. An
error in a command line function simply stops MultiSlice functioning correctly,
and since it has access to all the variables, it can cause data corruption
anywhere in the program.
Hence, in 3 simple steps, a command line function can be implemented.
What are the functions available to me (and what groups do they
belong to) ?
Note that, as before, including a Group IV function in a Group I function
automatically converts it to a full Group IV. There is no need to specifically
call these functions unless writing a Group IV or III function. Calling
it via variables is the usual case. Calling it via variables keeps a Group
I function a Group I function as some degree of error-correction/self-checking
is used when calling Group IV functions using variables only. There is
no real need to use any of these functions by calling them directly. This
is provided simply as a reference.
|
Fn Call | Fn Name | Args Reqd. | Group | Description of function |
ctomass.c | void | activate_ctomass_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | IV | Activate Centre-Of-Mass Callback |
edge.c | void | edge_sobel_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | 0 | Edge Sobel Callback |
edge.c | void | edge_kirsch_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | 0 | Edge Kirsch Callback |
edge.c | void | edge_prewitt_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | 0 | Edge Prewitt Callback |
edge.c | void | edge_frei_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | 0 | Edge Frei Callback |
edge.c | void | line_frei_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | 0 | Line Frei Callback |
edge.c | void | edge_marr_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | 0 | Edge Marr Callback |
edge.c | void | edge_roberts_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | 0 | Edge Roberts Callback |
edge.c | void | edge_vert_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | 0 | Edge Vertices Callback |
edge.c | void | create_edge_hv_dialog | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | 0 | Create the Erode Dialog Box |
edge.c | void | activate_edge_hv_dialog | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | IV | Activate the Erode Dialog Box |
edge.c | void | deactivate_edge_hv_dialog | void | I | Deactivate the Erode Dialog Box |
edge.c | static void | ok_edge_hvbutton_callback | Widget w, XtPointer client_data, XmSelectionBoxCallbackStruct *call_data | IV | Callback for User pressing OK on Erode Box |
edge.c | static void | cancel_edge_hv_callback | Widget w, XtPointer client_data, XmSelectionBoxCallbackStruct *call_data | IV | Callback for User pressing Cancel on Erode Box |
edge.c | void | edge_hv | int iterations | IV | Erode function |
edge.c | void | create_edge_dilate_dialog | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | IV | Create the Dilate Dialog Box |
edge.c | void | activate_edge_dilate_dialog | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | IV | Activate the Dilate Dialog Box |
edge.c | void | deactivate_edge_dilate_dialog | void | I | Deactivate the Dilate dialog |
edge.c | static void | ok_edge_dilatebutton_callback | Widget w, XtPointer client_data, XmSelectionBoxCallbackStruct *call_data | IV | User presses OK on Dilate Dialog Box |
edge.c | static void | cancel_edge_dilate_callback | Widget w, XtPointer client_data, XmSelectionBoxCallbackStruct *call_data | IV | User presses Cancel on Dilate Dialog Box |
edge.c | void | edge_dilate | int loop | IV | Dilate function |
edge.c | void | edge_unsharp_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | IV | Edge Unsharp Callback |
edge.c | void | mean_filter_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | 0 | Mean Filter Callback |
edge.c | void | create_smooth_t_dialog | Widget parent | 0 | Smooth T dialog Creation |
edge.c | void | activate_smooth_t_dialog | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | 0 | Smooth T Dialog Activation |
edge.c | void | deactivate_smooth_t_dialog | void | 0 | Smooth T Dialog deactivation |
edge.c | static void | ok_smooth_tbutton_callback | Widget w, XtPointer client_data, XmSelectionBoxCallbackStruct *call_data | 0 | OK button pressed - Smooth T dialog |
edge.c | static void | cancel_smooth_t_callback | Widget w, XtPointer client_data, XmSelectionBoxCallbackStruct *call_data | 0 | Cancel button pressed - Smooth T dialog |
edge.c | void | smooth_t | int t | 0 | Smooth T Function |
edge.c | void | smooth_mask1_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | 0 | Smooth Mask 1 Callback |
edge.c | void | smooth_mask2_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | 0 | Smooth Mask 2 Callback |
edge.c | void | median_filter_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | 0 | Median Filter Callback |
edge.c | void | median_vf_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | II | Median VF Callback |
edge.c | void | create_hough_dialog | Widget parent | IV | Hough Dialog Creation |
edge.c | void | activate_hough_dialog | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | IV | Hough Dialog Activation |
edge.c | void | deactivate_hough_dialog | void | IV | Hough Dialog Deactivation |
edge.c | static void | ok_hough_callback | Widget w, XtPointer client_data, XmSelectionBoxCallbackStruct *call_data | IV | OK button Callback - Hough Dialog |
edge.c | static void | cancel_hough_callback | Widget w, XtPointer client_data, XmSelectionBoxCallbackStruct *call_data | IV | Cancel button Callback - Hough Dialog |
edge.c | void | hough | int t | IV | Hough Function |
edge.c | void | create_threshold_dialog | Widget parent | IV | Threshold Dialog Creation |
edge.c | void | activate_threshold_dialog | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | IV | Threshold Dialog Activation |
edge.c | void | deactivate_threshold_dialog | void | IV | Threshold Dialog Deactivation |
edge.c | static void | ok_threshbutton_callback | Widget w, XtPointer client_data, XmSelectionBoxCallbackStruct *call_data | IV | OK button Callback - Threshold Dialog |
edge.c | static void | cancel_threshbutton_callback | Widget w, XtPointer client_data, XmSelectionBoxCallbackStruct *call_data | IV | Cancel button Callback - Threshold Dialog |
edge.c | void | thresholding | int t | IV | Thresholding Function |
edge.c | void | histogram_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | IV | Histogram Function Callback |
edge.c | void | histo_eq_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | IV | Histogram Function Computation |
editing_tools.c | void | create_editing_tools_window | Widget parent | IV | Create floating menu |
editing_tools.c | void | activate_editing_tools_window | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | IV | Activate the menu |
editing_tools.c | void | tracking_callback | Widget w, XtPointer client_data, XmDrawingAreaCallbackStruct *call_data | IV | Tracking last function callback |
editing_tools.c | void | rectangles_callback | Widget w, XtPointer client_data, XmDrawingAreaCallbackStruct *call_data | IV | Rectangle Drawing Callback |
editing_tools.c | void | circles_callback | Widget w, XtPointer client_data, XmDrawingAreaCallbackStruct *call_data | IV | Circle Drawing Callback |
editing_tools.c | void | ellipses_callback | Widget w, XtPointer client_data, XmDrawingAreaCallbackStruct *call_data | IV | Ellipse Drawing Callback |
editing_tools.c | void | clear_figure_callback | Widget w, XtPointer client_data, XmDrawingAreaCallbackStruct *call_data | IV | Clear the figure callback |
editing_tools.c | void | quit_me_callback | Widget w, XtPointer client_data, XmDrawingAreaCallbackStruct *call_data | IV | Quit the floating menu |
editing_tools.c | void | start_tracking | Widget w, XtPointer data, XEvent *p_event | II | Start cursor tracking |
editing_tools.c | void | continue_tracking | Widget w, XtPointer data, XEvent *p_event | IV | Continue cursor tracking |
editing_tools.c | void | end_tracking | Widget w, XtPointer data, XEvent *p_event | IV | End cursor tracking |
editing_tools.c | void | start_rubberband | Widget w, XtPointer data, XEvent *p_event | IV | Start the rubberbanding |
editing_tools.c | void | continue_rubberband | Widget w, XtPointer data, XEvent *p_event | IV | Continue the rubberbanding |
editing_tools.c | void | end_rubberband | Widget w, XtPointer data, XEvent *p_event | IV | Edn the rubberbanding |
editing_tools.c | void | draw_figure | Display *d, Window w, GC gc | IV | Draw the figure with XOR mask |
editing_tools.c | void | show_region | NODEPTR aux | IV | Show the regions |
editing_tools.c | void | get_point_list_of_polygon | XPoint *points, int *numpoints | IV | Get a points list in the polygon |
exit.c | void | create_exit_dialog | Widget parent | IV | Create the exit dialog |
exit.c | void | activate_exit_dialog | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | IV | Activate the exit dialog |
exit.c | void | deactivate_exit_dialog | void | IV | Deactivate the exit dialog |
exit.c | static void | exit_button_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | IV | Callback for the OK button on the exit dialog |
exit.c | void | cancel_button_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | IV | Callback for the Cancel button on the exit dialog |
filters.c | static void | convo_vectorx | matrix m, float *mask, int len, float *max, float *min, float resul[][IMAGE_HEIGHT] | IV | Procedures to apply the convolution operation |
filters.c | static void | convo_vectory | matrix m, float *mask, int len, float *max, float *min, float resul[][IMAGE_HEIGHT] | IV | Procedures to apply the convolution operation |
filters.c | static void | convolution | matrix m, float y[SIZE2][SIZE2],int length, float *max, float *min, float resul[][IMAGE_HEIGHT] | IV | Procedures to apply the convolution operation |
filters.c | void | get_gaussian | float s, float *y, int *len | IV | Procedures to get the masks |
filters.c | void | get_derigaussian | float s, float *y, int *len | IV | Procedures to get the masks |
filters.c | void | get_2derigaussian | float s, float *y, int *len | IV | Procedures to get the masks |
filters.c | void | create_sigma_dialog | Widget parent | IV | Sigma Dialog Creation |
filters.c | void | activate_gaussian_dialog | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | IV | Gaussian Dialog Activation |
filters.c | void | deactivate_sigma_dialog | void | IV | Sigma Dialog Deactivation |
filters.c | static void | ok_sigmabutton_callback | Widget w, XtPointer client_data, XmSelectionBoxCallbackStruct *call_data | IV | OK button Callback - Sigma Dialog |
filters.c | static void | cancel_sigmabutton_callback | Widget w, XtPointer client_data, XmSelectionBoxCallbackStruct *call_data | IV | Cancel button Callback - Sigma Dialog |
filters.c | void | gaussian_filter | float sigma | IV | Gaussian Filter |
filters.c | void | activate_dgaussian_dialog | Widget w, XtPointer client_data,XmAnyCallbackStruct *call_data | IV | Activate Derivative Gaussian Filter Dialog |
filters.c | void | dgaussian_filter | float sigma | IV | Derivative Gaussian Filter |
filters.c | void | activate_d2gaussian_dialog | Widget w, XtPointer client_data,XmAnyCallbackStruct *call_data | IV | Activate second derivative Gaussian Filter Dialog |
filters.c | void | d2gaussian_filter | float sigma | IV | Second Derivative Gaussian Filter |
filters.c | void | activate_dgaux_gauy_dialog | Widget w, XtPointer client_data,XmAnyCallbackStruct *call_data | IV | Activate Derivative of a Gaussian in rows and Gaussian in columns Dialog |
filters.c | void | dgaux_gauy_filter | float sigma | IV | Derivative of a Gaussian in rows and Gaussian in columns Filter |
filters.c | void | activate_dgauy_gaux_dialog | Widget w, XtPointer client_data,XmAnyCallbackStruct *call_data | IV | Activate derivative Gaussian in columns and Gaussian in rows Filter Dialog |
filters.c | void | dgauy_gaux_filter | float sigma | IV | Derivative Gaussian in columns and Gaussian in rows Filter |
filters.c | void | activate_total_gradient_dialog | Widget w, XtPointer client_data,XmAnyCallbackStruct *call_data | IV | Activate Total Gradient= sqrt(pow(dgauxgauy,2)+pow(dgauygaux,2)) Filter Dialog |
filters.c | void | total_gradient_filter | float sigma | IV | Total Gradient= sqrt(pow(dgauxgauy,2)+pow(dgauygaux,2)) Filter |
filters.c | void | activate_gradient_x_y_dialog | Widget w, XtPointer client_data,XmAnyCallbackStruct *call_data | IV | Activate Gradient_x_y = sqrt(pow(gaussian_x,2)+pow(gaussian_y,2) Filter Dialog |
filters.c | void | gradient_x_y_filter | float sigma | IV | Gradient_x_y = sqrt(pow(gaussian_x,2)+pow(gaussian_y,2) Filter |
filters.c | void | differencex_filter | void | IV | Difference x filter, differences between horizontal adjacent points |
filters.c | void | differencey_filter | void | IV | Difference y filter, differences between vertical adjacent points |
filters.c | void | gradient_filter | void | IV | Gradient filter |
label.c | void | create_labels | Widget w1, Widget w2, Widget w3, Widget w4, Widget w5 | IV | Label Creation |
label.c | void | refresh_filename | void | IV | Filename display refresher |
label.c | void | refresh_action | void | IV | Action display refresher |
label.c | void | refresh_coord | int x, int y, int v | IV | Co-ordinate refresher |
measure.c | void | activate_area_callback | Widget w, XtPointer client_data,XmAnyCallbackStruct *call_data | IV | Activate selected area |
measure.c | void | activate_perimeter_callback | Widget w, XtPointer client_data,XmAnyCallbackStruct *call_data | IV | Activate selected perimeter |
measure.c | void | activate_circular_callback | Widget w, XtPointer client_data,XmAnyCallbackStruct *call_data | IV | Activate circular area |
menu.c | void | create_options_menu | Widget parent | IV | Creates the options menu |
menu.c | void | create_main_menu | Widget parent | IV | Creates the main menu |
menu.c | void | create_file_menu | Widget parent | IV | Creates the file menu |
menu.c | void | create_preprocessing_menu | Widget parent | IV | Creates the preprocessing menu |
menu.c | void | create_segmentation_menu | Widget parent | IV | Creates the segmentation menu |
menu.c | void | create_tools_menu | Widget parent | IV | Creates the tools menu |
menu.c | void | create_feature_menu | Widget parent | IV | Creates the feature menu |
menu.c | void | create_about_menu | Widget parent | IV | Creates the about menu |
menu.c | void | create_window_menu | Widget parent | IV | Creates the window menu |
menu.c | void | create_multi_menu | Widget parent | IV | Creates the multi-images menu |
menu.c | void | create_flasher | Widget parent | IV | Creates the animated flashing phoenix icon in the right hand corner |
neighbour.c | static void | get_neighbours | PATHPTR *list, TREEPTR root, char c[] | IV | Get adjoining neighbours |
neighbour.c | static void | analize | PATHPTR *list, TREEPTR root, char path[], short where | IV | Analyse neighbours |
neighbour.c | static void | include_sub_neigh | PATHPTR *list,char path[],TREEPTR node, short level,short where | IV | Include sub-neighbour pixels |
neighbour.c | static void | get_4_neighbours | char c[],char v1[],char v2[],char v3[],char v4[] | IV | Get N,S,E,W neighbours |
neighbour.c | static void | analize_label | char *c, short i, short pos | IV | Analyse labels |
neighbour.c | void | initialize_label | char c[], int start | IV | Initialise Labels |
neighbour.c | void | copy_label | char *dest, char *source | IV | Label copying function |
neighbour.c | void | write_label | char *c | IV | Label writing function |
neighbour.c | void | insert | PATHPTR *list, char n[] | IV | Insertion function |
open.c | void | sbox_set | Widget d, XtPointer client_data,XmToggleButtonCallbackStruct *call_data | IV | Selection box settings |
open.c | void | pbox_cb | Widget m, XtPointer client_data, XmSelectionBoxCallbackStruct *call_data | IV | Inverse selection box settings |
open.c | void | update_time | void | IV | Main Background Processor - Dynamic file loading/widget-creation/timeout/self-correction |
open.c | void | create_open_dialog | Widget parent | IV | Open a file dialog |
open.c | void | create_view_dialog | Widget parent | IV | Open a project dialog |
open.c | void | activate_open_dialog | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | IV | Activate open dialog |
open.c | void | activate_view_dialog | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | IV | Activate project open dialog |
open.c | void | deactivate_open_dialog | void | IV | Deactivate open dialog |
open.c | void | deactivate_view_dialog | void | IV | Deactivate project open dialog |
open.c | void | fs_ok | Widget w, XtPointer client_data, XmSelectionBoxCallbackStruct *call_data | IV | Callback for file selection OK |
open.c | void | fs_cancel | Widget w, XtPointer client_data, XmSelectionBoxCallbackStruct *call_data | IV | Callback for file selection CANCEL |
open.c | void | fv_ok | Widget w, XtPointer client_data, XmSelectionBoxCallbackStruct *call_data | IV | Callback for project selection OK |
open.c | void | fs_cancel | Widget w, XtPointer client_data, XmSelectionBoxCallbackStruct *call_data | IV | Callback for project selection CANCEL |
open.c | void | load_file | char *filename, Widget w | IV | File loader |
open.c | static void | setup_ximage | void | IV | XImage setup routines |
open.c | void | close_me_callback | Widget w, XtPointer client_data,XmDrawingAreaCallbackStruct *call_data | IV | Callback for file closing |
open.c | void | multi_window_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | IV | MultiWindow Operations callback |
open.c | void | reduce_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | IV | Image reduction callback |
open.c | void | expand_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | IV | Expanding function callback |
open.c | void | cascade_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | IV | Cascading functions callback |
open.c | void | tile_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | IV | Tiling functions callback |
open.c | void | operate_callback | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | IV | MultiImage Operations callback |
open.c | void | resize_callback | void | IV | Resizing functions |
open.c | void | reduction | void | IV | Reduction functions |
open.c | void | delreload | void | IV | Delete and Reload functions |
open.c | void | deletestring | void | IV | Delete String functions |
region.c | void | create_region_dialog | Widget parent | IV | Create the region dialog |
region.c | void | activate_region_dialog | Widget w, XtPointer client_data,XmAnyCallbackStruct *call_data | IV | Activate the region dialog |
region.c | void | activate_image_dialog | Widget w, XtPointer client_data,XmAnyCallbackStruct *call_data | IV | Activate the image dialog |
region.c | void | deactivate_region_dialog | void | IV | Deactivate the region dialog |
region.c | static void | ok_button_callback | Widget w, XtPointer client_data,XmSelectionBoxCallbackStruct *call_data | IV | Callback for the OK button |
region.c | static void | cancel_button_callback | Widget w, XtPointer client_data,XmSelectionBoxCallbackStruct *call_data | IV | Callback for the cancel button |
region.c | void | start_growing | Widget w, XtPointer client_data, XEvent *event | IV | Start the growing algorithm |
region.c | static void | grow | int x, int y, unsigned long threshold | IV | Grow function |
region.c | static void | add_neighbours | NODEPTR *list_pixels, NODEPTR list_region,TPINFO *info, unsigned long mean, unsigned long threshold | IV | Add the neighbours |
region.c | void | start_image_growing | Widget w, XtPointer client_data,XmSelectionBoxCallbackStruct *call_data | IV | Image growing function starting |
region.c | static void | image_grow | Image growing function main | IV | unsigned long threshold |
region.c | int | region_cut_callback | Widget w, XtPointer client_data,XmAnyCallbackStruct *call_data | IV | Region cutting function |
region.c | void | start_cut | Widget w, XtPointer client_data, XEvent *event | IV | Start cutting |
region.c | static void | cut | void | 0 | Cutting function |
region.c | static void | create | NODEPTR *list | 0 | List creation |
region.c | static int | list_empty | NODEPTR list | IV | List empty checking |
region.c | static void | insert | NODEPTR *list, TPINFO *info | IV | List insertion |
region.c | static TPINFO | delete_first | NODEPTR *list | IV | First item on list deletion |
region.c | static unsigned int | num_elem | NODEPTR list | IV | Number of elements in the list |
region.c | static int | search | int x, int y | IV | Searching list |
region.c | static void | free_list | NODEPTR *list | IV | Freeing list |
region.c | static unsigned long | calculate_mean | NODEPTR list | IV | Calculating mean from list |
region.c | static int | inside_limits | int x, int y | IV | Is it inside limits ? |
region.c | static int | inside_region | int x, int y | IV | Is it inside region ? |
region.c | static int | inside_threshold | unsigned long pixel, unsigned long mean,unsigned long threshold | IV | Is it inside threshold ? |
region.c | static void | view_pixel | NODEPTR list, unsigned long mean | IV | View the pixel |
region.c | static void | sort_array | HISTO_ARRAY *A | IV | Function for sorting an array |
save.c | void | create_save_as_interface | Widget parent | IV | Create the save as dialog box |
save.c | void | exit_save_as_dialog | void | IV | Exit the dialog box |
save.c | void | save_as_callback | Widget w, XtPointer client_data,XmAnyCallbackStruct *call_data | IV | Save the file |
save.c | static Widget | create_file_select_dialog | Widget parent | IV | Select the file |
save.c | static void | activate_file_select_dialog | void | IV | Activate file selector dialog |
save.c | static void | deactivate_file_select_dialog | void | IV | Deactivate file selection |
save.c | static void | fs_ok_callback | Widget w, XtPointer client_data, XmFileSelectionBoxCallbackStruct *call_data | IV | OK - save the file callback |
save.c | static void | fs_cancel_callback | Widget w, XtPointer client_data,XmFileSelectionBoxCallbackStruct *call_data | IV | Cancel - no file saving callback |
save.c | static void | create_overwrite_dialog | Widget parent | IV | Create overwrite file dialog |
save.c | static void | activate_overwrite_dialog | void | IV | Activate overwrite file dialog |
save.c | static void | deactivate_overwrite_dialog | void | IV | Deactivate overwrite dialog |
save.c | static void | overwrite_yes_callback | Widget w, XtPointer client_data,XmAnyCallbackStruct *call_data | IV | Overwrite file dialog |
save.c | static void | overwrite_no_callback | Widget w, XtPointer client_data,XmAnyCallbackStruct *call_data | IV | Do not overwrite file dialog |
save.c | static void | create_save_fail_dialog | Widget parent | IV | Create save failure dialog |
save.c | static void | activate_save_fail_dialog | void | IV | Activate save failure dialog |
save.c | static void | deactivate_save_fail | void | IV | Deactivate save failure dialog |
save.c | static void | save_fail_ok_callback | Widget w, XtPointer client_data,XmAnyCallbackStruct *call_data | IV | OK button callback - Save fail dialog |
save.c | static int | save_app_workspace | char *filename | IV | Save application workspace |
save.c | static int | does_file_exist | char *filename | IV | Test for file exist |
save.c | static void | do_save | void | IV | Do the saving |
save.c | static char | *set_temp_filename | char *new_filename | IV | Set temporary filename |
save.c | static char | *get_temp_filename | void | IV | Get temporary filename |
save.c | static char | *set_filename | char *new_filename | IV | Set the filename |
save.c | static char | *get_filename | void | IV | Get the filename |
main.c | void | create_main_menu | Widget parent | IV | Create main menu |
main.c | void | create_labels | Widget w1, Widget w2, Widget w3, Widget w4, Widget w5 | IV | Create labels |
main.c | void | handle_expose_1 | Widget w, XtPointer client_data,XmDrawingAreaCallbackStruct *call_data | IV | Handle exposure pic 1 |
main.c | void | handle_expose_2 | Widget w, XtPointer client_data,XmDrawingAreaCallbackStruct *call_data | IV | Handle exposure pic 2 |
main.c | void | mouse_track_1 | Widget w, XtPointer client_data, XEvent *event | IV | Mouse Tracking pic 1 |
main.c | void | mouse_track_2 | Widget w, XtPointer client_data, XEvent *event | IV | Mouse Tracking pic 2 |
main.c | void | refresh_action | void | IV | Refresh actions |
main.c | void | refresh_coord | int x, int y, int v | IV | Refreshing mouse coordinates |
main.c | void | sq | int b | IV | Compression handler |
main.c | void | prepare_handlers | int sel | IV | File handler preparation |
main.c | void | remove_event_handlers | int sel | IV | Remove file handlers |
main.c | void | setup_display | Widget w | IV | Setup the display |
main.c | void | print_callback | Widget w, XtPointer client_data,XmAnyCallbackStruct *call_data | IV | Print a file |
main.c | XtCallbackProc | handle_expose_y | Widget w, XtPointer client_data,XmDrawingAreaCallbackStruct *call_data | IV | File handlers for all other files |
main.c | XtCallbackProc | squish | Widget w, XtPointer client_data,XmAnyCallbackStruct *call_data | IV | Compress current file handler |
split_merge.c | void | create_split_dialog | Widget parent | IV | Create the split-merge dialog |
split_merge.c | void | activate_split_dialog | Widget w, XtPointer client_data,XmAnyCallbackStruct *call_data | IV | Activate the dialog |
split_merge.c | void | start_split | Widget w, XtPointer client_data,XmSelectionBoxCallbackStruct *call_data | IV | Start the split-merge |
split_merge.c | TREEPTR | split | short deviation, short x, short y, short level | IV | Start splitting function |
split_merge.c | static void | create_merge_dialog | Widget parent | IV | Create merge dialog |
split_merge.c | static void | activate_merge_dialog | Widget w, XtPointer client_data,XmAnyCallbackStruct *call_data | IV | Activate the merge dialog |
split_merge.c | static void | start_merge | Widget w, XtPointer client_data,XmSelectionBoxCallbackStruct *call_data | IV | Start the merging |
split_merge.c | static MERGEPTR | merge | TREEPTR root, short condition | IV | Merge function |
split_merge.c | static void | analize_tree | TREEPTR node, short condition, short reg, int level | IV | Analyse tree |
split_merge.c | static void | create_merged_region_list | MERGEPTR *list | IV | Merge region list |
split_merge.c | static void | add_new_merged_region | MERGEPTR *list | IV | Add a new merged region |
split_merge.c | static void | insert_leaf_list | MERGEPTR *list, TREEPTR leaf | IV | Insert into list |
split_merge.c | static void | merge_lists | MERGEPTR *list1,MERGEPTR *list2 | IV | Merge lists function |
split_merge.c | static void | display_contour | MERGEPTR merged_region_list | IV | Display contours |
split_merge.c | static void | display_tree | TREEPTR node | IV | Display tree |
split_merge.c | TREEPTR | get_leaf | char path[] | IV | Get a leaf |
split_merge.c | static Region | get_merged_region | LEAFPTR actual_region | IV | Get a merged region |
split_merge.c | static void | free_tree | TREEPTR node | IV | Free the tree memory |
split_merge.c | static void | free_merge | MERGEPTR *merged_region_list | IV | Free the merged regions |
split_merge.c | static int | similar | char p[], char q[], short condition | IV | Similar region comparision |
split_merge.c | void | insert_path | PATHPTR *first, PATHPTR *end, char n[] | IV | Path insertion |
split_merge.c | static void | delete_first | PATHPTR *list, char value[] | IV | Delete first item entry |
split_merge.c | void | view_path_list | PATHPTR *path | IV | View the list |
split_merge.c | static float | get_deviation | float mean, float sqr_mean | IV | Get deviations |
version.c | void | create_version_dialog | Widget parent | IV | Create the version dialog |
version.c | void | activate_version_dialog | Widget w, XtPointer client_data,XmAnyCallbackStruct *call_data | IV | Activate the version dialog |
version.c | void | help_moi | Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data | II | Help me function |
version.c | void | deactivate_version_dialog | void | I | Deactivate the version dialog |
version.c | static void | button_callback | Widget w, XtPointer client_data,XmAnyCallbackStruct *call_data | II | OK button callback |
watershed.c | void | watershed_callback | Widget w, XtPointer client_data,XmAnyCallbackStruct *call_data | II | Watershed function callback |
watershed.c | static void | watershed_contour | void | IV | Contour mapping function |
watershed.c | static void | create_p_list | NODEPTR *list | II | Create the p lists |
watershed.c | static void | insert_p_list | NODEPTR *list, TPINFO *info | IV | Insert into p lists |
watershed.c | static void | view_p_list | NODEPTR list | IV | View a p list |
watershed.c | static void | free_p_list | NODEPTR list | IV | Free a p list |
watershed.c | static void | fifo_init | TPINFO p, FIFO *pixel_q | IV | First in first out list initiation |
watershed.c | static void | fifo_add | TPINFO p, FIFO *pixel_q | IV | FIFO add element |
watershed.c | static TPINFO | fifo_first | FIFO *pixel_q | IV | FIFO first element |
watershed.c | static int | fifo_empty | FIFO *pixel_q | IV | FIFO empty testing |
watershed.c | static int | image_pixel | int x, int y | IV | Image pixels retrieve |
watershed.c | static int | labeled_neighbour | int x, int y,unsigned long o[IMAGE_WIDTH][IMAGE_HEIGHT] | IV | Labelled neighbour processing |
zoom.c | void | create_zoom_dialog | Widget parent | IV | Create the zoom dialog |
zoom.c | void | activate_zoom_dialog | Widget w, XtPointer client_data,XmAnyCallbackStruct *call_data | II | Activate the zoom dialog |
zoom.c | static void | ok_button_callback | Widget w, XtPointer client_data, XmSelectionBoxCallbackStruct *call_data | II | OK button callback - Zoom dialog |
zoom.c | void | start_zoom | Widget w, XtPointer client_data, XEvent *event | II | Start Zooming |
zoom.c | void | move_zoom | Widget w, XtPointer data, XEvent *p_event | II | Move the zooming box |
How can I convert a function written for the old slice to the new environment ?
Very simply. All the old code fits in the new one without any changes
at all. It will not execute,
but will compile without any errors. Simply compile it and refer to
the basic conversion checklist.
Following that, simply run and debug.
How do I handle Inter-Process-Communications (IPC's) ?
IPC communications via XCUTBUFFER0 are integrally supported within MultiSlice
although they have been disabled as there is no known use for them at this
stage. Simply uncomment the IPC code in the main file and use it as it
has been debugged and tested extensively. The code is simple and is as
given below :-
if(XFetchBytes(p_disp,&i) != NULL){
if(i==21){
fprintf(stderr,"XCUTBUFF0 written to.\n");
/*Cut Buffer read. */
XtCloseDisplay(XtDisplay(main_window));exit(-1);}}
i=21; XStoreBytes(p_disp,text,i); /*
Cut buffer write. */
How can I change the default icon in MultiSlice ?
Simply save the icon you want in xbm format (X11 Bitmap Metafile) and
copy the bit values to
icon.h. Recompile and run. MovieConvert on SGI's should handle the
conversion between (say)
a Microsoft Windows .ico file to xbm.
How do I change small things like colors/menus/fonts without writing
a Group IV function ?
MultiSlice supports X-Windows screen and device independence.
Programmers can change colors, menu text, fonts etc. simply by editing
the file Slice and reloading the database with xrdb -load Slice.
The .sgiresources file is given below as shown :-
4Dwm*useIconBox: True
4Dwm*SG_autoSave: False
4Dwm*moveOpaque: True
*multiClickTime: 200
*scheme: Vancouver
The Slice file is given below as shown :-
! Filename Slice
!
! Resource file for MultiSlice RTP located
! in the home directory or in the $APPRESDIR directory
*input label.background:
blueviolet
*input label.foreground:
White
*output label.background:
blueviolet
*output label.foreground:
White
*file label.background:
blueviolet
*file label.foreground:
White
*action label.background:
DarkGrey
*action label.foreground:
White
*coord label.background:
DarkGrey
*coord label.foreground:
White
! Resource settings for the main menu
slice*background:
cadetblue3
slice*borderColor:
cadetblue1
*version dialog_popup.title:
Version Dialog
*version pixmap.background:
IndianRed2
*version title.fontList:
"*times*bold-r*14*"
*version group.fontList:
"*times*bold-r*14*"
*version button.background:
DarkGrey
*version button.foreground:
White
*version button.labelString:
Close
How do I test my routine when completed ?
MultiSlice requires Grp I,II,III,IV functions to be tested extensively
on implementation. If they cannot be implemented correctly, a sample program
should be written to simulate MultiSlice's operation by varying the variables
under programmer control. On implementation, the following tests are required
of all functions, irrespective of groups :-
1. Normal functioning.
Test the function by running a random function on a file, followed
by the function to be tested on the output of the first function.
2. Heavy load functioning.
Test the function under heavy load conditions by loading 20 files,
erasing them using the deallocate function, loading another 19 and finally
using the function to process a file in the center position (say, 7).
3. Worst case crash testing.
Load 19 files, run your function, simulate an error by putting a small
error code into the background processor set to trigger after 15-20 seconds,
and run your function again. The small error code can be simulated by inserting
the following into the background processor :-
if (time = 90) {error_code();}
Replace error_code with the error to be simulated.
4. Random time testing.
Load a single file into the program. Run your function using the background
processor 20 times at random time intervals. The function should run and
produce 19 outputs but not execute the 20th time if proper system self-checks
have been implemented correctly.
5. User input testing.
If your routine enters user input, simulate an exceptionally large,
non-numeric, exceptionally small, negative and zero values as inputs. The
routine should be able to reject the invalid input without causing any
errors.
6. Interrupt testing.
Change the background processor's time interval from the default of
2000ms to 200ms. Run your function. This will simulate heavy interruption
from the background processing mechanism.
7. Memory leak testing.
Your function should have some sort of variable protection mechanism.
Simulate random changes to certain variables using the background processor
at odd intervals of time.
8. Value testing.
Test your function on a completely white-background file, a black-background
and a random-noise background. If the function has a dividing mechanism,
test it for a divide by zero. If it has a multiply, test for an infinite
multiply output.
9. Screen independence testing.
Test your function by using it in falsecolor mode. If it writes to
the screen directly, simulate placing the window in the background, under
another window. Simulate false mouse-clicks in invalid areas, attempts
to resize the window and fake keypresses.
10. Finally, ask another person to test it. Although this is an optional
test, it is best to test it with a second person present at the controls.
At the end of these tests, the function should be reasonably well tested.
Although it is impossible to completely tyest a function, these tests will
ensure a high degree of confidence in correct function execution at run-time.
What is screen independence and how will it affect me (as
a programer) ?
Screen independence is a way of isolating what happens on the screen
to what actually
is present in the data set. Since the old slice was screen dependent,
it was prone to
crashes, garbled data sets and various other effects of using the screen.
Changing the
screen mode would effectively change the data set. A program which
operated and left
artifacts on the screen could lead to mis-diagnosis at worst or addition
of an artifact to
the image. Proceeding with a filter on that same image would lead to
unpredictable results.
Since the old slice worked on one image at a time, this effect was
minimized to a certain
extent. Working with 10 images at once, would, however, increase the
chances of corruption
dramatically. Hence, the data set in MultiSlice is regarded as a read-only
object. Functions
are not given permission to change it in any way. They can garble the
screen, change the
colors and draw objects over the screen images, but they cannot change
the base data set.
As an additional precaution, every image is refreshed from the disk
before a function is applied
to it. After a function completes it's task, the image is automatically
saved to disk
(each time under a different filename). In addition, if the user does
not save the
files and the program terminates normally, the temporary files are
wiped clean.
As a programmer, screen independence should not affect you at all.
By default,
the environment runs in array mode and no functions use the screen.
However, if you have
a very specific function that does use the screen (except for drawing,
where full
functionality is provided even in array mode) you will have to run
it as a Group IV program
and ensure it does not affect the rest of the program in any way. As
of the current date,
there does not appear to be any functions which have to use the screen
in any specific
way. XtGetPixel will however, function normally for any Group IV program
which has full access
to all system functions. It is NOT recommended to use a screen-dependent
function for the
reasons stated above. You may, however, do so if you wish to.
Below is a sample of screen independence at it's best. The system is
running in falsecolor
mode. A zoom function is used which does not know anything about the
mode used. It does not even
import the falsecolor variable. However, it works on the data set,
and, as with all other functions,
it leaves the screen display to a Group IV background processing function.
The result ? A zoom in falsecolor as required with complete screen
independence.
Any screen independent function runs in any required screen mode/color
without any alterations.
All current MultiSlice functions are completely screen-independent.
FalseColor Mode
Another example is a concurrently running true 3D OpenGL application
running in full color
with MultiSlice running in 8-bit gray with twenty files open, minimised.
OpenGL & MultiSlice
MultiSlice will run perfectly well in conjunction with OpenGL.
In addition, several example programs have been executed which demonstrate
the implementation of OpenGL in MultiSlice. Although not yet implemented,
OpenGL is supported in MultiSlice, both in the API and in the program code.
-EOF-