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
main.m
SineAppDelegate
View
Sine-Info.plist
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.
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);
CGContextConcatCTM(c, translate)
.@" y = sin(x)"
NSString
.
UIFont *font = [UIFont systemFontOfSize: 24]; [@" y = sin(x)" drawAtPoint: CGPointZero withFont: font];
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);