Last active
December 16, 2015 00:29
-
-
Save C4Tutorials/5348431 to your computer and use it in GitHub Desktop.
Trigonometry Tutorial
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// C4WorkSpace.m | |
// Trigonometry Tutorial | |
// | |
// Created by Travis Kirton. | |
// | |
#import "C4WorkSpace.h" | |
@implementation C4WorkSpace { | |
CGPoint A, B, C, D, M, P, Q, X, Y; | |
CGFloat radius, theta, dX, dY, s, slope, b, thetaA, thetaB; | |
C4Shape *circle, *poly, *mPt, *pPt, *qPt, *xPt, *yPt, *angleB, *angleD, *linePQ; | |
C4Label *lblA, *lblB, *lblC, *lblD, *lblM, *lblP, *lblQ, *lblX, *lblY; | |
} | |
-(void)setup { | |
[self setupCircleAndPoly]; | |
xPt = [C4Shape ellipse:CGRectMake(0, 0, 7, 7)]; | |
xPt.lineWidth = 2.0f; | |
xPt.strokeColor = C4GREY; | |
xPt.fillColor = C4RED; | |
[self setX]; | |
mPt = [xPt copy]; | |
[self setM]; | |
yPt = [mPt copy]; | |
[self setY]; | |
pPt = [yPt copy]; | |
qPt = [pPt copy]; | |
[self setPQ]; | |
angleD = [C4Shape ellipse:CGRectMake(0, 0, 80, 80)]; | |
angleD.style = circle.style; | |
angleB = [angleD copy]; | |
[self setAngleBD]; | |
[self createLabels]; | |
[self setLabelPositions]; | |
[self addShapesToPoly]; | |
[self addLabelsToPoly]; | |
[self addGesture:PAN name:@"adjust" action:@"adjust:"]; | |
[self maximumNumberOfTouches:1 forGesture:@"adjust"]; | |
[self addGesture:PAN name:@"rotate" action:@"rotate:"]; | |
[self minimumNumberOfTouches:2 forGesture:@"rotate"]; | |
} | |
-(void)setupCircleAndPoly { | |
circle = [C4Shape ellipse:CGRectMake(0,0,368,368)]; | |
circle.lineWidth = 2.0f; | |
circle.strokeColor = C4GREY; | |
circle.fillColor = [UIColor clearColor]; | |
thetaA = 1.15f; | |
thetaB = 0.3f; | |
radius = circle.width / 2.0f; | |
theta = PI * thetaA; | |
A = CGPointMake(radius*[C4Math sin:theta], radius*[C4Math cos:theta]); | |
theta = PI * thetaB; | |
B = CGPointMake(radius*[C4Math sin:theta], radius*[C4Math cos:theta]); | |
theta = PI * (2.0f-thetaA); | |
C = CGPointMake(radius*[C4Math sin:theta], radius*[C4Math cos:theta]); | |
theta = PI * (2.0f-thetaB); | |
D = CGPointMake(radius*[C4Math sin:theta], radius*[C4Math cos:theta]); | |
CGPoint polypts[4] = {A,B,C,D}; | |
poly = [C4Shape polygon:polypts pointCount:4]; | |
poly.style = circle.style; | |
poly.lineJoin = JOINBEVEL; | |
[poly closeShape]; | |
CGPoint polyAnchor = A; | |
polyAnchor.x = [C4Math map:polyAnchor.x fromMin:poly.origin.x max:poly.origin.x+poly.width toMin:0 max:1]; | |
polyAnchor.y = [C4Math map:polyAnchor.y fromMin:poly.origin.y max:poly.origin.y+poly.height toMin:0 max:1]; | |
poly.anchorPoint = polyAnchor; | |
poly.center = CGPointMake(circle.center.x+A.x,circle.center.x+A.y); | |
[circle addShape:poly]; | |
[self.canvas addShape:circle]; | |
circle.center = self.canvas.center; | |
} | |
-(void)setX { | |
//X is the mid-point of AD | |
X = CGPointMake((D.x + A.x)/2.0f,(D.y+A.y)/2.0f); | |
xPt.center = X; | |
} | |
-(void)setM { | |
//M is the intersection of the two internal lines of the polygon | |
CGFloat a1 = B.y - A.y; | |
CGFloat b1 = A.x - B.x; | |
CGFloat c1 = a1*A.x + b1*A.y; | |
CGFloat a2 = D.y - C.y; | |
CGFloat b2 = C.x - D.x; | |
CGFloat c2 = a2*C.x + b2*C.y; | |
CGFloat det = a1*b2 - a2 * b1; | |
M = CGPointMake((b2*c1 - b1*c2)/det, (a1*c2 - a2*c1)/det); | |
mPt.center = M; | |
} | |
-(void)setY { | |
CGFloat angleMCB = [self angleFromA:M b:C c:B]; | |
CGFloat angleCMY = [self angleFromA:X b:M c:D];//because they're equal | |
CGFloat angleCYM = PI - angleMCB - angleCMY; | |
CGFloat dCM = [C4Vector distanceBetweenA:C andB:M]; | |
CGFloat dMY = dCM/[C4Math sin:angleCYM] * [C4Math sin:angleMCB]; | |
dX = M.x - X.x; | |
dY = M.y - X.y; | |
CGFloat dMX = [C4Vector distanceBetweenA:M andB:X]; | |
CGFloat multiplier = (dMX + dMY)/dMX; | |
Y = CGPointMake(X.x + dX * multiplier, X.y + dY * multiplier); | |
yPt.center = Y; | |
} | |
-(CGFloat)angleFromA:(CGPoint)pt1 b:(CGPoint)pt2 c:(CGPoint)pt3 { | |
pt1.x -= pt2.x; | |
pt1.y -= pt2.y; | |
pt3.x -= pt2.x; | |
pt3.y -= pt2.y; | |
return [C4Vector angleBetweenA:pt1 andB:pt3]; | |
} | |
-(void)setPQ { | |
slope = dY / dX; | |
b = M.y; | |
CGFloat dr = [C4Math sqrt:(dX*dX+dY*dY)]; | |
CGFloat bigD = X.x*M.y - M.x*X.y; | |
CGFloat x, y; | |
//equ for x via wolfram | |
//x = (D*dY +- sgn(dY)*dx *sqrt(r2*dr2-D2))/dr2; | |
CGFloat sgn = dY / [C4Math absf:dY]; | |
x = (bigD*dY+sgn*dX*[C4Math sqrt:radius*radius*dr*dr-bigD*bigD])/(dr*dr); | |
y = slope*x + b; | |
P = CGPointMake(x, y); | |
x = (bigD*dY-sgn*dX*[C4Math sqrt:radius*radius*dr*dr-bigD*bigD])/(dr*dr); | |
y = slope*x + b; | |
Q = CGPointMake(x, y); | |
if(slope > 0) { | |
CGPoint temp = P; | |
P = Q; | |
Q = temp; | |
} | |
pPt.center = P; | |
qPt.center = Q; | |
} | |
-(void)addShapesToPoly { | |
CGPoint linePts[2] = {P,Q}; | |
linePQ = [C4Shape line:linePts]; | |
linePQ.style = circle.style; | |
[poly addObjects:@[angleB,angleD]]; | |
[poly addObjects:@[linePQ,mPt,xPt,yPt,pPt,qPt]]; | |
} | |
-(void)addLabelsToPoly { | |
[poly addObjects:@[lblA, lblB, lblC, lblD, lblM, lblP, lblQ, lblX, lblY]]; | |
} | |
-(void)setAngleBD { | |
theta = [self angleFromA:A b:D c:C]; | |
[angleD removeFromSuperview]; | |
angleD = nil; | |
[angleB removeFromSuperview]; | |
angleB = nil; | |
CGFloat dAD = [C4Vector distanceBetweenA:A andB:D]; | |
CGFloat r = [C4Math maxOfA:80 B:10.0f]; | |
angleD = [C4Shape ellipse:CGRectMake(0, 0, r, r)]; | |
angleD.style = circle.style; | |
angleD.center = D; | |
angleB = [angleD copy]; | |
angleB.center = B; | |
CGFloat rot = [self angleFromA:C b:D c:B]; | |
angleD.strokeStart = 1 - theta/TWO_PI - rot/TWO_PI; | |
angleD.strokeEnd = angleD.strokeStart + theta/TWO_PI; | |
angleB.strokeStart = rot/TWO_PI + 0.5f; | |
angleB.strokeEnd = angleB.strokeStart + theta/TWO_PI; | |
} | |
-(void)createLabels { | |
lblA = [C4Label labelWithText:@"A" font:[C4Font fontWithName:@"TimesNewRomanPS-ItalicMT" size:16.0f]]; | |
lblB = [C4Label labelWithText:@"B" font:lblA.font]; | |
lblC = [C4Label labelWithText:@"C" font:lblA.font]; | |
lblD = [C4Label labelWithText:@"D" font:lblA.font]; | |
lblP = [C4Label labelWithText:@"P" font:lblA.font]; | |
lblQ = [C4Label labelWithText:@"Q" font:lblA.font]; | |
lblM = [C4Label labelWithText:@"M" font:lblA.font]; | |
lblX = [C4Label labelWithText:@"X" font:lblA.font]; | |
lblY = [C4Label labelWithText:@"Y" font:lblA.font]; | |
} | |
-(void)setLabelPositions { | |
lblA.center = CGPointMake(A.x - 6.0f, A.y - 8.0f); | |
lblB.center = CGPointMake(B.x + 5.0f, B.y + 8.0f); | |
lblC.center = CGPointMake(C.x + 6.0f, C.y - 8.0f); | |
lblD.center = CGPointMake(D.x - 6.0f, D.y + 8.0f); | |
lblP.center = CGPointMake(P.x - 16.0f, P.y + 4.0f); | |
lblQ.center = CGPointMake(Q.x + 14.0f, Q.y - 4.0f); | |
lblM.center = CGPointMake(M.x-1.0f, M.y-16.0f); | |
lblX.center = CGPointMake(X.x-10.0f, X.y-8.0f); | |
lblY.center = CGPointMake(Y.x+12.0f, Y.y+8.0f); | |
} | |
-(void)adjust:(UIPanGestureRecognizer *)gesture { | |
CGPoint p = [gesture locationInView:self.canvas]; | |
CGFloat rot = (p.x / self.canvas.width)/2.0f; | |
if(p.y < self.canvas.center.y) [self setThetaA:rot+1 thetaB:thetaB]; | |
else [self setThetaA:thetaA thetaB:rot]; | |
} | |
-(void)rotate:(UIPanGestureRecognizer *)gesture { | |
CGPoint p = [gesture translationInView:self.canvas]; | |
p.x *= TWO_PI/self.canvas.width; | |
circle.rotation += p.x; | |
[gesture setTranslation:CGPointZero inView:self.canvas]; | |
lblA.rotation = -circle.rotation; | |
lblB.rotation = -circle.rotation; | |
lblC.rotation = -circle.rotation; | |
lblD.rotation = -circle.rotation; | |
lblM.rotation = -circle.rotation; | |
lblP.rotation = -circle.rotation; | |
lblQ.rotation = -circle.rotation; | |
lblX.rotation = -circle.rotation; | |
lblY.rotation = -circle.rotation; | |
} | |
-(void)setThetaA:(CGFloat)_thetaA thetaB:(CGFloat)_thetaB { | |
thetaA = _thetaA; | |
thetaB = _thetaB; | |
[poly removeFromSuperview]; | |
radius = circle.width / 2.0f; | |
theta = PI * thetaA; | |
A = CGPointMake(radius*[C4Math sin:theta], radius*[C4Math cos:theta]); | |
theta = PI * thetaB; | |
B = CGPointMake(radius*[C4Math sin:theta], radius*[C4Math cos:theta]); | |
theta = PI * (2.0f-thetaA); | |
C = CGPointMake(radius*[C4Math sin:theta], radius*[C4Math cos:theta]); | |
theta = PI * (2.0f-thetaB); | |
D = CGPointMake(radius*[C4Math sin:theta], radius*[C4Math cos:theta]); | |
CGPoint polypts[4] = {A,B,C,D}; | |
poly = [C4Shape polygon:polypts pointCount:4]; | |
poly.style = circle.style; | |
poly.lineJoin = JOINBEVEL; | |
CGPoint polyAnchor = A; | |
polyAnchor.x = [C4Math map:polyAnchor.x fromMin:poly.origin.x max:poly.origin.x+poly.width toMin:0 max:1]; | |
polyAnchor.y = [C4Math map:polyAnchor.y fromMin:poly.origin.y max:poly.origin.y+poly.height toMin:0 max:1]; | |
poly.anchorPoint = polyAnchor; | |
poly.center = CGPointMake(circle.width/2.0f+A.x,circle.height/2.0f+A.y); | |
[poly closeShape]; | |
[circle addShape:poly]; | |
[self.canvas addShape:circle]; | |
circle.center = self.canvas.center; | |
[self setX]; | |
[self setM]; | |
[self setY]; | |
[self setPQ]; | |
[self setAngleBD]; | |
[self setLabelPositions]; | |
[self addShapesToPoly]; | |
[self setLabelPositions]; | |
[self addLabelsToPoly]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment