スタンフォード大学のiPhoneアプリ開発講座の宿題(HelloPolly)

Hello Poly (Part I)Hello Poly (Part II)は以前の宿題で作成したPolygonShapeクラスを利用して、多角形のポリゴンを表示するというiPhoneアプリを作るという物である。

かなりのボリュームの宿題のため、全てのコードは載せないが、回答の要点だけを記載しておきたいと思う。

ポイントとしては、ポリゴンを表示するためにUIViewを継承した独自クラス(PolygonShape)を作成し、そのクラスのdrawRectメソッド内でCoreGrphicsのAPIを利用してポリゴンを描画する。

  • PolygonView.h
#import <UIKit/UIKit.h>
#import "PolygonShape.h"

@interface PolygonView : UIView {
	PolygonShape *polygon;
}
@property (assign) PolygonShape *polygon;
@end
  • PolygonView.m (drawRect)
- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGRect bounds = [self bounds];
    CGContextBeginPath(context);
    
    NSArray *pointsArray = [PolygonShape pointsForPolygonInRect:bounds
                        numberOfSides:[polygon numberOfSides]];
    NSEnumerator *pointsEnu = [pointsArray objectEnumerator];
    
    // firstPoint
    CGPoint firstPoint = [[pointsEnu nextObject] CGPointValue];
    CGContextMoveToPoint(context, firstPoint.x, firstPoint.y);
    // otherPoint
    for (NSValue *points in pointsEnu) {
        CGPoint thePoint = [points CGPointValue];
        CGContextAddLineToPoint(context, thePoint.x, thePoint.y);		
    }
    CGContextClosePath(context);
    [[UIColor redColor] setFill];
    [[UIColor blackColor] setStroke];
    CGContextDrawPath(context, kCGPathFillStroke);
}

単純にポリゴンを描画する以外に、追加課題としては以下のような物があった。

  • 何角形かを変更するスライダーを追加する。
  • ポリゴンを通常の線か破線で描くかを選択するスイッチを追加する。
  • 描画したポリゴンを指でタッチして回せるようにする。
  • 背景にグラデーションを付ける(ポリゴン内でも外でもどちらでもOK)。

以下、一部追加課題のやり方を簡単に記載。

  • ポリゴンを通常の線か破線で描くかを選択するスイッチを追加する。
// 破線にする場合
const CGFloat dashStyle[] = {4.0};
CGContextSetLineDash(context, 0.0, dashStyle, 1);
// 線の太さを変える場合
CGContextSetLineWidth(context, 4.0);
  • 描画したポリゴンを指でタッチして動かせるようにする。
// やり方は色々あると思うが、CGAffineTransformRotateを使用して
// PolygonViewごとローテーションさせるやり方
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    CGPoint olc_loc = [touch previousLocationInView:self];
    CGPoint new_loc = [touch locationInView:self];
    
    CGFloat angle = atan2(new_loc.y - olc_loc.y, new_loc.x - olc_loc.x);
    
    [UIView beginAnimations:@"advancedAnimations" context:nil];
    [UIView setAnimationDuration:0.3];
    self.transform = CGAffineTransformRotate(self.transform,
                                        angle / (2.0 * M_PI));
    [UIView commitAnimations];
}
  • 背景にグラデーションを付ける(ポリゴン内でも外でもどちらでもOK)。
    // ポリゴン内をグラデーションさせるには、CGContextClip(context)を
    // 使ってコンテキストを事前にクリップする必要有
    CGGradientRef gradient;
    CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
    CGFloat colors[] = 
    { 
        204.0 / 255.0, 224.0 / 255.0, 244.0 / 255.0, 1.00, 
        29.0 / 255.0, 156.0 / 255.0, 215.0 / 255.0, 1.00, 
        0.0 / 255.0,  50.0 / 255.0, 126.0 / 255.0, 1.00, 
    }; 
    gradient = CGGradientCreateWithColorComponents(rgb, colors,
                    NULL, sizeof(colors)/(sizeof(colors[0])*4)); 
    CGColorSpaceRelease(rgb);

より詳しい回答は以下をどうぞ。

私が作ったHelloPolyの最終形は以下。