iPhone黄金三角形

五角形から黄金三角形(頂角:32°、底角72°の二等辺三角形)の作図過程をアニメーションで表示するiPhoneアプリを書いていきます。


動作イメージ
XcodeからiOS6 iPhone Simulatorで動かすとこんな感じになります。

ポイント
五角形を書いて、その底角と頂角を線で結ぶと黄金三角形の出来上がりです。説明文を表示するコンソールにボタン1とボタン2を配置して押された番号に合わせて、1なら黄金三角形を一つ、2なら黄金三角形を二つ表示するようにしました。

サンプルコード

#import “ViewController.h”

#import <QuartzCore/QuartzCore.h>

@interface ViewController () {

    UILabel *console;

    CAShapeLayer *pentagon;

    CAShapeLayer *lineLayer;

    CGPoint vertex[5];

    NSMutableArray *angleLabels;

}

@end

@implementation ViewController

– (void)viewDidLoad

{

    [super viewDidLoad];

    self.view.backgroundColor = [UIColor whiteColor];

[self createGridSheet];

    [self createConsole];

    [self createPentagon];

}

– (void)createPentagon

{

    float r = 140;

    float dAngle = 2 * M_PI / 5.0;

    CGPoint o = CGPointMake(160, 380);

    

    for (int i=0; i<5; i++) {

        float angle = dAngle * i – M_PI/2.0;

        float x = r * cos(angle) + o.x;

        float y = r * sin(angle) + o.y;

        vertex[i] = CGPointMake(x, y);

    }

    

    UIBezierPath *path = [UIBezierPath bezierPath];

    [path moveToPoint:vertex[0]];

    for (int i=1; i<5; i++) {

        [path addLineToPoint:vertex[i]];

    }

    [path closePath];

    

    pentagon = [[CAShapeLayer alloc] init];

    pentagon.fillColor = [UIColor clearColor].CGColor;

    pentagon.strokeColor = [UIColor blackColor].CGColor;

    pentagon.lineWidth = 1;

    pentagon.path = path.CGPath;

    

    [self.view.layer addSublayer:pentagon];

}

– (void)createConsole

{

    console = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 280, 280/1.618)];

    console.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];

    console.text = @”黄金三角形の書き方;

    console.textAlignment = NSTextAlignmentCenter;

    console.textColor = [UIColor whiteColor];

    [self.view addSubview:console];

    

    for (int i=0; i<2; i++) {

        float x = console.bounds.size.width45 * (2-i);

        float y = console.bounds.size.height45;

        UILabel *btn = [[UILabel alloc] initWithFrame:CGRectMake(x, y, 40, 40)];

        btn.layer.cornerRadius = 20;

        btn.text = [NSString stringWithFormat:@”%d”, i + 1];

        btn.textAlignment = NSTextAlignmentCenter;

        btn.font = [UIFont boldSystemFontOfSize:20];

        btn.textColor = [UIColor lightGrayColor];

        btn.backgroundColor = [UIColor clearColor];

        btn.layer.borderColor = [UIColor lightGrayColor].CGColor;

        btn.layer.borderWidth = 4.0;

        [console addSubview:btn];

        

        console.userInteractionEnabled = YES;

        btn.userInteractionEnabled = YES;

        btn.tag = i + 1;

        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapButton:)];

        [btn addGestureRecognizer:tap];

    }

}

– (void)tapButton:(UITapGestureRecognizer*)gr

{

    switch (gr.view.tag) {

        case 1:

            [self showGoldenTriangleFromPentagon];

            break;

            

        case 2:

            [self showSecondaryGoldenTriangleFromPentagon];

            break;

            

        default:

            break;

    }

}

– (void)showGoldenTriangleFromPentagon

{

    [self clearCanvas];

    [self createPentagon];

    

    console.text = @”五角形の底角と頂点を結ぶ;

    lineLayer = [[CAShapeLayer alloc] init];

    lineLayer.strokeColor = [UIColor redColor].CGColor;

    lineLayer.fillColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:0.3].CGColor;

    lineLayer.lineWidth = 2.0;

    [self.view.layer addSublayer:lineLayer];

    UIBezierPath *path = [UIBezierPath bezierPath];

    [path moveToPoint:vertex[0]];

    [path addLineToPoint:vertex[2]];

    [path addLineToPoint:vertex[3]];

    [path closePath];

    

    lineLayer.path = path.CGPath;

    [self startDraw:lineLayer duration:1.5];

    

    // 角度を表示

    CGPoint p[] = {

        CGPointMake(vertex[0].x, vertex[0].y + 40),

        CGPointMake(vertex[2].x20, vertex[2].y20),

        CGPointMake(vertex[3].x + 20, vertex[3].y20),

    };

    NSArray *angles = @[@”36°”, @”72°”, @”72°”];

    for (int i=0; i<3; i++) {

        UILabel *angleLabel = [[UILabel alloc] init];

        angleLabel.text = [angles objectAtIndex:i];

        angleLabel.backgroundColor = [UIColor clearColor];

        [angleLabel sizeToFit];

        angleLabel.center = p[i];

        angleLabel.alpha = 0;

        [self.view addSubview:angleLabel];

        

        if (!angleLabels) {

            angleLabels = [[NSMutableArray alloc] init];

        }

        [angleLabels addObject:angleLabel];

        

        [UIView animateWithDuration:1.0 animations:^{

            angleLabel.alpha = 1.0;

        }];

    }

}

– (void)showSecondaryGoldenTriangleFromPentagon

{

    [self clearCanvas];

    [self createPentagon];

    

    console.text = @”二次的な黄金三角形;

    lineLayer = [[CAShapeLayer alloc] init];

    lineLayer.strokeColor = [UIColor redColor].CGColor;

    lineLayer.fillColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:0.3].CGColor;

    lineLayer.lineWidth = 2.0;

    [self.view.layer addSublayer:lineLayer];

    UIBezierPath *path = [UIBezierPath bezierPath];

    [path moveToPoint:vertex[0]];

    [path addLineToPoint:vertex[2]];

    [path addLineToPoint:vertex[3]];

    [path closePath];

    

    [path moveToPoint:vertex[1]];

    [path addLineToPoint:vertex[3]];

    [path addLineToPoint:vertex[4]];

    [path closePath];

    

    

    lineLayer.path = path.CGPath;

    [self startDraw:lineLayer duration:1.5];

    

    // 角度を表示

    CGPoint p[] = {

        CGPointMake(vertex[0].x + 5, vertex[0].y + 30),

        CGPointMake(vertex[2].x60, vertex[1].y10),

        CGPointMake(vertex[3].x + 70, vertex[1].y10),

        CGPointMake(vertex[1].x25, vertex[1].y + 10),

        CGPointMake(vertex[1].x80, vertex[1].y + 10),

        CGPointMake(vertex[1].x70, vertex[1].y + 40),

        CGPointMake(vertex[3].x + 40, vertex[3].y10),

        CGPointMake(vertex[2].x20, vertex[2].y10),

        CGPointMake(vertex[2].x40, vertex[2].y70),

    };

    NSArray *angles = @[@”36°”, @”72°”, @”72°”];

    for (int i=0; i<9; i++) {

        UILabel *angleLabel = [[UILabel alloc] init];

        angleLabel.text = [angles objectAtIndex:i%3];

        angleLabel.backgroundColor = [UIColor clearColor];

        [angleLabel sizeToFit];

        angleLabel.center = p[i];

        angleLabel.alpha = 0;

        [self.view addSubview:angleLabel];

        

        if (!angleLabels) {

            angleLabels = [[NSMutableArray alloc] init];

        }

        [angleLabels addObject:angleLabel];

        

        [UIView animateWithDuration:1.0 animations:^{

            angleLabel.alpha = 1.0;

        }];

    }

}

– (void)clearCanvas

{

    [pentagon removeFromSuperlayer];

    [lineLayer removeFromSuperlayer];

    

    for (UIView *v in angleLabels) {

        [v removeFromSuperview];

    }

    [angleLabels removeAllObjects];

}

#pragma mark – utility methods

– (void)createGridSheet

{

    UIBezierPath *path = [UIBezierPath bezierPath];

    float size = 32;

    for (int i=0; i<320/size; i++) {

        [path moveToPoint:CGPointMake(i * size, 0)];

        [path addLineToPoint:CGPointMake(i * size, 568)];

    }

    

    for (int i=0; i<568/size; 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 greenColor].CGColor;

    sl.lineWidth = 2;

    sl.lineDashPattern = @[@8, @2];

    sl.path = path.CGPath;

    

    [self.view.layer addSublayer:sl];

}

– (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