2010-10-31 88 views
14

我正在嘗試在給定角度(Theta)處繪製一個矩形對象中的漸變,其中漸變的末端觸及矩形的周長。在給定角度的矩形上查找點

Graph

我想到用切線會的工作,但我遇到麻煩瑣碎的問題。有一個簡單的算法,我只是想念?

結束結果

所以,這將是一個函數(角度,RectX1,RectX2,RectY1,RectY2)。我希望它以[x1,x2,y1,y2]的形式返回,以便漸變將在廣場上繪製。 在我的問題中,如果原點爲0,那麼x2 = -x1和y2 = -y1。但它並不總是在原點上。

+3

什麼照片有問題怎麼辦?只有線的一端(我假設線是這種情況下的斜邊)觸及邊界。該線會始終通過(或如圖所示,始於)起點? – aaronasterling 2010-10-31 02:42:01

+0

@aaronasterling,這是我對我想達到的理解。我需要X和Y.三角形會根據角度改變。 – bradlis7 2010-10-31 03:04:42

回答

31

我們叫一個b您的矩形兩側,(X0,Y0)您的矩形中心的座標。

你有四個區域考慮:

alt text

 
    Region from    to     Where 
    ==================================================================== 
     1  -arctan(b/a)  +arctan(b/a)  Right green triangle 
     2  +arctan(b/a)  π-arctan(b/a)  Upper yellow triangle 
     3  π-arctan(b/a)  π+arctan(b/a)  Left green triangle 
     4  π+arctan(b/a)  -arctan(b/a)  Lower yellow triangle 

一個小三角福,我們可以得到的座標爲每個區域所需交集。

alt text

所以Z0爲交點爲區域1和3
Z1表達被用於交點爲區域2和所需的株中的表達4

根據區域從(X0,Y0)傳遞到Z0或Z1。所以記住譚(φ)= SIN(φ)/餘弦(φ)

 

    Lines in regions  Start     End 
    ====================================================================== 
     1 and 3   (X0,Y0)  (X0 + a/2 , (a/2 * Tan(φ))+ Y0 
     2 and 4   (X0,Y0)  (X0 + b/(2* Tan(φ)) , b/2 + Y0) 

要知道的談的每個象限中的符號(φ),並且該角度總是從正x測量軸鎖定。

HTH!

+0

幹得好!我會看看我能用這些信息做些什麼。 – bradlis7 2010-11-01 23:39:58

+0

優秀的答案!謝謝! – BillyBBone 2012-02-26 08:06:43

+0

我不明白你的答案或其他答案中的兩個角度φ和θ代表什麼 - 這個問題只是指定一個角度嗎?對於區域1中的相交/結束點,與3相比,不應該有不同的x座標(對於區域2中的相交點與4相比,不同的y座標)? – 2012-03-02 01:20:42

3

繼你的照片後,我會假定矩形的居中位置是(0,0),右上角是(w,h)。然後連接(0,0)到(w,h)的直線與X軸形成一個角度φ,其中tan(φ)= h/w。

假設θ > φ,我們正在尋找您繪製的線與矩形的上邊緣相交的點(x,y)。然後y/x = tan(θ)。我們知道y = h所以求解x,得到x = h/tan(θ)。

如果θ < φ,該線與(x,y)處的矩形的右邊緣相交。這一次,我們知道x = w,所以y = tan(θ)* w。

1

有一個很好的(更方案的iOS /目標-C)的回答這個問題在Find the CGPoint on a UIView rectangle intersected by a straight line at a given angle from the center point涉及以下步驟:

  1. 假設角度大於或等於0且小於2 *π ,從0(東)逆時針方向。
  2. 獲取與矩形右邊相交的y座標[tan(angle)* width/2]。
  3. 檢查此y座標是否在矩形框中(絕對值小於或等於高度的一半)。
  4. 如果y交點在矩形中,那麼如果角度小於π/ 2或大於3π/ 2,則選擇右邊緣(寬度/ 2,-y座標)。否則,選擇左邊緣(-width/2,y座標)。
  5. 如果右邊交點的y座標超出邊界,則計算交點的底部邊緣[高度/ tan(角度)的一半]的x座標。
  6. 接下來確定您是要上邊還是下邊。如果角度小於π,我們需要底部邊緣(x,-half高度)。否則,我們需要頂邊(-x座標,高度的一半)。
  7. 然後(如果幀的中心不是0,0),將該點偏移幀的實際中心。
9

好吧,哇!,我終於得到了這個。

注意:我基於belisarius的真棒答案。如果你喜歡這個,請也喜歡他。我所做的只是將他所說的話變成代碼。

下面是它在Objective-C中的樣子。它應該很簡單,可以轉換爲任何你喜歡的語言。

+ (CGPoint) edgeOfView: (UIView*) view atAngle: (float) theta 
{ 
    // Move theta to range -M_PI .. M_PI 
    const double twoPI = M_PI * 2.; 
    while (theta < -M_PI) 
    { 
     theta += twoPI; 
    } 

    while (theta > M_PI) 
    { 
     theta -= twoPI; 
    } 

    // find edge ofview 
    // Ref: http://stackoverflow.com/questions/4061576/finding-points-on-a-rectangle-at-a-given-angle 
    float aa = view.bounds.size.width;           // "a" in the diagram 
    float bb = view.bounds.size.height;           // "b" 

    // Find our region (diagram) 
    float rectAtan = atan2f(bb, aa); 
    float tanTheta = tan(theta); 

    int region; 
    if ((theta > -rectAtan) 
    && (theta <= rectAtan)) 
    { 
     region = 1; 
    } 
    else if ((theta > rectAtan) 
    &&  (theta <= (M_PI - rectAtan))) 
    { 
     region = 2; 
    } 
    else if ((theta > (M_PI - rectAtan)) 
    ||  (theta <= -(M_PI - rectAtan))) 
    { 
     region = 3; 
    } 
    else 
    { 
     region = 4; 
    } 

    CGPoint edgePoint = view.center; 
    float xFactor = 1; 
    float yFactor = 1; 

    switch (region) 
    { 
     case 1: yFactor = -1;  break; 
     case 2: yFactor = -1;  break; 
     case 3: xFactor = -1;  break; 
     case 4: xFactor = -1;  break; 
    } 

    if ((region == 1) 
    || (region == 3)) 
    { 
     edgePoint.x += xFactor * (aa/2.);          // "Z0" 
     edgePoint.y += yFactor * (aa/2.) * tanTheta; 
    } 
    else                  // region 2 or 4 
    { 
     edgePoint.x += xFactor * (bb/(2. * tanTheta));      // "Z1" 
     edgePoint.y += yFactor * (bb/2.); 
    } 

    return edgePoint; 
} 

此外,這裏有一個我創建的測試視圖來驗證它的工作原理。創建這個視圖並將它放在某個地方,它會讓另一個小視圖圍繞邊緣滑動。

@interface DebugEdgeView() 
{ 
    int degrees; 
    UIView *dotView; 
    NSTimer *timer; 
} 

@end 

@implementation DebugEdgeView 

- (void) dealloc 
{ 
    [timer invalidate]; 
} 


- (id) initWithFrame: (CGRect) frame 
{ 
    self = [super initWithFrame: frame]; 
    if (self) 
    { 
     self.backgroundColor = [[UIColor magentaColor] colorWithAlphaComponent: 0.25]; 
     degrees = 0; 
     self.clipsToBounds = NO; 

     // create subview dot 
     CGRect dotRect = CGRectMake(frame.size.width/2., frame.size.height/2., 20, 20); 
     dotView = [[DotView alloc] initWithFrame: dotRect]; 
     dotView.backgroundColor = [UIColor magentaColor]; 
     [self addSubview: dotView]; 

     // move it around our edges 
     timer = [NSTimer scheduledTimerWithTimeInterval: (5./360.) 
               target: self 
               selector: @selector(timerFired:) 
               userInfo: nil 
               repeats: YES]; 
    } 

    return self; 
} 


- (void) timerFired: (NSTimer*) timer 
{ 
    float radians = ++degrees * M_PI/180.; 
    if (degrees > 360) 
    { 
     degrees -= 360; 
    } 

    dispatch_async(dispatch_get_main_queue(), ^{ 
     CGPoint edgePoint = [MFUtils edgeOfView: self atAngle: radians]; 
     edgePoint.x += (self.bounds.size.width/2.) - self.center.x; 
     edgePoint.y += (self.bounds.size.height/2.) - self.center.y; 
     dotView.center = edgePoint; 
    }); 
} 

@end 
+0

奇妙的代碼!我剛剛在Java中實現了這一點。我必須在計算中交換區域2和4,並且我必須在區域1和3中使用正的y因子,但是我認爲這是因爲在Cocoa/Objective-C中,原點是左下角。好樣的!幹得不錯! – Mike 2015-07-30 21:41:04

+0

你是否使用θ作爲弧度或「東方的度數」(順時針旋轉0到180度,逆時針旋轉0到-180度)? – MiltsInit 2016-05-31 19:54:11

6

的JavaScript版本:

function edgeOfView(rect, deg) { 
 
    var twoPI = Math.PI*2; 
 
    var theta = deg * Math.PI/180; 
 
    
 
    while (theta < -Math.PI) { 
 
    theta += twoPI; 
 
    } 
 
    
 
    while (theta > Math.PI) { 
 
    theta -= twoPI; 
 
    } 
 
    
 
    var rectAtan = Math.atan2(rect.height, rect.width); 
 
    var tanTheta = Math.tan(theta); 
 
    var region; 
 
    
 
    if ((theta > -rectAtan) && (theta <= rectAtan)) { 
 
     region = 1; 
 
    } else if ((theta > rectAtan) && (theta <= (Math.PI - rectAtan))) { 
 
     region = 2; 
 
    } else if ((theta > (Math.PI - rectAtan)) || (theta <= -(Math.PI - rectAtan))) { 
 
     region = 3; 
 
    } else { 
 
     region = 4; 
 
    } 
 
    
 
    var edgePoint = {x: rect.width/2, y: rect.height/2}; 
 
    var xFactor = 1; 
 
    var yFactor = 1; 
 
    
 
    switch (region) { 
 
    case 1: yFactor = -1; break; 
 
    case 2: yFactor = -1; break; 
 
    case 3: xFactor = -1; break; 
 
    case 4: xFactor = -1; break; 
 
    } 
 
    
 
    if ((region === 1) || (region === 3)) { 
 
    edgePoint.x += xFactor * (rect.width/2.);          // "Z0" 
 
    edgePoint.y += yFactor * (rect.width/2.) * tanTheta; 
 
    } else { 
 
    edgePoint.x += xFactor * (rect.height/(2. * tanTheta));      // "Z1" 
 
    edgePoint.y += yFactor * (rect.height/2.); 
 
    } 
 
    
 
    return edgePoint; 
 
};

+0

男人非常感謝你,我剛開始寫它,然後發現有人已經做到了:) – 2015-10-19 02:54:10

相關問題