This is LyapunovView.m in view mode; [Download] [Up]
/* Generated by Interface Builder */ #import "LyapunovView.h" #import <math.h> #import <appkit/tiff.h> #import <appkit/color.h> #import <appkit/graphics.h> #import <appkit/Control.h> #import <appkit/Matrix.h> #import <appkit/NXColorWell.h> #import <dpsclient/psops.h> #import <appkit/Application.h> #import <dpsclient/psops.h> #import <dpsclient/wraps.h> @implementation LyapunovView - initFrame:(const NXRect *)frm // designated initializer for a view { [super initFrame:frm]; return self; } - appDidInit:sender // final initialization { // set up default colors fromColor = NXConvertRGBToColor(1.0, 1.0, 0.0); toColor = NXConvertRGBToColor(0.01, 0.01, 0.0); backColor = NXConvertRGBToColor(0.0, 0.0, 0.05); [fromShade setColor:fromColor]; [toShade setColor:toColor]; [backShade setColor:backColor]; // set up plot type singleDot = NO; [plotType selectCellWithTag:singleDot]; // set up default position xPos = 0.0; yPos = 0.0; [[posMatrix findCellWithTag:0] setFloatValue:xPos]; [[posMatrix findCellWithTag:1] setFloatValue:yPos]; // set up default scale xScale = 1.0; yScale = 1.0; [[scaleMatrix findCellWithTag:0] setFloatValue:xScale]; [[scaleMatrix findCellWithTag:1] setFloatValue:yScale]; // set up default initial value initial = 0.1; [[initialValue findCellWithTag:0] setFloatValue:initial]; // set up default depth deep = 4000; [[depth findCellWithTag:0] setIntValue:deep]; // set up default pattern [[pattern findCellWithTag:0] setStringValue:"ab"]; // set up contrast [contrastText setFloatValue:2.0]; [contrastSlider setFloatValue:2.0]; return self; } - contrast:sender // adjust image contrast coeff { contrast = [sender floatValue]; [contrastText setFloatValue:contrast]; [contrastSlider setFloatValue:contrast]; return self; } - go:sender // begin calculation of image { register float total, t, tNew, r, a, b, expSum; float spMul, rb, gb, bb, rd, gd, bd, rk, gk, bk; register int ndx, x, n, pix, y, avgCnt; NXRect pixel, line; float log2 = log(2); pixel.size.width = 1; pixel.size.height = 1; line.size.height = 1; line.size.width = XSIZE; line.origin.x = 0; [self newParam:self]; // be sure we're up to date // set up color constants rb = NXRedComponent(fromColor); gb = NXGreenComponent(fromColor); bb = NXBlueComponent(fromColor); rd = NXRedComponent(toColor) - rb; gd = NXGreenComponent(toColor) - gb; bd = NXBlueComponent(toColor) - bb; rk = NXRedComponent(backColor); gk = NXGreenComponent(backColor); bk = NXBlueComponent(backColor); // main calc loop: calc line & draw it. expSum = 0; avgCnt = 0; [self lockFocus]; for (y=0; y<YSIZE; y++) { b = yPos + y*yScale/YSIZE; // get physical y-coord for (x=0; x<XSIZE; x++) { a = xPos + x*xScale/XSIZE; // get physical x-coord total = 0.0; t = initial; ndx = 0; for (n=0; n<deep; n++) { r = (patternNum[ndx] ? a : b); tNew = t * (1 - t) * r; ndx++; if (ndx >= patternLength) ndx = 0; total += log(fabs(r - 2 * r * tNew)) / log2; t = tNew; } space[x][y] = total / deep; // Lyapunov exponent approx. // put into pixel map w/color pix = (x+(YSIZE-y-1)*XSIZE)*RGB; if (total >= 0) { pixels[pix] = 255 * rk; // pix+RED = pix because RED=0 pixels[pix+GREEN] = 255 * gk; pixels[pix+BLUE] = 255 * bk; space[x][y] = 0; } else { // no chaos, so color it spMul = fabs(space[x][y]/contrast); // scale into color map if (spMul > 1.0) spMul = 1.0; if (fabs(space[x][y]) < 100000.0) { expSum += space[x][y]; avgCnt++; } pixels[pix] = 255 *(spMul * rd + rb); pixels[pix+GREEN]= 255*(spMul * gd + gb); pixels[pix+BLUE] = 255*(spMul * bd + bb); } if (singleDot) { // plot a pixel of it pixel.origin.x = x; pixel.origin.y = y; NXImageBitmap(&pixel, 1, 1, 8, 3, NX_MESHED, NX_COLORMASK, &pixels[(x+(YSIZE-y-1)*XSIZE)*RGB], NULL, NULL, NULL, NULL); [window flushWindow]; NXPing(); } } if (!singleDot) { // plot a line of it line.origin.y = y; NXImageBitmap(&line, XSIZE, 1, 8, 3, NX_MESHED, NX_COLORMASK, &pixels[(YSIZE-y-1)*XSIZE*RGB], NULL, NULL, NULL, NULL); [window flushWindow]; NXPing(); } } [self unlockFocus]; [avgOut setFloatValue:(expSum/avgCnt)]; [reApplyButton setEnabled:YES]; return self; } - reApply:sender // re do coloring on plot { register int x, y, pix; float rb, gb, bb, rd, gd, bd, rk, gk, bk; float spMul; NXRect pixel, line; [self newParam:self]; // be sure we're up to date // set up plotting bounds pixel.size.width = 1; pixel.size.height = 1; line.size.height = 1; line.size.width = XSIZE; line.origin.x = 0; // get color params rb = NXRedComponent(fromColor); gb = NXGreenComponent(fromColor); bb = NXBlueComponent(fromColor); rd = NXRedComponent(toColor) - rb; gd = NXGreenComponent(toColor) - gb; bd = NXBlueComponent(toColor) - bb; rk = NXRedComponent(backColor); gk = NXGreenComponent(backColor); bk = NXBlueComponent(backColor); // re-apply colors [self lockFocus]; for (y=0; y<YSIZE; y++) { for (x=0; x<XSIZE; x++) { pix = (x+(YSIZE-y-1)*XSIZE)*RGB; if (space[x][y] >= 0) { pixels[pix] = 255 * rk; // pix+RED = pix because RED=0 pixels[pix+GREEN] = 255 * gk; pixels[pix+BLUE] = 255 * bk; } else { // no chaos, so color it spMul = fabs(space[x][y]/contrast); // scale into color map if (spMul > 1.0) spMul = 1.0; pixels[pix] = 255 *(spMul * rd + rb); pixels[pix+GREEN]= 255*(spMul * gd + gb); pixels[pix+BLUE] = 255*(spMul * bd + bb); } } // plot a line of it line.origin.y = y; NXImageBitmap(&line, XSIZE, 1, 8, 3, NX_MESHED, NX_COLORMASK, &pixels[(YSIZE-y-1)*XSIZE*RGB], NULL, NULL, NULL, NULL); [window flushWindow]; NXPing(); } [self unlockFocus]; return self; } - newParam:sender // set up new parameters for calc { int count; // get colors fromColor = [fromShade color]; toColor = [toShade color]; backColor = [backShade color]; // get plotting method (dots or lines) singleDot = [[plotType selectedCell] tag]; // get x-y coordinates xPos = [[posMatrix findCellWithTag:0] floatValue]; yPos = [[posMatrix findCellWithTag:1] floatValue]; // get x-y scaling xScale = [[scaleMatrix findCellWithTag:0] floatValue]; yScale = [[scaleMatrix findCellWithTag:1] floatValue]; // get initial value for each point initial = [[initialValue findCellWithTag:0] floatValue]; // get depth deep = [[depth findCellWithTag:0] intValue]; // get pattern patternString = [[pattern findCellWithTag:0] stringValue]; for(count=0; patternString[count]!='\0'; count++) { patternNum[count] = ((patternString[count]=='a') ? 0 : 1); } patternLength = count; return self; } - drawSelf:(NXRect *)rects :(int)rectCount // redraws the screen. { PSsetgray(NX_DKGRAY); NXRectFill(&bounds); return self; } - mouseDown:(NXEvent *)e // stolen from MandelView.m /* * We implement the mouseDown method so the user can sweep out a section of * the view and select that as the current x,y,scale coordinates. */ { int looping = YES; int oldMask; NXRect bbox; NXPoint startPoint, currPoint; double newX, newY, newDX, newDY; NXCoord aspectRatio; float mvX = xPos; float mvY = yPos; float mvDX = xScale; float mvDY = yScale; aspectRatio = bounds.size.height / bounds.size.width; oldMask = [window addToEventMask:NX_MOUSEDRAGGEDMASK]; startPoint = e->location; [self convertPoint:&startPoint fromView:nil]; NXSetRect(&bbox,startPoint.x,startPoint.y,0.0,0.0); [self lockFocus]; while (looping) { e=[NXApp getNextEvent:NX_MOUSEUPMASK | NX_MOUSEDRAGGEDMASK]; currPoint = e->location; [self convertPoint:&currPoint fromView:nil]; bbox.size.width = 2*(currPoint.x - startPoint.x); bbox.size.height = 2*(currPoint.y - startPoint.y); /* Normalize bbox to always have positive width and height */ if (bbox.size.width < 0) bbox.size.width = -bbox.size.width; if (bbox.size.height < 0) bbox.size.height = -bbox.size.height; /* * constrain the box to have the aspect ratio of the view. Choose * whichever dimension is closer to the desired result. */ if ((bbox.size.height/bbox.size.width) > aspectRatio) { bbox.size.height = bbox.size.width * aspectRatio; } else { bbox.size.width = bbox.size.height / aspectRatio; } /* The startPoint is always at the center of the bbox */ bbox.origin.x = startPoint.x - .5 * bbox.size.width; bbox.origin.y = startPoint.y - .5 * bbox.size.height; PSnewinstance(); if (looping = (e->type == NX_MOUSEDRAGGED)) { PSsetinstance(YES); PSsetgray(NX_WHITE); NXFrameRect(&bbox); PSsetinstance(NO); } } [self unlockFocus]; [window setEventMask:oldMask]; if ((bbox.size.width > 0) && (bbox.size.height > 0)) { /* * At this point, bbox is in window coordinates. Set new controller * parameters based on this view's coordinates and the bounding box. */ newDX = (bbox.size.width*mvDX)/bounds.size.width; newDY = (bbox.size.height*mvDY)/bounds.size.height; newX = ((startPoint.x + bounds.origin.x) / bounds.size.width); newX = newX * mvDX + mvX - newDX/2; newY = ((startPoint.y + bounds.origin.y) / bounds.size.height); newY = newY * mvDY + mvY - newDY/2; /* * Note that we only update the text fields -- we * don't update the internal instance variables. If we were to update * the internal ivs, then the user would only get one chance with the * mouse down method because subsequent mouse-downs would work in terms * of the new coordinate system. */ [[posMatrix findCellWithTag:0] setFloatValue:newX]; [[posMatrix findCellWithTag:1] setFloatValue:newY]; [[scaleMatrix findCellWithTag:0] setFloatValue:newDX]; [[scaleMatrix findCellWithTag:1] setFloatValue:newDY]; } return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.