比率(1 : 2 : √5)の直角三角形ABCから黄金長方形の作成過程を動画で表示するiPhoneアプリを作っていきます。辺ABを半径にした円弧を描きます、円と辺ACの交点を点Dとして、CからDまでの長さを半径にした円をまた描きます辺BCとの交点をEとすると、黄金分割、BE:EC = 1:1.618 の出来上がり。
動作イメージ
XcodeからiOS6 iPhone Simulatorで動かすとこんな感じになります。
ポイント
画面の下の方に、書き方の説明と、次の手順に進むためのボタンを表示してみました。三角形は、画面の上部に表示しておいて、線はUIBezierPathとCAShapeLayerで描いています。次へをタップするタイミングで、UIBezierPathにアニメーションをかけています。
サンプルコード
#import “ViewController.h”
#import <QuartzCore/QuartzCore.h>
@interface ViewController () {
UILabel *console;
int page;
CGPoint A, B, C, D, E;
float angleA;
}
@end
@implementation ViewController
– (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor colorWithWhite:0.9 alpha:1];
[self createGridSheet];
// 1. AB:AC = 1:2の直角三角形 ABC
[self createRightTriangle];
[self createConsole];
}
– (void)createGridSheet
{
UIBezierPath *path = [UIBezierPath bezierPath];
float size = 16;
for (int i=0; i<20; i++) {
[path moveToPoint:CGPointMake(i * size, 0)];
[path addLineToPoint:CGPointMake(i * size, 568)];
}
for (int i=0; i<34; i++) {
[path moveToPoint:CGPointMake(0, i*size)];
[path addLineToPoint:CGPointMake(320, i*size)];
}
CAShapeLayer *sl = [[CAShapeLayer alloc] init];
sl.fillColor = [UIColor clearColor].CGColor;
sl.strokeColor = [UIColor colorWithRed:0 green:1 blue:0 alpha:0.5].CGColor;
sl.lineWidth = 1;
sl.path = path.CGPath;
[self.view.layer addSublayer:sl];
}
– (void)createRightTriangle
{
A = CGPointMake(50, 80);
B = CGPointMake(50, 190);
C = CGPointMake(270, 190);
// for D
angleA = atan2f(2, 1);
D = CGPointMake(A.x + 110.0 * sin(angleA), A.y + 110.0 * cos(angleA));
// for E
E = CGPointMake((220.0 / 2.618) + 50, 190);
// 1:2:√5
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:A];
[path addLineToPoint:B];
[path addLineToPoint:C];
[path closePath];
CAShapeLayer *sl = [[CAShapeLayer alloc] init];
sl.fillColor = [UIColor colorWithWhite:0 alpha:0.1].CGColor;
sl.strokeColor = [UIColor colorWithWhite:0 alpha:0.6].CGColor;
sl.lineWidth = 1;
sl.path = path.CGPath;
[self.view.layer addSublayer:sl];
// Label
UILabel *la = [[UILabel alloc] init];
la.font = [UIFont boldSystemFontOfSize:20];
la.text = @”A”;
la.textColor = [UIColor purpleColor];
la.backgroundColor = [UIColor clearColor];
[la sizeToFit];
la.center = CGPointMake(A.x – 10, A.y – 10);
[self.view addSubview:la];
UILabel *lb = [[UILabel alloc] init];
lb.font = [UIFont boldSystemFontOfSize:20];
lb.text = @”B”;
lb.textColor = [UIColor orangeColor];
lb.backgroundColor = [UIColor clearColor];
[lb sizeToFit];
lb.center = CGPointMake(B.x – 10, B.y + 10);
[self.view addSubview:lb];
UILabel *lc = [[UILabel alloc] init];
lc.font = [UIFont boldSystemFontOfSize:20];
lc.text = @”C”;
lc.textColor = [UIColor blueColor];
lc.backgroundColor = [UIColor clearColor];
[lc sizeToFit];
lc.center = CGPointMake(C.x + 10, C.y + 10);
[self.view addSubview:lc];
}
– (void)createConsole
{
console = [[UILabel alloc] initWithFrame:CGRectMake(20, 400, 280, 100)];
console.text = @”1 : 2 : √5 の三角形を描きます。“;
console.font = [UIFont systemFontOfSize:15];
console.textAlignment = 1;
console.backgroundColor = [UIColor colorWithWhite:0.3 alpha:0.3];
console.layer.cornerRadius = 10;
[self.view addSubview:console];
UILabel *next = [[UILabel alloc] initWithFrame:CGRectMake(200, 60, 80, 50)];
next.backgroundColor = [UIColor colorWithWhite:0 alpha:0.01];
next.text = @”- 次へ -“;
next.textAlignment = 1;
next.font = [UIFont boldSystemFontOfSize:15];
[console addSubview:next];
CABasicAnimation *ba = [CABasicAnimation animationWithKeyPath:@”opacity”];
ba.fromValue = @0.3;
ba.toValue = @1;
ba.duration = 1.0;
ba.repeatCount = 1000;
[next.layer addAnimation:ba forKey:nil];
console.userInteractionEnabled = YES;
next.userInteractionEnabled = YES;
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(next:)];
[next addGestureRecognizer:tap];
}
– (void)next:(UITapGestureRecognizer*)gr
{
page++;
switch (page) {
case 1:
[self arcWithCenterA];
console.text = @”線ABを半径に円を描きます。“;
break;
case 2:
[self arcWithCenterC];
console.text = @”線CDを半径に円をまた描きます。“;
break;
case 3:
[self createGoldenRectangle];
console.text = @”BE:EC = 1:1.618 ができました“;
break;
default:
break;
}
}
– (void)arcWithCenterA
{
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:A];
[path addLineToPoint:B];
float radius = A.y – B.y;
[path addArcWithCenter:A radius:radius startAngle:-M_PI/2.0 endAngle:-M_PI clockwise:NO];
CAShapeLayer *s1 = [[CAShapeLayer alloc] init];
s1.fillColor = [UIColor clearColor].CGColor;
s1.strokeColor = [UIColor redColor].CGColor;
s1.lineWidth = 2;
s1.lineDashPattern = @[@5, @5];
s1.path = path.CGPath;
[self.view.layer addSublayer:s1];
// animation UIBezierPath
[self startDraw:s1 duration:2.0];
UILabel *ld = [[UILabel alloc] init];
ld.font = [UIFont boldSystemFontOfSize:20];
ld.text = @”D”;
ld.textColor = [UIColor darkGrayColor];
ld.backgroundColor = [UIColor clearColor];
[ld sizeToFit];
ld.center = CGPointMake(D.x + 10, D.y – 10);
[self.view addSubview:ld];
}
– (void)arcWithCenterC
{
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:C];
[path addLineToPoint:D];
float radius = hypotf(C.x – D.x, C.y – D.y);
float start = M_PI + (M_PI/2.0 – angleA);
[path addArcWithCenter:C radius:radius startAngle:start endAngle:start – M_PI * 0.2 clockwise:NO];
CAShapeLayer *s1 = [[CAShapeLayer alloc] init];
s1.fillColor = [UIColor clearColor].CGColor;
s1.strokeColor = [UIColor redColor].CGColor;
s1.lineWidth = 2;
s1.lineDashPattern = @[@5, @5];
s1.path = path.CGPath;
[self.view.layer addSublayer:s1];
[self startDraw:s1 duration:2.0];
UILabel *le = [[UILabel alloc] init];
le.font = [UIFont boldSystemFontOfSize:20];
le.text = @”E”;
le.textColor = [UIColor darkGrayColor];
le.backgroundColor = [UIColor clearColor];
[le sizeToFit];
le.center = CGPointMake(E.x, E.y + 10);
[self.view addSubview:le];
}
– (void)createGoldenRectangle
{
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(E.x, E.y + 50)];
[path addLineToPoint:CGPointMake(E.x, E.y + 55)];
[path moveToPoint:CGPointMake(E.x, E.y + 50)];
[path addLineToPoint:CGPointMake(C.x, C.y + 50)];
CAShapeLayer *s1 = [[CAShapeLayer alloc] init];
s1.fillColor = [UIColor clearColor].CGColor;
s1.strokeColor = [UIColor redColor].CGColor;
s1.lineWidth = 2;
s1.path = path.CGPath;
[self.view.layer addSublayer:s1];
[self startDraw:s1 duration:0.5];
[self performSelector:@selector(createGoldenRectangle2) withObject:nil afterDelay:1.0];
[self performSelector:@selector(createGoldenRectangle3) withObject:nil afterDelay:2.0];
[self performSelector:@selector(createGoldenRectangle4) withObject:nil afterDelay:3.0];
}
– (void)createGoldenRectangle2
{
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(B.x, B.y + 50)];
[path addLineToPoint:CGPointMake(E.x, E.y + 50)];
CAShapeLayer *s2 = [[CAShapeLayer alloc] init];
s2.fillColor = [UIColor clearColor].CGColor;
s2.strokeColor = [UIColor redColor].CGColor;
s2.lineWidth = 2;
s2.path = path.CGPath;
[self.view.layer addSublayer:s2];
[self startDraw:s2 duration:0.5];
}
– (void)createGoldenRectangle3
{
CALayer *l = [self.view.layer.sublayers lastObject];
CATransform3D t = l.transform;
t = CATransform3DTranslate(t, E.x, E.y + 50, 0);
t = CATransform3DRotate(t, – M_PI *0.5, 0, 0, 1);
t = CATransform3DTranslate(t, –E.x, –E.y – 50, 0);
[UIView animateWithDuration:0.5 animations:^{
l.transform = t;
}];
}
– (void)createGoldenRectangle4
{
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(E.x, E.y + (E.x – B.x + 50))];
[path addLineToPoint:CGPointMake(C.x, C.y + (E.x – B.x + 50))];
[path addLineToPoint:CGPointMake(C.x, C.y + 50)];
CAShapeLayer *s2 = [[CAShapeLayer alloc] init];
s2.fillColor = [UIColor clearColor].CGColor;
s2.strokeColor = [UIColor redColor].CGColor;
s2.lineWidth = 2;
s2.path = path.CGPath;
[self.view.layer addSublayer:s2];
[self startDraw:s2 duration:0.5];
}
– (void)startDraw:(CALayer*)l duration:(float)duration
{
CABasicAnimation *a = [CABasicAnimation animationWithKeyPath:@”strokeEnd”];
a.duration = duration;
a.fromValue = @0;
a.toValue = @1;
[l addAnimation:a forKey:@”strokeEnd”];
}
– (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end