00001
00002
00003
00004
00005
00006
00007 #include <math.h>
00008 #include "thd_iochan.h"
00009
00010
00011
00012
00013 static char afni_host[128] = "." ;
00014 static char afni_name[128] = "\0" ;
00015 static int afni_port = 8005 ;
00016
00017 static int afni_verbose = 0 ;
00018
00019 static char * url = NULL ;
00020 static char * uff = NULL ;
00021
00022
00023
00024 int afni_io(void) ;
00025 void handle_tta( float xx , float yy , float zz ) ;
00026
00027 void exit_me_baby( void ){
00028 if( uff != NULL ) unlink(uff) ;
00029 return ;
00030 }
00031
00032 #include <signal.h>
00033 void sigfunc(int sig)
00034 {
00035 exit(1) ;
00036 }
00037
00038
00039
00040
00041
00042
00043
00044 int main( int argc , char * argv[] )
00045 {
00046 int narg , ii ;
00047
00048
00049
00050 if( argc == 2 && strncmp(argv[1],"-help",5) == 0 ){
00051 printf("Usage: plugout_tta [options]\n"
00052 "This program connects to AFNI and receives notification\n"
00053 "whenever the user changes Talairach coordinates.\n"
00054 "It then drives Netscape to display the closest figures\n"
00055 "from the Talairach-Tournoux atlas. Note that Netscape must\n"
00056 "be running on the same computer as this plugout, since it\n"
00057 "communicates with Netscape using a temporary URL file.\n"
00058 "Options:\n"
00059 " -host name Means to connect to AFNI running on the\n"
00060 " computer 'name' using TCP/IP. The default is to\n"
00061 " connect on the current host using shared memory.\n"
00062 " To connect to the current host with TCP/IP, use\n"
00063 " '-host localhost', or use the '-port' option.\n"
00064 " -v Verbose mode: prints out progress reports.\n"
00065 " -port pp Use TCP/IP port number 'pp'; default is 8005.\n"
00066 "The environment variable AFNI_TTAHOME controls where the atlas\n"
00067 "images are loaded from. If not given, a default value is used.\n"
00068 ) ;
00069 exit(0) ;
00070 }
00071
00072
00073
00074 atexit(exit_me_baby) ;
00075 signal(SIGINT ,sigfunc) ;
00076 signal(SIGBUS ,sigfunc) ;
00077 signal(SIGSEGV,sigfunc) ;
00078 signal(SIGTERM,sigfunc) ;
00079
00080
00081
00082 narg = 1 ;
00083 while( narg < argc ){
00084
00085
00086
00087 if( strncmp(argv[narg],"-host",5) == 0 ){
00088 narg++ ;
00089 if( narg >= argc ){
00090 fprintf(stderr,"-host needs a following name!\a\n"); exit(1);
00091 }
00092 strcpy( afni_host , argv[narg] ) ;
00093 narg++ ; continue ;
00094 }
00095
00096
00097
00098 if( strncmp(argv[narg],"-name",5) == 0 ){
00099 narg++ ;
00100 if( narg >= argc ){
00101 fprintf(stderr,"-name needs a following string!\a\n"); exit(1);
00102 }
00103 strcpy( afni_name , argv[narg] ) ;
00104 narg++ ; continue ;
00105 }
00106
00107
00108
00109 if( strncmp(argv[narg],"-v",2) == 0 ){
00110 afni_verbose = 1 ;
00111 narg++ ; continue ;
00112 }
00113
00114
00115
00116 if( strncmp(argv[narg],"-port",4) == 0 ){
00117 narg++ ;
00118 if( narg >= argc ){
00119 fprintf(stderr,"-port needs a following argument!\a\n"); exit(1);
00120 }
00121 afni_port = strtol( argv[narg] , NULL , 10 ) ;
00122 if( afni_port <= 0 ){
00123 fprintf(stderr,"-port needs a positive argument!\a\n"); exit(1);
00124 }
00125 if( strcmp(afni_host,".") == 0 ) strcpy(afni_host,"localhost") ;
00126 narg++ ; continue ;
00127 }
00128
00129
00130
00131 fprintf(stderr,"Unrecognized option: %s\a\n",argv[narg]) ;
00132 exit(1) ;
00133 }
00134
00135
00136
00137 while( 1 ){
00138 ii = afni_io() ;
00139 if( ii < 0 ) exit(0) ;
00140 iochan_sleep(100) ;
00141 }
00142
00143 }
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168 #define AFNI_OPEN_CONTROL_MODE 1
00169 #define AFNI_WAIT_CONTROL_MODE 2
00170 #define AFNI_OPEN_DATA_MODE 3
00171 #define AFNI_WAIT_DATA_MODE 4
00172 #define AFNI_CONTINUE_MODE 5
00173
00174
00175
00176 #define POACKSIZE 4
00177
00178 #define PO_ACK_BAD(ic) iochan_sendall( (ic) , "BAD" , POACKSIZE )
00179 #define PO_ACK_OK(ic) iochan_sendall( (ic) , "OK!" , POACKSIZE )
00180 #define PO_SEND(ic,str) iochan_sendall( (ic) , (str) , strlen((str))+1 )
00181
00182 int afni_io(void)
00183 {
00184 static int afni_mode = AFNI_OPEN_CONTROL_MODE ;
00185 static IOCHAN * afni_ioc = NULL ;
00186 int ii ;
00187
00188
00189
00190
00191
00192 if( afni_mode <= 0 ) return -1 ;
00193
00194
00195
00196
00197 if( afni_mode == AFNI_OPEN_CONTROL_MODE ){
00198 char afni_iocname[128] ;
00199
00200
00201
00202
00203 if( strcmp(afni_host,".") == 0 )
00204 sprintf( afni_iocname , "tcp:%s:7955" , "localhost" );
00205 else
00206 sprintf( afni_iocname , "tcp:%s:7955" , afni_host ) ;
00207 afni_ioc = iochan_init( afni_iocname , "create" ) ;
00208 if( afni_ioc == NULL ){
00209 fprintf(stderr,
00210 "Can't create control channel %s to AFNI!\n",afni_iocname) ;
00211 afni_mode = 0 ;
00212 return -1 ;
00213 }
00214 afni_mode = AFNI_WAIT_CONTROL_MODE ;
00215 if( afni_verbose )
00216 fprintf(stderr,"AFNI control channel created\n") ;
00217 }
00218
00219
00220
00221
00222 if( afni_mode == AFNI_WAIT_CONTROL_MODE ){
00223 ii = iochan_writecheck( afni_ioc , 5 ) ;
00224
00225
00226
00227
00228
00229
00230 if( ii < 0 ){
00231 fprintf(stderr,"Control channel to AFNI failed!\a\n") ;
00232 IOCHAN_CLOSE(afni_ioc) ;
00233 afni_mode = 0 ;
00234 return -1 ;
00235 } else if( ii > 0 ){
00236 afni_mode = AFNI_OPEN_DATA_MODE ;
00237 if( afni_verbose )
00238 fprintf(stderr,"AFNI control channel connected\n");
00239 } else {
00240 return 0 ;
00241 }
00242 }
00243
00244
00245
00246
00247 if( afni_mode == AFNI_OPEN_DATA_MODE ){
00248 char afni_iocname[128] ;
00249 char afni_buf[256] ;
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260 if( strcmp(afni_host,".") == 0 )
00261 strcpy( afni_iocname , "shm:test_plugout:1K+1K" ) ;
00262 else
00263 sprintf( afni_iocname , "tcp:%s:%d" , afni_host , afni_port ) ;
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275 if( afni_name[0] == '\0' ) strcpy(afni_name,"T-T-A") ;
00276
00277 sprintf( afni_buf , "TT_XYZ_DELTA\n"
00278 "PONAME %s\n"
00279 "IOCHAN %s" ,
00280 afni_name , afni_iocname ) ;
00281
00282 if( afni_verbose )
00283 fprintf(stderr,"Sending control information to AFNI\n") ;
00284
00285
00286
00287 ii = iochan_sendall( afni_ioc , afni_buf , strlen(afni_buf)+1 ) ;
00288
00289
00290
00291
00292 if( ii < 0 ){
00293 fprintf(stderr,"Transmission of control data to AFNI failed!\a\n") ;
00294 IOCHAN_CLOSE(afni_ioc) ;
00295 afni_mode = 0 ;
00296 return -1 ;
00297
00298 } else {
00299
00300
00301
00302 ii = iochan_recvall( afni_ioc , afni_buf , POACKSIZE ) ;
00303 IOCHAN_CLOSE(afni_ioc) ;
00304
00305 if( ii < 0 || strncmp(afni_buf,"OK!",3) != 0 ){
00306 fprintf(stderr,"AFNI didn't like control information!\a\n") ;
00307 afni_mode = 0 ;
00308 return -1 ;
00309 }
00310
00311
00312
00313 afni_ioc = iochan_init( afni_iocname , "create" ) ;
00314 if( afni_ioc == NULL ){
00315 fprintf(stderr,
00316 "Can't open data channel %s to AFNI!\a\n",afni_iocname) ;
00317 afni_mode = 0 ;
00318 return -1 ;
00319 } else {
00320 afni_mode = AFNI_WAIT_DATA_MODE ;
00321 if( afni_verbose ) fprintf(stderr,"AFNI data channel created\n") ;
00322 }
00323 }
00324 }
00325
00326
00327
00328
00329 if( afni_mode == AFNI_WAIT_DATA_MODE ){
00330
00331 ii = iochan_goodcheck( afni_ioc , 5 ) ;
00332 if( ii < 0 ){
00333 fprintf(stderr,
00334 "AFNI data channel aborted before any data was sent!\a\n") ;
00335 IOCHAN_CLOSE( afni_ioc ) ;
00336 afni_mode = 0 ;
00337 return -1 ;
00338 } else if( ii > 0 ){
00339 afni_mode = AFNI_CONTINUE_MODE ;
00340 if( afni_verbose ) fprintf(stderr,"AFNI data channel is open\n") ;
00341 } else {
00342 return 0 ;
00343 }
00344 }
00345
00346
00347
00348
00349
00350 if( afni_mode == AFNI_CONTINUE_MODE ){
00351 char afni_buf[256] ;
00352 float xx , yy , zz ;
00353 int ix , jy , kz ;
00354
00355 ii = iochan_readcheck( afni_ioc , 0 ) ;
00356
00357
00358
00359
00360
00361 if( ii < 0 ){
00362 fprintf(stderr,"AFNI data channel aborted!\a\n") ;
00363 IOCHAN_CLOSE(afni_ioc) ;
00364 afni_mode = 0 ;
00365 return -1 ;
00366 } else if( ii == 0 ){
00367 return 0 ;
00368 }
00369
00370
00371
00372 ii = iochan_recv( afni_ioc , afni_buf , 256 ) ;
00373
00374 if( ii <= 0 ){
00375 fprintf(stderr,"AFNI data channel recv failed!\a\n") ;
00376 IOCHAN_CLOSE(afni_ioc) ;
00377 afni_mode = 0 ;
00378 return -1 ;
00379 }
00380
00381
00382
00383
00384 ii = sscanf( afni_buf , "TT_XYZ %f %f %f" , &xx,&yy,&zz ) ;
00385
00386
00387
00388
00389 if( ii < 3 ){
00390 fprintf(stderr,"AFNI sent bad data: %s\a\n",afni_buf) ;
00391 PO_ACK_BAD(afni_ioc) ;
00392 } else {
00393 PO_ACK_OK(afni_ioc) ;
00394 if( afni_verbose )
00395 fprintf(stderr,"AFNI sent TT coords %9.3f %9.3f %9.3f\n",xx,yy,zz) ;
00396 handle_tta(xx,yy,zz) ;
00397 }
00398 }
00399
00400 return 0 ;
00401 }
00402
00403
00404
00405 #define CORONAL_NUM 38
00406 static float coronal_yy[] = {
00407 -100, -95, -90, -85, -80, -75, -70, -65,
00408 -60, -55, -50, -45, -40, -35, -32, -28,
00409 -24, -20, -16, -12, -8, -4, 0, 4,
00410 8, 12, 16, 20, 24, 28, 32, 35,
00411 40, 45, 50, 55, 60, 65
00412 } ;
00413 static char * coronal_ff[] = {
00414 "tt_corm99.gif" , "tt_corm95.gif" , "tt_corm90.gif" , "tt_corm85.gif" ,
00415 "tt_corm80.gif" , "tt_corm75.gif" , "tt_corm70.gif" , "tt_corm65.gif" ,
00416 "tt_corm60.gif" , "tt_corm55.gif" , "tt_corm50.gif" , "tt_corm45.gif" ,
00417 "tt_corm40.gif" , "tt_corm35.gif" , "tt_corm32.gif" , "tt_corm28.gif" ,
00418 "tt_corm24.gif" , "tt_corm20.gif" , "tt_corm16.gif" , "tt_corm12.gif" ,
00419 "tt_corm08.gif" , "tt_corm04.gif" , "tt_corp00.gif" , "tt_corp04.gif" ,
00420 "tt_corp08.gif" , "tt_corp12.gif" , "tt_corp16.gif" , "tt_corp20.gif" ,
00421 "tt_corp24.gif" , "tt_corp28.gif" , "tt_corp32.gif" , "tt_corp35.gif" ,
00422 "tt_corp40.gif" , "tt_corp45.gif" , "tt_corp50.gif" , "tt_corp55.gif" ,
00423 "tt_corp60.gif" , "tt_corp65.gif"
00424 } ;
00425
00426 #define SAGITTAL_NUM 18
00427 static float sagittal_xx[] = {
00428 0, 3, 5, 9, 13, 17, 21, 25, 29, 33 ,
00429 37, 41, 43, 47, 51, 55, 59, 61
00430 } ;
00431 static char * sagittal_ff[] = {
00432 "tt_sag00g.gif", "tt_sag03.gif" , "tt_sag05.gif" , "tt_sag09.gif" ,
00433 "tt_sag13.gif" , "tt_sag17.gif" , "tt_sag21.gif" , "tt_sag25.gif" ,
00434 "tt_sag29.gif" , "tt_sag33.gif" , "tt_sag37.gif" , "tt_sag41.gif" ,
00435 "tt_sag43.gif" , "tt_sag47.gif" , "tt_sag51.gif" , "tt_sag55.gif" ,
00436 "tt_sag59.gif" , "tt_sag61.gif"
00437 } ;
00438
00439 #define AXIAL_NUM 27
00440 static float axial_zz[] = {
00441 -40 , -36 , -32 , -28 , -24 , -20 , -16 , -12 , -8 , -4 ,
00442 -1 , 1 , 4 , 8 , 12 , 16 , 20 , 24 , 28 , 32 , 35 ,
00443 40 , 45 , 50 , 55 , 60 , 65
00444 } ;
00445 static char * axial_ff[] = {
00446 "tt_horm40.gif" , "tt_horm36.gif" , "tt_horm32.gif" , "tt_horm28.gif" ,
00447 "tt_horm24.gif" , "tt_horm20.gif" , "tt_horm16.gif" , "tt_horm12.gif" ,
00448 "tt_horm08.gif" , "tt_horm04.gif" , "tt_horm01.gif" , "tt_horp01.gif" ,
00449 "tt_horp04.gif" , "tt_horp08.gif" , "tt_horp12.gif" , "tt_horp16.gif" ,
00450 "tt_horp20.gif" , "tt_horp24.gif" , "tt_horp28.gif" , "tt_horp32.gif" ,
00451 "tt_horp35.gif" , "tt_horp40.gif" , "tt_horp45.gif" , "tt_horp50.gif" ,
00452 "tt_horp55.gif" , "tt_horp60.gif" , "tt_horp65.gif"
00453 } ;
00454
00455 #define TTAHOME "http://varda.biophysics.mcw.edu/~cox/TTA/"
00456
00457 void handle_tta( float xx , float yy , float zz )
00458 {
00459 char * tname ;
00460 int ii,jj,kk , qqq ;
00461 static int ii_old=-1 , jj_old=-1 , kk_old=-1 ;
00462 FILE * fp ;
00463 static char nbuf[444] ;
00464 static char * ttahome ;
00465
00466
00467
00468 if( url == NULL ){
00469 tname = tempnam(NULL,"tta") ;
00470 url = (char *) malloc(strlen(tname)+16) ;
00471 uff = url + 5 ;
00472 strcpy(url,"file:") ; strcat(url,tname) ; strcat(url,".html") ;
00473 free(tname) ;
00474 sprintf(nbuf,"netscape -remote 'openURL(%s)'" , url ) ;
00475 fprintf(stderr,"Temporary URL file is %s\n",uff) ;
00476
00477 ttahome = getenv( "AFNI_TTAPATH" ) ;
00478 if( ttahome == NULL ) ttahome = TTAHOME ;
00479 }
00480
00481
00482
00483 xx = fabs(xx) ;
00484 if( xx <= sagittal_xx[0] ){
00485 ii = 0 ;
00486 } else if( xx >= sagittal_xx[SAGITTAL_NUM-1] ){
00487 ii = SAGITTAL_NUM - 1 ;
00488 } else {
00489 for( ii=1 ; ii < SAGITTAL_NUM && xx > sagittal_xx[ii] ; ii++ ) ;
00490 if( fabs(xx-sagittal_xx[ii-1]) < fabs(xx-sagittal_xx[ii]) ) ii-- ;
00491 }
00492
00493
00494
00495 if( yy <= coronal_yy[0] ){
00496 jj = 0 ;
00497 } else if( yy >= coronal_yy[CORONAL_NUM-1] ){
00498 jj = CORONAL_NUM - 1 ;
00499 } else {
00500 for( jj=1 ; jj < CORONAL_NUM && yy > coronal_yy[jj] ; jj++ ) ;
00501 if( fabs(yy-coronal_yy[jj-1]) < fabs(yy-coronal_yy[jj]) ) jj-- ;
00502 }
00503
00504
00505
00506 if( zz <= axial_zz[0] ){
00507 kk = 0 ;
00508 } else if( zz >= axial_zz[AXIAL_NUM-1] ){
00509 kk = AXIAL_NUM - 1 ;
00510 } else {
00511 for( kk=1 ; kk < AXIAL_NUM && zz > axial_zz[kk] ; kk++ ) ;
00512 if( fabs(zz-axial_zz[kk-1]) < fabs(zz-axial_zz[kk]) ) kk-- ;
00513 }
00514
00515 if( ii == ii_old && jj == jj_old && kk == kk_old ) return ;
00516
00517
00518
00519 fp = fopen( uff , "w" ) ;
00520 if( fp == NULL ){ fprintf(stderr,"Can't write URL file\n") ; return ; }
00521
00522 fprintf(fp , "<HEAD>\n"
00523 "<title>T-T Atlas Pages</title>\n"
00524 "</HEAD>\n"
00525 "<BODY>\n"
00526 "<img align=middle src=\"%s%s\"><p>\n"
00527 "<img align=middle src=\"%s%s\"><p>\n"
00528 "<img align=middle src=\"%s%s\"><p>\n"
00529 "</BODY>\n" ,
00530 ttahome , axial_ff[kk] ,
00531 ttahome , coronal_ff[jj] ,
00532 ttahome , sagittal_ff[ii] ) ;
00533
00534 fclose(fp) ;
00535
00536 if( afni_verbose )
00537 fprintf(stderr,"Axial=%s Coronal=%s Sagittal=%s\n",
00538 axial_ff[kk] , coronal_ff[jj] , sagittal_ff[ii] ) ;
00539
00540
00541
00542 qqq = system(nbuf) ;
00543 if( qqq != 0 )
00544 fprintf(stderr,"Can't send command to Netscape - is it running?\n") ;
00545
00546 ii_old = ii ; jj_old = jj ; kk_old = kk ;
00547 return ;
00548 }