2012-03-02 68 views
9

在iOS中,我試圖確定矩形上的點,該矩形與從中心點到外圍的虛線相交該矩形以預定的角度。假設我知道中心點,矩形的大小和角度(從東經0度開始,再向東逆時針經過90度,向東逆時針經過90度,向西逆時針經過90度,向西逆時針旋轉180度) 。我需要知道交點的座標。從中心點以給定角度與直線相交的UIView矩形上找到CGPoint

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);  
} 

回答

17

調試而不是你的代碼,我只解釋我會怎麼做。

首先,幾個術語。我們將xRadius定義爲框架寬度的一半,將yRadius定義爲框架高度的一半。

現在考慮框架的四個邊,並將它們延伸爲無限長的線。在這四線的頂部,打好通過框架的中心,在您指定的角度傳遞線路:

diagram of rectangle with overlaid line

假設幀以原點爲中心 - 框架的中心在座標(0,0)。我們可以很容易地計算對角線與框架右邊緣的相交點:座標是(xRadius,xRadius * tan(angle))。我們可以很容易地計算對角線與框架頂部邊緣的相交點:座標是(-yRadius/tan(angle),-yRadius)。

(爲什麼我們否定的頂邊相交的座標呢?因爲UIView座標系從正規的數學座標系統翻轉。在數學,y座標對頁面的頂部增加。在UIView,Y座標朝向視圖的底部增加)。

因此,我們可以簡單地計算線條與框架右邊緣的交點。如果該交點位於框架之外,那麼我們知道該線必須與之前的頂部邊緣相交,它與右邊緣相交。我們如何判斷右邊交點是否超出界限?如果它的y座標(xRadius * tan(angle))大於yRadius(或小於-yRadius),那麼它是超出界限的。

所以把它都聚集在一個方法,我們首先通過計算xRadiusyRadius

- (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

是這樣的:

edgepoint screen shot

+0

超讚!謝謝。我有一些麻煩,因爲在我的情況下,我沒有意識到我必須在我的UIImageview子類(對於來這裏的其他新手)中使用[self.superview convertPoint:thePoint toView:self]。 – 2012-03-03 15:08:48

+0

夢幻般的答案! – mrvincenzo 2013-07-12 09:53:16

+0

我正在學習你的代碼,這是非常好的,試圖理解如果我想旋轉圖像,並仍然保持邊緣檢測怎麼辦?有什麼想法嗎? – flooie 2015-07-24 14:56:51

相關問題