Skip to content
Snippets Groups Projects
kira_parti.cc 51.1 KiB
Newer Older
		tsp->val[SPECK_NCLUMP] = -tsp->val[SPECK_NCLUMP];
		/* Also, propagate all leaves' set membership to CM nodes */
		sl->sel[ntotal] = ww->unionsel;

	    } else if(ww->interactsel && id < ww->nleafsel) {
		/* For leaf nodes, if at least one star in this
		 * group is in the interaction set,
		 * then add all other group members to it.
		 */
		sl->sel[ntotal] = ww->leafsel[id] |= ww->interactsel;
		/* Making trails? */
	    }
	    if(ww->trailsel.use != SEL_NONE &&
		    SELECTED( ww->leafsel[id], &ww->trailsel )) {
		kira_add_trail( st, ww, id, tsp );
	    } else if(ww->trailonly) {
		kira_erase_trail( st, ww, id );
	    for(i = 0, vd = ww->vd; i <= SPECK_STYPE; i++, vd++) {
		float v = tsp->val[i];
		if(vd->min > v) vd->min = v;
		if(vd->max < v) vd->max = v;
		vd->sum += v;
	    }
	    ntotal++;
slevy's avatar
 
slevy committed
	    tsp = NextSpeck(tsp, sl, 1);
slevy's avatar
slevy committed
	}

	/* For all marks (rings, etc.) in this subtree */
slevy's avatar
 
slevy committed
	count = marksl->nspecks - mns;
	for(k = 0; k < count; k++) {
	    msp->val[SPECK_NCLUMP] += nleaves;
	    if(msp->val[0] < 0)
		msp->val[SPECK_NCLUMP] = -msp->val[SPECK_NCLUMP]; // negate nclump for CM nodes
	    marksl->sel[mns+k] = ww->unionsel;
slevy's avatar
 
slevy committed
	    msp = NextSpeck(msp, sl, 1);
	}
slevy's avatar
slevy committed
    }
slevy's avatar
 
slevy committed

slevy's avatar
 
slevy committed
    if(ww->wastracking < 0) ww->wastracking = 0;	// Detach if tracked pcle not found now

    for(i = 0, vd = ww->vd; i < SPECK_NDATAFIELDS && i < MAXVAL; i++, vd++) {
	struct valdesc *tvd = &st->vdesc[ st->curdata ][ i ];

	tvd->nsamples = ntotal;
	if(vd->min > vd->max) {
	    vd->min = vd->max = 0;
	    tvd->nsamples = 0;
	}
	tvd->min = vd->min;
	tvd->max = vd->max;
	tvd->sum = vd->sum;
	tvd->mean = tvd->nsamples > 0 ? vd->sum / tvd->nsamples : 0;
    }

    specks_reupdate( st, sl );

    ww->bufno = 1 - ww->bufno;
slevy's avatar
slevy committed
    return sl;
}

struct specklist *kira_get_parti( struct dyndata *dd, struct stuff *st, double realtime )
slevy's avatar
slevy committed
{
    struct worldstuff *ww = (struct worldstuff *)dd->data;
slevy's avatar
slevy committed

slevy's avatar
slevy committed
    if (ww == NULL || ww->nh == 0)
slevy's avatar
slevy committed
	return NULL;

    ww->treq = realtime;

    if (realtime < ww->tmin) realtime = ww->tmin;
    if (realtime > ww->tmax) realtime = ww->tmax;

slevy's avatar
 
slevy committed
    if (ww->tcur == realtime && ww->slvalid)
slevy's avatar
slevy committed
	return ww->sl;

    int ih = ww->ih;
    int nh = ww->nh;

    worldbundle *wb = ww->wh[ih];
    for(; realtime > wb->get_t_max() && ih < nh-1; ih++, wb = ww->wh[ih])
	;
    for(; realtime < wb->get_t_min() && ih > 0; ih--, wb = ww->wh[ih])
	;
#if OLDTREE
    pdyn *root = create_interpolated_tree(wb, realtime);
    ww->sl = kira_to_parti(root, dd, st, ww);
    rmtree(root);
#else
    pdyn *root = create_interpolated_tree2(wb, realtime);
    ww->center_pos = get_center_pos();
    ww->center_vel = get_center_vel();
    ww->sl = kira_to_parti(root, dd, st, ww);
slevy's avatar
slevy committed

    ww->ih = ih;
    ww->tcur = realtime;

slevy's avatar
 
slevy committed
    ww->slvalid = 1;
slevy's avatar
slevy committed
    return ww->sl;
}

#define TRAILGAP 1		/* bit in alpha byte of rgba -> "don't draw from prev pt to here" */

void kira_add_trail( struct stuff *st, worldstuff *ww, int id, struct speck *sp )
{
    if(id < 0) id = ww->maxstars + id;
    if(id <= 0 || id > ww->maxstars || ww->maxtrail <= 0) return;

    struct trailhead *th = &ww->trails[id];
    int bps = ww->sl->bytesperspeck;
    if(th->maxtrail <= 0) {
	th->maxtrail = ww->maxtrail;
	th->specks = (struct speck *)NewN( char, th->maxtrail*bps );
	th->ntrails = 0;
	th->next = 0;
    }
    if(th->ntrails > th->maxtrail)
	th->ntrails = th->maxtrail;
    if(th->next < 0 || th->next >= th->maxtrail)
	th->next = 0;
    struct speck *tsp = (struct speck *)(((char *)th->specks) + th->next*bps);
    memcpy( tsp, sp, bps );
    vsub( &tsp->p, &tsp->p, &ww->trackpos );
    if(fabs(th->lasttime - ww->treq) > ww->maxtrailgap) {
	((char *)&tsp->rgba)[3] = TRAILGAP;	/* alpha "1" bit is on for post-gap trail points */
    } else {
	((char *)&tsp->rgba)[3] = 0;
    }
    tsp->val[0] = ww->treq;
    th->lasttime = ww->treq;
    if(++th->next >= th->maxtrail)
	th->next = 0;
    if(++th->ntrails > th->maxtrail)
	th->ntrails = th->maxtrail;
    if(id >= ww->maxtrailno)
	ww->maxtrailno = id+1;
}

void kira_erase_trail( struct stuff *st, worldstuff *ww, int id )
{
    if(id < 0) id = ww->maxstars + id;
    if(id <= 0 || id > ww->maxstars || ww->maxtrail <= 0) return;
    struct trailhead *th = &ww->trails[id];
    th->next = th->ntrails = 0;
    if(id+1 == ww->maxtrailno) {
	while(ww->maxtrailno > 0 && ww->trails[ww->maxtrailno-1].ntrails == 0)
	    ww->maxtrailno--;
    }
}

void kira_track_break( struct worldstuff *ww, Point *newtrack )
{
    Point incr;
    vsub( &incr, newtrack, &ww->trackpos );
    for(int id = 0; id < ww->maxstars; id++) {
	struct trailhead *th = &ww->trails[id];
	if(th->ntrails > 0) {
	    struct speck *sp = th->specks;
	    for(int i = 0; i < th->maxtrail; i++) {
		vsub( &sp->p, &sp->p, &incr );
		sp = NextSpeck(sp, ww->sl, 1);
	    }
	}
    }
    // ww->trackpos = *newtrack;  no, let caller do that.
}

void kira_maxtrail( struct dyndata *dd, struct stuff *st, int newmax )
{
    int i;
    struct worldstuff *ww = (struct worldstuff *)dd->data;
    ww->maxtrail = newmax;
    if(ww->trails == NULL) return;
    int bps = ww->sl->bytesperspeck;
    char *spare = (char *)malloc( bps * newmax );

    for(i = 0; i < ww->maxstars; i++) {
	struct trailhead *th = &ww->trails[i];
	if(th->maxtrail == 0)
	    continue;
	if(th->ntrails > newmax) th->ntrails = newmax;
	int first = (th->next + th->maxtrail - th->ntrails) % th->maxtrail;
	char *base = (char *)th->specks;
	if(first < th->next) {
	    memmove( spare, base + first*bps, th->ntrails*bps ); 
	} else {
	    /* rearrange two pieces: 0..next-1  first..max-1
	     * into 0..keep-1  keep..keep+next-1
	     */
	    int keep = th->maxtrail - first;
	    memcpy( spare, base + first*bps, keep*bps );
	    memmove( spare + keep*bps, base, th->next*bps );
	}
	Free( th->specks );
	th->specks = (struct speck *)NewN( char, newmax*bps );
	memcpy( th->specks, spare, th->ntrails*bps );
	th->next = th->ntrails;
	th->maxtrail = newmax;
    }
    free(spare);
}



int kira_draw( struct dyndata *dd, struct stuff *st, struct specklist *slhead, Matrix *Tc2w, float radperpix )
slevy's avatar
 
slevy committed
{
    struct worldstuff *ww = (struct worldstuff *)dd->data;
slevy's avatar
 
slevy committed

    if(ww == NULL || !dd->enabled)
	return 0;
slevy's avatar
 
slevy committed

slevy's avatar
 
slevy committed
    struct specklist *sl;
slevy's avatar
 
slevy committed
    float halftickscale = 0.5 * ww->tickscale;
    int inpick = st->inpick;
    int slno;
slevy's avatar
 
slevy committed

    static Point zero = {0,0,0};
    Point fwdvec = {0,0,-radperpix};	// scaled by pixels-per-radian
slevy's avatar
 
slevy committed
    Point eyepoint, fwd, unitfwd;
slevy's avatar
 
slevy committed
    float fwdd;

    vtfmpoint( &eyepoint, &zero, Tc2w );
    vtfmvector( &fwd, &fwdvec, Tc2w );
    fwdd = -vdot( &eyepoint, &fwd );
slevy's avatar
 
slevy committed
    vunit( &unitfwd, &fwd );
slevy's avatar
 
slevy committed

#define MAXRING 32
    Point fan[MAXRING];
    int nring = 24;
    int i;
    for(i = 0; i < nring; i++) {
	float th = 2*M_PI*i / nring;
	vcomb( &fan[i],  cos(th),(Point *)&Tc2w->m[0*4+0],
			 sin(th),(Point *)&Tc2w->m[1*4+0] );
    }


    for(sl = slhead, slno = 1; sl != NULL; sl = sl->next, slno++) {
	if(sl == ww->sl) {
	    specks_slno = slno;

	} else if(sl->special == MARKERS) {
slevy's avatar
 
slevy committed
	    int ns = sl->nspecks;
	    struct speck *sp = sl->specks;

	    if(inpick) {
		glLoadName(slno);
		glPushName(0);
	    }
slevy's avatar
 
slevy committed
	    for(i = 0; i < ns; i++, sp = NextSpeck(sp, sl, 1)) {
		float unitperpix = vdot( &fwd, &sp->p ) + fwdd;
		if(unitperpix <= 0) continue;
slevy's avatar
 
slevy committed

		if( !SELECTED(sl->sel[i], &st->seesel) )
		    continue;
slevy's avatar
 
slevy committed
		if(ww->treerings == KIRA_ON ||
			(ww->treerings == KIRA_ROOTS && sp->val[SPECK_TREEADDR] == 1)) {
		    float ringpixels = fabs(sp->val[SPECK_RINGSIZE] * ww->ringscale) / unitperpix;
slevy's avatar
 
slevy committed
		    if(ringpixels < ww->ringmin) ringpixels = ww->ringmin;
		    if(ringpixels > ww->ringmax) ringpixels = ww->ringmax;
		    float rring = ringpixels * unitperpix;
		    int step = ringpixels>20 ? 1 : ringpixels>8 ? 2 : 3;

		    if(inpick) glLoadName(i);
		    else glColor3ubv( (GLubyte *)&sp->rgba );
slevy's avatar
 
slevy committed
		    glBegin( GL_LINE_LOOP );
		    for(int k = 0; k < nring; k+=step)
			glVertex3f( sp->p.x[0] + rring*fan[k].x[0],
				    sp->p.x[1] + rring*fan[k].x[1],
				    sp->p.x[2] + rring*fan[k].x[2] );
		    glEnd();
		}
		if(ww->treearcs != KIRA_OFF) {
		    float mu = sp->val[SPECK_MU];
		    float *sep = &sp->val[SPECK_SEPVEC];

		    if(inpick) glLoadName(i);
		    else glColor3ubv( (GLubyte *)&sp->rgba );
slevy's avatar
 
slevy committed
		    glBegin( GL_LINES );

		    if(ww->treearcs != KIRA_TICK) {
			glVertex3f(
			    sp->p.x[0] - mu*sep[0],
			    sp->p.x[1] - mu*sep[1],
			    sp->p.x[2] - mu*sep[2] );
			glVertex3f(
			    sp->p.x[0] + (1-mu)*sep[0],
			    sp->p.x[1] + (1-mu)*sep[1],
			    sp->p.x[2] + (1-mu)*sep[2] );
		    }

		    if(ww->treearcs == KIRA_CROSS || ww->treearcs == KIRA_TICK) {
			Point cr;
			vcross( &cr,  &unitfwd, (Point *)sep );
			float sepsep = vdot((Point *)sep, (Point *)sep);
			float sepfwd = vdot((Point *)sep, &unitfwd);
			float scaleby = halftickscale / sqrt(1 - sepfwd*sepfwd/sepsep);
			glVertex3f(
			   sp->p.x[0] - scaleby*cr.x[0],
			   sp->p.x[1] - scaleby*cr.x[1],
			   sp->p.x[2] - scaleby*cr.x[2] );
			glVertex3f(
			   sp->p.x[0] + scaleby*cr.x[0],
			   sp->p.x[1] + scaleby*cr.x[1],
			   sp->p.x[2] + scaleby*cr.x[2] );
		    }
		    glEnd();
		}
slevy's avatar
 
slevy committed
	    }
slevy's avatar
 
slevy committed
	}
    }
    glLineWidth( ww->trailpsize );
    glEnable( GL_BLEND );
    glBlendFunc( GL_SRC_ALPHA, GL_ONE );

    int alpha = 0, rgbmask = ~0;
    ((GLubyte *)&alpha)[3] = (int) (255 * ww->trailalpha);
    ((GLubyte *)&rgbmask)[3] = 0;
    if(inpick) {
	glPushName( specks_slno );
	glPushName( 0 );
    }

    glPointSize( 1.5 );
    glPushMatrix();
    glTranslatef( ww->trackpos.x[0], ww->trackpos.x[1], ww->trackpos.x[2] );
    for(i = 0; i < ww->maxtrailno; i++) {
	struct trailhead *th = &ww->trails[i];
	if(th->ntrails == 0 || th->maxtrail <= 0)
	    continue;
	if(inpick)
	    glLoadName( i );
	glBegin( GL_LINE_STRIP );
	int first = (th->next + th->maxtrail - th->ntrails) % th->maxtrail;
	int k, rgb = 0, rgba = 0;
slevy's avatar
slevy committed
	struct speck *sp;
	char *base = (char *)th->specks;
	int bps = ww->sl->bytesperspeck;
	int from1 = first;
	int to1 = (first < th->next) ? th->next : th->maxtrail;
	int from2 = 0;
        int to2 = (first < th->next) ? 0 : th->next;
	int wasgap = 0, ingap = 0;
	Point *prev = NULL;
	for(k = from1; k < to1; k++) {
	    sp = (struct speck *)(base + k*bps);
	    ingap = ((char *)&sp->rgba)[3] & TRAILGAP;
	    if(wasgap != ingap) {
		glEnd();
		if(ingap) {
		    glBegin( GL_POINTS );
		} else {
		    glBegin( GL_LINE_STRIP );
		    glVertex3fv( prev->x );
		}
		wasgap = ingap;
	    }
	    if(rgb != (sp->rgba & rgbmask)) {
		rgb = sp->rgba & rgbmask;
		rgba = rgb | alpha;
		glColor4ubv( (GLubyte *)&rgba );
	    }
	    glVertex3fv( sp->p.x );
	    prev = &sp->p;
	}
	for(k = from2; k < to2; k++) {
	    sp = (struct speck *)(base + k*bps);
	    ingap = ((char *)&sp->rgba)[3] & TRAILGAP;
	    if(wasgap != ingap) {
		glEnd();
		if(ingap) {
		    glBegin( GL_POINTS );
		} else {
		    glBegin( GL_LINE_STRIP );
		    glVertex3fv( prev->x );
		}
		wasgap = ingap;
	    }
	    if(rgb != (sp->rgba & rgbmask)) {
		rgb = sp->rgba & rgbmask;
		rgba = rgb | alpha;
		glColor4ubv( (GLubyte *)&rgba );
slevy's avatar
slevy committed
	    }
	    glVertex3fv( sp->p.x );
	    prev = &sp->p;
slevy's avatar
slevy committed
	}
    glPopMatrix();
    if(inpick) {
	glPopName();
	glPopName();
slevy's avatar
slevy committed
    }
    return 1;
}

int kira_parse_args( struct dyndata *dd, struct stuff *st, int argc, char **argv )
{
    char *swhat = argv[1];
    char *sval = argc>2 ? argv[2] : NULL;
    int what;
    double val;
    worldstuff *ww = (worldstuff *)dd->data;
    int changed = 0;

    if(0!=strncmp(argv[0], "kira", 4))	/* accept "kira" or "kiractl" */
	return 0;
    if(swhat == NULL) swhat = "?";

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

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

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

    } else if(!strcmp(swhat, "span") || !strcmp(swhat, "ringspan")) {
	if(argc>2 && (val = getfloat( argv[2], -1 )) >= 0)
		kira_set( dd, st, KIRA_RINGMIN, val );
	if(argc>3 && (val = getfloat( argv[3], -1 )) >= 0)
		kira_set( dd, st, KIRA_RINGMAX, val );
	msg("kiractl ringspan %.0f %.0f",
	    kira_get( dd, st, KIRA_RINGMIN ), kira_get( dd, 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( dd, st, what,
		 (0==strncmp(sval, "root", 4)) ? KIRA_ROOTS : getbool(sval, KIRA_ON) );
	val = kira_get( dd, st, what );
	msg("kiractl %s %s %g",
	    what==KIRA_NODES ? "nodes" : "rings",
	    val==2 ? "root" : val==1 ? "on" : "off",
	    kira_get( dd, st, KIRA_TICKSCALE ));

    } else if(!strncmp(swhat, "tree", 3) || !strcmp(swhat, "arc")) {
	if(sval)
	    kira_set( dd, 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( dd, st, KIRA_TICKSCALE, val );
	val = kira_get( dd, st, KIRA_TREE );
	msg("kiractl tree %s",
	    val==KIRA_CROSS ? "cross" : val==KIRA_TICK ? "tick"
	    : val ? "on" : "off");

    } else if(!strncmp(swhat, "mscale", 4) || !strcmp(swhat, "massscale")) {
	if(!ww->truemassscale || strchr(sval, '!')) {
	    ww->massscale = getfloat( sval, ww->massscale );
	msg("kiractl mscale %g (kira says %g)",
		ww->massscale, mass_scale_factor());
    } else if(!strncmp(swhat, "track", 4)) {
	if(sval)
	    kira_set( dd, st, KIRA_TRACK, getbool(sval, 0) );
	val = kira_get( dd, st, KIRA_TRACK );
	msg(val == 0 ? "kiractl track off" : "kiractl track %d", (int)val);

    } else if(!strncmp(swhat, "center", 6)) {
	    int just = 0;
	    if(!strncmp(sval,"off",3) || !strcmp(sval,"inertial")) {
		ww->centered = 0;
		just = 1;
	    } else if(!strcmp(sval,"on")) {
		/* fine */
	    } else if(!strcmp(sval,"next") || sval[0] == '+') {
		ww->which_center++;
	    } else if(isdigit(sval[0])) {
		ww->which_center = atoi(sval);
	    } else {
		just = 1;
	    }
	    if(ww->which_center >= get_n_center())
		ww->which_center %= get_n_center();
	    if(!just) ww->centered = 1;
	    if(ww->centered)
		set_center( ww->wh, ww->nh, ww->which_center );

	msg("kira center %s%d(%s) (center pos %g %g %g vel %g %g %g)",
	  ww->centered ? "" : "off ",
	  ww->which_center, get_center_id(),
	  ww->center_pos[0], ww->center_pos[1], ww->center_pos[2],
	  ww->center_vel[0], ww->center_vel[1], ww->center_vel[2] );
    
    } else if(!strcmp(swhat, "maxtrail")) {
	if(sval)
	    kira_maxtrail( dd, st, getbool(sval, ww->maxtrail) );
	msg("kira maxtrail %d", ww->maxtrail);

    } else if(!strcmp(swhat, "trail")) {
	if(sval) {
	    if(!strcmp(sval, "clear")) {
		for(int i = 0; i < ww->maxstars; i++)
		    kira_erase_trail( st, ww, i );
	    } else {
		int a = 2;
		if(!strcmp(sval, "only")) {
		    ww->trailonly = 1;
		    a = 3;
		} else {
		    ww->trailonly = 0;
		}
		parse_selexpr( st, rejoinargs( a, argc, argv ), NULL, &ww->trailsel, "kira trail" );
	    }
	}
	msg("kira trail%s %s (%s)", ww->trailonly ? " only":"",
		    show_selexpr( st, NULL, &ww->trailsel ),
		    selcounts( st, st->sl, &ww->trailsel ));
    } else if(!strncmp(swhat, "trailgap", 6)) {
	if(sval) {
	    ww->maxtrailgap = getfloat( sval, ww->maxtrailgap );
	    changed = 1;
	}
	msg("kira trailgaptime %g", ww->maxtrailgap);

    } else if(!strncmp(swhat, "pick", 2)) {
	int picking = getbool( sval, (st->picked == kira_picked) );
	if(picking) {
	    specks_all_picks( st, kira_picked, dd );
	} else {
	    specks_all_picks( st, NULL, NULL );
	}

    } else if(!strncmp(swhat, "int", 3)) {
	what = parse_selexpr( st, rejoinargs( 2, argc, argv ), &ww->intdest, &ww->intsrc, "kira intsel" );
	if(what != 3)
	    selsrc2dest( st, &ww->intsrc, &ww->intdest );
	ww->intdest.wanted &= ~ww->intdest.wanton;	/* interact always OR's into existing set */

	msg("kiractl interact %s", show_selexpr(st, &ww->intdest, &ww->intsrc));

    } else if(!strncasecmp(swhat, "hr", 2)) {
#if !USE_PLOT
	msg("kira hrdiag: H-R diagram not available");
#else
	Fl_Plot *plot = ww->plot;
	if(plot == NULL) {
	    msg("kira hrdiag: not initialized?");
	    return 1;
	}
	if(sval) {
	    if(!strcmp(sval, "on") || !strcmp(sval, "off")) {
		parti_hrdiag_on( getbool(sval, 1) );
		if(argc > 3) argc--, argv++, sval = argv[2];
	    }
	    if(!strcmp(sval, "range")) {
		float xxyyrange[4] = { plot->x0(), plot->x1(), plot->y0(), plot->y1() };
		getfloats( &xxyyrange[0], 4, 3, argc, argv );
		plot->xrange( xxyyrange[0], xxyyrange[1] );
		plot->yrange( xxyyrange[2], xxyyrange[3] );
	    }
	}
	msg( "kira hrdiag %s range %g %g(logT) %g %g(logL)",
		plot->visible_r() ? "on":"off",
		plot->x0(), plot->x1(), plot->y0(), plot->y1() );
#endif
    } else {
	msg("kiractl {node|ring} {on|off|root} | tree {on|off|cross|tick} [<tickscale>] | size {sep|semimaj} | scale <fac> | span <minpix> <maxpix> | track <id>| intsel <dest> = <src>");
    if(changed) {
	kira_invalidate( dd, st );
	parti_redraw();
    }
    return 1;
slevy's avatar
 
slevy committed
}

void turnoff( struct specklist *sl, SelOp *dest ) {
    if(sl && sl->sel && sl->nsel >= sl->nspecks && dest && dest->use == SEL_DEST) {
	SelMask *sel = sl->sel;
	for(int i = 0; i < sl->nspecks; i++) {
	    SELUNSET( sel[i], dest );
	}
	sl->selseq++;
    }
}

int kira_picked( struct stuff *st, GLuint *hit, struct specklist *sl, int speckno )
{
    struct dyndata *dd = (struct dyndata *)st->pickinfo;
    worldstuff *ww = (worldstuff *)dd->data;
#if CAVE || !USE_PLOT
    retain = 1;
#else
    retain = Fl::event_state(FL_CTRL);
#endif

    if(hit == NULL) {
	if(speckno > 0 && !retain) {
	    turnoff( ww->sl, &ww->picksel );
	    turnoff( ww->marksl, &ww->picksel );
	    ww->pickcount = 0;
	}
	if(speckno == 0) {
	    if(ww->pickcount > 0 || !retain) {
		st->selseq++;
		kira_invalidate( dd, st );
		parti_redraw();
	    }
	}
	return 0;
    }

    if(ww->sl == sl && sl->sel && sl->nsel >= sl->nspecks) {
	if(speckno < 0 || speckno >= sl->nspecks) return 0;
	if(ww->picksel.use == SEL_DEST)
	    SELSET( sl->sel[speckno], &ww->picksel );
	struct speck *sp = NextSpeck( sl->specks, sl, speckno );
	float teff = expf( sp->val[SPECK_TLOG] * M_LN10 );
	enum spectral_class st = get_spectral_class( teff );
	enum luminosity_class lc = get_luminosity_class( teff, sp->val[SPECK_LUM] );
	msg("[id %g nc %g mass %.3g Tlog %.2f L %.3g root %g stype %d(%s %s%s) speck %d]",
		sp->val[SPECK_ID], sp->val[SPECK_NCLUMP],
		sp->val[SPECK_MASS], sp->val[SPECK_TLOG],
		sp->val[SPECK_LUM], sp->val[SPECK_ROOTID],
		(int)sp->val[SPECK_STYPE],
		type_string((enum stellar_type)sp->val[SPECK_STYPE]),
		type_string(st), type_string(lc),
static float HRplot_dotsize = 2.5;
static float HRplot_alpha = 0.7;
slevy's avatar
slevy committed

int kira_HRplot_events( Fl_Plot *plot, int ev ) {
    if(ev == FL_KEYBOARD) {
	switch(Fl::event_text()[0]) {
	case 'b': HRplot_dotsize *= 1.33; break;
	case 'B': HRplot_dotsize /= 1.33; break;
	case 'a': HRplot_alpha = 1 - (1 - HRplot_alpha)*.75; break;
	case 'A': HRplot_alpha = 1 - (1 - HRplot_alpha)*1.33; break;
	case '\033': parti_hrdiag_on( 0 ); break;
slevy's avatar
slevy committed
	return 0;	/* let Fl_Plot::handle have at it too */
    }
    return 0;
}


void kira_HRplot( Fl_Plot *plot, struct stuff *st, struct dyndata *dd )
{
    if(dd == NULL) return;
    worldstuff *ww = (worldstuff *)dd->data;
    int inpick = plot->inpick();
slevy's avatar
slevy committed
    int wasemph = -1;
    int plainalpha = (int) (255 * HRplot_alpha);
    int emphalpha = (int) (255 * (1 - (1 - HRplot_alpha)*.5));
    int alpha = plainalpha;

    glEnable( GL_BLEND );
slevy's avatar
slevy committed
    glBlendFunc( GL_SRC_ALPHA, GL_ONE );
    glDisable( GL_ALPHA_TEST );
    glEnable( GL_POINT_SMOOTH );
    glPointSize( HRplot_dotsize );
    float xmin = plot->x0();
    float xmax = plot->x1();
    if(xmin > xmax) xmin = xmax, xmax = plot->x0();
    float ymin = plot->y0();
    float ymax = plot->y1();
    if(ymin > ymax) ymin = ymax, ymax = plot->y0();

    int slno = 1;
    for(struct specklist *sl = ww->sl; sl != NULL; sl = sl->next, slno++) {
	if(sl->special != SPECKS)
	    continue;

	if(inpick) {
	    glLoadName(slno);
	    glPushName(0);
	}
	glBegin( GL_POINTS );
	int ns = sl->nspecks;
	struct speck *sp = sl->specks;
	for(int i = 0; i < ns; i++, sp = NextSpeck(sp, sl, 1)) {
	    if(sp->val[SPECK_MU] != 0 || sp->val[SPECK_LUM] <= 0)
		continue;	/* leaf nodes only */
	    int rgba = sp->rgba;
slevy's avatar
slevy committed
	    if( !SELECTED(sl->sel[i], &st->seesel) )
		continue;
	    if(inpick) {
		glEnd();
		glLoadName(i);
		glBegin( GL_POINTS );
slevy's avatar
slevy committed
	    } else {
		int isemph = st->emphsel.use != SEL_NONE &&
					SELECTED( sl->sel[i], &st->emphsel );
		if(isemph != wasemph) {
		    glPointSize( isemph ? HRplot_dotsize*1.5 : HRplot_dotsize );
		    alpha = isemph ? emphalpha : plainalpha;
slevy's avatar
slevy committed
		    wasemph = isemph;
		}
slevy's avatar
slevy committed
	    ((unsigned char *)&rgba)[3] = alpha;
	    glColor4ubv( (GLubyte *)&rgba );

	    float x = sp->val[SPECK_TLOG];
	    float y = sp->val[SPECK_LUM] > 0 ? log10f( sp->val[SPECK_LUM] ) : ymin;
	    glVertex2f( x<xmin ? xmin : x>xmax ? xmax : x,
			y<ymin ? ymin : y>ymax ? ymax : y );
	glEnd();
	if(inpick) glPopName();
#endif /*USE_PLOT*/
#endif /* USE_KIRA */