矩形の重なりを求めるプログラム

二つの矩形の重なり領域を求めるには、次の方法で求められるようだ。

// 二つの矩形の重なり部分を求める。
static CGRect intersect(CGRect a, CGRect b) {
    float sx = MAX(a.origin.x, b.origin.x);
    float sy = MAX(a.origin.y, b.origin.y);
    float ex = MIN(a.origin.x + a.size.width, b.origin.x + b.size.width);
    float ey = MIN(a.origin.y + a.size.height, b.origin.y + b.size.height);
    
    float w = ex - sx;
    float h = ey - sy;
    if (w > 0 && h > 0) {
        return CGRectMake(sx, sy, w, h);
    }
    return CGRectMake(0, 0, 0, 0); // 重なっていない
}

二つの矩形の重なり領域を求めるiPhoneアプリを作ってみよう。次の順番にプログラムを作成していく。

  • 矩形を描画する
  • タッチ座標を取得して、その位置に矩形を描画する。
  • 画面中央に固定の矩形を描画、タッチ位置にもうひとつの矩形を描画。二つの矩形の重なり領域を描画。

はじめに矩形の描画から。CGContextStrokeRectを使うと矩形が描画される。

- (void)drawRect:(CGRect)rect
{
    CGContextRef c = UIGraphicsGetCurrentContext();
    CGContextSetRGBStrokeColor(c, 0, 0, 0, 1);
    CGContextSetLineWidth(c, 1);
    
    CGContextStrokeRect(c, CGRectMake(10, 10, 100, 100));
}

次にタッチ座標の取得して、その位置に矩形を描画する。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{
    UITouch* touch = [touches anyObject];
    _point = [touch locationInView:self];
    [self setNeedsDisplay];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch* touch = [touches anyObject];
    _point = [touch locationInView:self];
    [self setNeedsDisplay];
}

変数_pointにタッチ位置を保存している。setNeedsDisplayを呼び出して再描画を要求し、drawRect:の中で_pointの値を参照してタッチ位置に矩形を描画する。

drawRect:では、二つの矩形を描画し、その二つの矩形の重なり領域を求めている。

- (void)drawRect:(CGRect)rect
{
    CGContextRef c = UIGraphicsGetCurrentContext();
    CGContextSetRGBStrokeColor(c, 0, 0, 0, 1);
    CGContextSetLineWidth(c, 1);
    CGContextStrokeRect(c, _rect1);
    
    // タッチ位置に矩形を描画する
    float x = _point.x - _size.width / 2;
    float y = _point.y - _size.height / 2;
    CGRect rect2 = CGRectMake(x, y, _size.width, _size.height);
    CGContextStrokeRect(c, rect2);
    
    // 重なり部分を描画
    CGRect r = intersect(_rect1, rect2);    
    if (r.size.width > 0) {
        CGContextFillRect(c, r);
    }
}

以上で完成です。下のスクリーンショットのような感じで、重なり領域は黒で塗りつぶしています。

f:id:noriok:20120219215723p:plain

完成コードは以下です。

#import "MyView.h"

// 二つの矩形の重なり部分を求める。
static CGRect intersect(CGRect a, CGRect b) {
    float sx = MAX(a.origin.x, b.origin.x);
    float sy = MAX(a.origin.y, b.origin.y);
    float ex = MIN(a.origin.x + a.size.width, b.origin.x + b.size.width);
    float ey = MIN(a.origin.y + a.size.height, b.origin.y + b.size.height);
    
    float w = ex - sx;
    float h = ey - sy;
    if (w > 0 && h > 0) {
        return CGRectMake(sx, sy, w, h);
    }
    return CGRectMake(0, 0, 0, 0); // 重なっていない
}

@implementation MyView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        _point = CGPointMake(0, 0);   // タッチ座標
        _size  = CGSizeMake(200, 30); // タッチ座標に描画する矩形のサイズ
        
        _rect1 = CGRectMake(100, 100, 90, 90); // 固定位置に描画する矩形
    }
    return self;
}

- (void)drawRect:(CGRect)rect
{
    CGContextRef c = UIGraphicsGetCurrentContext();
    CGContextSetRGBStrokeColor(c, 0, 0, 0, 1);
    CGContextSetLineWidth(c, 1);
    CGContextStrokeRect(c, _rect1);
    
    // タッチ位置に矩形を描画する
    float x = _point.x - _size.width / 2;
    float y = _point.y - _size.height / 2;
    CGRect rect2 = CGRectMake(x, y, _size.width, _size.height);
    CGContextStrokeRect(c, rect2);
    
    // 重なり部分を描画
    CGRect r = intersect(_rect1, rect2);    
    if (r.size.width > 0) {
        CGContextFillRect(c, r);
    }
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{
    UITouch* touch = [touches anyObject];
    _point = [touch locationInView:self];
    [self setNeedsDisplay];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch* touch = [touches anyObject];
    _point = [touch locationInView:self];
    [self setNeedsDisplay];
}

@end