The
View
’s
init
method sets the
backgroundColor
to
white.
The
drawRect(_:)
method draws the X and Y axes in blue and the graph of
AppDelegate.swift
:
unchanged.
ViewController.swift
:
unchanged.
View.swift
:
added the
init
that takes an
NSCoder
,
and
drawRect(_:)
.
Info.plist
:
the
UISupportedInterfaceOrientations
property now allows only one orientation.
To launch the app in landscape orientation, select the Sine project at the top of the Xcode Project Navigator. At the top of the center panel of Xcode, select General. Under Deployment Info → Device Orientation, check Landscape Left (home button on the left) and uncheck the other three orientations.
The graph of
sin
passes through the origin at a perfect 45°
angle.
The iPhone Y axis points downwards by default,
so
the
uprightTransform
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.
let y: CGFloat = sin(x);to any one of the following.
let y: CGFloat = cos(x) let y: CGFloat = x * x; //parabola let y: CGFloat = x * x / 4; //shorter parabola let y: CGFloat = -x * x / 4; //upside down parabola let y: CGFloat = sqrt(abs(x)); //sideways half parabola let y: CGFloat = sqrt(4 * 4 - x * x); //semicircle let y: CGFloat = x; //diagonal line let y: CGFloat = floor(x); //Walk like an Egyptian. let y: CGFloat = floor(4 * sin(x)); //Mayan ruins. let y: CGFloat = x * sin(3 * x); //CERN. let y: CGFloat = 3 * sin(80 / x); //The Outer Limits.Then change it back to
let y: CGFloat = sin(x);
c
.
The expression
" y = sin(x)"
String
.
let attributes: [String: AnyObject] = [NSFontAttributeName: UIFont.systemFontOfSize(24)]; " y = sin(x)".drawAtPoint(bounds.origin, withAttributes: attributes);
drawRect:
method of class
View
immediately before the
“Draw the axes in faint blue” comment.
//Create a callback that will be called over and over //to draw each cell of the graph paper. //Each cell consists of two lines: // | // | // | // +------------- let drawPattern: CGPatternDrawPatternCallback = {s, c in //draw pattern using context... let scale = UnsafePointer<CGFloat>(s).memory; CGContextBeginPath(c); CGContextSetLineWidth(c, 1 / scale); CGContextMoveToPoint(c, 0, 1); //top of L CGContextAddLineToPoint(c, 0, 0); //vertical line CGContextAddLineToPoint(c, CGFloat(M_PI / 2), 0); //horizontal line CGContextStrokePath(c); } var callbacks = CGPatternCallbacks(version: 0, drawPattern: drawPattern, releaseInfo: nil); let rect: CGRect = CGRect(x: 0, y: 0, width: pi/2, height: 1); //pattern's bounding box let pattern: CGPatternRef = CGPatternCreate( &scale, //first argument passed to drawPattern rect, transform, rect.size.width, rect.size.height, //no distance between cells CGPatternTiling.ConstantSpacing, false, //Graph paper is monochromatic (a "stencil" pattern). &callbacks )!; //Draw the background graph paper in very faint blue. CGContextBeginPath(c); //Tell it that the pattern's colors are RGB, not CYMK or grayscale. let colorSpace: CGColorSpaceRef = CGColorSpaceCreateDeviceRGB()!; let patternColorSpace: CGColorSpaceRef = CGColorSpaceCreatePattern(colorSpace)!; CGContextSetFillColorSpace(c, patternColorSpace); //Fill the background with the pattern. let color: [CGFloat] = [0, 0, 1, 0.25]; //rgb alpha CGContextSetFillPattern(c, pattern, color); CGContextFillRect(c, CGRectApplyAffineTransform(bounds, CGAffineTransformInvert(transform)));Change the
scale
that is decared right after pi
from a
let
to a
var
.
If we had just said
CGContextFillRect(c, bounds);instead of
CGContextFillRect(c, CGRectApplyAffineTransform(bounds, CGAffineTransformInvert(transform)));then only the first quadrant of the plane (to the upper right of the origin) would have been filled with graph paper. That’s because the pattern starts at the origin and moves towards higher x and y values.
scale
as a parameter to the callback
because the callback has no access to the variables in the surrounding method.
Could we also pass
rect
to the callback?
If so, we could change the third argument of
CGContextMoveToPoint
to
rect.size.height
,
and we could change the second argument of the second
CGContextAddLineToPoint
to
rect.size.width
.