Vấn đề phát hiện va chạm đường tròn


11

Tôi hiện đang phát triển một bản sao đột phá và tôi đã đạt được một rào cản trong việc phát hiện va chạm giữa một quả bóng (vòng tròn) và một viên gạch (đa giác lồi) hoạt động chính xác. Tôi đang sử dụng thử nghiệm phát hiện va chạm Circle-Line trong đó mỗi dòng đại diện và cạnh trên gạch đa giác lồi.

Trong phần lớn thời gian, kiểm tra Circle-Line hoạt động chính xác và các điểm va chạm được giải quyết chính xác.

Phát hiện va chạm làm việc chính xác.

Tuy nhiên, đôi khi mã phát hiện va chạm của tôi trả về sai do phân biệt đối xử âm khi bóng thực sự giao nhau với gạch.

Phát hiện va chạm không thành công.

Tôi nhận thức được sự không hiệu quả của phương pháp này và tôi đang sử dụng các hộp giới hạn căn chỉnh trục để cắt giảm số lượng gạch được thử nghiệm. Mối quan tâm chính của tôi là nếu có bất kỳ lỗi toán học nào trong mã của tôi dưới đây.

/* 
 * from and to are points at the start and end of the convex polygons edge.
 * This function is called for every edge in the convex polygon until a
 * collision is detected. 
 */

bool circleLineCollision(Vec2f from, Vec2f to)
{
    Vec2f lFrom, lTo, lLine;
    Vec2f line, normal;
    Vec2f intersectPt1, intersectPt2;
    float a, b, c, disc, sqrt_disc, u, v, nn, vn;
    bool one = false, two = false;

    // set line vectors
    lFrom = from - ball.circle.centre;      // localised
    lTo = to - ball.circle.centre;          // localised
    lLine = lFrom - lTo;                    // localised
    line = from - to;

    // calculate a, b & c values
    a = lLine.dot(lLine);
    b = 2 * (lLine.dot(lFrom));
    c = (lFrom.dot(lFrom)) - (ball.circle.radius * ball.circle.radius);

    // discriminant
    disc = (b * b) - (4 * a * c);

    if (disc < 0.0f)
    {
        // no intersections
        return false;
    }
    else if (disc == 0.0f)
    {
        // one intersection
        u = -b / (2 * a);

        intersectPt1 = from + (lLine.scale(u));
        one = pointOnLine(intersectPt1, from, to);

        if (!one)
            return false;
        return true;
    }
    else
    {
        // two intersections
        sqrt_disc = sqrt(disc);
        u = (-b + sqrt_disc) / (2 * a);
        v = (-b - sqrt_disc) / (2 * a);
        intersectPt1 = from + (lLine.scale(u));
        intersectPt2 = from + (lLine.scale(v));

        one = pointOnLine(intersectPt1, from, to);
        two = pointOnLine(intersectPt2, from, to);

        if (!one && !two)
            return false;
        return true;
    }
}

bool pointOnLine(Vec2f p, Vec2f from, Vec2f to)
{
    if (p.x >= min(from.x, to.x) && p.x <= max(from.x, to.x) && 
        p.y >= min(from.y, to.y) && p.y <= max(from.y, to.y))
        return true;
    return false;
}

Tôi không thể tìm thấy bất kỳ sự khác biệt nào giữa lLine và dòng ...
FxIII

Kiểm tra pointOnLine có thể được đơn giản hóa và thực hiện trước khi tính toán điểm thực tế.
FxIII

sqrt_disc được tính như thế nào?
FxIII

Xin lỗi FxIII Tôi đã có một chút bối rối khi tôi bản địa hóa các vectơ của mình Tôi không nhận ra các vectơ sẽ giống nhau khi chúng bị trừ đi. Tôi đã làm sạch mã của mình một chút trước khi tôi đăng và tôi quên không đặt sqrt_disc = sqrt(disc);lại. Cảm ơn rất nhiều vì câu trả lời của bạn bên dưới nó đã giúp tôi rất nhiều.
jazzdawg

Câu trả lời:


20

Đoạn chạy từ A đến B có thể được tính là

P (t) = A + D · t trong đó DB - At chạy từ 0 đến 1

Bây giờ vòng tròn được căn giữa vào gốc tọa độ (di chuyển AB nếu cần thiết để đặt tâm vào gốc) và có bán kính r .

Bạn có một giao điểm nếu với một số t bạn nhận được rằng P có cùng độ dài r hoặc tương đương, độ dài của bình phương P tương đương với

Độ dài bình phương của một vectơ thu được khi thực hiện sản phẩm chấm của vectơ (điều này đúng đến mức nếu tìm thấy một thao tác phù hợp cho sản phẩm chấm, anh ta có thể xác định khái niệm độ dài mới và nhất quán)

P · P = ( A + D · t) · ( A + D · t) =

A · A + 2 A · D t + D · D

Chúng tôi muốn tìm xem chúng tôi nhận được P · P = r² để cuối cùng chúng tôi tự hỏi mình khi nào

A · A + 2 A · D t + D · D t² = r²

Hoặc khi nào

D · D t² + 2 A · D t + A · A -r² = 0

đây là phương trình bậc hai rất nổi tiếng

at² + bt + c = 0

với

a = D · D ; b = 2 A · D và c = A · A -r²

Chúng ta phải kiểm tra xem b² - 4ac xác định có dương hay không và vì vậy chúng ta tìm thấy 2 giá trị của t cung cấp cho chúng ta các điểm giao nhau P (t).

t phải nằm trong khoảng từ 0 đến 1 nếu không chúng tôi đã tìm thấy các giải pháp nằm trên đường thẳng đi qua AB nhưng đó là trước A hoặc sau B

[BIÊN TẬP]

Vì các câu hỏi khác có thể tìm thấy một số trợ giúp cho câu trả lời này, tôi quyết định cố gắng đơn giản hóa lý do trong chỉnh sửa này bằng một số hình ảnh. điều kiện bắt đầu Đây là điều kiện bắt đầu. Bây giờ tập trung vào phân khúc A_B

Phân đoạn chạy từ A đến B

D là vectơ di chuyển A vào B vì vậy nếu t nằm trong khoảng từ 0 đến 1, D · t là "phân số thích hợp" của D nên điểm A + D · t nằm trong đoạn A_B : các điểm màu nâu xuất hiện khi t là từ 0 đến 1 và màu xanh đậm là khi t> 1.

Bây giờ chúng ta có thể đơn giản hóa mọi thứ nếu chúng ta di chuyển trung tâm của vòng tròn vào Nguồn gốc. Điều này có thể luôn luôn được thực hiện bởi vì chỉ là một sự thay đổi đơn giản của hệ tọa độ bảo tồn hình học, góc, giao điểm, số đo, v.v.

vòng tròn di chuyển đến trung tâm

Bây giờ chúng ta có một cách đơn giản để tính chiều dài của P khi t thay đổi và nói rằng t P vượt qua ranh giới của vòng tròn.

Ví dụ

Như bạn thấy P ' có chiều dài lớn hơn r trong khi P " nhỏ hơn r. Vì cả chiều dài vectơ và r đều là số dương, nên mối quan hệ của thứ tự lớn hơn hoặc nhỏ hơn được bảo toàn là chúng ta tính toán mối quan hệ giữa các chiều dài bình phương và bán kính bình phương. P * 1P * 2 là điểm làm cho | P | ² bằng r²

Như đã đề cập trong phần chỉnh sửa trước, chúng tôi đến để có được một phương trình bậc hai trong đó t là biến của chúng tôi. Như đã biết các giá trị giải pháp của phạm vi t từ trường hợp khi t là một vài số phức - có nghĩa là không có giao điểm; trường hợp khi t là hai nghiệm bằng nhau - có nghĩa là có một giao điểm; trường hợp khi có hai giải pháp riêng biệt - điều đó có nghĩa là có hai giao điểm.

The Discriminant được sử dụng để phân biệt điều kiện trước đó và kiểm tra tính hợp lệ được thực hiện trên t để xem liệu đó có phải là giao điểm hợp lệ nhưng bên ngoài phân khúc của chúng tôi hay không - nghĩa là giải pháp t phải có thực và từ 0 đến 1 để được coi là giao điểm phù hợp trong phân khúc A_B


3
Đây là thuật toán phù hợp để sử dụng. Một mô tả thực sự tốt về cách thức hoạt động của nó có thể được tìm thấy trong Phiên bản thứ ba kết xuất thời gian thực , trang 787 đến 791. Nếu bạn có thể tìm thấy nó trong thư viện, rất đáng để xem.
Darcy Rayner

4
Với upvote thứ 8 cho câu trả lời này, tôi đã đạt được 2k điểm danh tiếng. Tôi đánh giá rất cao sự tin tưởng bạn đã đặt vào tôi. Đây vừa là sự ghi nhận những nỗ lực của tôi vừa là sự kích thích để tiếp tục nỗ lực hết mình trong việc đưa ra câu trả lời chất lượng cao nhất có thể. Cảm ơn bạn
FxIII

Đợi đã, tài khoản này cho hai trường hợp góc chính xác? Chẳng hạn, một vòng tròn có thể đi qua mặt phẳng được xác định bởi đường bên ngoài t0 <= t <= t1, nhưng nhấn vào điểm cuối của đoạn đường một lát sau. Bạn cần kiểm tra khoảng cách tối thiểu giữa các điểm cuối đường và đường dẫn vòng tròn. Nếu khoảng cách đó nhỏ hơn bán kính vòng tròn, thì đường kẻ đã bị đánh.
Darcy Rayner

@DarcyRayner bạn có nghĩa là trường hợp khi cả hai điểm nằm trong khu vực vòng tròn?
FxIII
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.