This is ParameterController.m in view mode; [Download] [Up]
// ParameterController.m
// By Charles G. Fleming, Halchin and Fleming.
// You may freely copy, distribute and reuse this code.
// Halchin and Fleming, and the author disclaim any warranty of any kind,
// expressed or implied, as to its fitness for any particular use.
#import "ParameterController.h"
#import <stdlib.h>
#import <strings.h>
#import "MathTool.h"
#import "MathGraph.h"
#import <appkit/TextField.h>
#import <appkit/ScrollView.h>
#import <appkit/Text.h>
#import <appkit/Font.h>
#import "DomainAndRange.h"
#import <appkit/Button.h>
#import <appkit/Window.h>
#import <appkit/Button.h>
#import <appkit/defaults.h> // for NXArgv
#import <sys/param.h> // for MAXPATHLEN
#import <libc.h> // for chdir, getwd
@implementation ParameterController
// Start Mathematica and load the package "Laplace". Modify the scroll view
// that will display the nongraphical results. Bring the windows on
// screen in the order desired.
- appDidInit:sender
{
char *commandString;
char packagePath[MAXPATHLEN], fullPath[MAXPATHLEN], *suffix;
// This will set up and start Mathematica.
[mathTool initMath:self];
// Clear the variable t in Mathematica. Send 1 to be evaluated so that Mathematica doesn't
// say that NULL was returned.
[mathTool executeCommand:"Clear[t]; 1" resultType:INPUT];
// Set up the path to the Mathematica package Laplace.m.
strcpy(packagePath, NXArgv[0]);
if (suffix = rindex(packagePath, '/'))
*suffix = '\0';
if(packagePath) // appPath is the pathname of a directory. chdir causes the
chdir(packagePath); // directory to become the current working directory.
getwd(packagePath); // This copies the absolute pathname of the current working
// directory into appPath.
sprintf(fullPath, "%s/Laplace.m",packagePath);
// Construct the string that will be used to load the Laplace Transform
// package.
commandString = malloc(MAXPATHLEN);
sprintf(commandString, "<<%s", fullPath);
// Send the command to the MathTool. Get the result from the MathTool,
// (it will be null) but do not display it.
[mathTool executeCommand:commandString resultType:NONE];
free(commandString);
// Set up the scroll view so that it can handle Mathematica's output.
[[resultScrollView docView] setFont:[Font newFont:"Courier" size:12]];
// Widen the margins in the scroll view to make Mathematica's output
// about 1/8 inch from the margins.
[[resultScrollView docView] setMarginLeft:5 right:5 top:5 bottom:5];
// Bring the windows on screen.
[[mathGraph window] orderFront:sender];
[[resultScrollView window] orderFront:sender];
[self makeKeyAndOrderFront:sender];
// This flag is used to detect whether or not the result view and graph
// view may need to be cleared.
notCleared = NO;
return self;
}
// Solve the differential equation using a the function "Laplace".
- compute:sender
{
char *commandString, *resultString;
float mass, friction, springConstant, forcingFrequency;
float forcingMagnitude, initialPosition, initialVelocity;
// Get the current values from all of the fields.
mass = [massField floatValue];
friction = [frictionField floatValue];
springConstant = [springConstantField floatValue];
forcingFrequency = [forcingFrequencyField floatValue];
forcingMagnitude = [forcingMagnitudeField floatValue];
initialPosition = [initialPositionField floatValue];
initialVelocity = [initialVelocityField floatValue];
// Construct the string that will be used to execute the "Laplace"
// command to solve the differential equation.
commandString = malloc(500);
sprintf(commandString, "Laplace[%f,%f,%f,%f,%f,%f,%f]", mass, friction,
springConstant, forcingMagnitude, forcingFrequency,
initialPosition, initialVelocity);
// Send the command to the MathTool and get the result in a form
// suitable for displaying.
[mathTool executeCommand:commandString resultType:OUTPUT];
resultString = [mathTool outputTextString];
// Display the result in the scroll view.
[[resultScrollView window] orderFront:self];
[[resultScrollView docView] setText:resultString];
// Also get the result from Mathematica in a form that can be used
// for generating graphics.
[mathTool executeCommand:commandString resultType:INPUT];
solution = [mathTool inputTextString];
// Enable the graphics buttons so that the solution can be plotted.
[plotButton setEnabled:YES];
[graphSettingsButton setEnabled:YES];
// This is used to detect whether or not the result view and graph
// view may need to be cleared.
notCleared = YES;
free(commandString);
return self;
}
// Display the solution obtained using "Laplace".
- plotSolution:sender
{
char *commandString, *graphicsString;
double domainLowerBound, domainUpperBound, rangeLowerBound;
double rangeUpperBound, aspectRatio;
// Build the command to generate the graphics and get the graphics
// string from Mathematica.
// First get the domain and range from the domainAndRange window.
if([[domainAndRange defaultButton:self] state])
{
domainLowerBound = [domainAndRange domainLower];
domainUpperBound = [domainAndRange domainUpper];
commandString = malloc(50 + strlen(solution));
sprintf(commandString, "Plot[%s, {t, %f, %f}]", solution,
domainLowerBound, domainUpperBound);
}
else
{
domainLowerBound = [domainAndRange domainLower];
domainUpperBound = [domainAndRange domainUpper];
rangeLowerBound = [domainAndRange rangeLower];
rangeUpperBound = [domainAndRange rangeUpper];
aspectRatio = (rangeUpperBound - rangeLowerBound)/ (domainUpperBound -
domainLowerBound);
commandString = malloc(160 + strlen(solution));
sprintf(commandString, "Plot[%s, {t, %f, %f}, PlotRange->{%f, %f},
AspectRatio->%f]", solution,
domainLowerBound, domainUpperBound, rangeLowerBound,
rangeUpperBound, aspectRatio);
}
// Send the Plot command to Mathematica.
[mathTool executeCommand:commandString resultType:GRAPHICS];
graphicsString = [mathTool graphicsString];
// Graph the result.
[[mathGraph window] orderFront:self];
[mathGraph display:graphicsString];
free(commandString);
return self;
}
// Whenever a slider moves, place its value into the corresponding field.
- setValues:sender
{
int tag;
// Find which slider moved.
tag = [sender tag];
// Put the slider's value in the field.
switch (tag)
{
case 0:
[massField setFloatValue:[sender floatValue]];
break;
case 1:
[frictionField setFloatValue:[sender floatValue]];
break;
case 2:
[springConstantField setFloatValue:[sender floatValue]];
break;
case 3:
[forcingMagnitudeField setFloatValue:[sender floatValue]];
break;
case 4:
[forcingFrequencyField setFloatValue:[sender floatValue]];
break;
case 5:
[initialPositionField setFloatValue:[sender floatValue]];
break;
case 6:
[initialVelocityField setFloatValue:[sender floatValue]];
break;
}
// Clear only when necessary.
if (notCleared)
{
// Disable the graphics buttons until the solve button has
// been pushed again. Clear the displays.
[plotButton setEnabled:NO];
[graphSettingsButton setEnabled:NO];
[mathGraph clearMathGraph];
[[resultScrollView docView] setText:""];
notCleared = NO;
}
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.