/* Inspect3D.m		by Mike Gravina		July 1992
 * Controls 3d perspective plots
 *
 * Copyright (C)  1991  The Board of Trustees of
 * The Leland Stanford Junior University.  All Rights Reserved.
 */ 

#import "HGraphicView.h"
#import "Inspect3D.h"

const char Inspect3D_h_rcsid[] = INSPECT3D_H_ID;
const char Inspect3D_m_rcsid[] = "$Id: Inspect3D.m,v 2.22 1993/03/23 22:49:00 rensing Exp $";


#import "FineSlider.h"
#import "NewInspector.h"
#import "Plot.h"
#import "h3D.h"

#define PI 3.1415926536
#define RAD_TO_DEG 180.0/PI

@implementation Inspect3D

- initInspFor:aDraw
{
    NXBundle	*bundle;
    char	buffer[MAXPATHLEN+1];
    
    [super initInspFor:aDraw];
    
    bundle = [NXBundle bundleForClass:[self class]];
    if ( [bundle getPath:buffer forResource:"Inspect3D" ofType:"nib"] ) {
    	[NXApp loadNibFile:buffer owner:self
                 withNames:NO  fromZone:[self zone]];
    }
    [theInspector addView:[contentBox contentView]
    		 withName:"3D Options" withSupervisor:self];
    return self;
}


- showError:(char *)errorMessage
{
    NXRunAlertPanel("Error", errorMessage, "OK", NULL, NULL);
    return self;
}

- updateView
{
    threeD_t	       *threeD;  
    graphtype_t		type;	  
    
    if (firstPlot) {
    	disp = [firstPlot histDisplay];
	type = h_getDispType( disp );
	if ( type == LEGOPLOT || type == THREEDSCATTER ) {
	    [distanceSlider       setEnabled:YES];
	    [phiSlider            setEnabled:YES];
	    [thetaSlider          setEnabled:YES];
	    [distText             setEnabled:YES];
	    [phiText              setEnabled:YES];
	    [thetaText            setEnabled:YES];
	    [cubeSwitch           setEnabled:YES];
	    [grayMatrix           setEnabled:YES];
	    if (disp->threeDWorkArea == NULL) return self;
	    threeD = disp->threeDWorkArea;
	    [thetaSlider setFloatValue:disp->theta];
	    [thetaText setFloatValue:RAD_TO_DEG*disp->theta];
	    [phiSlider setFloatValue:-disp->phi];
	    [phiText setFloatValue:-RAD_TO_DEG*disp->phi];
	    [distanceSlider setFloatValue:-1/disp->dist];
	    [distText setFloatValue:disp->dist];
    
	    [cubeSwitch setState:(int)threeD->doCube];
	    [wireFrameSwitch setState:(int)threeD->doWireFrame];
	    [fillSwitch setState:(int)threeD->doFill];
	    [meshSwitch setState:(int)threeD->doMesh];
    
	    if (disp->graphtype == LEGOPLOT) {
		[wireFrameSwitch setEnabled:YES];
		[fillSwitch setEnabled:YES];
		[meshSwitch setEnabled:YES];
	    } 
	    else if (disp->graphtype == THREEDSCATTER) {
		[wireFrameSwitch setEnabled:NO];
		[fillSwitch setEnabled:NO];
		[meshSwitch setEnabled:NO];
	    } 
        } else {
	    [distanceSlider       setEnabled:NO];
	    [phiSlider            setEnabled:NO];
	    [thetaSlider          setEnabled:NO];
	    [distText             setEnabled:NO];
	    [phiText              setEnabled:NO];
	    [thetaText            setEnabled:NO];
	    [cubeSwitch           setEnabled:NO];
	    [wireFrameSwitch      setEnabled:NO];
	    [fillSwitch           setEnabled:NO];
	    [meshSwitch           setEnabled:NO];
	    [grayMatrix           setEnabled:NO];
	}
    }
    return self;
}

- reset:sender
{
    [graphicView graphicsPerform:@selector(reset3D) andDraw:YES];
    [[graphicView window] flushWindow];
    return self;
}

- newGray:sender
{
    id                  thisSlider;
    struct {
    	int                 faceNo;
    	float               value;
    } grayValue;    
    thisSlider = [sender selectedCell];
    grayValue.faceNo = [thisSlider tag];
    grayValue.value = [thisSlider floatValue];
    [graphicView graphicsPerform:@selector(newGray3D:)
                           with :(id)&grayValue andDraw:YES];
    [[graphicView window] flushWindow];
    return self;
}

- newTheta:sender
{
    float angle;    

    angle = [sender floatValue];
    [thetaText setFloatValue:RAD_TO_DEG * angle];
    [graphicView graphicsPerform:@selector(newTheta3D:)
                           with :(float *)&angle andDraw:YES];
    [[[graphicView window] flushWindow] makeKeyWindow];
    return self;
}

- newPhi:sender
{
    float angle;    

    angle = [sender floatValue];
    [phiText setFloatValue:RAD_TO_DEG * angle];
    [graphicView graphicsPerform:@selector(newPhi3D:)
                           with :(float *)&angle andDraw:YES];
    [[[graphicView window] flushWindow] makeKeyWindow];
    return self;
}

- newDist:sender
{
    float distance;

    distance = [sender floatValue];
    if (distance < 1.8) {
	[self showError:"Distance must be greater than 1.8"];
	return self;
    }
    [distanceSlider setFloatValue:-1./ distance];
    [distText setFloatValue:distance];
    [graphicView graphicsPerform:@selector(newDist3D:)
                           with :(float *)&distance andDraw:YES];
    [[[graphicView window] flushWindow] makeKeyWindow];
    return self;
}

- newInvDist:sender
{
    float               invDist, distance;
    
    invDist = -[sender floatValue];
    if (invDist == 0.)
	distance = HUGE;
    else
	distance = 1./ invDist;
    [distText setFloatValue:distance];
    [graphicView graphicsPerform:@selector(newDist3D:)
                           with :(float *)&distance andDraw:YES];
    [[[graphicView window] flushWindow] makeKeyWindow];
    return self;
}

- newTheta_degrees:sender
{
    float angle;    

    angle = [sender floatValue] / RAD_TO_DEG;
    [thetaSlider setFloatValue:angle];
    [thetaText setFloatValue:angle];
    [graphicView graphicsPerform:@selector(newTheta3D:)
                           with :(float *)&angle andDraw:YES];
    [[[graphicView window] flushWindow] makeKeyWindow];
    return self;
}

- newPhi_degrees:sender
{
    float angle;    

    angle = [sender floatValue] / RAD_TO_DEG;
    [phiSlider setFloatValue:angle];
    [phiText setFloatValue:angle];
    [graphicView graphicsPerform:@selector(newPhi3D:)
                           with :(float *)&angle andDraw:YES];
    [[[graphicView window] flushWindow] makeKeyWindow];
    return self;
}

- toggleCube:sender
{
    BOOL state;
    
    state = (BOOL)[sender state];
    [graphicView graphicsPerform:@selector(toggleCube3D:)
                           with :(BOOL *)&state andDraw:YES];
    [[graphicView window] flushWindow];
    return self;
}

- toggleWireFrame:sender;
{
    BOOL state;
    
    state = (BOOL)[sender state];
    [graphicView graphicsPerform:@selector(toggleWireFrame3D:)
                           with :(BOOL *)&state andDraw:YES];
    [[graphicView window] flushWindow];
    return self;
}

- toggleFill:sender
{
    BOOL state;
    
    state = (BOOL)[sender state];
    [graphicView graphicsPerform:@selector( toggleFill3D:)
                           with :(BOOL *)&state andDraw:YES];
    [[graphicView window] flushWindow];
    return self;
}

- toggleMesh:sender
{
    BOOL state;
    
    state = (BOOL)[sender state];
    [graphicView graphicsPerform:@selector(toggleMesh3D:)
                           with :(BOOL *)&state andDraw:YES];
    [[graphicView window] flushWindow];
    return self;
}

- mouseMoved:(const NXPoint *)offset in:sender withKey:(int)flag
{
        threeD_t	       *threeD;  	  
	float	theta,phi;
		
	disp = ([sender histDisplay]);
	threeD = disp->threeDWorkArea;
	
	if (flag & NX_COMMANDMASK) {	/*command key was held down */
		theta = disp->theta + ((offset->x)*3.14/180);
		if (theta > 3.14) theta = theta - 6.28; /* pi * 2 */
		if (theta < -3.14) theta = 6.28 + theta;
	
		[sender newTheta3D:&theta];
	
		phi = -disp->phi + ((offset->y)*3.14/180);
		if (phi > 1.57) phi = -3.14 + phi;
		if (phi < -1.57) phi = 3.14 + phi;
		[sender newPhi3D:&phi];
	}
	if (flag & NX_CONTROLMASK) {
		float	diff,dist;
		diff = [distanceSlider mmaxValue] - [distanceSlider mminValue];
		dist = disp->dist + ((offset->y)*diff/100);
		if (dist > -1./[distanceSlider mmaxValue]) dist = -1./[distanceSlider mmaxValue];
		if (dist < -1./[distanceSlider mminValue]) dist = -1./[distanceSlider mminValue];
		[sender newDist3D:&dist];
	}
	return self;
}
@end
