始点と終点の二点の座標から、矩形を描くUIBezierPathを返す関数つくってみたったー
こんなの
どうやって計算してるの
みんな大好き回転行列を用いて計算してます。
\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回、回転行列をかける?)
また、組み込み関数や他のライブラリ等で簡単にできるよ!などあればご一報いただけると幸いです🤜🤛