Skip to content
Snippets Groups Projects
partibrains.c 151 KiB
Newer Older
teuben's avatar
teuben committed
" read  [-t time] DATAFILENAME	read data file (e.g. to add new specks)",
" ieee  [-t time] IEEEIOFILE	read IEEEIO file (starting at given timestep)",
" sdb   [-t time] SDBFILE	read .sdb star-data file",
" annot [-t time] string	set annotation string (for given timestep)",
slevy's avatar
 
slevy committed
" add  DATAFILECOMMAND		enter a single datafile command (ditto)",
teuben's avatar
teuben committed
" every N			subsample: show every Nth particle",
" bound				show bounds (coordinate range of all particles)",
" clipbox {on | off | X0,X1 Y0,Y1 Z0,Z1 | CENX,Y,Z RADX,Y,Z | X0 Y0 Z0  X1 Y1 Z1} clipping region",
" add box [-n boxno] [-l level] CENX,Y,Z RX,RY,RZ | X0 Y0 Z0 X1 Y1 Z1  marker-box",
" boxlabels                     show box numbers",
" boxaxes                       show R/G/B axes from X0,Y0,Z0 box corner"
#if CAVEMENU
" boxes {off|on|only}		hide/show all AMR boxes",
" {hide|show} LEVELNO ...	hide/show AMR boxes of those levels (or \"all\")",
" {point|polygon|texture} {on|off}",
" fmenu HEIGHT  -or-  fmenu XPOS YPOS  -or- fmenu wall WALLNO",
#else
" readpath  FILENAME.wf		read Wavefront camera path (from virdir \"wfout\")",
" play  SPEED[f]		play path (at SPEED times normal speed)",
"			(with \"f\" suffix, play every SPEEDth frame)",
" frame FRAMENO			go to Nth frame",
" focal FOCALLEN		focal length (determines fly/tran speed)",
" clip  NEAR FAR		clipping distances",
" interest X Y Z		center of rotation for orbit/rotate",
" snapset  filestem [frameno]	set snapshot parameters",
" snapshot [frameno]		take snapshot [uses convert(1)]",
slevy's avatar
 
slevy committed
" kira {node|ring|size|scale|span|track}  starlab controls; try \"kira ?\"",
teuben's avatar
teuben committed
#endif
    };

    for(i = 0; i < COUNT(help1); i++)
	msg(help1[i], MAXVAL-1);
  

  } else if(!strcmp( argv[0], "read" )) {
	if(argc > 1)
	    specks_read( &st, argv[1] );

  } else if(!strcmp( argv[0], "include" )) {
#ifdef NOTYET
#endif

  } else if( !strcmp(argv[0], "on") || !strcmp(argv[0], "off")
	    || !strcmp(argv[0], "enable") || !strcmp(argv[0], "disable") ) {

	st->useme = argc>1 ? getbool(argv[1], st->useme) : (argv[0][1]=='n');
	msg(st->useme ? "enabled" : "disabled");
	
  } else if(!strcmp( argv[0], "eval" ) || !strcmp(argv[0], "add")) {
	int k, io[2];
	FILE *tf;
	char fdname[64+L_tmpnam];

#ifdef WIN32
	tmpnam(fdname);
	tf = fopen(fdname, "w");
#else /* unix */
	pipe(io);
	sprintf(fdname, "/dev/fd/%d", io[0]);
	tf = fdopen(io[1], "w");
#endif
	if(tf == NULL) {
	    fprintf(stderr, "Yeow: can't make temp file?\n");
	} else {
	    for(k = 1; k < argc; k++)
		fprintf(tf, "%s ", argv[k]);
	    fprintf(tf, "\n");
	    fclose(tf);
	    specks_read( &st, fdname );
#ifdef WIN32
	    unlink(fdname);
#endif
	}

#ifndef WIN32
	close(io[0]);
#endif

  } else if(!strcmp( argv[0], "async" )) {
	char tbuf[5120];
	tbuf[0] = '\0';
	for(i = 1; i < argc; i++)
	    sprintf(tbuf+strlen(tbuf), " %s", argv[i]);
	specks_add_async( st, tbuf );

  } else if(!strcmp( argv[0], "update" )) {
	parti_update();

  } else if(!strcmp( argv[0], "hist" )) {
	register struct specklist *sl;
	register struct speck *sp;
	Point xmin,xmax, mean, mid, radius;
	int nspecks, nclipped, nthreshed, nlow, nhigh, nundefined;
	int clipping = (st->clipbox.level > 0);
	int threshing = st->usethresh & P_USETHRESH;
	int nbuckets = 11;
	int dolog = 0;
	int *bucket;
	float v, vmin, vmax, vrange;
	int histvar;
	int i, k, bno;
	struct valdesc *vd;

	for(i=1,k=1; i+1 < argc; k++) {
	    int yes = argv[i][0] == '-';
	    if(argv[i][0] != '-' && argv[i][1] != '+') break;
	    switch(argv[i][k]) {
		case 't': threshing = yes ? THRESHBIT : 0; break;
		case 'c':
		case 'b': clipping = yes; break;
		case 'n':
		    sscanf(argv[i][++k] ? &argv[i][k] : argv[++i],
			"%d", &nbuckets);
		    i++; k=0;
		    break;
		case 'l': dolog = yes; break;
		case '\0': i++; k=0;
	    }
	}

	if(!specks_set_byvariable( st, argv[i], &histvar )) {
	    msg("hist %s: expected name/index of data variable", argv[i]);
	    return 1;
	}

	vd = &st->vdesc[st->curdata][histvar];
	vmin = vd->min;
	vmax = vd->max;

	if(i+1<argc) sscanf(argv[i+1], "%f", &vmin);
	if(i+2<argc) sscanf(argv[i+2], "%f", &vmax);

	if(vmax < vmin)
	    v = vmax, vmax = vmin, vmin = v;

	if(dolog && (vmin <= 0 || vmax <= 0)) {
	    msg("hist: can't take logs (-l) if range includes zero!");
	    dolog = 0;
	}
	if(dolog) {
	    vmin = log(vmin);
	    vmax = log(vmax);
	}
	vrange = (nbuckets-1) / ((vmax>vmin) ? vmax - vmin : 1);

	if(nbuckets<=0 || nbuckets>20000) {
	    msg("hist -n %d: Incredible number of histogram buckets", nbuckets);
	    return -1;
	}

	bucket = NewA(int, nbuckets);
	memset(bucket, 0, nbuckets*sizeof(int));

	nspecks = nclipped = nthreshed = nundefined = nlow = nhigh = 0;
	for(sl = st->sl; sl != NULL; sl = sl->next) {
	    if((sp = sl->specks) == NULL || sl->text != NULL)
		continue;
	    nspecks += sl->nspecks;
	    if(sl->bytesperspeck < SMALLSPECKSIZE(histvar+1)) {
		nundefined += sl->nspecks;
		continue;
	    }
	    for(i = sl->nspecks; --i >= 0; sp = NextSpeck( sp, sl, 1 )) {
		if(clipping &&
		  (sp->p.x[0] < st->clipbox.p0.x[0] ||
		   sp->p.x[0] > st->clipbox.p1.x[0] ||
		   sp->p.x[1] < st->clipbox.p0.x[1] ||
		   sp->p.x[1] > st->clipbox.p1.x[1] ||
		   sp->p.x[2] < st->clipbox.p0.x[2] ||
		   sp->p.x[2] > st->clipbox.p1.x[2])) {
			nclipped++;
			continue;
		}
		if(threshing & sp->rgba) {
			nthreshed++;
			continue;
		}
		v = sp->val[histvar];
		if(dolog) {
		    if(v <= 0) {
			nundefined++;
			continue;
		    }
		    v = log(v);
		}
		bno = (int) ((v - vmin)*vrange);
		if(bno < 0) nlow++;
		else if(bno >= nbuckets) nhigh++;
		else bucket[bno]++;
	    }
	}
	if(nspecks == 0) {
	    msg("No specks loaded yet");
	} else {
	    msg("hist -n %d %s%s%s%d(%s) %g %g => ",
		nbuckets, dolog?"-l ":"", clipping?"-c ":"", threshing?"-t ":"",
		histvar, vd->name,
		dolog ? exp(vmin) : vmin,
		dolog ? exp(vmax) : vmax);
	    msg("Total %d, %d < min, %d > max, %d undefined, %d clipped, %d threshed",
		nspecks, nlow, nhigh, nundefined, nclipped, nthreshed);
	    k = nlow;
	    msg("%d\t< %g", nlow, dolog ? exp(vmin) : vmin);
	    for(i = 0; i < nbuckets; i++) {
		v = vmin + ( (vrange>0) ? i / vrange : 0 );
		msg("%d\t>= %g", bucket[i], dolog ? exp(v) : v);
	    }
	    msg("%d\t> %g", nhigh, dolog ? exp(vmax) : vmax);
	}


  } else if(!strcmp( argv[0], "bound" )) {
	register struct specklist *sl;
	register struct speck *sp;
	Point xmin,xmax, mean, mid, radius;
	int minmaxk = MAXVAL+1, maxmaxk = 0;
	int nspecks = 0;

	xmin.x[0] = xmin.x[1] = xmin.x[2] = 1e38;
	xmax.x[0] = xmax.x[1] = xmax.x[2] = -1e38;
	mean.x[0] = mean.x[1] = mean.x[2] = 0;
	for(sl = st->sl; sl != NULL; sl = sl->next) {
	    int i, maxk;
	    if((sp = sl->specks) == NULL)
		continue;
	    for(maxk=0; maxk<MAXVAL && SMALLSPECKSIZE(maxk)<sl->bytesperspeck; maxk++)
		;
	    if(minmaxk > maxk) minmaxk = maxk;
	    if(maxmaxk < maxk) maxmaxk = maxk;
	    for(i = sl->nspecks; --i >= 0; sp = NextSpeck( sp, sl, 1 )) {
		if(xmin.x[0] > sp->p.x[0]) xmin.x[0] = sp->p.x[0];
		if(xmax.x[0] < sp->p.x[0]) xmax.x[0] = sp->p.x[0];
		mean.x[0] += sp->p.x[0];
		if(xmin.x[1] > sp->p.x[1]) xmin.x[1] = sp->p.x[1];
		if(xmax.x[1] < sp->p.x[1]) xmax.x[1] = sp->p.x[1];
		mean.x[1] += sp->p.x[1];
		if(xmin.x[2] > sp->p.x[2]) xmin.x[2] = sp->p.x[2];
		if(xmax.x[2] < sp->p.x[2]) xmax.x[2] = sp->p.x[2];
		mean.x[2] += sp->p.x[2];
	    }
	    nspecks += sl->nspecks;
	}
	if(nspecks == 0) {
	    msg("No specks loaded yet");
	} else {
	
	    vscale( &mean, 1.0/nspecks, &mean );
	    vcomb( &mid, .5,&xmin, .5,&xmax );
	    vcomb( &radius, .5,&xmax, -.5,&xmin );
	    msg( "%d specks in range %g %g %g .. %g %g %g",
		nspecks, xmin.x[0],xmin.x[1],xmin.x[2],
		xmax.x[0],xmax.x[1],xmax.x[2]);
	    msg( "midbbox %g %g %g  boxradius %g %g %g",
		mid.x[0],mid.x[1],mid.x[2],
		radius.x[0],radius.x[1],radius.x[2]);
	    msg( "mean %g %g %g", mean.x[0],mean.x[1],mean.x[2] );
	}

  } else if(!strcmp( argv[0], "fspeed" )) {
	if(argc>1) {
teuben's avatar
teuben committed
	    specks_set_fspeed( st, getfloat(argv[1], st->fspeed) );
teuben's avatar
teuben committed
	    st->playnext = 0.0;
	}
	msg("fspeed %g steps per real-time second", st->fspeed);

  } else if(!strcmp( argv[0], "speed" )) {
	if(argc>1)
slevy's avatar
 
slevy committed
	    specks_set_speed( st, getfloat(argv[1], clock_speed(st->clk)) );
	msg("speed %g steps per anim second", clock_speed(st->clk));
teuben's avatar
teuben committed
	
  } else if(!strcmp( argv[0], "run" )) {
slevy's avatar
 
slevy committed
	parti_set_running( st, getbool( argv[1], 1 ) );
teuben's avatar
teuben committed
	st->playnext = 0.0;

slevy's avatar
 
slevy committed
  } else if(!strcmp( argv[0], "depthsort" )) {
	if(argc > 1) st->depthsort = getbool(argv[1], st->depthsort);
	msg("depthsort %s", st->depthsort ? "on" : "off" );

teuben's avatar
teuben committed
  } else if(!strcmp( argv[0], "fade" )) {
	char *fmt = "fade what?";
	if(argc>1) {
	    if(!strncmp(argv[1],"sph",3) || !strncmp(argv[1],"rad",3))
		st->fade = F_SPHERICAL;
	    else if(!strncmp(argv[1],"pla",3))
		st->fade = F_PLANAR;
	    else if(!strncmp(argv[1],"con",3) || !strncmp(argv[1],"ort",3))
		st->fade = F_CONSTANT;
	    else if(!strncmp(argv[1],"knee",3))
		st->fade = F_KNEE12;
	    else if(!strncmp(argv[1],"lin",3))
		st->fade = F_LINEAR;
	    else {
		msg("fade {sph|planar|const|linear|knees}");
		return -1;
	    }
	}
	if(argc>2) sscanf(argv[2], "%f", &st->fadeknee2);
	if(argc>3) sscanf(argv[3], "%f", &st->knee2steep);
	if(argc>4) sscanf(argv[4], "%f", &st->fadeknee1);
	if(argc>5) sscanf(argv[5], "%f%*c%f%*c%f",
			&st->fadecen.x[0], &st->fadecen.x[1], &st->fadecen.x[2]);
	if(argc>6) sscanf(argv[6], "%f", &st->fadecen.x[1]);
	if(argc>7) sscanf(argv[7], "%f", &st->fadecen.x[2]);
	switch(st->fade) {
	case F_SPHERICAL: fmt = "fade spherical  (1/r^2 from eyepoint)"; break;
	case F_PLANAR:    fmt = "fade planar     (1/r^2 from eye plane)"; break;
	case F_CONSTANT:  fmt = "fade const %g   (as if seen at given dist)"; break;
	case F_LINEAR:    fmt = "fade linear %g  (1/r, scaled to match planar at dist)"; break;
	case F_KNEE12:	  fmt = "fade knees %g %g  %g (fardist, steepness, neardist)"; break;
	case F_LREGION:	  fmt = "fade lregion %g  %g %g  %g %g %g (refdist; steepness, Rregion)"; break;
	}
	msg(fmt, st->fadeknee2, st->knee2steep, st->fadeknee1,
		st->fadecen.x[0], st->fadecen.x[1], st->fadecen.x[2]);

  } else if(!strcmp( argv[0], "clipbox" ) || !strcmp( argv[0], "cb" )) {
	Point cen, rad;
	int k;
	switch(argc) {
	case 2:	st->clipbox.level = getbool(argv[1], st->clipbox.level);
		break;
	case 3: if(3==sscanf(argv[1], "%f%*c%f%*c%f",
				&cen.x[0],&cen.x[1],&cen.x[2])
			&& 0 < (k = sscanf(argv[2], "%f%*c%f%*c%f",
				&rad.x[0],&rad.x[1],&rad.x[2]))) {
		    if(k==1) rad.x[1] = rad.x[2] = rad.x[0];
		    vsub( &st->clipbox.p0, &cen, &rad );
		    vadd( &st->clipbox.p1, &cen, &rad );
		    st->clipbox.level = 1;	/* activate */
		} else {
		    msg("clipbox: xmin,xmax ymin,ymax zmin,zmax  or cenx,y,z radiusx,y,z");
		}
		break;
	case 4:
		if(2 == sscanf(argv[1], "%f%*c%f", &cen.x[0], &rad.x[0]) &&
		   2 == sscanf(argv[2], "%f%*c%f", &cen.x[1], &rad.x[1]) &&
		   2 == sscanf(argv[3], "%f%*c%f", &cen.x[2], &rad.x[2])) {
		    st->clipbox.p0 = cen;
		    st->clipbox.p1 = rad;
		    st->clipbox.level = 1;	/* activate */
		} else {
		    msg("clipbox: xmin,xmax ymin,ymax zmin,zmax  or cenx,y,z radiusx,y,z");
		}
		break;

	case 7: for(k = 0; k < 3; k++) {
		    if(sscanf(argv[k+1], "%f", &st->clipbox.p0.x[k]) <= 0
			|| sscanf(argv[k+4], "%f", &st->clipbox.p1.x[k]) <= 0)
			break;
		}
		if(k == 3) {
		    st->clipbox.level = 1;
		} else {
		    msg("clipbox: xmin ymin zmin  xmax ymax zmax");
		}
		break;
	}
	vcomb( &cen, .5, &st->clipbox.p0, .5, &st->clipbox.p1 );
	vcomb( &rad, -.5, &st->clipbox.p0, .5, &st->clipbox.p1 );
	msg("clipbox %s  (%g,%g  %g,%g  %g,%g  or  %g,%g,%g %g,%g,%g)",
		st->clipbox.level ? "on":"off",
		st->clipbox.p0.x[0], st->clipbox.p1.x[0],
		st->clipbox.p0.x[1], st->clipbox.p1.x[1],
		st->clipbox.p0.x[2], st->clipbox.p1.x[2],
		cen.x[0],cen.x[1],cen.x[2],  rad.x[0],rad.x[1],rad.x[2]);

  } else if(!strcmp( argv[0], "object" ) || sscanf( argv[0], "g%d", &i ) > 0) {
	struct stuff *tst = st;
	i = parti_object( argv[ argv[0][0]=='g' ? 0 : 1 ], &tst );
	if(i>=0 && argv[0][0] == 'g' && argc > 1) {
	    specks_parse_args( &tst, argc-1, argv+1 );
	} else {
	    st = tst;
	    msg("object g%d selected (%d particles)", i,
		specks_count( st->sl ));
	}

slevy's avatar
 
slevy committed
  } else if(!strcmp( argv[0], "gall" ) || !strncmp( argv[0], "allobj", 6 )) {
	parti_allobjs( argc-1, argv+1 );
teuben's avatar
teuben committed

  } else if(!strcmp(argv[0], "tfm")) {
	int inv = 0;
	int mulWorldside = 0, mulObjside = 0;
	int hpr = 0;
	int calc = 0;
	int any, more, a0;
	float scl;
	Matrix ot, t;
	Point xyz;
	float aer[3];
	char *key;

	i = 1;
	key = argv[i];
	if(key == NULL) key = "";
	for(more = 1; *key != '\0' && more; key++) {
	  switch(*key) {
	  case '=': break;
	  case '*': mulWorldside = 1; break;
	  case '/': inv = 1; break;
	  case 'h': case 'p': case 'r': hpr = 1; break;
	  case ' ': case '\t': break;
	  case '\0':
		if(i < argc-1) {
		    key = argv[++i];
		    break;
		}
		/* else fall into default */
	  default: more = 0; key--; break;
	  }
	}

	parti_geto2w( st, parti_object( NULL, &st ), &ot );

	
	a0 = i;
	argv[a0] = key;
	for(any = 0; any < 16 && a0+any<argc
			&& sscanf(argv[a0+any], "%f", &t.m[any]) > 0; any++)
		;
	switch(any) {
	case 1:
		scl = t.m[0];
		t = Tidentity;
		t.m[0*4+0] = t.m[1*4+1] = t.m[2*4+2] = scl;
		break;
	case 6:
	case 7:		/* ignore fovy if included */
		xyz = *(Point *)&t.m[0];
		if(hpr) {
		    aer[0] = t.m[3], aer[1] = t.m[4], aer[2] = t.m[5];
		} else {
		    /* Note we permute: px py pz rx ry rz == px py pz e a r */
		    aer[1] = t.m[3], aer[0] = t.m[4], aer[2] = t.m[5];
		}
		xyzaer2tfm( &t, &xyz, aer );
		break;

	case 16: break;
	case 0:  t = ot; break;
	default:
	    msg("Usage: tfm [*] [/] [\"hpr\"] [16 numbers or 6 numbers] [=]");
	    return -1;
	}

	for(i = a0+any-1; i < argc; i++) {
	    if(strchr(argv[i], '=')) calc = 1;
	    if(strchr(argv[i], '*')) mulObjside = 1;
	}

	if(any) {
	    if(inv)
		eucinv( &t, &t );
	    if(mulWorldside)
		mmmul( &t, &ot, &t );
	    if(mulObjside)
		mmmul( &t, &t, &ot );

	    /* with trailing '=', just print result without assignment */

	    if(!calc)
		parti_seto2w( st, parti_object( NULL, &st ), &t );
	}

	tfm2xyzaer( &xyz, aer, &t );
	msg("obj2w:  x y z %s   %g %g %g  %g %g %g",  hpr?"h p r":"rx ry rz",
		xyz.x[0],xyz.x[1],xyz.x[2],  aer[1-hpr],aer[hpr],aer[2] );
	for(i = 0; i < 3; i++)
	    msg(" %10.7f %10.7f %10.7f %10.7f", t.m[i*4+0],t.m[i*4+1],t.m[i*4+2],t.m[i*4+3]);
	msg(" %10.7g %10.7g %10.7g %10.7g", t.m[3*4+0],t.m[3*4+1],t.m[3*4+2],t.m[3*4+3]);
	eucinv( &t, &t );
	tfm2xyzaer( &xyz, aer, &t );
	msg("w2obj:  x y z %s   %g %g %g  %g %g %g",  hpr?"h p r":"rx ry rz",
		xyz.x[0],xyz.x[1],xyz.x[2],  aer[1-hpr],aer[hpr],aer[2] );
	for(i = 0; i < 3; i++)
	    msg(" %10.7f %10.7f %10.7f %10.7f", t.m[i*4+0],t.m[i*4+1],t.m[i*4+2],t.m[i*4+3]);
	msg(" %10.7g %10.7g %10.7g %10.7g", t.m[3*4+0],t.m[3*4+1],t.m[3*4+2],t.m[3*4+3]);

  } else if(!strcmp( argv[0], "bgcolor" )) {
	char *result, given[64];
	if(argc == 4) {
	    sprintf(given, "%.10s,%.10s,%.10s", argv[1],argv[2],argv[3]);
	    result = parti_bgcolor( given );
	} else {
	    result = parti_bgcolor( argv[1] );
	}
	msg("bgcolor %s", result);

	    
#if !CAVEMENU
	/* virdir emulation */

  } else if(!strcmp( argv[0], "stereo" )) {
	for(i = 1; i < argc; i++)
	    parti_stereo( argv[i] );

	msg("stereo %s", parti_stereo(NULL));

  } else if(!strncmp( argv[0], "snapset", 7 ) || !strcmp( argv[0], "snapshot" )) {
	char *frameno = NULL, *basename = NULL;
	char *tail = NULL;
	if(argc > 2) frameno = argv[2];
	if(argc == 2) {
	    strtol(argv[1], &tail, 0);
	    if(tail != argv[1] && *tail == '\0')
		frameno = argv[1];
	}
	if(argc > 1 && frameno == NULL)
	    basename = argv[1];
	parti_snapset( basename, frameno );
	if(0!=strncmp( argv[0], "snapset", 7 )) {
	    char snapinfo[1024]; 
	    if(parti_snapshot(snapinfo) >= 0)
		msg("Snapped %s", snapinfo);
	}

  } else if(!strcmp( argv[0], "move" ) || !strcmp( argv[0], "move-objects" )) {
	i = parti_move( argv[1], &st );
	msg(i>=0 ? "move-objects on ; g%d selected" : "move-objects off", i);
	    
  } else if(!strcmp( argv[0], "clip" )) {
	msg("%s", parti_clip( argv[1], argc>2?argv[2]:NULL ) );

  } else if(!strcmp( argv[0], "ortho" )) {
#ifdef NOTYET
	int ortho = parti_ortho( argc>1 ? argv[1] : NULL);
	float fov = parti_fov(NULL);
	msg(ortho ? "ortho on (fov %g units)" : "ortho off (fov %g degrees)"
#endif

  } else if(!strcmp( argv[0], "fov" ) || !strcmp( argv[0], "fovy" )) {
	float fovy = parti_fovy( (argc>1) ? argv[1] : NULL );
	msg("fovy %g", fovy);

  } else if(!strncmp( argv[0], "focal", 5 )) {
	float focallen = parti_focal( (argc>1) ? argv[1] : NULL );
	msg("focallength %g", focallen);

  } else if(!strncmp( argv[0], "jump", 4 )) {
	Point xyz;
	float aer[3];
	static int stupid[3] = {1,0,2};	/* aer -> rx ry rz */
	Matrix c2w;
	parti_getc2w( &c2w );
	tfm2xyzaer( &xyz, aer, &c2w );
	if(argc>1) {
	    for(i=1; i<argc && i<4+3; i++) {
		if(i-1<3) xyz.x[i-1] = getfloat(argv[i], xyz.x[i-1]);
		else aer[stupid[i-4]] = getfloat(argv[i], aer[stupid[i-4]]);
	    }
	    xyzaer2tfm( &c2w, &xyz, aer );
	    parti_setc2w( &c2w );
	}
	msg("jump %g %g %g  %g %g %g  (XYZ RxRyRz)",
		xyz.x[0],xyz.x[1],xyz.x[2],
		aer[1],aer[0],aer[2]);

  } else if((!strcmp( argv[0], "rdata" ) || !strcmp(argv[0], "readpath"))
		&& argc>1) {
	char *tfname = argv[1];
	char *realfile = findfile( NULL, tfname );
	if(realfile == NULL) {
	    tfname = (char *)alloca(strlen(argv[1]) + 32);
	    sprintf(tfname, "data/record/%s%s", argv[1],
		strstr(argv[1], ".wf") ? "" : ".wf");
	    realfile = findfile( NULL, tfname+12 );
	}
	if(realfile == NULL)
	    realfile = findfile( NULL, tfname );
	if(realfile)
	    parti_readpath( st, realfile );
	else
	    msg("%s: can't find \"%s\" nor data/record/... nor ...wf",
		argv[0],argv[1]);

  } else if(!strcmp( argv[0], "play" )) {
	parti_play( st, argc>1 ? argv[1] : NULL );

  } else if(!strcmp( argv[0], "frame" )) {
	struct wfpath *pp;
	i = parti_frame( st, argv[1], &pp );
	msg("frame %d (of %d..%d)", pp->curframe,
		pp->frame0, pp->nframes + pp->frame0 - 1);

  } else if(!strcmp( argv[0], "interest") || !strcmp( argv[0], "int" ) ||
		!strcmp( argv[0], "center" ) ||
		!strcmp( argv[0], "cen" )) {
	Point cen;
	float censize = parti_getcensize();
	parti_getcenter( &cen );
	if(argc > 1) {
	    sscanf(argv[1], "%f%*c%f%*c%f%*c%f",
		&cen.x[0],&cen.x[1],&cen.x[2], &censize);
	    if(argc > 3)
		for(i=0;i<3;i++)
		    cen.x[i] = getfloat(argv[i+1], cen.x[i]);
	    if(argc == 3 || argc == 5)
		sscanf(argv[argc-1], "%f", &censize);
	    parti_center( &cen );
	    if(censize != parti_getcensize())
		parti_censize( censize );
	}
#if CAVEMENU
	msg("center %g %g %g", cen.x[0],cen.x[1],cen.x[2]);
#else
	msg("center %g %g %g  %g(radius)", cen.x[0],cen.x[1],cen.x[2], censize);
#endif
  } else if(!strcmp( argv[0], "censize" )) {
	if(argc>1)
	    parti_censize( getfloat(argv[1], parti_getcensize()));
	msg("censize %g  (interest-marker size)", parti_getcensize());

#endif /*non-CAVEMENU*/

  } else if(!strcmp( argv[0], "step" )) {
slevy's avatar
 
slevy committed
	if(argc>1) {
	    if(argv[1][0] == '+') {
		if(argv[1][1] != '\0')
		    clock_set_step( st->clk, getfloat(&argv[1][1], 0) );
		clock_step( st->clk, 1 );
	    } else if(!strcmp(argv[1], "-")) {
		clock_step( st->clk, -1 );
	    } else {
		clock_set_time( st->clk, getfloat(argv[1], 0) );
	    }
teuben's avatar
teuben committed
	}
slevy's avatar
 
slevy committed

teuben's avatar
teuben committed

#if !CAVEMENU
slevy's avatar
 
slevy committed
	parti_set_running( st, 0 );
	specks_set_timestep(st);
teuben's avatar
teuben committed
#endif
teuben's avatar
teuben committed
	msg("step %g", st->currealtime);
teuben's avatar
teuben committed

slevy's avatar
 
slevy committed
  } else if(!strcmp( argv[0], "trange" ) || !strcmp( argv[0], "steprange" )) {
	double utmin = st->utmin;
	double utmax = st->utmax;
	double utwrap = st->utwrap;
	if(argc>1) {
	    if(!strcmp(argv[1],"on")) st->usertrange = 1;
	    else if(!strcmp(argv[1],"off")) st->usertrange = 0;
	    else {
		st->utmin = getfloat( argv[1], utmin );
		if(argc>2) st->utmax = getfloat( argv[2], utmax );
		if(argc>3) st->utwrap = getfloat( argv[3], utwrap );
		if(utmin != st->utmin || utmax != st->utmax)
		    st->usertrange = 1;
	    }
	}
	msg(st->usertrange ?
	    "trange %lg %lg  %lg (tmin tmax twrap)"
	  : "trange off   (%lg %lg  %lg  tmin tmax twrap)",
		st->utmin, st->utmax, st->utwrap);
slevy's avatar
 
slevy committed

teuben's avatar
teuben committed
  } else if(!strcmp( argv[0], "fwd" )) {
slevy's avatar
 
slevy committed
	if(argc>1)
	    clock_set_fwd( st->clk, getbool(argv[1], 1) );
	IFMENU( set_fwd( clock_fwd(st->clk), ment.fwd, st ) );
teuben's avatar
teuben committed

  } else if(!strcmp( argv[0], "gscale" )) {
	if(argc>1) sscanf(argv[1], "%f", &st->gscale);
	msg("gscale %g (scaling particles), then translating by %g %g %g",
		st->gscale, st->gtrans.x[0],st->gtrans.x[1],st->gtrans.x[2]);

  } else if(!strcmp( argv[0], "clearobj" )) {
	struct specklist **slp;
	slp = specks_timespecksptr( st, st->curdata, st->curtime );
	specks_discard( st, slp );
	st->sl = *slp;

  } else if(!strcmp( argv[0], "every" )) {
	if(argc>1) sscanf(argv[1], "%d", &st->subsample);
	if(st->subsample <= 0) st->subsample = 1;
	msg("display every %dth particle (of %d)",
			st->subsample, specks_count(st->sl));

slevy's avatar
 
slevy committed
  } else if(!strncmp( argv[0], "everycomp", 9 )) {
	st->everycomp = getbool(argv[1], st->everycomp);
	msg("everycomp %d (%s compensate for \"every\" subsampling)",
		st->everycomp,
		st->everycomp ? "do" : "don't");

teuben's avatar
teuben committed
  } else if(!strncmp( argv[0], "color", 5 )) {
	struct valdesc *vd;
	if(argc>1) {
	    if(!specks_set_byvariable( st, argv[1], &st->coloredby ))
		st->coloredby = CONSTVAL;
	}
	vd = &st->vdesc[st->curdata][st->coloredby];
	if(argc>2 && (!strncmp(argv[2], "int", 3) ||
		      !strncmp(argv[2], "exact", 5))) {
	    vd->call = 0;
	    vd->cexact = 1;
	    vd->cmin = 0;
	    argc--, argv++;
	}
	if(argc>2 && (!strncmp(argv[2], "cont", 4) || !strcmp(argv[2], "-exact"))) {
	   vd->cexact = 0;
	   argc--, argv++;
	}
	if(argc>2 && sscanf(argv[2], "%f", &vd->cmin))
	    vd->call = 0;
	if(argc>3 && sscanf(argv[3], "%f", &vd->cmax))
	    vd->call = 0;
	if((vd->cmin == vd->cmax && vd->cmin == 0) ||
	   (argc>2 && (!strcmp(argv[2],"-") || !strcmp(argv[2],"all")))) {

	    vd->cmin = vd->min, vd->cmax = vd->max, vd->call = 1;
	}
	if(argc>4 && st->coloredby == CONSTVAL) sscanf(argv[4], "%f", &vd->mean);
	if(st->coloredby == CONSTVAL) {
	    msg("coloring-by rgb %.3f %.3f %.3f",
		vd->cmin, vd->cmax, vd->mean);
	} else if(vd->cexact) {
	    msg("coloring-by %d(%s) exactly (cindex=data+%g; data %g..%g, cmap 0..%d)",
		st->coloredby, vd->name, vd->cmin,
		vd->min,vd->max, st->ncmap-1);
	} else {
	    if(vd->min == vd->cmin && vd->max == vd->cmax || vd->nsamples==0) {
		msg("coloring-by %d(%s) %g.. %g mean %.3g]",
		    st->coloredby, vd->name,
		    vd->cmin, vd->cmax, vd->mean);
	    } else {
		msg("coloring-by %d(%s) %g.. %g (data %g..%g mean %.3g)",
		    st->coloredby, vd->name,
		    vd->cmin, vd->cmax, vd->min, vd->max, vd->mean);
	    }
	}
	if(argc>1)
	    st->colorseq++;

  } else if(!strcmp( argv[0], "datavar" ) || !strcmp( argv[0], "dv" )) {
	int min = 0, max = CONSTVAL-1;
	if(argc>1 && specks_set_byvariable( st, argv[1], &min ))
	    max = min;
	if(st->ndata>1)
	    msg("In dataset %d %s:", st->curdata, st->dataname[st->curdata]);
	for(i = min; i <= max; i++) {
	    struct valdesc *vd = &st->vdesc[st->curdata][i];
	    if(max>min && vd->name[0] == '\0' && vd->max == vd->min)
		continue;
	    msg("datavar %d %s  %g.. %g mean %g%s%s",
		i, vd->name[0]=='\0'?"\"\"" : vd->name,
		vd->min, vd->max, vd->mean,
		st->sizedby==i ? "[lum]" : "",
		st->coloredby==i ? "[color]" : "");
	}

  } else if(!strcmp( argv[0], "datawait" )) {
	if(argc>1) {
	    switch(i = getbool(argv[1],-1)) {
	    case 0:
	    case 1:
		st->datasync = i;
		break;
	    }
	    msg("datawait %s", st->datasync ? "on" : "off");
	}
	specks_datawait(st);

slevy's avatar
 
slevy committed
  } else if(!strncmp(argv[0], "kira", 4)) {
slevy's avatar
 
slevy committed
	char *swhat = argv[1];
	char *sval = argc>2 ? argv[2] : NULL;
	int what;
	double val;
#ifndef USE_KIRA
	msg("Need to recompile with -DUSE_KIRA");
#else
	if(swhat == NULL) swhat = "?";

	if(!strncmp(swhat, "sep", 3) || !strncmp(swhat, "semi", 4)) {
	    kira_set( st, KIRA_RINGSIZE, swhat[2]=='p' ? KIRA_RINGSEP : KIRA_RINGA );
	    msg("kiractl ringsize %s",
		kira_get( st, KIRA_RINGSIZE ) == KIRA_RINGSEP ? "separation" : "semimajor");

slevy's avatar
 
slevy committed
	} else if(!strcmp(swhat, "ringsize") || !strcmp(swhat, "ringscale") || !strcmp(swhat, "size")) {
slevy's avatar
 
slevy committed
	    if(sval) {
		val = !strncmp(sval,"sep",3) ? KIRA_RINGSEP
		    : !strncmp(sval,"semi",4) ? KIRA_RINGA
		    : !strcmp(sval,"a") ? KIRA_RINGA
		    : kira_get( st, KIRA_RINGSIZE );
		kira_set( st, KIRA_RINGSIZE, val );
		if(argc > 3)
		    kira_set( st, KIRA_RINGSCALE,
			getfloat( argv[3], kira_get( st, KIRA_RINGSCALE ) ) );
	    }
	    msg("kiractl ringsize %s %g",
		kira_get( st, KIRA_RINGSIZE ) == KIRA_RINGSEP ? "separation" : "semimajor",
		kira_get( st, KIRA_RINGSCALE ));

	} else if(!strcmp(swhat, "ringscale") || !strcmp(swhat, "scale")) {
	    if(sval)
		kira_set( st, KIRA_RINGSCALE, getfloat( sval, kira_get(st,KIRA_RINGSCALE) ) );
	    msg("kiractl ringscale %g", kira_get(st,KIRA_RINGSCALE));

	} else if(!strcmp(swhat, "span") || !strcmp(swhat, "ringspan")) {
	    if(argc>2 && (val = getfloat( argv[2], -1 )) >= 0)
		    kira_set( st, KIRA_RINGMIN, val );
	    if(argc>3 && (val = getfloat( argv[3], -1 )) >= 0)
		    kira_set( st, KIRA_RINGMAX, val );
	    msg("kiractl ringspan %.0f %.0f",
		kira_get( st, KIRA_RINGMIN ), kira_get( st, KIRA_RINGMAX ));

	} else if(!strncmp(swhat, "nod", 3) || !strncmp(swhat, "ring", 4)) {
	    what = swhat[0]=='n' ? KIRA_NODES : KIRA_RINGS;
	    if(sval)
		kira_set( st, what,
		     (0==strncmp(sval, "root", 4)) ? KIRA_ROOTS : getbool(sval, KIRA_ON) );
	    val = kira_get( st, what );
slevy's avatar
 
slevy committed
	    msg("kiractl %s %s %g",
slevy's avatar
 
slevy committed
		what==KIRA_NODES ? "nodes" : "rings",
slevy's avatar
 
slevy committed
		val==2 ? "root" : val==1 ? "on" : "off",
		kira_get( st, KIRA_TICKSCALE ));

	} else if(!strncmp(swhat, "tree", 2) || !strcmp(swhat, "arc")) {
	    if(sval)
		kira_set( st, KIRA_TREE,
		    sval[0]=='c' ? KIRA_CROSS : sval[0]=='t' ? KIRA_TICK
		    : getbool(sval, KIRA_ON) );
	    if(argc>3 && sscanf(argv[3], "%lf", &val)>0)
		kira_set( st, KIRA_TICKSCALE, val );
	    val = kira_get( st, KIRA_TREE );
	    msg("kiractl tree %s",
		val==KIRA_CROSS ? "cross" : val==KIRA_TICK ? "tick"
		: val ? "on" : "off");
slevy's avatar
 
slevy committed

slevy's avatar
 
slevy committed
	} else if(!strncmp(swhat, "track", 2)) {
	    if(sval)
		kira_set( st, KIRA_TRACK, getbool(sval, 0) );
	    val = kira_get( st, KIRA_TRACK );
	    msg(val == 0 ? "kiractl track off" : "kiractl track %d", (int)val);

slevy's avatar
 
slevy committed
	} else {
slevy's avatar
 
slevy committed
	    msg("kiractl {node|ring} {on|off|root} | tree {on|off|cross|tick} [<tickscale>] | size {sep|semimaj} | scale <fac> | span <minpix> <maxpix> | track <id>");
slevy's avatar
 
slevy committed
	}
#endif

teuben's avatar
teuben committed
  } else if(!strncmp( argv[0], "lum", 3 )) {
	struct valdesc *vd;
	if(argc>1) {
	    if(!specks_set_byvariable( st, argv[1], &st->sizedby ))
		st->sizedby = CONSTVAL;
	}
	vd = &st->vdesc[st->curdata][st->sizedby];
	if(argc>2) vd->lall = 0, vd->lmin = getfloat(argv[2], vd->lmin);
	if(argc>3) vd->lall = 0, vd->lmax = getfloat(argv[3], vd->lmax);
	if(vd->lmin == vd->lmax && vd->lmin == 0 ||
	       argc>2 && (!strcmp(argv[2],"-") || !strcmp(argv[2],"all"))) {
	    vd->lmin = vd->min, vd->lmax = vd->max, vd->lall = 1;
	}
	if(st->sizedby == CONSTVAL) {
	    msg("lum-by constant %g", vd->lmin);
	} else {
	    msg("lum-by %d (%s) [%g..%g mean %.3g]", st->sizedby,
		vd->name, vd->lmin, vd->lmax, vd->mean);
	}
	if(argc>1)
	    st->sizeseq++;

  } else if(!strcmp( argv[0], "cmap" ) || !strcmp( argv[0], "boxcmap" )) {
	char *tfname = argv[1];
	char *realfile = findfile( NULL, argv[1] );
	if(argc != 2) {
	    msg("Usage: %s <ascii-file-of-RGB-triples>", argv[0]);
	} else {
	    if(argc > 1 && realfile == NULL) {
		tfname = (char *)alloca( strlen(argv[1]) + 6 );
		sprintf(tfname, "%s.cmap", argv[1]);
		realfile = findfile( NULL, tfname );
	    }
	    if(realfile != NULL) {
		if(argv[0][0] == 'b') {
slevy's avatar
 
slevy committed
		    specks_read_cmap( st, realfile, &st->boxncmap, &st->boxcmap, NULL );
teuben's avatar
teuben committed
		} else {
slevy's avatar
 
slevy committed
		    specks_read_cmap( st, realfile, &st->ncmap, &st->cmap, &st->cookedcmap );
teuben's avatar
teuben committed
		    st->colorseq++; /* Must recompute particle coloring */
		}
	    } else {
		msg("%s: can't find \"%s\" nor ....cmap", argv[0], argv[1]);
	    }
	}

  } else if(!strncmp( argv[0], "cment", 5 ) || !strncmp( argv[0], "boxcment", 8 )) {
	int i, r,g,b;
	unsigned char *cvp;
	int isbox = argv[0][0] == 'b';
	int ncmap = isbox ? st->boxncmap : st->ncmap;
	int *cmap = isbox ? st->boxcmap : st->cmap;

	if(argc>1) {
	    i = atoi(argv[1]);
	    if(i < 0 || i > ncmap) {
		msg("cment: %d out of range (must be 0..%d)", i, st->ncmap-1);
	    } else {
		if(argc>4) {
		    r=255*atof(argv[2]);
		    g=255*atof(argv[3]);
		    b=255*atof(argv[4]);
		    cmap[i] = PACKRGBA(r,g,b,0);
		    if(st->sl) st->colorseq++;	/* force recolor */
		}
		cvp = (unsigned char *)&cmap[i];
		msg("%scment %d  %.3f %.3f %.3f  (of cmap 0..%d",
			isbox ? "box" : "",
			i, cvp[0]/255., cvp[1]/255., cvp[2]/255.,
			st->ncmap-1);
	    }
	} else {
	    msg("Usage: %scment colorindex [r g b]", isbox ? "box" : "");
	}

  } else if(!strncmp( argv[0], "only", 4 )) {
	int plus = !strcmp(argv[0], "only+");
	int minus = !strcmp(argv[0], "only-");
	int exact = !strcmp(argv[0], "only=");
	int total = 0, chosen = 0, waschosen = 0;
	int tvar = -1;
	int all = 0;
	int k;
	int nspecks, nvisible, needthresh;
	struct specklist *sl;
	struct speck *sp;

	if(argc>1) {
	    if(!strcmp(argv[1], "all") || !strcmp(argv[1], "*")) all = 1;
	    if(!strcmp(argv[1], "none")) all = -1;
	}
	if(!all && ((!plus && !minus && !exact) ||
		!specks_set_byvariable( st, argv[1], &tvar))) {
	    msg("only+/only-/only=  \"all\"|\"none\"|varname value minvalue-maxvalue ...");
	}

	plus |= exact;

	if(exact || all) {
	    /* preset all values */
	    int wipebit = (plus && all>0) ? 0 : THRESHBIT;
	    for(sl = st->sl; sl != NULL; sl = sl->next) {
		if((sp = sl->specks) == NULL || sl->text != NULL)
		    continue;
		for(k = sl->nspecks; --k >= 0; sp = NextSpeck(sp, sl, 1))
		    sp->rgba = (sp->rgba & ~THRESHBIT) | wipebit;
	    }
	}

	/*
	 * If a thresh variable is given, use "plus" to choose
	 * whether to make that speck visible.
	 * NOTE that specks with THRESHBIT on are *invisible*!
	 */
	for(i = 2; i < argc; i++) {
	    float vmin = -1e38, vmax = 1e38;

	    if(argv[i][0] == '<') vmax = atof(argv[i]+1);
	    else if(argv[i][0] == '>') vmin = atof(argv[i]+1);
	    else {
		switch(sscanf(argv[i], "%f%*c%f", &vmin, &vmax)) {
		case 1: vmax = vmin; break;
		case 2: break;
		default:
		    msg("%s: \"%s\": expected N or <N or >N or N-M",
			argv[0], argv[i]);
		    return -1;
		}
	    }

	    for(sl = st->sl; sl != NULL; sl = sl->next) {
		if((sp = sl->specks) == NULL || sl->text != NULL || tvar<0
			|| SMALLSPECKSIZE(tvar+1) > sl->bytesperspeck)
		    continue;
		for(k = sl->nspecks; --k >= 0; sp = NextSpeck(sp, sl, 1)) {
		    if(sp->val[tvar]>=vmin && sp->val[tvar]<=vmax)
			sp->rgba = plus ? sp->rgba & ~THRESHBIT
					: sp->rgba | THRESHBIT;
		}
	    }
	}

	nspecks = nvisible = 0;
	for(sl = st->sl; sl != NULL; sl = sl->next) {
	    if((sp = sl->specks) == NULL || sl->text != NULL)
		continue;
	    nspecks += sl->nspecks;
	    for(k = sl->nspecks; --k >= 0; sp = NextSpeck(sp, sl, 1)) {
		if(!(sp->rgba & THRESHBIT))
		    nvisible++;
	    }
	}

	needthresh = (st->usethresh&P_USETHRESH)==0 && nvisible < nspecks;
	if(needthresh)
	    st->usethresh |= P_USETHRESH;
	msg("only %d visible of %d%s", nvisible, nspecks,
		needthresh ? " (selecting \"thresh on\")" : "");

  } else if(!strncmp( argv[0], "thresh", 6 )) {
	int i, expect = -1;
	float v;
	char smin[16], smax[16], *arg;
	int changed = 0;
	for(i = 1; i < argc; i++) {