Làm thế nào để hình dạng (hình chữ nhật) làm việc trong cây Quad?


10

Tôi đã được thông báo rằng cây tứ giác là cấu trúc dữ liệu lý tưởng cho trò chơi của tôi, nhưng tôi gặp khó khăn trong việc hiểu chính xác hình dạng hoạt động như thế nào trong cây tứ giác.

Tôi đang làm điều này bằng JavaScript, nhưng tôi nghĩ những câu hỏi này có thể áp dụng cho bốn cây trong bất kỳ ngôn ngữ nào.

Tôi nghĩ tôi chủ yếu là hiểu được cách cơ bản (x, y) điểmchèn điểm công trình trong cây quad, và rằng tôi có thể làm điều đó trên giấy.

Đây là một JSfiddle về thử nghiệm của tôi với các điểm.

điểm cây bốn

Ngoài một trường hợp, các bài kiểm tra của tôi với các điểm đang hoạt động như mong đợi.

Nhưng sự nhầm lẫn của tôi bắt đầu khi các hình dạng như hình chữ nhật có liên quan. Khi bạn đang lấy từ một cây tứ giác có hình dạng, nó có kiểm tra từng điểm của hình dạng không, và chúng rơi vào nút nào? Và làm thế nào để chèn hình dạng thậm chí hoạt động, khi nó chấp nhận các tham số (x, y, chiều rộng, chiều cao) cho mỗi hình dạng? Nó có sử dụng chiều rộng / chiều cao từ điểm bắt đầu để tính các điểm góc khác, sau đó được phân phối vào các nút thích hợp không? Nếu một hình dạng được chèn kéo dài thành bốn nút, dữ liệu của hình dạng đó có được lưu vào tất cả bốn nút không?

Và khi một phương thức truy xuất chấp nhận một hình dạng là tham số (x, y, chiều rộng, chiều cao), điều gì đang thực sự xảy ra? Đây có phải là lần đầu tiên nhìn thấy các nút mà hình dạng sẽ kéo dài đến đâu nếu nó được chèn vào, và sau đó lấy tất cả các đối tượng của các nút đó?

Tôi có một JSfiddle làm việc với các hình dạng , nhưng tôi hoàn toàn bối rối về kết quả thử nghiệm của mình. Tôi đang nhận được các đối tượng trùng lặp được trả lại!

hình dạng cây quad

Ví dụ, hình vuông màu đỏ là một hình vẽ tương đương với các tham số tôi đang nhập vào phương thức truy xuất của mình. Tôi nghĩ rằng vì hình vuông màu đỏ này trải dài cả bốn nút, nên nó sẽ trả về mọi đối tượng trong cây tứ giác! Nhưng nó không, và tôi gặp khó khăn trong việc hợp lý hóa những gì nó trở lại. Tôi có một số bài kiểm tra khác hiện đang được bình luận, nhưng bạn có thể bỏ bình luận và chạy chúng để xem kết quả khó hiểu hơn!

Như đã nói, nếu tôi muốn trả về tất cả các điểm trong cây tứ giác, tôi sẽ làm thế nào? Một phương thức lấy bằng cách sử dụng một hình dạng toàn bộ kích thước của giới hạn? Ví dụ: lấy (0, 0, canvas. Thong, canvas.height)?

Các thư viện JavaScript quadtree Tôi đang sử dụng đã được gọi bằng các nguồn khác nhau, vì vậy tôi cho rằng việc thực hiện thực tế là chính xác và có uy tín.

Tôi nghĩ rằng rất nhiều sự nhầm lẫn của tôi có thể xuất phát từ sự hiểu lầm về thuật ngữ cây bốn lá. Giống như, tại sao họ nói giới hạn thay vì kích thước, khi một "điểm" cũng có các tham số chiều rộng / chiều cao? Đây có phải là vấn đề của quy ước / tay ngắn, hay chúng là những khái niệm hoàn toàn khác nhau?

Cảm ơn vì đã dành thời gian cho tôi!


Chúng được lưu trữ trong cây quad như bình thường, theo vị trí của chúng. Thông thường những người ở trung tâm, nhưng có thể ở trong góc như bạn đã xác định. Câu hỏi của bạn có thể là một bản sao của câu hỏi này: QuadTree: chỉ lưu trữ điểm hoặc vùng?
MichaelHouse

Tôi đã đọc câu hỏi đó, nhưng tôi vẫn không hoàn toàn hiểu câu trả lời :(. "Bạn phải lưu nó trong nút nhỏ nhất chứa hoàn toàn nó - ngay cả khi điều này vượt quá khả năng (sử dụng một thùng chứa có thể thay đổi kích thước)." - Khi anh ấy cho biết nút nhỏ nhất HOÀN TOÀN chứa nó, nếu đối tượng rất lớn, nút đó có thường là nút không có lá không? Như trong một nút cao hơn chỉ bao gồm các nút khác? Điều đó dường như không đúng tôi, vì điều đó có nghĩa là nút chứa sẽ có 1 lá và 4 nút nhỏ hơn trong đó.
user2736286

1
@ user2736286 Nếu bạn xem mã cho bộ tứ lib (nó không dài lắm), bạn có thể thấy nó lưu trữ hình chữ nhật trong các nút ở mức cao hơn để giữ cho chúng không bị viền biên. Xem các tham chiếu đến _stuckChildrentrường trong mã. Bạn cũng có thể thấy điều này trong mẫu "truy xuất các mục có giới hạn" - nó luôn làm nổi bật màu đỏ các nút nằm trên đường viền của các nút mà bạn đã nhấp, cho đến tận nút gốc.
Nathan Reed

@ user2736286 Ngoài ra, lib tứ giác dường như có một lỗi trong việc truy xuất các mục có giới hạn - nếu bạn cung cấp cho nó một chỉnh sửa truy vấn mà đặt một số đường viền nút, nó sẽ không trả về tất cả các đường trong các nút mà truy vấn chạm vào. Bạn cũng có thể thấy điều này một cách dễ dàng trong "truy xuất các mục có giới hạn" bằng cách nhấp vào gần các đường viền nút.
Nathan Reed

@NathanReed Trước đó tôi đã cố gắng hiểu mã, nhưng tôi không đủ kỹ năng để hiểu nó mà không có nền tảng khái niệm. Nhờ mã giả John McDonald, giờ đây tôi đã hiểu cách hình chữ nhật được chèn vào các nút, nhưng tôi nghĩ rằng tôi vẫn chưa rõ về cách thức hoạt động của truy xuất. Đối với "lấy vật phẩm có giới hạn" - tôi hoàn toàn bối rối trước ví dụ này. Giống như, khi tôi nhấp vào một chỉnh lưu vừa vặn với một trong các nút nhỏ nhất, tại sao tất cả các phần tử khác bên ngoài nút đó cũng được tô sáng?
dùng2736286

Câu trả lời:


10

Quadtrees thường lưu trữ và truy xuất hình chữ nhật. Một điểm là một trường hợp cụ thể trong đó chiều rộng và chiều cao bằng không. Logic sau đây được sử dụng để tìm nhà cho các hình chữ nhật mới trong cây, bắt đầu bằng nút gốc:

void Store(Rectangle rect)
{
    if(I have children nodes)
    {
        bool storedInChild = false;
        foreach(Node childNode in nodes)
        {
            if(this rectangle fits entirely inside the childNode bounds)
            {
                childNode.Store(rect);   // Go deeper into the tree
                storedInChild = true;
                break;
            }
        }
        if(not storedInChild)
        {
            Add this rectangle to the current node
        }
    }
    else
    {
        Add this rectangle to the current node
    }
}

Lưu ý rằng hình chữ nhật có thể được lưu trữ ở bất kỳ độ sâu nào, nó không phải là hình tứ giác. Nếu hình chữ nhật đứng trên ranh giới ngay ở cấp độ gốc, bộ tứ gốc sẽ lưu trữ hình chữ nhật.

Ví dụ, hình vuông màu đỏ là một hình vẽ tương đương với các tham số tôi đang nhập vào phương thức truy xuất của mình. Tôi nghĩ rằng vì hình vuông màu đỏ này trải dài cả bốn nút, nên nó sẽ trả về mọi đối tượng trong cây tứ giác! Nhưng nó không, và tôi gặp khó khăn trong việc hợp lý hóa những gì nó trở lại.

Khi truy vấn tứ giác, nó sẽ chỉ trả về các hình chữ nhật được chứa bởi truy vấn. Trong ví dụ của bạn, bạn buộc mỗi trong số 4 hình tứ con được xem xét chi tiết hơn vì hình chữ nhật truy vấn màu đỏ giao nhau với mỗi hình tứ con. Vì trẻ em không có thêm con, nên mỗi hình chữ nhật trong các hình con này sẽ được so sánh với hình chữ nhật màu đỏ. Vì không có hình chữ nhật nào trong cây va chạm với hình chữ nhật truy vấn màu đỏ, nên không có gì được trả về.

Bạn thực sự bắt đầu thấy lợi ích của tứ giác khi bạn có nhiều đối tượng và nhiều không gian cho các đối tượng tồn tại so với (các) khu vực truy vấn. Trong những trường hợp này, một khu vực truy vấn nhỏ có thể nhanh chóng loại bỏ các khối lớn của cây tứ giác khỏi xem xét. Chỉ các hình tứ giác giao nhau với hình chữ nhật truy vấn sẽ được xem xét chi tiết hơn.

BIÊN TẬP

Lấy lại thường được thực hiện như sau:

List<Rectangle> Query(Rectangle queryRect)
{
    List<Rectangle> results;
    foreach(Node childNode in children)
    {
        if(queryRect intersects with childNode bounds)
        {
            results += childNode.Query(queryRect);   // Dig deeper into the tree
        }
    }

    foreach(Rectangle I have stored in this quad)
    {
        if(queryRect intersects with rect)  // Your library doesn't do this
        {
            results += rect;
        }
    }

    return results;
}

Tuy nhiên, trong thư viện của bạn, dường như không kiểm tra xem các hình chữ nhật có trở lại giao nhau với truy vấn hay không, vì vậy bạn sẽ cần phải tự thêm nó.


Sau khi xem thư viện của bạn chi tiết hơn, thư viện của bạn sẽ trả về một danh sách tất cả các ứng cử viên va chạm có thể có cho hình chữ nhật truy vấn bạn chỉ định. Dường như công việc của bạn là so sánh hình chữ nhật truy vấn của bạn với từng ứng viên để xem liệu có xung đột thực sự hay không. Hầu hết các thư viện thực hiện bước cuối cùng đó cho bạn và chỉ trả lại các xung đột thực tế với vùng truy vấn. Vì vậy, tất cả những gì bạn cần làm là thêm một số logic trong retrievephương thức của bạn để cắt xén danh sách. Bạn có thể thấy những gì nó đang làm rõ hơn một chút ở đây: mikechambers.com/html5/javascript/QuadTree/examples/ Kẻ
John McDonald

1
@ user2736286 Trong trường hợp bạn chưa chọn nó, điều quan trọng cần lưu ý là đệ quy trong các hàm Truy vấn và Lưu trữ mà JohnMcDonald đã viết. Sẽ không có ý nghĩa nhiều nếu bạn không có phần đó. Đối với cả hai, mỗi đệ quy đi sâu hơn vào cây, tức là ra trên cành và cuối cùng thành lá.
TASagent

Cảm ơn John, mã giả của bạn rất hữu ích. Khi bạn nói "if (queryRect giao với giới hạn childNode)", về cơ bản điều đó có nghĩa là nếu queryRect được chứa trong giới hạn - một phần hay toàn bộ? Chỉ muốn được rõ ràng 100%. Ngoài ra, trong ví dụ "truy xuất mục theo giới hạn" đang được thảo luận, tôi có một hình ảnh về kết quả nhấp chuột của mình. Pic Dấu chấm màu xanh là nơi tôi nhấp. Vậy tại sao không chỉ có hai hình chữ nhật bên trong nút đó sáng? Tại sao các hình chữ nhật cách xa nó cũng được làm nổi bật? Tôi nghĩ đó là những gì thực sự làm tôi bối rối.
dùng2736286

Một phần hoặc đầy đủ. Nếu hai chạm, hoặc một trong hai được chứa hoàn toàn. Bạn muốn đọc wiki trên Quadtrees , nhưng tôi đã chụp ảnh của bạn và màu sắc được mã hóa để thể hiện các ranh giới con khác nhau. Tất cả các hình chữ nhật màu xanh đang giao nhau với ranh giới của các hình con thứ nhất, sau đó màu đỏ tươi sâu hơn một lớp và màu xanh lá cây sâu hơn một lớp. Hình chữ nhật màu đỏ giao nhau với hình tứ giác được nhấp. Thư viện của bạn trả về tất cả các đường trên ranh giới con cộng với tất cả được chứa trong bộ tứ con cuối cùng (màu đỏ): i.imgur.com/InB8KBj.png
John McDonald

Ok, vì vậy tôi đã cố gắng hết sức để xem mã nguồn của lib và cuối cùng tôi cũng hiểu hành vi của bị mắc kẹt, và tất cả những điều chỉnh thêm trong ảnh của tôi chỉ đơn giản là bị mắc kẹt. Ban đầu tôi nghĩ rằng bất kỳ phân vùng nào trải rộng trên nhiều nút sẽ chỉ có dữ liệu được sao chép và chèn vào mỗi nút nhỏ hơn. Bây giờ tôi nhận ra rằng bị mắc kẹt không bị chèn vào các nút mà nó mở rộng, mà chỉ đơn giản là nằm trong một nút có chứa nó, đó là lý do tại sao tôi cũng phải kiểm tra tất cả các nút cha và không chỉ là nút nhỏ nhất chứa trực tiếp truy vấn của tôi. Cảm ơn vì pic; bây giờ nó có ý nghĩa hơn nhiều :)
user2736286
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.