TweetFollow Us on Twitter

Harmonics
Volume Number:7
Issue Number:4
Column Tag:C Workshop

Harmonic Simulation

By Byron Miller, Minneapolis, MN

Simulating Reality on The Mac

This article is the end result of my desire to couple simulation techniques and the Mac’s graphical user interface to produce an application that mimics a physical system. It was the Mac’s graphical user interface that initially attracted me to the Mac for this application, because it is an ideal environment for visualizing the simulation results of “what if” analyses. In this article, the physical system I chose to simulate is damped harmonic motion.

I chose to simulate damped harmonic motion for two reasons: First is that the model is well understood -- it is a 2nd order differential equation. Its solution can be found by solving this equation or by extracting it from any elementary physics textbook and since the model is predefined, I do not have tackle the model generation phase (more on this below). Secondly, it is a good example because many physical systems (like pendulums and planets’ orbits) exhibit this type of harmonic motion.

Simulation Basics

The word simulation means different things to different people. Within the context of this paper I’ll use the definition used in Systems Simulation: “The Art and Science:” Simulation is the process of designing a model of a real system and conducting experiments with this model for the purpose of either understanding the behavior of the system or evaluating various strategies for the operation of the system.” This is a nice definition but how can it be applied to produce a model which is simulatable? In order to fully understand and apply simulation techniques the definition must be distilled down into its constituents. Simply put, simulation equals model generation plus experimentation plus verification.

Model generation is the process of describing the relationship of the inputs to the outputs of a system. This relation is referred to as the transfer function of the system and it is the actual model; as a side note, the generation phase is usually the most difficult part of the simulation process and may often seem more like an art than a science. This type of model generation is often referred to as black box or abstract modeling because a mathematical relationship is assigned to the box that describes a real physical system (for example a mass on a spring). There are two different approaches to this type of model generation: top-down and bottom-up. From a top-down view, the whole system is completely described by the single mathematical relationship. Whereas the bottom-up perspective describe a system that is simply a building block for creation of a larger system.

The model experimentation phase consists simply of observing and recording the relationship of the input to the output of the system, and its purpose is to prepare for verification. The model is run with various inputs, and the output from the system is recorded for the verification phase.

Verification determines whether the model accurately describes the system. If it does, the model is said to be valid. If not, a new model is generated and retested. The whole simulation cycle continues until the model is determined to be valid. [What constitutes a valid model is subjective and depends on the implementor. In other words, how comfortable is he/she with how closely his/her model represents the real one they are modeling.] a couple of different approaches may be used for determining validity. One is “heuristic”, meaning how close the output looks or “feels” like the real one. Under some conditions the heuristic validation approach may be enough. Other times, however, this may not be enough and a more formalized method may be needed to determine how close the model is to representing the real one. For this case, the statistical approach is used to see how closely the model resembles the real system.

Theory

When a pulling or a pushing force is applied to the system it has a tendency to return to its initial position with a certain force. This force is actually the sum of two separate forces which describe the system, the restoring force and the damped force (figure 1). These two forces completely describe the system. Once these forces are explicitly defined, the model generation phase is complete. The forces describing the system are:

 F = damping force + restoring force = - (b * (dx/dt) + kx)

where F is the total force of the system, b is the coefficient of friction, dx/dt is the velocity in the x direction, k is the elastic coefficient, x is the displacement, and the minus sign denotes that the sum of these forces is of equal and opposite magnitude of the external force applied to the system. Without going into all the mathematics, the solution to this equation is:

 x = (A * e-b * t/2 * m) * cos(w * t),

where w (omega) equals (1 / 2 * m ) * (4 * M * k - b^2)^0.5, and A is the initial displacement when an external force is released.

Translated the solution means that the output of the system “moves” (produces positive and negative values like a wave) back and forth with a maximum distance of A and with a frequency of omega (w).

Varying the values of b, k and m causes the system to behave differently. If b^2 < 4 * M * k the system oscillates indefinitely. On the other hand, if b^2 > 4 * M * k, the system oscillates for a while but eventually come to rest. If b^2 = 4 * M * k, the system immediately comes to rest. These three cases are referred to as underdamping, overdamping, and critical damping respectively.

Implementation

The program consists of three logical sections: computational, plot and status. The program itself is loosely layed out in a similar fashion; and each section is described in terms of functionality from the top level function that performs the task. The computational section performs all of the mathematical crunching to simulate the model. The plot section graphically displays the results, and the status section provides non-intuitive information on the simulation. Each section has a corresponding top level function which I shall describe briefly below.

Procedure Calculate Harmonics iteratively computes values from the mathematical model and then saves the results to a simulation result file. Calculate Harmonics begins by dynamically allocating enough storage for data (dynamic allocation is used over static storage methods because it allows the model to be bounded only by the amount of available ram). Next Calculate Harmonics arranges its input in the Standard Apple Numeric Environment (SANE) floating point format. The input is then converted into doubles for maintaining accuracy. After computation only the positive values are retained and coerced into an integer format. The integer values are then converted to the American Standard for Information Interchange (ASCII) format and stored in the simulation result file. The simulation result file contains the x and y labels in the first two lines followed by some number of x and y pairs delimited by a carriage return.

The plotting section is handled by the MainPlot function. MainPlot plots only the positive values of the solution. Input to MainPlot comes from the file generated by Calculate Harmonics. The plot function is accomplished by first creating the axes, gradients and then labeling the axes. Next the x and y coordinates are read in and converted from the file and space is allocated for them (also dynamically). The converted data is then normalized and transformed to map over into the quickdraw local coordinate system.

Status maintenance is handled by the top level function doStatus. DoStatus either stores information about the last simulation run, or displays the information of the last simulation. The function computes w (omega) and determines whether the simulation is over, under, or critically damped.

I should mention that I have included a handful of simple functions that already exist in the standard library. If you like, you may use these. I chose not to use them because including the library to the project adds about 10k to the executable program.

What’s Next?

You could improve the program or produce your own simulation. The program could be improved in terms of performance and functionality. For instance, updating could be accelerated by plotting the graph initially as a pict instead of redrawing it every time as it currently is written. Overall conversion time could be reduced by storing the data points in a binary format instead of in ASCII. From a feature standpoint the plotting could be expandable to support both positive and negative values. An ability to zoom the plot window and store the plot to a file or dump the plot to the printer would also be a nice feature. As is, this application serves as a teaching tool: ie, it provides an example of how a process is transformed to its mathematical equivalence.

The same techniques used to produce the HSIM application are applicable to other phenomenon and may be used to create simulations of your own. Remember the great thing about simulation is that it can be both useful and fun. Unlike the real world, the world of simulation is limited only by your imagination..., enjoy!

Bibliography

Halliday, D. and Resnick, R. Physics Parts 1 & 2, 3rd Edition:John Wiley and Sons, 1978.

Payne, J. A. Introduction to Simulation: Programming Techniques and Methods of Analysis. Mc Graw - Hill Inc., 1982.

Shannon, R. E. System Simulation: The Art and Science. Englewood Cliffs, NJ: Prentice - Hall Inc., 1975.

Listing:  Hanrmonic.h

#define FALSE    0
#define TRUE1

#define BASE_RES_ID400
#define NIL 0L
#define MOVE_TO_FRONT-1L
#define REMOVE_ALL_EVENTS 0

#define SLEEP    0L
#define NIL_MOUSE_REGION  0L
#define WNE_TRAP_NUM 0x60
#define UNIMPL_TRAP_NUM   0x9f

#define BANNER_OFFSET96
#define HORIZONTAL_OFFSET 0
#define INITIAL_ROW24
#define LEFT_MARGIN10
#define ROW_HEIGHT 15
#define START_ROW0

#define TEXT_FONT_SIZE    10/* in pixels */
#define GRAD_FONT_SIZE    6

#define APPLE_MENU_IDBASE_RES_ID
#define FILE_MENU_ID BASE_RES_ID+1
#define EDIT_MENU_ID BASE_RES_ID+2
#define OPTION_MENU_ID    BASE_RES_ID+3

#define TRANSFER_ITEM1
#define QUIT_ITEM3
#define ABOUT_ITEM 1
#define COPY_ITEM4
#define PASTE_ITEM 5
#define CLEAR_ITEM 6
#define CLIPBOARD_ITEM    7
#define SIMULATE_ITEM1
#define PLOT_ITEM2
#define STATUS_ITEM3

#define ABOUT_ALERT400
#define LAUNCH_ALERT 401
#define FREE_MEM_ALERT    402
#define ENOUGH_ALERT 403
#define ERR_ALERT404
#define HOSED_FILE_ALERT  405
#define CLIPBOARD_ALERT   406
#define EMPTY_ALERT407
#define PROCESS_ALERT409
#define X_ALERT  410
#define Y_ALERT  411

/* default resource IDs for editable text */

#define DEF_FRICTION_ID   401
#define DEF_AMPLITUDE_ID  402
#define DEF_ELASTIC_ID    403
#define DEF_START_ID 404
#define DEF_FINI_ID405
#define DEF_X_AXIS_ID406
#define DEF_Y_AXIS_ID407
#define DEF_MASS_ID408
#define DEF_INC_ID 409
#define DEF_SIM_ID 410

/* DITL item numbers */

#define FRICTION_VALUE    4
#define AMPLITUDE_VALUE   6
#define ELASTIC_VALUE8
#define START_VALUE10
#define FINI_VALUE 12
#define X_VALUE  14
#define Y_VALUE  16
#define MASS_VALUE 18
#define INC_VALUE20
#define SIM_NAME_VALUE    22

#define DRAG_THRESHOLD    30

#define OK_BUTTON1 /* dailog list items */
#define CANCEL_BUTTON2

#define ONTRUE
#define OFF FALSE

#define FLOAT_CONST4 /* floating pt numbers take up 4 bytes */

#define WATCH_ICON 4

#define WINDOW_HOME_LEFT  45/* global coords */
#define WINDOW_HOME_RIGHT 45
#define NEW_WINDOW_OFFSET 20
#define LEAVE_WHERE_IT_IS FALSE

#define MinusOne 0xFFFF

#define MIN 0
#define MAX 32767

/* have to be changed if graph does */

#define GRAD_X_DELTA 36   /* gradient delta on x axis */
#define GRAD_Y_DELTA 25   /* gradient delta on y axis */
#define GRAPH_X_DELTA367  
#define GRAPH_Y_DELTA204
#define GRAPH_X_OFFSET    40/* offset from right of window */
#define GRAPH_Y_OFFSET    244 /* offset from top of window */

/************* globals  ***************/

typedef struct
{
 StringPtrpfName;/* ptr to the name of launchee */
 short intparam;
 char   LC[2];   /* extended params: */
 long int extBlockLen;  /* # of bytes in extension == 6 */
 short intfFlags;/* finder file info flags */
 long int launchFlags;    /* bits 30, & 31 equal 1 for sublaunch */
}  LaunchStruct, *pLaunchStruct;

/* used by dialog input routines */
typedef struct
{
 Str255 frict, amp, elastic,
 start, fini, xVal, yVal,
 mass, ink,
 simName;
}  SavedSettings, *SavedSettingsPtr;
 
typedef struct
{
 int    length;  /* coord pair length */
 float  *xPtr;   /* ptr to list of x values */
 float  *yPtr;   /* ptr to list of y values */
}  xyCoords, *xyCoordsPtr;
Listing:  Harmonic.c

#include <strings.h>
#include <storage.h>

#include <QuickDraw.h>
#include <MacTypes.h>
#include <FontMgr.h>
#include <WindowMgr.h>
#include <MenuMgr.h>
#include <TextEdit.h>
#include <DialogMgr.h>
#include <EventMgr.h>
#include <DeskMgr.h>
#include <StdfilePkg.h>
#include <FileMgr.h>
#include <ToolboxUtil.h>
#include <ControlMgr.h>

#include “Harmonic.h”

/************* globals  ***************/
int errno;/* required by the math lib */

/**************  static globals  *****************/
char gCR[] = “\r”;
char gTAB[] = “\t”;
char gSP[] = “ “;/* space */
char gEOL[] = “\0”;

/* Simple Harmonic motion simulator application.
 The following are included into the project:
 
 mactraps lib
 math lib
 storage lib
 strings lib
 harmonic sim.c 
 harmonic functs.c
 plot.c
 utils.c
 
 Written by :  Byro
 Date : 03/05/90
 Modified : 04/27/90
 
 Version Log:    
*/

main()
{

 BooleandoneFlag = FALSE, WNEImplemented;
 EventRecordmyEvent;
 Handle ClipHandle;
 MenuHandle AppleMenu;
 Rect   DragRect;
 WindowPtrPlotWindow, ClipboardWindow,
 StatusWindow;

 ToolBoxInit();
 WindowInit(&PlotWindow, “\pPlot Window”);
 WindowInit(&StatusWindow, “\pStatus Window”);
 SetUpDragRect(&DragRect);
 MenuBarInit(&AppleMenu);
 CreateClipBoardWindow(&ClipboardWindow);
 ClipHandle = NewHandle(NIL);
 MainLoop(&doneFlag, &myEvent, &WNEImplemented, &DragRect, &AppleMenu, 
&PlotWindow, &ClipboardWindow, &StatusWindow, &ClipHandle);
}

ToolBoxInit()  
 /* initialization */
{
 InitGraf(&thePort);
 InitFonts();
 FlushEvents( everyEvent, REMOVE_ALL_EVENTS );
 InitWindows();
 InitMenus();
 TEInit();
 InitDialogs(NIL);
 InitCursor();
}

WindowInit(AppWindow, windowTitle)
 WindowPtr*AppWindow;
 Str255 *windowTitle;
{
 /* init window ptr */
 *AppWindow = GetNewWindow(BASE_RES_ID, NIL, MOVE_TO_FRONT);
 
 /* if can’t open window let user know */
 if (*AppWindow == NIL)
 {
 /* system dialog goes here */
 ExitToShell();  /* caio */
 }
 
 if (**windowTitle != NIL)
 SetWTitle(*AppWindow, windowTitle);
 
 SetPort(*AppWindow);/* make current graf port */
}

SetUpDragRect(DragRect)
 Rect *DragRect;
{
 *DragRect = screenBits.bounds;
 (*DragRect).left += DRAG_THRESHOLD;
 (*DragRect).right -= DRAG_THRESHOLD;
 (*DragRect).bottom -= DRAG_THRESHOLD;
}

MenuBarInit(AppleMenu)
 MenuHandle *AppleMenu;
{
 Handle myMenuBar;
 
 myMenuBar = GetNewMBar(BASE_RES_ID);
 SetMenuBar(myMenuBar);
 *AppleMenu = GetMHandle(APPLE_MENU_ID);
 AddResMenu(*AppleMenu, ‘DRVR’);
 DrawMenuBar();
}

CreateClipBoardWindow(ClipBoardWindow)
 WindowPtr*ClipBoardWindow;
{
 if (( *ClipBoardWindow = GetNewWindow(BASE_RES_ID, NIL, MOVE_TO_FRONT)) 
 == NIL)
 {
 NoteAlert(CLIPBOARD_ALERT, NIL);
 /* ExitToShell(); */
 }
 
 /* set window title */
 SetWTitle(*ClipBoardWindow, “\p Clip Board”);
 
 MoveWindow(*ClipBoardWindow, WINDOW_HOME_LEFT, WINDOW_HOME_RIGHT, LEAVE_WHERE_IT_IS);
}

MainLoop(doneFlag, myEvent, WNEImplemented, DragRect, AppleMenu, PlotWindow, 
CBWindow, StatWindow, clipHandle)
 Boolean*doneFlag;
 EventRecord*myEvent;
 Boolean*WNEImplemented;
 Rect   *DragRect;
 MenuHandle *AppleMenu;
 WindowPtr*PlotWindow, *CBWindow, *StatWindow;
 Handle *clipHandle;
{
 /* check to see if multifinder running */
 
 *WNEImplemented = (NGetTrapAddress(WNE_TRAP_NUM, ToolTrap) != NGetTrapAddress(UNIMPL_TRAP_NUM, 
ToolTrap));
 
 /* main program/Event loop */
 do
 {
 HandleEvent(doneFlag, myEvent, WNEImplemented, DragRect, AppleMenu, 
PlotWindow, CBWindow, StatWindow, clipHandle);
 } 
 while (*doneFlag == FALSE);
}

HandleEvent(doneFlag, myEvent, WNEImplemented, DragRect, AppleMenu, PlotWindow, 
CbWindow, StWindow, clipHandl)
 Boolean*doneFlag;
 EventRecord*myEvent;
 Boolean*WNEImplemented;
 Rect   *DragRect;
 MenuHandle *AppleMenu;
 WindowPtr*PlotWindow, *CbWindow, *StWindow;
 Handle *clipHandl;
{
 char   theChar;
 int    Err = noErr;
 MenuHandle itemHndl;
 
 static float  *xptr, *yptr;
 /* ptrs used to alloc/dealloc space */
 static Boolean  plotFile = FALSE;
 
 CursHandle theCursor;  
 /* changes cursor to a watch during update */
 
 /* multifinder check */
 
 if (*WNEImplemented)
 WaitNextEvent(everyEvent, myEvent, SLEEP, NIL_MOUSE_REGION);
 else
 {
 SystemTask(); /* time slice for OS */
 GetNextEvent(everyEvent, myEvent);
 }
 
 switch ((*myEvent).what)
 {
 case mouseDown:
 HandleMouseDown(doneFlag, myEvent,WNEImplemented, DragRect, AppleMenu, 
&plotFile, PlotWindow, CbWindow, StWindow);
 break;

 case nullEvent:
 case mouseUp:
 case keyUp:
 case updateEvt:
 /*  see if update is for this window or open file menu selected  & redraw 
window if either condition true */
 
 if (((WindowPtr) (*myEvent).message == *PlotWindow) || (plotFile == 
TRUE))
 {
 theCursor = GetCursor(WATCH_ICON);
 /* draw watch while waiting */
 SetCursor(*theCursor);
 
 BeginUpdate(*PlotWindow);

 /* main plotting routine */
 
 SetPort(*PlotWindow);
 Err = MainPlot(PlotWindow, &plotFile, &xptr, &yptr);
 EndUpdate(*PlotWindow);
 
 InitCursor();   /* restore cursor to default icon */
 plotFile = FALSE; /* reset after use */
 if (Err == CANCEL_BUTTON)
 {
 /* reenable menu selection if cancel button hit */
 
 itemHndl = GetMHandle(OPTION_MENU_ID);
 EnableItem(itemHndl, PLOT_ITEM);
 break; /* get out of event loop now! */
 }
 }
 
 /* chk if update for clip board window */
 
 if ((WindowPtr) (*myEvent).message == *CbWindow)
 {
 BeginUpdate(*CbWindow);
 SetPort(*CbWindow);
 DisplayClipboard(CbWindow, clipHandl);
 ShowWindow(*CbWindow);
 EndUpdate(*CbWindow);
 }
 
 /* chk if update for status window */
 if ((WindowPtr) (*myEvent).message == *StWindow)
 {
 BeginUpdate(*StWindow);
 SetPort(*StWindow);
 if ((doStatus((double) NIL, (double) NIL, 
   (double) NIL, “\p”, StWindow)) == TRUE)
 {
 ShowWindow(*StWindow);
 }
 EndUpdate(*StWindow);
 }
 break;
 case keyDown:
 case autoKey:
 theChar = (*myEvent).message & charCodeMask;
 if (((*myEvent).modifiers & cmdKey) != 0)
 HandleMenuChoice(MenuKey(theChar), doneFlag, AppleMenu, &plotFile, CbWindow, 
StWindow, PlotWindow);
 break;
 case activateEvt:
 break;
 default:
 break;
 }
 
 if (*doneFlag == TRUE)
 {
 if (xptr != NIL)/* release space if no errors */
 {
 if ((free(xptr)) == MinusOne)
 HandleError(FREE_MEM_ALERT); /* error dialog */
 }
 
 if (yptr != NIL)
 {
 if ((free(yptr)) == MinusOne)
 HandleError(FREE_MEM_ALERT); /* error dialog */
 }
 } 
}

HandleMouseDown(doneFlag, myEvent, WNEImplemented, DragRect, AppleMenu, 
plotFilePtr, plotWindow, cBwindow, sWindow)
 Boolean*doneFlag;
 EventRecord*myEvent;
 Boolean*WNEImplemented;
 Rect   *DragRect;
 MenuHandle *AppleMenu;
 Boolean*plotFilePtr;
 WindowPtr*plotWindow, *cBwindow, *sWindow;
{
 BooleanStillInGoAway;
 WindowPtrwhichWindow;
 short intthePart;
 long int menuChoice;
 MenuHandle disableHandle;
 static WindowPtroldPort;
 
 thePart = FindWindow((*myEvent).where, &whichWindow);
 switch(thePart)
 {
 case inContent:
 /* activate the window that was pt’d @  */
 
 GetPort(&oldPort);/* save current graph port  */
 SetPort(whichWindow);
 SelectWindow(whichWindow);
 break;
 case inMenuBar:
 menuChoice = MenuSelect((*myEvent).where);
 HandleMenuChoice(menuChoice, doneFlag, AppleMenu, plotFilePtr, cBwindow, 
sWindow, plotWindow);
 break;
 case inSysWindow:
 SystemClick(myEvent, whichWindow);
 break;
 case inDrag:
 DragWindow(whichWindow, (*myEvent).where, DragRect);
 break;
 case inGoAway:
 /* highlight close box when clicked */
 StillInGoAway = TrackGoAway(whichWindow, (*myEvent).where);
 if (StillInGoAway)
 {
 /* re-enable menu selection when window closed */
 if (whichWindow == *plotWindow)
 {
 disableHandle = GetMHandle(OPTION_MENU_ID);
 EnableItem(disableHandle, PLOT_ITEM);
 }
 if (whichWindow == *cBwindow)
 {
 disableHandle = GetMHandle(EDIT_MENU_ID);
 EnableItem(disableHandle, CLIPBOARD_ITEM);
 }
 
 if (whichWindow == *sWindow)
 {
 disableHandle = GetMHandle(OPTION_MENU_ID);
 EnableItem(disableHandle, STATUS_ITEM);
 }
 
 /* restore old graph port */
 SetPort(oldPort);
 HideWindow(whichWindow);
 SendBehind(whichWindow, NIL);
 }
 break;
 default:
 break;
 }
}

HandleMenuChoice(menuChoice, doneFlag, AppleMenu, plotFptr, cbWindow, 
stWindow, pltWindow)
 long   menuChoice;
 Boolean*doneFlag;
 MenuHandle *AppleMenu;
 Boolean*plotFptr;
 WindowPtr*cbWindow, *stWindow, *pltWindow;
{
 int theMenu;
 int theItem;
 
 if (menuChoice != FALSE)
 {
 theMenu = HiWord(menuChoice);
 theItem = LoWord(menuChoice);
 switch (theMenu)
 {
 case APPLE_MENU_ID:
 HandleAppleChoice(theItem, AppleMenu);
 break;
 case EDIT_MENU_ID:
 HandleEditChoice(theItem, cbWindow, pltWindow);
 break;
 case FILE_MENU_ID:
 HandleFileChoice(theItem, doneFlag);
 break;
 case OPTION_MENU_ID:
 HandleOptionChoice(theItem, plotFptr, stWindow);
 break;
 default:
 break;
 }
 HiliteMenu(0);
 }
}

HandleAppleChoice(theItem, AppleMenu)
 int theItem;
 MenuHandle *AppleMenu;
{
 Str255 accName;
 int    accNumber;
 short intitemNumber;
 DialogPtrAboutDialog;
 
 switch (theItem)
 {
 case ABOUT_ITEM:
 NoteAlert(ABOUT_ALERT, NIL);
 break;
 default: 
 GetItem(*AppleMenu, theItem, accName);
 accNumber = OpenDeskAcc(accName);
 break;
 }
}

HandleEditChoice(theItem, theCbWindow, thePlotWindow)
 int    theItem;
 WindowPtr*theCbWindow, *thePlotWindow;
{
 long   Err, *myPtr, ptr = NIL;
 MenuHandle editHandle;
 PScrapStuffmyScrapPtr;
 Str255 myEmptyStr;
 
 myPtr = (long *) gSP;

 /* generate update evnt for clipboard window */
 switch (theItem)
 {
 case COPY_ITEM:
 /* defined by application */
 break;
 case PASTE_ITEM:
 /* defined by application */
 break;
 case CLEAR_ITEM:
 /* clear clipboard; refer to I.M. I:385-386, I:461 */
 
 myScrapPtr = InfoScrap();
 Err = ZeroScrap();
 Err = PutScrap(1, ‘PAT ‘, myPtr);
 SetPort(*theCbWindow);
 EraseRect(&(*theCbWindow)->portRect);
 UnloadScrap();  /* put it on disk clipboard */
 break;
 case CLIPBOARD_ITEM:
 /* disable item when selected */
 
 editHandle = GetMHandle(EDIT_MENU_ID);
 DisableItem(editHandle, CLIPBOARD_ITEM);
 
 SetPort(*theCbWindow);
 SelectWindow(*theCbWindow);
 ShowWindow(*theCbWindow);
 break;
 default:
 break;
 }
}

HandleFileChoice(theItem, doneFlag)
 int theItem;
 Boolean*doneFlag;
{
 OSErr  DoLaunch();/* forward declaration */
 Boolean  SubLaunch; /* sublaunch if true and launch if false */
 int    Err = noErr;
 MenuHandle fileHandle;
 
 switch (theItem)
 {
 case TRANSFER_ITEM:
 /* quits current routine after launch */
 
 SubLaunch = FALSE;
 Err = DoLaunch(SubLaunch); 
 break;
 case QUIT_ITEM:
 *doneFlag = TRUE;
 break;
 }
 
 /* handle launch failure */
 
 if (Err != noErr)
 NoteAlert(LAUNCH_ALERT, NIL);
}

HandleOptionChoice(Item, PlotFPtr, sWindow)
 int    Item;
 Boolean*PlotFPtr;
 WindowPtr*sWindow;
{
 CursHandle theCursor;
 double atof(),
 Coeff = (double) NIL,
 Mass = (double) NIL,
 Elast = (double) NIL;
 MenuHandle OptionHndl;
 SavedSettings   getSettings, Settings;
 SavedSettingsPtrSettingsPtr;
 
 SettingsPtr = &getSettings;
 
 switch (Item)
 {
 case SIMULATE_ITEM:
 /* get input from dialog.  Convert strings to floats and 
 pass into calc harmonics if the structure ret’d from 
 handle dialog is valid */
 
 if (HandleDialog(&SettingsPtr) == TRUE)
 {
 theCursor = GetCursor(WATCH_ICON); /* wait cursor*/
 SetCursor(*theCursor);

 PtoC(&getSettings, &Settings);
 Coeff = atof(Settings.amp);
 Mass = atof(Settings.mass);
 Elast = atof(Settings.elastic);
 CalcHarmonic(Coeff, atof(Settings.frict), Elast, Mass, (int) atof(Settings.start), 
(int) atof(Settings.fini), 
(int) atof(Settings.ink), Settings.xVal, Settings.yVal);
 doStatus(Coeff, Mass, Elast, Settings.simName, sWindow);
 }
 InitCursor(); /* reset to default cursor */
 break;
 case PLOT_ITEM:
 OptionHndl = GetMHandle(OPTION_MENU_ID);
 DisableItem(OptionHndl, PLOT_ITEM);
 *PlotFPtr = TRUE;
 break;
 case STATUS_ITEM:
 /* disable menu selection */
 
 OptionHndl = GetMHandle(OPTION_MENU_ID);
 DisableItem(OptionHndl, STATUS_ITEM);
 
 /* display status window */
 SetPort(*sWindow);
 if ((doStatus(Coeff, Mass, Elast, “\p”, sWindow)) == TRUE)
 {
 SelectWindow(*sWindow);
 ShowWindow(*sWindow);
 }
 else
 {
 OptionHndl = GetMHandle(OPTION_MENU_ID);
 EnableItem(OptionHndl, STATUS_ITEM);
 }
 break;
 default:
 break;
 }
}

DisplayClipboard(BoardWindow, ClipHandle)
 WindowPtr*BoardWindow;
 Handle *ClipHandle;
{
 Rect myRect;
 long length, offset;
 
 if ((length = GetScrap(*ClipHandle, ‘TEXT’, &offset)) < 0)
 {
 if ((length = GetScrap(*ClipHandle, ‘PICT’, &offset)) < 0)
 ;/* NoteAlert(CLIPBOARD_ALERT, NIL); */
 else
 {
 /* display pict data */
 
 myRect = (*BoardWindow)->portRect;
 CenterPict(*ClipHandle, &myRect);
 DrawPicture(*ClipHandle, &myRect);
 }
 }
 else
 {
 /* display text data */
 
 HLock(*ClipHandle);
 TextBox(**ClipHandle, length, &(thePort->portRect), teJustLeft);
 HUnlock(*ClipHandle);
 }
}

OSErr LaunchIt(pLnch)
 pLaunchStruct pLnch;
/* This function is pascal call back routine.  It lanches nu apps; refer 
to pp. 118 & 119 in the ls c manual for more info.
 note:  result code < 0 means error */
{
 asm
 {
 move.l 8(sp),a0 /* pops ptr into a0 */
 _Launch/* calls launch */
 /* OSErr ret’d in d0 */
 }
}

OSErr DoLaunch(subLaunch)
Boolean subLaunch; /* sublaunch if true & launch if false */
{
 LaunchStruct  myLaunch;
 Point  where;   /* where to display dialog */
 SFReplyreply;   /* reply record */
 SFTypeList myFileTypes;  /* we only want appls */
 short intnumFileTypes = 1;
 HFileInfomyPB;
 StringPtrdirNameStr;
 OSErr  err;
 OSErr  LaunchIt();/* forward declare funct */
 
 where.h = 80;
 where.v = 90;
 myFileTypes[0] = ‘APPL’; /* only appls */
 
 /* let the user choose the file to launch */
 SFGetFile(where, “”, NIL, numFileTypes, myFileTypes, NIL, &reply);
 
 if (reply.good)
 {
 dirNameStr = (StringPtr) &reply.fName;
 /* init to file selected */
 
 /* get finder flags */
 myPB.ioCompletion = NIL;
 myPB.ioNamePtr = dirNameStr;
 myPB.ioVRefNum = reply.vRefNum;
 myPB.ioFDirIndex = 0;
 myPB.ioDirID = 0;
 err = PBGetCatInfo((CInfoPBPtr) &myPB, FALSE);
 if (err != noErr)
 return(err);  /* how to handle this? */
 
 /* set the current volume to where the target appl is */
 
 err = SetVol(NIL, reply.vRefNum);
 if (err != noErr)
 return(err);  /* ditto */
 
 /* set up the launch params */
 
 myLaunch.pfName = (StringPtr) &reply.fName;       /* ptr to our filename 
*/
 myLaunch.param = 0; 
 /* we don’t want alt screen or sound buffs */
 
 /* set up LC so as to tell launch that htere is non-junk next */
 
 myLaunch.LC[0] = ‘L’;  myLaunch.LC[1] = ‘C’;
 myLaunch.extBlockLen = 6;
 /* len of param blk past this long word */
 
 /* copy flags; set bit 6 of low byte to 1 for RO access: */
 
 myLaunch.fFlags = myPB.ioFlFndrInfo.fdFlags;      /* from _GetCatInfo 
*/
 
 /* test sublaunch & set launch flags accordingly */
 
 if (subLaunch)
 myLaunch.launchFlags = 0xC0000000;
 /* set 2 high bit for sublaunch */
 else
 myLaunch.launchFlags = 0x00000000;/* launch & quit */
 /* Debugger(); */
 err = LaunchIt(&myLaunch); /* call _Launch */
 if (err < 0)
 {
 /* launch failed, put up alert to tell user */
 /* LaunchFailed();*/
 return(err);
 }
 else
 return(noErr);
 }
}

CenterPict(thePicture, myRectPtr)
 PicHandlethePicture;
 Rect   *myRectPtr;
{
 Rect windRect, 
 pictureRect;
 
 windRect = *myRectPtr;
 pictureRect = (**(thePicture)).picFrame;
 myRectPtr->top = (windRect.bottom - windRect.top - (pictureRect.bottom 
- pictureRect.top)) / 2 + windRect.top;
 myRectPtr->bottom = myRectPtr->top + (pictureRect.bottom - pictureRect.top);
 myRectPtr->left = (windRect.right - windRect.left - (pictureRect.right 
- pictureRect.left)) / 2 + windRect.left;
 myRectPtr->right = myRectPtr->left + (pictureRect.right - pictureRect.left);
}
Listing:  Harmonic Func.c

#include <storage.h>
#include <strings.h>
#include <math.h>

#include <QuickDraw.h>
#include <MacTypes.h>
#include <FontMgr.h>
#include <WindowMgr.h>
#include <MenuMgr.h>
#include <TextEdit.h>
#include <DialogMgr.h>
#include <EventMgr.h>
#include <DeskMgr.h>
#include <StdfilePkg.h>
#include <FileMgr.h>
#include <ToolboxUtil.h>
#include <ControlMgr.h>

#include “Harmonic.h”

extern  int errno; /* required by math lib */
extern  chargTAB[];
extern  chargCR[];
/* Created by  : Byro
 date : 03/05/90
 modified : 04/25/90 */

CalcHarmonic(Coeff, dampingCoeff, elasticConst, mass, initInterval, finalInterval, 
increment, xLbl, yLbl)
 double Coeff,
 dampingCoeff,
 elasticConst, /* comment later */
 mass;
 int    initInterval,
 finalInterval,
 increment;
 char *xLbl,
 *yLbl;
/* This section of code is the compute engine of the simple harmonic 
motion simulator application.  It allocates storage, computes the function, 
and stores the data before returning to calling routine. */
{
 double alpha,
 amplitude,
 beta,
 *dataPtr,/* used for dynamic storage of data pts */
 omega,
 *tPtr; /* used to free data ptr */
 int    i,
 *t1Ptr,
 *timePtr;
 
 alpha = dampingCoeff / (2 * mass);
 omega = sqrt((double) (4 * mass * elasticConst - (dampingCoeff * dampingCoeff))) 
/ (2 * mass);
 beta = dampingCoeff / (2 * mass * omega);

 /* allocate n + 1 doubles;SANE f.p. double uses 10 bytes per number 
*/
 
 dataPtr = (double *) malloc((int) (((finalInterval / increment) * 10) 
+ 10));
 
 /* allocate n + 2 ints; SANE ints use 2 bytes each */
 
 timePtr = (int *) malloc((int) (((finalInterval / increment) * 2) + 
4));
 
 if ((dataPtr == NIL) || (timePtr == NIL))
 {
 /* display error dialog */
 NoteAlert(ENOUGH_ALERT, NIL);
 return;
 }
 
 tPtr = dataPtr; 
 /* save ptr to alloced space to free correctly */
 t1Ptr = timePtr;
 
 for (i = initInterval; i <= finalInterval; i += increment)
 {
 /* note the values for cos and sin are in radians */
 amplitude = (Coeff * exp((double) (-alpha * i))) * (cos(omega * i) + 
beta * sin(omega * i));
 
 *dataPtr = amplitude;  /* store value */
 *timePtr = i; /* store time interval */
 dataPtr++; timePtr++;
 }
 *timePtr = MinusOne;/* end of data delimiter */ 
 
 /* store labels x, y, and data into an ascii file .  Note: floats must 
be converted to ascii before storing into file.
Also free data ptr space on exit. */
 /* restore ptrs */
 
 dataPtr = tPtr;
 timePtr = t1Ptr;
 
 SaveToFile(xLbl, yLbl, dataPtr, timePtr);
 free(tPtr);
 free(t1Ptr);
}

SaveToFile(Xlbl, Ylbl, Dptr, Tptr)
 char *Xlbl, *Ylbl;
 double *Dptr;
 int    *Tptr;
/* This function converts the data pts to ascii and writes them to a 
text file along with their associated axis labels. */
{
 double tmp;
 int    fRefNum; /* file reference number */
 long   count;   /* buffer length */
 SFReplyreply;
 static Str255 Fname = “\p”;/* initialize file name */
 static Point  where = {100, 104};
 Str255 holder;
 
 SFPutFile(where, “\pSave File as:”, “\pSim Result File”, 0L, &reply);
 if (reply.good) /* cancel if button not pressed */
 {
 /* delete existing file */
 FSDelete(reply.fName, reply.vRefNum);
 
 /* create nu one */
 Create(reply.fName, reply.vRefNum, ‘HSIM’, ‘TEXT’);
 if (FSOpen(reply.fName, reply.vRefNum, &fRefNum) == noErr)
 {
 /* write axis labels into file */
 
 strcpy(holder, Xlbl);  /* x-axis */
 count = strlen(holder);
 FSWrite(fRefNum, &count, holder);
 count = 1;
 FSWrite(fRefNum, &count, gCR);  /* write nu line */

 strcpy(holder, Ylbl);  /* y-axis */
 count = strlen(holder);
 FSWrite(fRefNum, &count, holder);
 count = 1;
 FSWrite(fRefNum, &count, gCR);  /* write nu line */

 while (*Tptr != MinusOne)
 {
 if (*Dptr > 0)
 {
 /* save only + ive numbers */
 
 itoa((int) *Tptr, holder); 
 /* convert time variable */
 count = strlen(holder);
 FSWrite(fRefNum, &count, holder); 
 /* write time string */
 
 count = 1; /* write tab to file */
 FSWrite(fRefNum, &count, gTAB);
 
 tmp = ceil(*Dptr);
 /* round up to next highest int */
 itoa((int) tmp, holder); 
 /* convert to ascii string */
 count = strlen(holder);  /* compute buffer len */
 FSWrite(fRefNum, &count, holder); 
 /* write out amplitude */
 
 count = 1;
 FSWrite(fRefNum, &count, gCR);  /* write nu line */
 }
 Dptr++;
 Tptr++; 
 }
 
 /* insures that buffer get written to disk */
 FlushVol(“\p”, reply.vRefNum);
 FSClose(fRefNum);
 }
 }
}

HandleDialog(settingsPtr)
 SavedSettingsPtr *settingsPtr;
/* This funct handles the input of parameters via a dialog. */
{
 int    itemHit,
 dialogDone = FALSE,
 frictFlag = FALSE, ampFlag = FALSE, elastFlag = FALSE, 
 startFlag = FALSE, finiFlag = FALSE, xFlag = FALSE,           
 yFlag = FALSE,
 massFlag = FALSE, inkFlag = FALSE, simNameFlag =              
 FALSE, itemType;
 Rect   itemRect;
 Handle itemHandle;
 DialogPtrsettingsDialog;
 
 doDialog(&settingsDialog); 
 /* create dialog and load default setttings */
 /* init settingsPtr with default values here */
 
 SaveDefaults(&settingsDialog, settingsPtr);
 SelectWindow(settingsDialog);
 ShowWindow(settingsDialog);
 /* the dialog is initially invisible */
 while (dialogDone == FALSE)
 {
 ModalDialog(NIL, &itemHit);
 switch (itemHit)
 {
 case OK_BUTTON :
 HideWindow(settingsDialog);
 DisposDialog(settingsDialog);
 dialogDone = TRUE;
 break;
 case CANCEL_BUTTON :
 HideWindow(settingsDialog);
 DisposDialog(settingsDialog);
 dialogDone = TRUE;
 return(FALSE);
 break;
 case FRICTION_VALUE :
 if (frictFlag == FALSE)
 SelIText(settingsDialog, FRICTION_VALUE, MIN, MAX);
 /* get edited value */
 GetDItem(settingsDialog, FRICTION_VALUE, &itemType, &itemHandle, &itemRect);
 /* put it in ptr to struct  */
 GetIText(itemHandle, &(**settingsPtr).frict);
 frictFlag = TRUE;
 break;
 case AMPLITUDE_VALUE :
 if (ampFlag == FALSE)
 SelIText(settingsDialog, AMPLITUDE_VALUE, MIN, MAX);
 /* get edited value */
 GetDItem(settingsDialog, AMPLITUDE_VALUE, &itemType, &itemHandle, &itemRect);
 /* put it in ptr to struct  */
 GetIText(itemHandle, &(**settingsPtr).amp);
 ampFlag = TRUE;
 break;
 case ELASTIC_VALUE :
 if (elastFlag == FALSE)
 SelIText(settingsDialog, ELASTIC_VALUE, MIN, MAX);
 /* get edited value */
 GetDItem(settingsDialog, ELASTIC_VALUE, &itemType, &itemHandle, &itemRect);
 /* put it in ptr to struct  */
 GetIText(itemHandle, &(**settingsPtr).elastic);
 elastFlag = TRUE;
 break;
 case START_VALUE :
 if (startFlag == FALSE)
 SelIText(settingsDialog, START_VALUE, MIN, MAX);
 /* get edited value */
 GetDItem(settingsDialog, START_VALUE, &itemType, &itemHandle, &itemRect);
 /* put it in ptr to struct  */
 GetIText(itemHandle, &(**settingsPtr).start);
 startFlag = TRUE;
 break;
 case FINI_VALUE :
 if (finiFlag == FALSE)
 SelIText(settingsDialog, FINI_VALUE, MIN, MAX);
 /* get edited value */
 GetDItem(settingsDialog, FINI_VALUE, &itemType, &itemHandle, &itemRect);
 /* put it in ptr to struct  */
 GetIText(itemHandle, &(**settingsPtr).fini);
 finiFlag = TRUE;
 break;
 case X_VALUE :
 if (xFlag == FALSE)
 SelIText(settingsDialog, X_VALUE, MIN, MAX);
 /* get edited value */
 GetDItem(settingsDialog, X_VALUE, &itemType, &itemHandle, &itemRect);
 /* put it in ptr to struct  */
 GetIText(itemHandle, &(**settingsPtr).xVal);
 xFlag = TRUE;
 break;
 case Y_VALUE :
 if (yFlag == FALSE)
 SelIText(settingsDialog, Y_VALUE, MIN, MAX);
 /* get edited value */
 GetDItem(settingsDialog, Y_VALUE, &itemType, &itemHandle, &itemRect);
 /* put it in ptr to struct  */
 GetIText(itemHandle, &(**settingsPtr).yVal);
 yFlag = TRUE;
 break;
 case MASS_VALUE :
 if (massFlag == FALSE)
 SelIText(settingsDialog, MASS_VALUE, MIN, MAX);
 /* get edited value */
 GetDItem(settingsDialog, MASS_VALUE, &itemType, &itemHandle, &itemRect);
 /* put it in ptr to struct  */
 GetIText(itemHandle, &(**settingsPtr).mass);
 massFlag = TRUE;
 break;
 case INC_VALUE :
 if (inkFlag == FALSE)
 SelIText(settingsDialog, INC_VALUE, MIN, MAX);
 /* get edited value */
 GetDItem(settingsDialog, INC_VALUE, &itemType, &itemHandle, &itemRect);
 /* put it in ptr to struct  */
 GetIText(itemHandle, &(**settingsPtr).ink);
 inkFlag = TRUE;
 break;
 case SIM_NAME_VALUE :
 if (simNameFlag == FALSE)
 SelIText(settingsDialog, SIM_NAME_VALUE, MIN, MAX);
 /* get edited value */
 GetDItem(settingsDialog, SIM_NAME_VALUE, &itemType, &itemHandle, &itemRect);
 /* put it in ptr to struct  */
 GetIText(itemHandle, &(**settingsPtr).simName);
 simNameFlag = TRUE;
 break; 
 }
 } /* while */
 if (postProcess(settingsPtr) == FALSE) 
 /* chk struct for invalid chars */
 {
 /* display error dialogs */
 Alert(PROCESS_ALERT, NIL);
 return(FALSE);
 }
 
 /* hndl x, y axis differential chk */
 if (validateX(settingsPtr) == FALSE)
 {
 NoteAlert(X_ALERT, NIL);
 return(FALSE);
 }
 if (validateY(settingsPtr) == FALSE)
 {
 NoteAlert(Y_ALERT, NIL);
 return(FALSE);
 }
 
 return(TRUE);
}

doDialog(SettingsDialog)
 DialogPtr *SettingsDialog;
/* create dialog and load default strings. */
{
 int    itemType;
 Rect   itemRect;
 Handle itemHandle;
 StringHandle  DefFrictH,
 DefAmpH, DefElastH,
 DefStartH, DefFiniH,
 DefXH, DefYH,
 DefMassH, DefIncH, DefSimNameH;
 
 DefFrictH = GetString(DEF_FRICTION_ID);     
 /* generate default string hndls */
 DefAmpH = GetString(DEF_AMPLITUDE_ID);
 DefElastH = GetString(DEF_ELASTIC_ID);
 DefStartH = GetString(DEF_START_ID);
 DefFiniH = GetString(DEF_FINI_ID);
 DefXH = GetString(DEF_X_AXIS_ID);
 DefYH = GetString(DEF_Y_AXIS_ID);
 DefMassH = GetString(DEF_MASS_ID);
 DefIncH = GetString(DEF_INC_ID);
 DefSimNameH = GetString(DEF_SIM_ID);
 
 *SettingsDialog = GetNewDialog(BASE_RES_ID, NIL, MOVE_TO_FRONT);
 
 if (*SettingsDialog == NIL)
 {
 /* display malloc dialog error */
 StopAlert(ENOUGH_ALERT, NIL);
 ExitToShell();
 }
 
 /* load default settings */
 GetDItem(*SettingsDialog, FRICTION_VALUE, &itemType, &itemHandle, &itemRect);
 HLock(DefFrictH);
 SetIText(itemHandle, *DefFrictH);
 HUnlock(DefFrictH);

 GetDItem(*SettingsDialog, AMPLITUDE_VALUE, &itemType, &itemHandle, &itemRect);
 
 HLock(DefAmpH);
 SetIText(itemHandle, *DefAmpH);
 HUnlock(DefAmpH);

 GetDItem(*SettingsDialog, ELASTIC_VALUE, &itemType, &itemHandle, &itemRect);

 HLock(DefElastH);
 SetIText(itemHandle, *DefElastH);
 HUnlock(DefElastH);

 GetDItem(*SettingsDialog, START_VALUE, &itemType, &itemHandle, &itemRect);

 HLock(DefStartH);
 SetIText(itemHandle, *DefStartH);
 HUnlock(DefStartH);

 GetDItem(*SettingsDialog, FINI_VALUE, &itemType, &itemHandle, &itemRect);

 HLock(DefFiniH);
 SetIText(itemHandle, *DefFiniH);
 HUnlock(DefFiniH);

 GetDItem(*SettingsDialog, X_VALUE, &itemType, &itemHandle, &itemRect);

 HLock(DefXH);
 SetIText(itemHandle, *DefXH);
 HUnlock(DefXH);

 GetDItem(*SettingsDialog, Y_VALUE, &itemType, &itemHandle, &itemRect);

 HLock(DefYH);
 SetIText(itemHandle, *DefYH);
 HUnlock(DefYH);

 GetDItem(*SettingsDialog, MASS_VALUE, &itemType, &itemHandle, &itemRect);

 HLock(DefMassH);
 SetIText(itemHandle, *DefMassH);
 HUnlock(DefMassH);
 
 GetDItem(*SettingsDialog, INC_VALUE, &itemType, &itemHandle, &itemRect);

 HLock(DefIncH);
 SetIText(itemHandle, *DefIncH);
 HUnlock(DefIncH);
 
 GetDItem(*SettingsDialog, SIM_NAME_VALUE, &itemType, &itemHandle, &itemRect);

 HLock(DefSimNameH);
 SetIText(itemHandle, *DefSimNameH);
 HUnlock(DefSimNameH);
}

SaveDefaults(myDialog, settings)
 DialogPtr*myDialog;
 SavedSettingsPtr*settings;
/* puts default settings in structure */
{
 int    itemHit,
 itemType;
 Rect itemRect;
 Handle itemHndl;
 
 GetDItem(*myDialog, FRICTION_VALUE, &itemType, &itemHndl, &itemRect);
 GetIText(itemHndl, &(**settings).frict);
 
 GetDItem(*myDialog, AMPLITUDE_VALUE, &itemType, &itemHndl, &itemRect);
 GetIText(itemHndl, &(**settings).amp);

 GetDItem(*myDialog, ELASTIC_VALUE, &itemType, &itemHndl, &itemRect);
 GetIText(itemHndl, &(**settings).elastic);

 GetDItem(*myDialog, START_VALUE, &itemType, &itemHndl, &itemRect);
 GetIText(itemHndl, &(**settings).start);

 GetDItem(*myDialog, FINI_VALUE, &itemType, &itemHndl, &itemRect);
 GetIText(itemHndl, &(**settings).fini);

 GetDItem(*myDialog, X_VALUE, &itemType, &itemHndl, &itemRect);
 GetIText(itemHndl, &(**settings).xVal);

 GetDItem(*myDialog, Y_VALUE, &itemType, &itemHndl, &itemRect);
 GetIText(itemHndl, &(**settings).yVal);
 
 GetDItem(*myDialog, MASS_VALUE, &itemType, &itemHndl, &itemRect);
 GetIText(itemHndl, &(**settings).mass);
 
 GetDItem(*myDialog, INC_VALUE, &itemType, &itemHndl, &itemRect);
 GetIText(itemHndl, &(**settings).ink);
 
 GetDItem(*myDialog, SIM_NAME_VALUE, &itemType, &itemHndl, &itemRect);
 GetIText(itemHndl, &(**settings).simName);
}

postProcess(settings)
 SavedSettingsPtr*settings;
/* Post Process parses all fields ret’d by input dialog to check for 
invalid characters.  It returns a value of true to the calling routine 
if all the fields are correct. */
{
 int    num;
 Ptr    chPtr;
 Str255 Astring;
 
 chPtr = (char *) &(**settings).frict;
 if (chkValid(chPtr) == FALSE)
 /* ret false if invalid char detected */
 return(FALSE);
 
 chPtr = (char *) &(**settings).amp;
 if (chkValid(chPtr) == FALSE)
 /* ret false if invalid char detected */
 return(FALSE);

 chPtr = (char *) &(**settings).elastic;
 if (chkValid(chPtr) == FALSE)
 /* ret false if invalid char detected */
 return(FALSE);

 chPtr = (char *) &(**settings).start;
 if (chkValid(chPtr) == FALSE)
 /* ret false if invalid char detected */
 return(FALSE);
 P2Cstr(chPtr, Astring);
 num = atoi(Astring);/* chk for -ive condition */
 if (num < 0)
 return(FALSE);

 chPtr = (char *) &(**settings).fini;
 if (chkValid(chPtr) == FALSE)
 /* ret false if invalid char detected */
 return(FALSE);
 P2Cstr(chPtr, Astring);
 num = atoi(Astring);/*  -ive || equal to 0 condition */
 if ((num < 0) || (num == 0))
 return(FALSE);

 chPtr = (char *) &(**settings).mass;
 if (chkValid(chPtr) == FALSE)
 /* ret false if invalid char detected */
 return(FALSE);
 P2Cstr(chPtr, Astring);
 num = atoi(Astring);
 if ((num < 0) || (num == 0))
 return(FALSE);
 
 chPtr = (char *) &(**settings).ink;
 if (chkValid(chPtr) == FALSE)
 /* ret false if invalid char detected */
 return(FALSE);
 P2Cstr(chPtr, Astring);
 num = atoi(Astring);
 if ((num < 0) || (num == 0))
 return(FALSE);

 return(TRUE);
}

chkValid(cPtr)
 char *cPtr;
/* checks pascal strings for non-numeric characters and returns true 
value if no invalid characters are detected. */
{
 char ch;
 int    i,
 length = 0,
 minusCount = 0,
 plusCount = 0,
 ptCount = 0;
 
 length = *cPtr; /* extract length of pascal string */
 
 if (length == 0)
 return(FALSE);  /* zero length string */
 
 for (i = 1; i <= length; i++)
 {
 ch = *(cPtr + i);
 if ((ch >= ‘0’) && (ch <= ‘9’))
 ;
 else
 {
 switch (ch)
 {
 case ‘.’ :
 ptCount++;
 break;
 case ‘+’ :
 plusCount++;
 break;
 case ‘-’ :
 minusCount++;
 break;
 default :
 return(FALSE);
 break;
 }
 }
 
 /* return false if more than one detected */
 if ((ptCount > 1) || (plusCount > 1) || (minusCount > 1))
 return(FALSE);
 }
 return(TRUE);
}

PtoC(oldSettings, nuSettings)
 SavedSettingsPtroldSettings, nuSettings;
/* Pascal string to C string transforms the pascal strings in the structure 
oldSettings into C strings and places them into the structure nuSettings. 
*/
{
 P2Cstr((*oldSettings).frict, (*nuSettings).frict);
 P2Cstr((*oldSettings).amp, (*nuSettings).amp);
 P2Cstr((*oldSettings).elastic, (*nuSettings).elastic);
 P2Cstr((*oldSettings).start, (*nuSettings).start);
 P2Cstr((*oldSettings).fini, (*nuSettings).fini);
 P2Cstr((*oldSettings).xVal, (*nuSettings).xVal);
 P2Cstr((*oldSettings).yVal, (*nuSettings).yVal);
 P2Cstr((*oldSettings).mass, (*nuSettings).mass);
 P2Cstr((*oldSettings).ink, (*nuSettings).ink);
 P2Cstr((*oldSettings).simName, (*nuSettings).simName);
}

validateX(SettingsPtr)
 SavedSettingsPtr*SettingsPtr;
/* Validate X checks to see if the differential of x is divisible by 
ten. If it is the function returns a true; otherwise it returns a value 
of false. */
{
 double atof();
 int    delta,
 aNumber;
 Str255 Start,
 Finish;
 
 P2Cstr((**SettingsPtr).fini, Finish); 
 /* convert strs to C strings */
 P2Cstr((**SettingsPtr).start, Start);
 
 delta = atof(Finish) - atof(Start);
 
 aNumber = delta / 10;
 if(aNumber > 0)
 return(TRUE);
 else
 return(FALSE);
}

validateY(SettingsPtr)
 SavedSettingsPtr*SettingsPtr;
/* Validate Y checks to see if the differential of y is divisible by 
eight. If it is the function returns a true; otherwise it returns a value 
of false. */
{
 double atof();
 int    aNumber;
 Str255 Amp;
 
 P2Cstr((**SettingsPtr).amp, Amp); 
 /* convert pascal str to C str */
 
 aNumber = atof(Amp);
 if (aNumber >= 8)
 return(TRUE);
 else
 return(FALSE);
}

doStatus(Coeff, Mass, Elast, sName, win)
 double Coeff, Mass, Elast;
 Str255 *sName;
 WindowPtr*win;
/* Do Status is used to either store information about the last simulation, 
or to display the status of the last simulation recorded. The action 
depends on the contents of the parameters passed to the routine. */
{
 int    currentRow = 12, leftMargin = 10, rowOffset = 24;
 Str255 num2str;
 
 static Boolean  beenHereBefore = FALSE;
 static double b = NIL, bSqr = NIL, fourMK = NIL, k = NIL, m = NIL, omega 
= NIL;
 static Str255 NameOfLastSim;
 
 if ((Mass == NIL) && (beenHereBefore == TRUE))
 {
 /* update screen only */
 TextFont(1);  /* change textfont to application */
 
 EraseRect(&(*win)->portRect);
 MoveTo(leftMargin, currentRow);
 DrawString(“\pSimulation Name:    “);
 DrawString(&NameOfLastSim);
 currentRow = currentRow + rowOffset;
 MoveTo(leftMargin, currentRow);
 DrawString(“\pAngular Velocity:    “);
 NumToString((long) omega, num2str);
 DrawString(num2str);
 currentRow = currentRow + rowOffset;
 MoveTo(leftMargin, currentRow);
 if (bSqr < fourMK)
 DrawString(“\pThe function is underdamped”);
 if (bSqr > fourMK)
 DrawString(“\pThe function is overdamped”);
 if (bSqr == fourMK)
 DrawString(“\pThe function is critically damped”);
 
 TextFont(NIL);  /* reset font to default */
 return(TRUE);
 }
 
 if (Mass != NIL)
 {
 b = Coeff; /* save input from current simulation */
 m = Mass;
 k = Elast;
 C2Pstr(sName, NameOfLastSim);
 bSqr = b * b;
 fourMK = 4 * m *k;
 omega = (0.5 * m) * sqrt(fourMK - bSqr);
 beenHereBefore = TRUE;
 return(TRUE);
 }
 return(FALSE);
}

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Dash 4.0.0 - Instant search and offline...
Dash is an API documentation browser and code snippet manager. Dash helps you store snippets of code, as well as instantly search and browse documentation for almost any API you might use (for a full... Read more
Bookends 12.7.9 - Reference management a...
Bookends is a full-featured bibliography/reference and information-management system for students and professionals. Bookends uses the cloud to sync reference libraries on all the Macs you use.... Read more
TrailRunner 3.8.834 - Route planning for...
TrailRunner is the perfect companion for runners, bikers, hikers, and all people wandering under the sky. Plan routes on a geographical map. Import GPS or workout recordings and journalize your... Read more
iFFmpeg 6.2.5 - Convert multimedia files...
iFFmpeg is a comprehensive media tool to convert movie, audio and media files between formats. The FFmpeg command line instructions can be very hard to master/understand, so iFFmpeg does all the hard... Read more
DaisyDisk 4.4 - $9.99
DaisyDisk allows you to visualize your disk usage and free up disk space by quickly finding and deleting big unused files. The program scans your disk and displays its content as a sector diagram... Read more
iFFmpeg 6.2.5 - Convert multimedia files...
iFFmpeg is a comprehensive media tool to convert movie, audio and media files between formats. The FFmpeg command line instructions can be very hard to master/understand, so iFFmpeg does all the hard... Read more
DaisyDisk 4.4 - $9.99
DaisyDisk allows you to visualize your disk usage and free up disk space by quickly finding and deleting big unused files. The program scans your disk and displays its content as a sector diagram... Read more
BetterTouchTool 2.07 - Customize Multi-T...
BetterTouchTool adds many new, fully customizable gestures to the Magic Mouse, Multi-Touch MacBook trackpad, and Magic Trackpad. These gestures are customizable: Magic Mouse: Pinch in / out (zoom... Read more
BetterTouchTool 2.071 - Customize Multi-...
BetterTouchTool adds many new, fully customizable gestures to the Magic Mouse, Multi-Touch MacBook trackpad, and Magic Trackpad. These gestures are customizable: Magic Mouse: Pinch in / out (zoom... Read more
BetterTouchTool 2.07 - Customize Multi-T...
BetterTouchTool adds many new, fully customizable gestures to the Magic Mouse, Multi-Touch MacBook trackpad, and Magic Trackpad. These gestures are customizable: Magic Mouse: Pinch in / out (zoom... Read more

RPG Djinn Caster (Games)
RPG Djinn Caster 1.0.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.0 (iTunes) Description: SPECIAL PRICE 38% OFF(USD 7.99 -> USD 4.99)!!!A Fantasy Action RPG of far foreign lands! Summon the Djinns and rise to... | Read more »
Alto's Odyssey gets its first trail...
There's finally video evidence of Alto's Odyssey, the follow up to the 2015 App Store hit, Alto's Adventure. It looks just as soothing and atmospheric as Alto's last outing, but this time players will be journeying to the desert. Whereas Alto's... | Read more »
Last week on Pocket Gamer
What’s going on in the wider world of portable gaming? Each week we ask that question of our sister website Pocket Gamer. The PG team covers iOS gaming, just like 148Apps, but it also strays into the world of Android games and handheld consoles... | Read more »
Pokémon GO Generation 2 evolution guide
At long last, Niantic Labs finally unleashed the Generation 2 Pokémon into the wild. Pokémon GO trainers are scrambling to grab up this new set of 80 Pokémon. There are some special new tricks required to catch all of these new beasties, though.... | Read more »
The best new games we played this week
It feels as though the New Year got off to a creaking start as far as mobile games go, but that's changed over the past few weeks. The last few days alone have seen the debut of a number of wonderful games, so we thought we'd take the time to... | Read more »
Recruit more scallywags and discover new...
Get ready to show off your sea legs all over again in Oceans & Empires’ new grand update, which aims to make the act of rising to the role of seven seas ruler even more fresh and appealing, thanks to a richness of new content on both iOS and... | Read more »
Mage the Ascension: Refuge (Games)
Mage the Ascension: Refuge 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: The groundbreaking roleplaying game Mage: The Ascension manifests in our turbulent present with Refuge, an... | Read more »
Vampire: Prelude (Games)
Vampire: Prelude 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: The classic roleplaying game Vampire: The Masquerade returns to digital games with a Prelude of things to come. Experience a... | Read more »
Digby Forever Guide: How to dig to the d...
Digby Forever is a sparkling homage to arcade classics, and while you may be tiring of the number of arcade games being thrown at you, this endless digger finds many ways to stand out from the rest of the pack. The game manages to be challenging... | Read more »
The best sales on the App Store this wee...
It's been quite the week in mobile games, but if the latest releases(there were some pretty darn good ones, in case you missed out) aren't really doing the trick, perhaps some of these discounted games will. Many of these premium games had their... | Read more »

Price Scanner via MacPrices.net

13-inch 2.0GHz Space Gray MacBook Pro on sale...
Adorama has the non-Touch Bar 13″ 2.0GHz Space Gray MacBook Pro in stock today for $100 off MSRP. Shipping is free, and Adorama charges NY & NJ sales tax only: - 13″ 2.0GHz MacBook Pro Space Gray... Read more
13-inch Touch Bar MacBook Pros on sale for $1...
B&H Photo has select 2016 Apple 13″ Touch Bar MacBook Pros in stock today and up to $100 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 13″ 2.9GHz/512GB Touch Bar MacBook... Read more
KSI-1802R SX Disinfect-able Keyboard With Wav...
KSI has unveiled a new, innovative medical keyboard, the KSI-1802R SX, at HIMSS 2017, running February 19-22 in Orlando, Florida. KSI-1802R SX is the only keyboard that combines dual factor... Read more
15-inch Touch Bar MacBook Pros on sale for up...
Amazon has 15″ Touch Bar MacBook Pros in stock today and on sale for up to $150 off MSRP including free shipping: - 15″ 2.7GHz Touch Bar MacBook Pro Space Gray: $2720.38 $79 off MSRP - 15″ 2.7GHz... Read more
Apple’s Education discount saves up to $300 o...
Purchase a new Mac or iPad using Apple’s Education Store and take up to $300 off MSRP. All teachers, students, and staff of any educational institution qualify for the discount. Shipping is free: -... Read more
13-inch 1.6GHz/256GB MacBook Air on sale for...
Newegg has the 13″ 1.6GHz/256GB MacBook Air (MMGG2LL/A) on sale for $1029.99 including free shipping. Their price is $170 off MSRP, and it’s the lowest price available for this model. Choose Newegg... Read more
Save up to $600 with Apple refurbished Mac Pr...
Apple has Certified Refurbished Mac Pros available for up to $600 off the cost of new models. An Apple one-year warranty is included with each Mac Pro, and shipping is free. The following... Read more
12-inch 1.1GHz Retina MacBooks on sale for $1...
B&H has 12″ 1.1GHz Retina MacBooks on sale for $150 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 12″ 1.1GHz Space Gray Retina MacBook: $1149 $150 off MSRP - 12″ 1.1GHz... Read more
InTouch Health Expands iOS And Windows Produc...
Specialty telehealth enterprise provider InTouch Health has announced an expanded range of FDA Class I listed medical devices and software solutions for ambulatory, non-acute and non-emergent... Read more
iMobie Airs World’s 1st iCloud Manager with M...
iMobie Inc., an Apple-related software company, announced their newly-updated iPhone manager AnyTrans with exclusive feature to sync and manage contents across multiple iCloud accounts. With it,... Read more

Jobs Board

*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Manager *Apple* Systems Administration - Pu...
Req ID 3315BR Position Title Manager, Apple Systems Administration Job Description The Manager of Apple Systems Administration oversees the administration and Read more
*Apple* Technician - nfrastructure (United S...
Let’s Work Together Apple Technician This position is based in Portland, ME Life at nfrastructure At nfrastructure, we understand that our success results from our Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Manager *Apple* Systems Administration - Pu...
Req ID 3315BR Position Title Manager, Apple Systems Administration Job Description The Manager of Apple Systems Administration oversees the administration and Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.