home link download back number special issue

HMDT - Special Issue / Sketch BP / ポリゴンツールのドローオブジェクトの移動の実装


- Modification -

ポリゴンツールのドローオブジェクトの移動の実装

ポリゴンツールのドローオブジェクトの移動に必要なもの

ここでは、ポリゴンを移動したり、大きさを変えることを考えてみよう。つまり、マウスで選択して動かしたり、ハンドルを動かしてサイズを変えるときのことね。

Sketch のいままでのオブジェクト、四角や円や円弧は、領域を決めるとそれだけで描くものが決まった。オブジェクトを一意に決定するのに、それしか情報が必要じゃなかったからね。だけど、ポリゴンの場合は、各点の情報がある。だから、オブジェクトを動かしたときは、それを全部動かさないといけないし、サイズを変えたら、点の間の比率を変えないといけない。そのために、アフィン変換を使おう。NSAffineTransform を使えば、それをカバーしてくれる。

というわけで、インスタンス変数に NSAffineTransform の変数を用意しておくことにしよう。あと今回は、オブジェクトのサイズを変えていって、反転したときは特別な処理が必要になる。それのためのフラグも用意しておこう。

Sketch/DocumentModel.subproj/SKTPolygon.h (created by mkino)
@interface SKTPolygon : SKTGraphic {
    ...
    NSAffineTransform*	_transform;
    BOOL				           _isFlippedVertically;
    BOOL				           _isFlippedHorizontally;
    ...
}

この 3 つの変数を使って、オブジェクトの移動と変形を実装するぞ!


ポリゴンツールのドローオブジェクトの移動の実装

ドローオブジェクトの移動に必要な実装は、bezierPath でおこなうことにした。流れは、

  • アンカーポイントの配列から、ベジエ曲線を作る
  • そのベジエ曲線を移動、変形する

っていう感じになるんだ。


アンカーポイントの配列からベジエ曲線を作る

まず、もとになるベジエ曲線を作る。これは origBezierPath っていうメソッドでやらせることにした。

Sketch/DocumentModel.subproj/SKTPolygon.m (created by mkino)
- (NSBezierPath*)origBezierPath {
    NSBezierPath*	path = [NSBezierPath bezierPath];
    int	count = [_anchorPoints count];
    int	i;
    
    if (count >= 1) {
        [path moveToPoint:[self pointAtIndex:0]];
        
        if (count >= 2) {
            for (i = 1; i < [_anchorPoints count]; i++) {
                [path lineToPoint:[self pointAtIndex:i]];
            }
        }
        
        if (_isPathClosed) {
            [path closePath];
        }
        
    }
    
    [path setLineWidth:[self strokeLineWidth]];
    
    return path;
}

基本は、アンカーポイントの配列から、順々に NSBzierPath の lineToPoint: をしていく、ってことだ。まず、アンカーポイントが 1 個あったら、そこに moveToPoint: する。さらにポイントがあるなら、lineToPoint: していく。パスを閉じるなら、closePath する。これで完了。


ベジエ曲線を移動、変形する

で、origBezierPath でベジエ曲線を作ったら、それを移動変形してやるんだ。それは bezierPath でやっている。

Sketch/DocumentModel.subproj/SKTPolygon.m (created by mkino)
- (NSBezierPath*)bezierPath {
    NSBezierPath* path = [self origBezierPath];
    NSRect        bounds = [self bounds];
    NSRect        bezierBounds = [path bounds];
    float         scaleX = 0.0f, scaleY = 0.0f;
    
    if (![self isCreating] && ([self isMoving] || [self isSizeChanging])) {
        [_transform setTransformStruct:SKTNormalizeStruct];
        
        // For moving
        [_transform translateXBy:bounds.origin.x yBy:bounds.origin.y];
        
        // For size changing
        if (bezierBounds.size.width != 0) {
            scaleX = bounds.size.width / bezierBounds.size.width;
        }
        if (bezierBounds.size.height != 0) {
            scaleY = bounds.size.height / bezierBounds.size.height;
        }
        [_transform scaleXBy:scaleX yBy:scaleY];
        
        // Back to origin
        [_transform translateXBy:-bezierBounds.origin.x 
                             yBy:-bezierBounds.origin.y];
        
        // For vertical flip
        if (_isFlippedVertically) {
            [_transform prependTransform:SKTVerticalFlipTransform];
            [_transform translateXBy:
                -(2 * bezierBounds.origin.x + bezierBounds.size.width) 
                                 yBy:0.0];            
        }
        // For horizontal flip
        if (_isFlippedHorizontally) {
            [_transform prependTransform:SKTHorizontalFlipTransform];
            [_transform translateXBy:0.0 
                                 yBy:
                -(2 * bezierBounds.origin.y + bezierBounds.size.height)]; 
        }
    }
    
    return [_transform transformBezierPath:path];
}

ベジエ曲線の作成後、そのベジエ曲線の領域 bezierBounds と、移すべき領域 bounds とを求める。そして、bezierBounds から bounds へと転写するアフィン変換を求めてやるんだ。translateXBy:yBy:scalXBy:yBy: とを使って求めることができるんだ。

あと、反転したときは、特別な処理が必要。反転用のアフィン変換をしてやる必要がある。そのための構造体を作って、それをかけてやることで実現しているんだ。垂直反転用の構造体は SKTVerticalFlipStruct = { -1, 0, 0, 1, 0, 0 }、水平反転用の構造体は SKTHorizontalFlipStruct = { 1, 0, 0, -1, 0, 0 } なんだ。

で、アフィン変換が決まったら、NSAffineTransform の transformBezierPath: を使って、ベジエ曲線を変形してやる。これで出来上がり。


- ソースコードのダウンロード -

HMDT - Download / Sketch BP


Home | Link | Download | Back Number | Speciall Issue

Sketch BP

mailto: mkino@xd5.so-net.ne.jp

HMDT