2012-03-02 28 views
9

Trong iOS, tôi đang cố xác định điểm trên hình chữ nhật được cắt bởi một đường ảo từ điểm trung tâm đến chu vi hình chữ nhật ở một góc được xác định trước.Tìm CGPoint trên hình chữ nhật UIView giao nhau bằng một đường thẳng tại một góc nhất định từ điểm giữa

Nói rằng tôi biết điểm trung tâm, kích thước hình chữ nhật và góc (bắt đầu từ 0 độ cho hướng Đông và đi ngược chiều kim đồng hồ qua 90 cho Bắc và 180 cho Tây và 270 cho Nam đến 360 độ cho phương Đông) . Tôi cần phải biết tọa độ của điểm giao nhau.

Câu trả lời toán học hơi khó hiểu (với tôi) nhưng có lẽ là chính xác tại Finding points on a rectangle at a given angle đã dẫn tôi thử mã sau đây, nhưng nó không hoạt động đúng. Câu hỏi này tương tự như câu hỏi đó, nhưng tôi đang tìm một phương pháp Objective-C/iOS đã được sửa chữa chứ không phải là một đáp ứng toán học chung.

Tôi nghĩ rằng một phần của vấn đề mã phải làm với việc sử dụng góc 0 đến 360 độ (bằng radian không có khả năng số âm), nhưng có khả năng là các vấn đề khác. Mã dưới đây chủ yếu sử dụng ký hiệu được xác định trong the answer from belisarius, bao gồm cả nỗ lực của tôi để tính điểm giao nhau cho từng khu vực được xác định tại đó.

Mã này là trong lớp con UIImageView tôi:

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

Trả lời

17

Thay vì gỡ lỗi mã của bạn, tôi sẽ chỉ giải thích làm thế nào tôi sẽ làm điều này.

Đầu tiên, một vài thuật ngữ. Hãy xác định xRadius bằng một nửa chiều rộng của khung và yRadius bằng một nửa chiều cao của khung.

Bây giờ hãy xem xét bốn cạnh của khung và mở rộng chúng dưới dạng các dòng vô hạn. Trên đầu trang của bốn dòng, đặt một dòng đó đi qua trung tâm của khung ở góc định của bạn:

diagram of rectangle with overlaid line

Hãy nói rằng khung tập trung tại gốc - trung tâm của khung hình là tại tọa độ (0,0). Chúng ta có thể dễ dàng tính toán nơi đường chéo cắt ngang cạnh phải của khung: tọa độ là (xRadius, xRadius * tan(angle)). Và chúng ta có thể dễ dàng tính toán nơi đường chéo cắt cạnh trên của khung: tọa độ là (-yRadius/tan(angle), -yRadius).

(Tại sao chúng ta phủ nhận tọa độ cho giao lộ trên cùng? Bởi vì hệ thống toạ độ UIView được lật từ hệ tọa độ toán học bình thường.Trong một tính toán, y tọa độ tăng lên phía trên cùng của trang. tọa độ tăng về phía dưới cùng của chế độ xem.)

Vì vậy, chúng tôi chỉ có thể tính toán giao điểm của đường thẳng với cạnh phải của khung. Nếu giao lộ đó nằm ngoài khung, thì chúng ta biết đường phải giao cắt cạnh trên cùng trước nó cắt cạnh phải. Làm cách nào để chúng tôi biết liệu giao lộ cạnh phải có vượt quá giới hạn không? Nếu tọa độ y của nó (xRadius * tan(angle)) lớn hơn yRadius (hoặc nhỏ hơn -yRadius), nó nằm ngoài giới hạn.

Vì vậy, để đặt nó tất cả cùng nhau trong một phương pháp, chúng tôi bắt đầu bằng cách tính toán 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; 

Sau đó chúng tôi tính toán tọa độ y của giao lộ với cạnh phải:

CGPoint pointRelativeToCenter; 
    CGFloat tangent = tanf(radians); 
    CGFloat y = xRadius * tangent; 

Chúng tôi kiểm tra xem giao lộ có nằm trong khung không:

if (fabsf(y) <= yRadius) { 

Khi chúng ta biết nó nằm trong khung hình, chúng ta phải tìm ra liệu chúng ta có muốn giao lộ với cạnh phải hay cạnh trái. Nếu góc nhỏ hơn π/2 (90 °) hoặc lớn hơn 3π/2 (270 °), chúng tôi muốn cạnh phải. Nếu không, chúng tôi muốn cạnh trái.

 if (radians < (CGFloat)M_PI_2 || radians > (CGFloat)(M_PI + M_PI_2)) { 
      pointRelativeToCenter = CGPointMake(xRadius, y); 
     } else { 
      pointRelativeToCenter = CGPointMake(-xRadius, -y); 
     } 

Nếu toạ độ y của giao điểm bên phải • là * ngoài giới hạn, chúng tôi tính toán tọa độ x của giao lộ với cạnh dưới.

} else { 
     CGFloat x = yRadius/tangent; 

Tiếp theo, chúng tôi tìm hiểu xem chúng tôi có muốn cạnh trên hoặc cạnh dưới cùng không. Nếu góc nhỏ hơn π (180 °), chúng tôi muốn cạnh dưới. Nếu không, chúng tôi muốn cạnh trên.

 if (radians < (CGFloat)M_PI) { 
      pointRelativeToCenter = CGPointMake(x, yRadius); 
     } else { 
      pointRelativeToCenter = CGPointMake(-x, -yRadius); 
     } 
    } 

Cuối cùng, chúng tôi đã bù điểm được tính bằng trung tâm thực tế của khung và trả lại.

return CGPointMake(pointRelativeToCenter.x + CGRectGetMidX(frame), 
     pointRelativeToCenter.y + CGRectGetMidY(frame)); 
} 

thử nghiệm dự án ở đây: https://github.com/mayoff/stackoverflow-radial-intersection

Trông như thế này:

edgepoint screen shot

+0

Fabulous! Cảm ơn. Tôi đã có một chút rắc rối với điều này bởi vì trong trường hợp của tôi, tôi đã không nhận ra tôi phải [self.superview convertPoint: thePoint toView: self] trong lớp con UIImageview của tôi (cho những người mới đến đây). –

+0

Câu trả lời tuyệt vời! – mrvincenzo

+0

Tôi đang nghiên cứu mã của bạn, điều này thật tuyệt vời, cố gắng hiểu phải làm gì nếu tôi muốn xoay hình ảnh và vẫn giữ nguyên tính năng phát hiện cạnh? Có suy nghĩ gì không? – flooie

Các vấn đề liên quan