2010-04-18 37 views
12

There is a very handy set of 2d geometry utilities here.Làm thế nào để tính cả góc dương và âm giữa hai dòng?

GócBetweenLines có vấn đề. Kết quả luôn luôn là tích cực. Tôi cần phải phát hiện cả hai góc độ tích cực và tiêu cực, vì vậy nếu một dòng là 15 độ "trên" hoặc "dưới đây" dòng khác, hình dạng rõ ràng sẽ khác nhau.

Cấu hình tôi có là một dòng vẫn giữ nguyên, trong khi dòng kia quay và tôi cần hiểu hướng nó đang quay bằng cách so sánh nó với đường tĩnh.

EDIT: để trả lời nhận xét của swestrup bên dưới, tình hình thực tế là tôi có một dòng và tôi ghi lại vị trí bắt đầu của nó. Dòng sau đó quay từ vị trí bắt đầu của nó, và tôi cần tính toán góc từ vị trí bắt đầu đến vị trí hiện tại. Ví dụ: nếu nó đã xoay theo chiều kim đồng hồ thì đó là vòng quay dương; nếu ngược chiều kim đồng hồ, thì âm tính. (Hoặc ngược lại.)

Làm cách nào để cải thiện thuật toán sao cho nó trả về góc là dương hoặc âm tùy thuộc vào cách các đường được định vị?

+0

Cho hai đoạn đường giao nhau tùy ý, thật khó để xác định đoạn nào là 'trên' đoạn kia và thậm chí là góc nào để đo, vì chúng thường tạo thành hình dạng 'X'. Bạn có lẽ luôn luôn sử dụng hai dòng với một điểm khởi đầu chung? Điều đó làm cho nó thẳng tiến hơn rất nhiều. – swestrup

+0

Xin lỗi, tôi đã làm rõ. Tôi đang thực sự nói về một dòng duy nhất và vòng quay của nó liên quan đến vị trí bắt đầu của nó. – Jaanus

+0

Bạn muốn phạm vi nào? Bạn có muốn toàn bộ -pi thành pi hoặc bạn có hài lòng với chỉ -pi/2 đến pi/2 tức là bạn có quan tâm đến hướng của đường thẳng hay không? – Troubadour

Trả lời

8

@ câu trả lời của duffymo là đúng, nhưng nếu bạn không muốn triển khai sản phẩm chéo, bạn có thể sử dụng chức năng atan2. Điều này trả về một góc giữa - π và π và bạn có thể sử dụng nó trên mỗi dòng (hoặc chính xác hơn là các vectơ đại diện cho các dòng).

Nếu bạn nhận được một góc θ cho (dòng stationary) đầu tiên, bạn sẽ phải chuẩn hóa góc φ cho dòng thứ hai là giữa θ-π và θ + π (bằng cách thêm & plusmn; 2 π). Góc giữa hai dòng sẽ là φ - θ.

+1

Tất cả những thứ vectơ này làm nổ tung đầu tôi. (Xin lỗi, tôi quên rất nhiều toán học của tôi ...) Bây giờ, tôi chỉ tính toán atan2 cho cả hai dòng và so sánh chúng, hoạt động tốt. Cảm ơn. – Jaanus

+0

Cũng triển khai bên dưới. – Jaanus

0

chức năng đó đang làm việc tại RADS

Có RADS 2pi trong một vòng tròn đầy đủ (360 độ)

Vì vậy, tôi tin rằng answear bạn đang tìm kiếm chỉ đơn giản là giá trị trả về - 2pi

Nếu bạn đang yêu cầu có một hàm trả về cả hai giá trị cùng một lúc, thì bạn đang yêu cầu ngắt ngôn ngữ, hàm chỉ có thể trả về một giá trị duy nhất. Bạn có thể vượt qua nó hai con trỏ mà nó có thể sử dụng để thiết lập giá trị để thay đổi có thể tồn tại sau khi kết thúc frunction và chương trình của bạn có thể tiếp tục hoạt động. Nhưng không thực sự là một cách hợp lý để giải quyết vấn đề này.

Sửa

Chỉ cần nhận thấy rằng các chức năng thực sự chuyển đổi rads để Degrees vì ​​nó trả về giá trị. Nhưng nguyên tắc tương tự cũng sẽ hiệu quả.

7

Đây là một vấn đề dễ dàng liên quan đến vectơ 2D. Sin của góc giữa hai vectơ liên quan đến sản phẩm chéo giữa hai vectơ. Và "ở trên" hoặc "bên dưới" được xác định bằng dấu hiệu của vectơ do sản phẩm chéo tạo ra: nếu bạn vượt qua hai vectơ A và B, và sản phẩm chéo được tạo là dương, thì A là "dưới" B; nếu nó âm, A là "ở trên" B. Xem Mathworld để biết chi tiết.

Đây là cách tôi có thể mã nó trong Java:

package cruft; 

import java.text.DecimalFormat; 
import java.text.NumberFormat; 

/** 
* VectorUtils 
* User: Michael 
* Date: Apr 18, 2010 
* Time: 4:12:45 PM 
*/ 
public class VectorUtils 
{ 
    private static final int DEFAULT_DIMENSIONS = 3; 
    private static final NumberFormat DEFAULT_FORMAT = new DecimalFormat("0.###"); 

    public static void main(String[] args) 
    { 
     double [] a = { 1.0, 0.0, 0.0 }; 
     double [] b = { 0.0, 1.0, 0.0 }; 

     double [] c = VectorUtils.crossProduct(a, b); 

     System.out.println(VectorUtils.toString(c)); 
    } 

    public static double [] crossProduct(double [] a, double [] b) 
    { 
     assert ((a != null) && (a.length >= DEFAULT_DIMENSIONS) && (b != null) && (b.length >= DEFAULT_DIMENSIONS)); 

     double [] c = new double[DEFAULT_DIMENSIONS]; 

     c[0] = +a[1]*b[2] - a[2]*b[1]; 
     c[1] = +a[2]*b[0] - a[0]*b[2]; 
     c[2] = +a[0]*b[1] - a[1]*b[0]; 

     return c; 
    } 

    public static String toString(double [] a) 
    { 
     StringBuilder builder = new StringBuilder(128); 

     builder.append("{ "); 

     for (double c : a) 
     { 
      builder.append(DEFAULT_FORMAT.format(c)).append(' '); 
     } 

     builder.append("}"); 

     return builder.toString(); 
    } 
} 

Kiểm tra dấu hiệu của thành phần thứ 3. Nếu nó dương, A là "dưới" B; nếu nó âm, A là "trên" B - miễn là hai vectơ nằm trong hai góc phần tư ở bên phải của trục y. Rõ ràng, nếu chúng ở cả hai góc phần tư bên trái trục y thì ngược lại là đúng.

Bạn cần suy nghĩ về khái niệm trực quan của mình về "ở trên" và "bên dưới". Điều gì sẽ xảy ra nếu A ở góc phần tư đầu tiên (0 < = θ < = 90) và B ở góc phần tư thứ hai (90 < = θ < = 180)? "Trên" và "bên dưới" mất ý nghĩa của chúng.

Dòng sau đó xoay từ vị trí bắt đầu của nó, và tôi cần phải tính toán góc từ khi bắt đầu của nó vị trí đến vị trí hiện tại. Ví dụ: nếu nó đã xoay theo chiều kim đồng hồ, nó là vòng quay dương; nếu ngược chiều kim đồng hồ, sau đó âm. (Hoặc ngược lại.)

Đây chính xác là sản phẩm chéo. Dấu hiệu của thành phần thứ 3 là dương cho ngược chiều kim đồng hồ và âm cho chiều kim đồng hồ (khi bạn nhìn xuống mặt phẳng quay).

+0

Điều này nghe có vẻ tuyệt vời, nhưng việc chuyển đổi số nhân thành mã là một chút ngoài tôi, tôi đã hy vọng được lười biếng và nhận được nó ở dạng mã: P tức là đầu vào: cái tôi có, tọa độ của các điểm cuối của 2 dòng; đầu ra: góc đã ký. – Jaanus

+0

C'mon ... Phép nhân vectơ chỉ là phép nhân. Bạn có thể viết mã cho một công thức không? Hai vectơ trong, một vectơ. Bạn muốn ngôn ngữ nào? – duffymo

+0

Mã giả hoặc C là tốt – Jaanus

1

Phương pháp 'nhanh chóng và bẩn' bạn có thể sử dụng là giới thiệu dòng tham chiếu thứ ba R. Vì vậy, cho hai dòng A và B, tính các góc giữa A và R rồi B ​​và R và trừ chúng.

Tính toán này gấp đôi số lần thực sự cần thiết nhưng dễ giải thích và gỡ lỗi.

+0

Tôi hiểu atan2 về cơ bản thực hiện chính xác điều đó, với trục x là dòng giới thiệu. – Jaanus

19

Đây là việc thực hiện đề xuất của brainjam. (Nó làm việc với những ràng buộc của tôi rằng sự khác biệt giữa các dòng được đảm bảo đủ nhỏ mà không cần phải bình thường hóa bất cứ điều gì.)

CGFloat angleBetweenLinesInRad(CGPoint line1Start, CGPoint line1End, CGPoint line2Start, CGPoint line2End) { 
    CGFloat a = line1End.x - line1Start.x; 
    CGFloat b = line1End.y - line1Start.y; 
    CGFloat c = line2End.x - line2Start.x; 
    CGFloat d = line2End.y - line2Start.y; 

    CGFloat atanA = atan2(a, b); 
    CGFloat atanB = atan2(c, d); 

    return atanA - atanB; 
} 

Tôi thích nó ngắn gọn. Phiên bản vectơ có ngắn gọn hơn không?

+3

Theo tôi, đây phải là câu trả lời được chấp nhận. – Emil

+1

Tôi chấp nhận câu trả lời của câu trả lời từ khi tôi thực sự yêu cầu thuật toán, và nói chung tôi không thích chấp nhận câu trả lời của riêng tôi, đặc biệt nếu đó là một dẫn xuất của câu trả lời khác, tôi muốn đưa ra tín dụng. – Jaanus

+0

+1 Điều này thật khéo léo! Đã lưu tôi giờ trị giá tính toán hình học và gỡ lỗi! –

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