9
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

もちろん俺らは抵抗するで?技術で🤜🤛Advent Calendar 2017

Day 11

二点の座標から矩形を描くUIBezierPathをつくってみた

Last updated at Posted at 2017-12-13

始点と終点の二点の座標から、矩形を描くUIBezierPathを返す関数つくってみたったー

こんなの

rect.gif

どうやって計算してるの

みんな大好き回転行列を用いて計算してます。

\begin{eqnarray}
\begin{pmatrix}
x^{\prime} \\ y^{\prime}
\end{pmatrix}
=
\begin{pmatrix}
\cos\theta & -\sin\theta \\
\sin\theta & \cos\theta \\
\end{pmatrix}
\begin{pmatrix}
x \\ y
\end{pmatrix}
\end{eqnarray}

詳しくは高校数学の教科書を引っ張り出してにらめっこしてください。
尚、回転角θは時計回りを正として計算してます。

ソースコード

Objective-C

.m
- (UIBezierPath *)getRectangleBezierPathFromBeginPoint:(CGPoint)beginPoint toPoint:(CGPoint)toPoint width:(CGFloat)width {
    // x方向,y方向の変位
    CGFloat deltaX = toPoint.x - beginPoint.x;
    CGFloat deltaY = toPoint.y - beginPoint.y;

    // 二点間の直線とX軸のなす角
    CGFloat radian = (deltaX == 0)? (M_PI/2) : atan(deltaY / deltaX);
    
    CGFloat halfWidth = width / 2.;
    
    CGPoint beginUpperPoint = [self rotationPoint:CGPointMake(beginPoint.x, beginPoint.y - halfWidth) radian:radian basePoint:beginPoint];
    CGPoint beginUnderPoint = [self rotationPoint:CGPointMake(beginPoint.x, beginPoint.y + halfWidth) radian:radian basePoint:beginPoint];
    CGPoint endUpperPoint = CGPointMake(beginUpperPoint.x + deltaX, beginUpperPoint.y + deltaY);
    CGPoint endUnderPoint = CGPointMake(beginUnderPoint.x + deltaX, beginUnderPoint.y + deltaY);
    
    UIBezierPath *path = [UIBezierPath bezierPath];
    path.lineWidth = 1.0;
    
    [path moveToPoint:beginUpperPoint];
    [path addLineToPoint:beginUnderPoint];
    [path addLineToPoint:endUnderPoint];
    [path addLineToPoint:endUpperPoint];
    [path addLineToPoint:beginUpperPoint];
    [path closePath];
    
    return path;
}


/**
 回転させた後の座標を返します

 @param point 回転元座標
 @param radian 角度(ラジアン)
 @param basePoint 回転軸となる座標
 @return 回転後の座標
 */
- (CGPoint)rotationPoint:(CGPoint)point radian:(CGFloat)radian basePoint:(CGPoint)basePoint {
    CGPoint rotationPoint = CGPointZero;
    rotationPoint.x = (point.x - basePoint.x) * cos(radian) - (point.y - basePoint.y) * sin(radian);
    rotationPoint.y = (point.x - basePoint.x) * sin(radian) + (point.y - basePoint.y) * cos(radian);
    
    rotationPoint.x = rotationPoint.x + basePoint.x;
    rotationPoint.y = rotationPoint.y + basePoint.y;
    return rotationPoint;
}

Swift

.swift
extension UIBezierPath {
    static func squareFromPoints(from beginPoint: CGPoint, to toPoint: CGPoint, width: CGFloat) -> UIBezierPath {

        func rotation(point: CGPoint, radian: CGFloat, basePoint: CGPoint) -> CGPoint {
            var rotationPoint = CGPoint.zero
            rotationPoint.x = (point.x - basePoint.x) * cos(radian) - (point.y - basePoint.y) * sin(radian)
            rotationPoint.y = (point.x - basePoint.x) * sin(radian) + (point.y - basePoint.y) * cos(radian)

            rotationPoint.x = rotationPoint.x + basePoint.x
            rotationPoint.y = rotationPoint.y + basePoint.y
            return rotationPoint
        }

        let deltaX = toPoint.x - beginPoint.x
        let deltaY = toPoint.y - beginPoint.y

        let radian = (deltaX == 0) ? (CGFloat.pi/2) : atan(deltaY / deltaX)

        let halfWidth = width/2

        let beginUpperPoint = rotation(point: CGPoint(x: beginPoint.x, y: beginPoint.y - halfWidth), radian: radian, basePoint: beginPoint)
        let beginUnderPoint = rotation(point: CGPoint(x: beginPoint.x, y: beginPoint.y + halfWidth), radian: radian, basePoint: beginPoint)

        let endUpperPoint = CGPoint(x: beginUpperPoint.x + deltaX, y: beginUpperPoint.y + deltaY)
        let endUnderPoint = CGPoint(x: beginUnderPoint.x + deltaX, y: beginUnderPoint.y + deltaY)

        let path = UIBezierPath()
        path.lineWidth = 1

        path.move(to: beginUpperPoint)
        path.addLine(to: beginUnderPoint)
        path.addLine(to: endUnderPoint)
        path.addLine(to: endUpperPoint)
        path.addLine(to: beginUpperPoint)
        path.close()

        return path
    }
}

おわりに

終点の回転後座標の算出方法として、始点の回転後の座標に対して単純に変位量を加算して求めていますが、
もっとイケてる算出方法とかありますかね・・・?
(終点に対して2回、回転行列をかける?:confused:)

また、組み込み関数や他のライブラリ等で簡単にできるよ!などあればご一報いただけると幸いです🤜🤛

9
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?