Sine

The application delegate contains two instance variables: a window and a View (derived from UIView). The View has an initWithFrame: method that sets the background color to white. It also has a drawRect: method that draws the X axis, Y axis, and the graph of

y = sin(x)
as x goes from –2π to 2π.

Source code in Sine.zip

  1. main.m
  2. Class SineAppDelegate
  3. Class View
  4. Sine-Info.plist

Stroke the path

The graph of sin passes through the origin at a perfect 45° angle. The iPhone Y axis points downwards by default, so CGContextScaleCTM has a negative vertical scale to make it point upwards. (Yes, I know the loop counter should have been an integer to avoid roundoff errors.)

Since we are drawing lines instead of filling in areas, we must call CGContextSetRGBStrokeColor instead of CGContextSetRGBFillColor. At the end, we must call CGContextStrokePath instead of CGContextFillPath. A minor bother when connecting a series of points with lines is that we have to call CGContextMoveToPoint for the first point and CGContextAddLineToPoint for each subsequent point.

Things to try

  1. Would it look more Bauhaus with a line width of 10?

  2. Graph a different function. Change the punchline
    		CGFloat y = sinf(x);
    
    to any one of the following.
    		CGFloat y = cosf(x)
    
    		CGFloat y = x * x;	//parabola
    		CGFloat y = x * x / 4;	//shorter parabola
    		CGFloat y = -x * x / 4;	//upside down parabola
    		CGFloat y = sqrtf(fabsf(x));	//sideways half parabola
    		CGFloat y = sqrtf(5 * 5 - x * x);	//semicircle
    
    		CGFloat y = x;		//diagonal line
    		CGFloat y = floorf(x);	//Walk like an Egyptian.
    		CGFloat y = floorf(5 * sinf(x));	//Mayan ruins.
    		CGFloat y = x * sinf(3 * x);	//CERN.
    		CGFloat y = 3 * sinf(80 / x);	//The Outer Limits.
    
    Then change it back to
    		CGFloat y = sinf(x);
    

  3. Draw a caption in the upper left corner before the call to CGContextConcatCTM(c, translate). The expression @" y = sin(x)" is an object of class NSString.
    	UIFont *font = [UIFont systemFontOfSize: 24];
    	[@" y = sin(x)" drawAtPoint: CGPointZero withFont: font];
    

  4. Use a pattern to draw graph paper in the background, a bit lighter than the axes. The following function is not a method. Insert it into View.m immediately above the @implementation directive.
    /*
    Each cell of the graph paper has two lines at a right angle:
    
    	|
    	|
    	|
    	+-------------
    */
    
    //Dimensions of each cell.  The cell will be scaled (magnified) by the
    //same factor as the main drawing, so we have to make the lines very thin.
    
    const CGFloat hSize = M_PI / 2; //horizontal: 1/2 the length of 1 hump of sine curve
    const CGFloat vSize = 1;        //vertical: height of hump
    
    static void drawCell(void *p, CGContextRef c)
    {
    	CGFloat scale = *(CGFloat *)p;
    	CGContextSetLineWidth(c, 1 / scale);
    	CGContextBeginPath(c);
    
    	CGContextMoveToPoint(c, 0, vSize);	//top of L
    	CGContextAddLineToPoint(c, 0, 0);	//vertical line
    	CGContextAddLineToPoint(c, hSize, 0);	//horizontal line
    
    	CGContextStrokePath(c);
    }
    
    Insert the following code into the drawRect: method of class View immediately after you create scale.
    	//Pattern cell origin in lower left corner, Y axis points up.
    	CGAffineTransform patternScale = CGAffineTransformMakeScale(scale,  scale);
    
    	CGAffineTransform patternTransform =
    		CGAffineTransformConcat(patternScale, translate);
    
    	//Graph paper, faint blue in background.
    
    	//Tell it that our colors are RGB, not CYMK or grayscale.
    	CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceRGB();
    	CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(baseSpace);
    	CGContextSetFillColorSpace(c, patternSpace);
    	CGColorSpaceRelease(patternSpace);
    	CGColorSpaceRelease(baseSpace);
    
    	static const CGPatternCallbacks callbacks = {0, drawCell, NULL};
    
    	CGPatternRef pattern = CGPatternCreate(
    		&scale,		//argument passed to drawCell
    		CGRectMake(0, 0, hSize, vSize),
    		patternTransform,
    		hSize, vSize,	//distance between cells: none at all
    		kCGPatternTilingConstantSpacing,
    		false,	//Graph paper is monochromatic (a "stencil" pattern).
    		&callbacks
    	);
    
    	static const CGFloat color[] = {0, 0, 1, 0.25};	//rgb alpha
    	CGContextSetFillPattern(c, pattern, color);
    	CGPatternRelease(pattern);
    	CGContextFillRect(c, self.bounds);