在iOS中,我试图确定一个矩形上的点,该矩形与从中心点到矩形周长的假想线相交,并以预定角度。
假设我知道中心点,矩形的大小和角度(从东方0度开始,向北逆时针方向90度,西方180度,南方270度至东方360度)。我需要知道交叉点的坐标。
Finding points on a rectangle at a given angle对我来说有点令人困惑(但对我而言)数学但可能是准确的答案让我尝试了以下代码,但它无法正常工作。这个问题与那个问题类似,但我正在寻找一个更正的Objective-C / iOS方法,而不是一般的数学响应。
我认为代码问题的一部分与使用单个0到360度角(弧度不可能有负数)输入有关,但可能还有其他问题。下面的代码主要使用the answer from belisarius中定义的符号,包括我尝试为那里定义的四个区域中的每个区域计算交叉点。
此代码位于我的UIImageView子类中:
- (CGPoint) startingPointGivenAngleInDegrees:(double)angle {
double angleInRads = angle/180.0*M_PI;
float height = self.frame.size.height;
float width = self.frame.size.width;
float x0 = self.center.x;
float y0 = self.center.y;
// region 1
if (angleInRads >= -atan2(height, width) && angleInRads <= atan2(height, width)) {
return CGPointMake(x0 + width/2, y0 + width/2 * tan(angleInRads));
}
// region 2
if (angleInRads >= atan2(height, width) && angleInRads <= M_PI - atan2(height, width)) {
return CGPointMake(x0 + height / (2*tan(angleInRads)),y0+height/2);
}
// region 3
if (angleInRads >= M_PI - atan2(height, width) && angleInRads <= M_PI + atan2(height, width)) {
return CGPointMake(x0 - width/2, y0 + width/2 * tan(angleInRads));
}
// region 4
return CGPointMake(x0 + height / (2*tan(angleInRads)),y0-height/2);
}
答案 0 :(得分:21)
我只是解释如何执行此操作,而不是调试代码。
首先,几个术语。我们将xRadius
定义为帧宽度的一半,将yRadius
定义为帧高度的一半。
现在考虑框架的四个边缘,并将它们扩展为无限线。在这四条线的顶部,铺设一条以指定角度穿过框架中心的线:
假设框架以原点为中心 - 框架的中心位于坐标(0,0)处。我们可以轻松计算对角线与框架右边缘相交的位置:坐标为(xRadius
,xRadius * tan(angle)
)。我们可以轻松计算对角线与框架顶边相交的位置:坐标为(-yRadius / tan(angle)
,-yRadius
)。
(为什么我们否定顶边交点的坐标?因为UIView
坐标系从正常的数学坐标系中翻转。在数学中,y坐标朝页面顶部增加。 UIView
,y坐标朝视图底部增加。)
因此我们可以简单地计算线与帧右边缘的交点。如果该交点位于框架之外,那么我们知道该线必须在与相交之前与顶边相交。我们如何判断右边交叉点是否超出范围?如果其y坐标(xRadius * tan(angle)
)大于yRadius
(或小于-yRadius
),则超出界限。
因此,要将它们放在一个方法中,我们首先计算xRadius
和yRadius
:
- (CGPoint)radialIntersectionWithConstrainedRadians:(CGFloat)radians {
// This method requires 0 <= radians < 2 * π.
CGRect frame = self.frame;
CGFloat xRadius = frame.size.width / 2;
CGFloat yRadius = frame.size.height / 2;
然后我们计算与右边缘的交点的y坐标:
CGPoint pointRelativeToCenter;
CGFloat tangent = tanf(radians);
CGFloat y = xRadius * tangent;
我们检查交叉点是否在框架中:
if (fabsf(y) <= yRadius) {
一旦我们知道它在框架中,我们必须弄清楚我们是否想要与右边缘或左边缘的交点。如果角度小于π/ 2(90°)或大于3π/ 2(270°),我们需要右边缘。否则我们想要左边缘。
if (radians < (CGFloat)M_PI_2 || radians > (CGFloat)(M_PI + M_PI_2)) {
pointRelativeToCenter = CGPointMake(xRadius, y);
} else {
pointRelativeToCenter = CGPointMake(-xRadius, -y);
}
如果右边缘交点的y坐标是*越界,我们计算与底边相交的x坐标。
} else {
CGFloat x = yRadius / tangent;
接下来,我们弄清楚我们是想要顶边还是底边。如果角度小于π(180°),我们需要底边。否则,我们想要最上层。
if (radians < (CGFloat)M_PI) {
pointRelativeToCenter = CGPointMake(x, yRadius);
} else {
pointRelativeToCenter = CGPointMake(-x, -yRadius);
}
}
最后,我们将计算点偏移到帧的实际中心并返回它。
return CGPointMake(pointRelativeToCenter.x + CGRectGetMidX(frame),
pointRelativeToCenter.y + CGRectGetMidY(frame));
}
在此测试项目:https://github.com/mayoff/stackoverflow-radial-intersection
看起来像这样:
答案 1 :(得分:4)
这是罗布的答案,是迅速的律法复制和粘贴。
func findEdgePoint(angle: CGFloat) -> CGPoint {
let intersection: CGPoint
let xRad = frame.width / 2
let yRad = frame.height / 2
let tangent = tan(angle)
let y = xRad * CGFloat(tangent)
if fabs(y) <= yRad {
if angle < CGFloat.pi / 2 || angle > 3 * CGFloat.pi / 2 {
intersection = CGPoint(x: xRad, y: y)
} else {
intersection = CGPoint(x: -xRad, y: -y)
}
} else {
let x = yRad / CGFloat(tangent)
if angle < CGFloat.pi {
intersection = CGPoint(x: x, y: yRad)
} else {
intersection = CGPoint(x: -x, y: -yRad)
}
}
return intersection
}
// heck yeah rob, he's the man
// if he can't solve it, no one can