This is InspectAxes.m in view mode; [Download] [Up]
/* InspectAxes.m by Paul Rensing Nov. 1992
* Controls axis frills
*
* Copyright (C) 1992 The Board of Trustees of
* The Leland Stanford Junior University. All Rights Reserved.
*/
#import "HGraphicView.h"
#import "InspectAxes.h"
const char InspectAxes_h_rcsid[] = INSPECTAXES_H_ID;
const char InspectAxes_m_rcsid[] = "$Id: InspectAxes.m,v 2.30.2.3 1994/02/08 20:29:06 rensing Exp $";
#import "FineSlider.h"
#import "NewInspector.h"
#import "Plot.h"
#import <float.h>
#define RB_HIGH 0
#define RB_LOW 1
#define RB_WIDTH 2
#define RB_OFF 3
#define MAXBINS 500
#define DEFAULT_BINS 50
#define SCALE_FACTOR 5.0
/*
* bug fix: FLT_MIN=1.17549435e-38 is actually 0
*/
#undef FLT_MIN
#define FLT_MIN 2e-38f
@implementation InspectAxes
static BOOL checkDisplay( display disp, binding_t axis,
float *low, float *high, int *num )
{
graphtype_t type;
BOOL checkBins;
type = h_getDispType( disp );
if (( type == COLORPLOT && (axis == XAXIS || axis == YAXIS))
|| type == LEGOPLOT
|| (type == HISTOGRAM && axis == XAXIS)) {
checkBins = YES;
} else {
checkBins = NO;
}
if ( checkBins ) *num = h_getBinNum(disp, axis);
h_getRange( disp, axis, low, high );
return checkBins;
}
- initInspFor:aDraw
{
NXBundle *bundle;
char buffer[MAXPATHLEN+1];
unsigned int i;
[super initInspFor:aDraw];
bundle = [NXBundle bundleForClass:[self class]];
if ( [bundle getPath:buffer forResource:"InspectAxes" ofType:"nib"] ) {
[NXApp loadNibFile:buffer owner:self
withNames:NO fromZone:[self zone]];
}
[theInspector addView:[contentBox contentView]
withName:"Axis Options" withSupervisor:self];
/* make sure the tag are set to something consistent */
axis = XAXIS;
[self setTags];
/*
* we've got to do the following nonsense because can't stretch out spacing
* of slider from IB
*/
rbSlider[0] = rbSlider0;
rbSlider[1] = rbSlider1;
rbSlider[2] = rbSlider2;
rbSlider[3] = rbSlider3;
for ( i = 0; i < 4; i++ ) {
[rbSlider[i] setScaleFactor:SCALE_FACTOR];
}
numLimitCheck = [limitCheckButton state];
currentDim = 1;
prevIndex = -1;
prevValue = 999.999;
return self;
}
/* Action methods */
- tickOption:sender
{
plotloc_t loc=0;
if ([[TickMatrix findCellWithTag:PLOTBOTTOM] state] == 1)
loc += PLOTBOTTOM;
if ([[TickMatrix findCellWithTag:PLOTTOP] state] == 1)
loc += PLOTTOP;
if ([[TickMatrix findCellWithTag:PLOTLEFT] state] == 1)
loc += PLOTLEFT;
if ([[TickMatrix findCellWithTag:PLOTRIGHT] state] == 1)
loc += PLOTRIGHT;
[graphicView graphicsPerform:@selector(setTickLocation:to:)
with:(id)&axis with:(id)&loc andDraw:YES];
[[graphicView window] flushWindow];
return self;
}
- scaleOption:sender
{
plotloc_t loc;
loc = [[sender selectedCell] tag ];
[graphicView graphicsPerform:@selector(setScaleLocation:to:)
with:(id)&axis with:(id)&loc andDraw:YES];
[[graphicView window] flushWindow];
return self;
}
- labelOption:sender
{
plotloc_t loc;
loc = [[sender selectedCell] tag ];
[graphicView graphicsPerform:@selector(setLabelLocation:to:)
with:(id)&axis with:(id)&loc andDraw:YES];
[[graphicView window] flushWindow];
return self;
}
/*
* Respond to the appropriate x axis matrix
*/
- scaleFontSize:sender
{
float fontSize;
fontSize = [sender floatValue];
[graphicView graphicsPerform:@selector(setScaleFontSize:to:)
with:(id)&axis with:(id)&fontSize andDraw:YES];
[[graphicView window] flushWindow];
return self;
}
- tickLength:sender
{
float len;
len = [sender floatValue];
[graphicView graphicsPerform:@selector(setTickLength:to:)
with:(id)&axis with:(id)&len andDraw:YES];
[[graphicView window] flushWindow];
return self;
}
- axisSelection:sender
{
axis = [[sender selectedCell] tag ];
[self setTags];
[self updateView];
return self;
}
- limitCheck:sender
{
numLimitCheck = [limitCheckButton state];
return self;
}
- rebin:sender
{
NXPoint p;
float svalue, toff, tlow, thigh, delta, deltaoff;
float plo, phi;
double dnum;
int i;
int slider_index;
BOOL re_display = NO;
BOOL logAxis, checkBins=NO;
display adisplay = [firstPlot histDisplay];
BOOL zpmode;
slider_index = -1;
for (i = 0; i < 4; i++) {
if (sender == rbSlider[i]) {
slider_index = i;
break;
}
}
svalue = [sender floatValue];
h_getRange(adisplay, axis, &plo, &phi );
zpmode = [zpbutton state];
if ( (i < 4) && ((slider_index != prevIndex) || (svalue != prevValue))) {
prevIndex = slider_index;
prevValue = svalue;
if (( graphtype == COLORPLOT && (axis == XAXIS || axis == YAXIS))
|| graphtype == LEGOPLOT
|| (graphtype == HISTOGRAM && axis == XAXIS)) {
checkBins = YES;
} else {
checkBins = NO;
}
logAxis = h_getLogAxis(adisplay, axis);
switch (slider_index) {
case RB_HIGH:
if (logAxis && svalue <= 0.0) svalue = 2*FLT_MIN;
if (checkBins) {
thigh = MAX( svalue, low + 2.0*width );
delta = thigh - high;
if (ABS(delta) > width) {
i = (delta > 0) ? delta / width : delta / width + 1;
num = num + i;
if ( zpmode ) num = num + i;
num = [self limitCheck:num against: MAXBINS ];
high = high + i * width;
if ( zpmode ) low = low - i*width;
high = MAX(high, low + width);
re_display = YES;
}
} else {
high = MAX(svalue,low*(1.0+2.0*FLT_EPSILON));
if (zpmode) low = plo - (high - phi);
re_display = YES;
}
if (re_display) [rbForm setFloatValue:high at:RB_HIGH];
break;
case RB_LOW:
if (logAxis && svalue <= 0.0) svalue = 2*FLT_MIN;
if (checkBins) {
tlow = MIN(svalue, high - 2 * width);
delta = low - tlow;
if (ABS(delta) > width) {
i = delta / width;
if ( !zpmode ) {
num = num + i;
num = [self limitCheck:num against: MAXBINS ];
}
low = low - i * width;
if (zpmode) high = high - i*width;
low = MIN(low, high - width);
re_display = YES;
}
} else {
low = MIN(svalue,high*(1.0-2.0*FLT_EPSILON));
if ( zpmode ) high = phi + ( low - plo );
re_display = YES;
}
if (re_display) [rbForm setFloatValue:low at:RB_LOW];
break;
case RB_WIDTH:
if (checkBins) {
/*
* Given width, adjust nbins and high to closest values
* giving an integral number of bins
*/
width = [rbSlider[RB_WIDTH] floatValue];
dnum = (high - low) / width;
if (dnum > (((float)floor(dnum) + (float)ceil(dnum))/2.0))
{
num = ceil(dnum);
} else {
num = floor(dnum);
}
num = [self limitCheck:num against: MAXBINS ];
high = low + num * width;
[rbForm setFloatValue:width at:RB_WIDTH];
[rbForm setFloatValue:high at:RB_HIGH];
re_display = YES;
}
break;
case RB_OFF:
toff = svalue; /* slider value */
deltaoff = toff - offset;
low = low + width * deltaoff;
high = high + width * deltaoff;
offset = toff;
[rbForm setFloatValue:high at:RB_HIGH];
[rbForm setFloatValue:low at:RB_LOW];
[rbForm setFloatValue:offset at:RB_OFF];
re_display = YES;
break;
}
if (re_display == YES) {
p.x = low;
p.y = high;
[graphicView graphicsPerform:@selector(setNumBins:to:)
with:(id)&axis with :(id)&num andDraw:NO];
[graphicView graphicsPerform:@selector(setRange:to:)
with:(id)&axis with:(id)&p andDraw:YES];
[autoScaleButton setState:NO];
if (zpmode) {
if ( slider_index == RB_HIGH ) {
[rbForm setFloatValue:low at:RB_LOW];
} else if ( slider_index == RB_LOW ) {
[rbForm setFloatValue:high at:RB_HIGH];
}
}
width = (high - low) / (num);
}
}
if ( re_display == YES ) {
[[[graphicView window] flushWindow] makeKeyWindow];
}
return self;
}
- rebinForm:sender
{
NXPoint p;
double dnum;
float thigh, tlow, twidth=0.0, toff;
int sel;
BOOL re_display = NO;
BOOL logAxis, checkBins;
display adisplay = [firstPlot histDisplay];
sel = [rbForm selectedIndex];
logAxis = h_getLogAxis(adisplay, axis);
if ( ((graphtype == COLORPLOT|| graphtype == LEGOPLOT)
&& (axis == XAXIS || axis == YAXIS))
|| (graphtype == HISTOGRAM && axis == XAXIS)) {
checkBins = YES;
} else {
checkBins = NO;
}
thigh = [rbForm floatValueAt:RB_HIGH];
tlow = [rbForm floatValueAt:RB_LOW];
if (checkBins) {
if (sel == RB_WIDTH) {
twidth = [rbForm floatValueAt:RB_WIDTH];
dnum = (thigh - tlow) / twidth;
if (dnum > ((floor(dnum) + ceil(dnum)) / 2.0)) {
num = ceil(dnum);
} else {
num = floor(dnum);
}
num = MAX(num, 2);
num = [self limitCheck:num against:MAXBINS];
if (sel == RB_HIGH)
tlow = thigh - num * twidth;
else
thigh = tlow + num * twidth;
} else {
num = h_getBinNum(adisplay, axis);
}
}
if (logAxis && tlow <= 0.0)
tlow = 2 * FLT_MIN;
if (tlow >= thigh) {
if (checkBins)
thigh = tlow + twidth;
else
thigh = tlow * (1.0 + 2.0 * FLT_EPSILON) + 2.0 * FLT_MIN;
}
if ((high != thigh) || (sel == RB_HIGH)) {
re_display = YES;
high = thigh;
}
if ((low != tlow) || (sel == RB_LOW)) {
re_display = YES;
low = tlow;
}
if ((twidth != width) || (sel == RB_WIDTH)) {
if (checkBins) {
re_display = YES;
width = twidth;
}
}
toff = [rbForm floatValueAt:RB_OFF];
if (toff != offset) {
re_display = YES;
toff = MIN(toff, 1.0);
toff = MAX(toff, -1.0);
high -= offset * width;
low -= offset * width;
offset = toff;
high += offset * width;
low += offset * width;
}
if ( re_display == YES ) {
p.x = low;
p.y = high;
[graphicView graphicsPerform:@selector(setRange:to:)
with:(id)&axis with:(id)&p andDraw:NO];
[graphicView graphicsPerform:
@selector(setNumBins:to:) with:(id)&axis with:(id)&num andDraw:YES];
width = (high - low)/num;
[rbForm setFloatValue:width at:RB_WIDTH];
}
[[[graphicView window] flushWindow] makeKeyWindow];
return self;
}
- scaleType:sender
{
/* called when the AutoScale or logScale button is clicked */
SEL theMethod = 0;
int theState;
theState = [sender state];
switch ([sender tag])
{
case 0: /* AutoScale X-axis */
theMethod = @selector(setAutoScale:to:);
break;
case 2: /* Log Scale X-axis */
theMethod = @selector(setLogScale:to:);
break;
}
[graphicView graphicsPerform:theMethod
with:&axis with :(id)&theState andDraw:YES];
[[[graphicView window] flushWindow] makeKeyWindow];
return self;
}
- mouseMoved:(const NXPoint *)point in:sender withKey:(int)flag
{
display disp;
binding_t xaxis = XAXIS, yaxis = YAXIS, zaxis = ZAXIS;
NXPoint p;
float lo, hi;
int no;
float diff, range;
BOOL checkBins, logAxis;
if ( selectedPlot ) {
disp = [selectedPlot histDisplay];
} else {
disp = [selectedPlot histDisplay];
}
if ( !disp ) return self;
logAxis = h_getLogAxis(disp, XAXIS);
checkBins = checkDisplay( disp, XAXIS, &lo, &hi, &no );
range = hi - lo;
diff = 2.0 * range;
p.y = hi - point->x * diff / 100;
if ( logAxis && lo <= range ) {
diff = 10.0 * lo - 0.1 * lo;
}
p.x = lo - point->x * diff / 100;
[graphicView graphicsPerform:@selector(setRange:to:)
with:(id)&xaxis with:(id)&p andDraw:YES];
logAxis = h_getLogAxis(disp, YAXIS);
checkBins = checkDisplay( disp, YAXIS, &lo, &hi, &no );
range = hi - lo;
diff = 2.0 * range;
p.y = hi - point->y * diff / 100;
if ( logAxis && lo <= range ) {
diff = 10.0 * lo - 0.1 * lo;
}
p.x = lo - point->y * diff / 100;
[graphicView graphicsPerform:@selector(setRange:to:)
with:(id)&yaxis with:(id)&p andDraw:YES];
logAxis = h_getLogAxis(disp, ZAXIS);
checkBins = checkDisplay( disp, ZAXIS, &lo, &hi, &no );
range = hi - lo;
diff = 2.0 * range;
p.y = hi - point->x * diff / 100;
if ( logAxis && lo <= range ) {
diff = 10.0 * lo - 0.1 * lo;
}
p.x = lo - point->x * diff / 100;
[graphicView graphicsPerform:@selector(setRange:to:)
with:(id)&zaxis with:(id)&p andDraw:YES];
[[[graphicView window] flushWindow] makeKeyWindow];
return self;
}
/* Internal methods */
- setTags
{
if (axis == XAXIS)
{
[[TickMatrix cellAt:0 :0] setTitle:"Bottom"];
[TickMatrix setTag:PLOTBOTTOM at:0 :0];
[[ScaleMatrix cellAt:0 :0] setTitle:"Bottom"];
[ScaleMatrix setTag:PLOTBOTTOM at:0 :0];
[[LabelMatrix cellAt:0 :0] setTitle:"Bottom"];
[LabelMatrix setTag:PLOTBOTTOM at:0 :0];
[[TickMatrix cellAt:0 :1] setTitle:"Top"];
[TickMatrix setTag:PLOTTOP at:0 :1];
[[ScaleMatrix cellAt:0 :1] setTitle:"Top"];
[ScaleMatrix setTag:PLOTTOP at:0 :1];
[[LabelMatrix cellAt:0 :1] setTitle:"Top"];
[LabelMatrix setTag:PLOTTOP at:0 :1];
}
else if (axis == YAXIS)
{
[[TickMatrix cellAt:0 :0] setTitle:"Left"];
[TickMatrix setTag:PLOTLEFT at:0 :0];
[[ScaleMatrix cellAt:0 :0] setTitle:"Left"];
[ScaleMatrix setTag:PLOTLEFT at:0 :0];
[[LabelMatrix cellAt:0 :0] setTitle:"Left"];
[LabelMatrix setTag:PLOTLEFT at:0 :0];
[[TickMatrix cellAt:0 :1] setTitle:"Right"];
[TickMatrix setTag:PLOTRIGHT at:0 :1];
[[ScaleMatrix cellAt:0 :1] setTitle:"Right"];
[ScaleMatrix setTag:PLOTRIGHT at:0 :1];
[[LabelMatrix cellAt:0 :1] setTitle:"Right"];
[LabelMatrix setTag:PLOTRIGHT at:0 :1];
}
return self;
}
- titleForm:sender
{
const char *string;
string = [titleForm stringValueAt:0];
switch (axis) {
case XAXIS:
[graphicView graphicsPerform:@selector(NameAxisX:)
with:(id)string andDraw:YES];
break;
case YAXIS:
[graphicView graphicsPerform:@selector(NameAxisY:)
with:(id)string andDraw:YES];
break;
case ZAXIS:
[graphicView graphicsPerform:@selector(NameAxisZ:)
with:(id)string andDraw:YES];
break;
default :
string = NULL;
break;
}
[[graphicView window] flushWindow];
return self;
}
- resetTitle:sender
{
const char *string;
display disp;
if ( !selectedPlot ) {
return self;
}
switch (axis) {
case XAXIS:
string = "%x";
[graphicView graphicsPerform:@selector(NameAxisX:)
with:(id)string andDraw:YES];
break;
case YAXIS :
disp = [selectedPlot histDisplay];
if ( h_getDispType(disp) == HISTOGRAM ) {
string = "Entries / %dx bin";
} else {
string = "%y";
}
[graphicView graphicsPerform:@selector(NameAxisY:)
with:(id)string andDraw:YES];
break;
case ZAXIS :
string = "%z";
[graphicView graphicsPerform:@selector(NameAxisZ:)
with:(id)string andDraw:YES];
break;
default :
string = NULL;
break;
}
[titleForm setStringValue:string at:0];
[[graphicView window] flushWindow];
return self;
}
- updateView
{
display disp;
int pos;
plotloc_t loc;
float f;
if ( selectedPlot )
disp = [ selectedPlot histDisplay ];
else if (firstPlot )
disp = [ firstPlot histDisplay ];
else {
lastPlot = nil;
return self;
}
/*
* set the axis title
*/
switch (axis) {
case XAXIS:
[titleForm setStringValue:h_getAxisLabel(disp,XAXIS) at:0];
break;
case YAXIS:
[titleForm setStringValue:h_getAxisLabel(disp,YAXIS) at:0];
break;
case ZAXIS:
[titleForm setStringValue:h_getAxisLabel(disp,ZAXIS) at:0];
break;
default :
[titleForm setStringValue:"" at:0];
break;
}
/*
* set the tick buttons
*/
loc = h_getTickLocation( disp, axis );
for (pos = 1; pos <= 16; pos <<= 1)
{
if (loc & pos)
[TickMatrix selectCellWithTag:pos];
}
/*
* set the scale radio buttons
*/
loc = h_getScaleLocation( disp, axis );
[ScaleMatrix selectCellWithTag:(int)loc];
/*
* set the scale radio buttons
*/
loc = h_getLabelLocation( disp, axis );
[LabelMatrix selectCellWithTag:(int)loc];
/*
* set the font size field
*/
f = h_getScaleFontSize( disp, axis );
[ScaleFontSize setFloatValue: f];
f = h_getTickLength( disp, axis );
[TickLength setFloatValue: f];
[self updateOptions];
[self updateSliders];
if ( lastPlot != firstPlot) {
prevIndex = -1;
prevValue = 999.999;
}
lastPlot = firstPlot;
return self;
}
- updateOptions
{
display disp;
BOOL enable;
if (!selectedPlot)
disp = [selectedPlot histDisplay];
else
disp = [firstPlot histDisplay];
graphtype = h_getDispType(disp);
if (graphtype == HISTOGRAM)
currentDim = 1;
else
currentDim = 2;
if (graphtype == LEGOPLOT
|| graphtype == THREEDSCATTER
|| graphtype == COLORPLOT
|| (graphtype == HISTOGRAM && axis == XAXIS)) {
enable = NO;
} else {
enable = YES;
}
[logScaleButton setEnabled:enable];
[autoScaleButton setState:h_getAutoScale(disp, axis)];
[logScaleButton setState:h_getLogAxis(disp, axis)];
return self;
}
- updateSliders
{
float range;
BOOL logAxis, checkBins;
display disp;
if (!selectedPlot)
disp = [selectedPlot histDisplay];
else
disp = [firstPlot histDisplay];
logAxis = h_getLogAxis(disp, axis);
checkBins = checkDisplay( disp, axis, &low, &high, &num );
if (checkBins) {
width = (high - low) / num;
[rbForm setFloatValue:width at: RB_WIDTH];
[rbSlider[RB_WIDTH] setMinValue:(width * 0.5)];
[rbSlider[RB_WIDTH] setMaxValue:(width * 1.5)];
[rbSlider[RB_WIDTH] setFloatValue:width];
[rbSlider[RB_WIDTH] setEnabled:YES];
[[rbForm cellAt:RB_WIDTH :0] setEnabled:YES];
} else {
width = 0.0;
[rbForm setStringValue:"" at:RB_WIDTH];
[rbSlider[RB_WIDTH] setEnabled:NO];
[[rbForm cellAt:RB_WIDTH :0] setEnabled:NO];
}
range = high - low;
[rbForm setFloatValue:high at:RB_HIGH];
[rbForm setFloatValue:low at:RB_LOW];
[rbSlider[RB_HIGH] setMinValue:(double) (low + width)];
[rbSlider[RB_HIGH] setMaxValue:(double) (high + range)];
[rbSlider[RB_HIGH] setFloatValue:high];
if (logAxis) {
if (low <= range) {
[rbSlider[RB_LOW] setMinValue:(double) low/10.0];
[rbSlider[RB_LOW] setMaxValue:(double) low*10.0];
} else {
[rbSlider[RB_LOW] setMinValue:(double) (low - range)];
[rbSlider[RB_LOW] setMaxValue:(double) (high - width)];
}
} else {
[rbSlider[RB_LOW] setMinValue:(double) (low - range)];
[rbSlider[RB_LOW] setMaxValue:(double) (high - width)];
}
[rbSlider[RB_LOW] setFloatValue:low];
if (checkBins) {
[rbForm setFloatValue:0. at:RB_OFF ];
[rbSlider[RB_OFF] setMinValue:-1.];
[rbSlider[RB_OFF] setMaxValue: 1.];
[rbSlider[RB_OFF] setFloatValue: 0.];
[rbSlider[RB_OFF] setEnabled:YES];
[[rbForm cellAt:RB_OFF :0] setEnabled:YES];
} else {
[rbForm setStringValue:"" at:RB_OFF];
[rbSlider[RB_OFF] setEnabled:NO];
[[rbForm cellAt:RB_OFF :0] setEnabled:NO];
}
offset = 0.0;
return self;
}
- (int) limitCheck:(int) nbins against:(int)maxbins
{
int irc;
static int prevnbins=0;
if ( numLimitCheck == NO ) return nbins;
if ( nbins > maxbins && numLimitCheck == YES ) {
if (nbins == prevnbins) {
nbins = maxbins;
return nbins; /* ignore double events */
}
prevnbins = nbins;
irc = NXRunAlertPanel( "Alert",
"Greater than %d bins may cause performace problems",
"Cancel", "Proceed", NULL, maxbins );
if ( irc == NX_ALERTDEFAULT ) {
nbins = maxbins;
} else {
numLimitCheck = NO;
[ limitCheckButton setState: NO ];
}
}
return nbins;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.