2 डी में, मैं किसी बिंदु पर निकटतम वस्तु को कुशलता से कैसे खोज सकता हूं?


35

मेरे पास एक बड़ा खेल इंजन है और मैं अंकों की सूची के निकटतम खोजने के लिए एक सुविधा चाहूंगा।

मैं बस पाइथागोरस प्रमेय का उपयोग प्रत्येक दूरी को खोजने और न्यूनतम एक को चुनने के लिए कर सकता था, लेकिन उन सभी के माध्यम से पुनरावृत्ति की आवश्यकता होती है।

मेरे पास एक टक्कर प्रणाली भी है, जहां अनिवार्य रूप से मैं वस्तुओं को एक छोटी ग्रिड (एक मिनिमैप की तरह) पर छोटी वस्तुओं में बदल देता हूं और केवल अगर वस्तुएं समान ग्रिड में मौजूद होती हैं, तो मैं टकरावों की जांच करता हूं। मैं ऐसा कर सकता था, केवल निकटता की जाँच के लिए ग्रिड रिक्ति को बड़ा बनाता था। (हर एक वस्तु की जाँच करने के बजाय।) हालाँकि, यह मेरे बेस क्लास में अतिरिक्त सेटअप लेगा और पहले से ही अव्यवस्थित वस्तु को हटा देगा। यह इसके लायक है?

क्या कुछ कुशल और सटीक है जो मैं यह पता लगाने के लिए उपयोग कर सकता हूं कि अंक और आकारों की सूची के आधार पर कौन सी वस्तु निकटतम है?


X और y पदों के वर्ग संस्करणों को स्टोर करें ताकि आप अंत में महंगा sqrt करने के बिना पाइथागोरस प्रमेय कर सकें।
जोनाथन कॉनेल

3
इसे निकटतम पड़ोसी खोज कहा जाता है । इसके बारे में इंटरनेट पर बहुत कुछ लिखा है। सामान्य समाधान किसी प्रकार के अंतरिक्ष-विभाजन वाले पेड़ का उपयोग करना है।
ब्लूराजा - डैनी पफ्लुघोफ्ट

जवाबों:


38

निकटतम-पड़ोसी खोजों में एक क्वाड / ऑक्ट्री के साथ समस्या यह है कि निकटतम वस्तु नोड्स के बीच विभाजन में सही बैठी हो सकती है। टक्करों के लिए, यह ठीक है, क्योंकि यदि यह नोड में नहीं है, तो हम इसके बारे में परवाह नहीं करते हैं। लेकिन इस चौदहवें उदाहरण पर विचार करें:

चौपाई उदाहरण

यहां, भले ही काली वस्तु और हरी वस्तु एक ही नोड में हो, लेकिन काली वस्तु नीले आइटम के सबसे करीब है। ultifinitus का जवाब केवल निकटतम-पड़ोसी की गारंटी दे सकता है कि आपके पेड़ की हर वस्तु को सबसे कम संभव नोड में रखा गया है जो इसे शामिल कर सकता है, या एक अद्वितीय नोड में - यह अधिक अक्षम चतुर्भुज की ओर जाता है। (ध्यान दें कि एक संरचना को लागू करने के कई अलग-अलग तरीके हैं जिन्हें क्वाड / ऑक्ट्री कहा जा सकता है - इस एप्लिकेशन में अधिक सख्त कार्यान्वयन काम कर सकते हैं।)

एक बेहतर विकल्प एक केडी-ट्री होगा । केडी-पेड़ों में एक बहुत ही कुशल निकटतम पड़ोसी खोज एल्गोरिदम है जिसे आप कार्यान्वित कर सकते हैं, और इसमें किसी भी संख्या में आयाम हो सकते हैं (इसलिए "के / आयाम")।

विकिपीडिया से एक महान और सूचनात्मक एनीमेशन: kd-tree निकटतम पड़ोसी खोज

केडी-पेड़ों का उपयोग करने के साथ सबसे बड़ी समस्या है, अगर मैं सही ढंग से याद करता हूं, तो यह है कि संतुलन बनाए रखते हुए वस्तुओं को सम्मिलित / निकालना अधिक कठिन है। इसलिए, मैं स्थैतिक वस्तुओं जैसे घरों और पेड़ों के लिए एक केडी-ट्री का उपयोग करने की सलाह दूंगा जो अत्यधिक संतुलित है, और दूसरा जिसमें खिलाड़ी और वाहन शामिल हैं, जिन्हें नियमित रूप से संतुलन की आवश्यकता होती है। निकटतम स्थिर ऑब्जेक्ट और निकटतम मोबाइल ऑब्जेक्ट ढूंढें, और उन दो की तुलना करें।

अन्त में, केडी-वृक्षों को लागू करना अपेक्षाकृत सरल है, और मुझे यकीन है कि आप उनके साथ C ++ पुस्तकालयों की भीड़ पा सकते हैं। मुझे जो याद है, उससे आर-पेड़ बहुत अधिक जटिल हैं, और शायद ओवरकिल अगर आपको ज़रूरत है तो एक साधारण निकटतम पड़ोसी खोज है।


1
शानदार उत्तर, छोटा विवरण "केवल एक निकटतम गारंटी-पड़ोसी केवल आपके पेड़ में हर वस्तु को सबसे छोटी संभव नोड में रखा गया है" मेरा मतलब था कि एक ही और पड़ोसी नोड्स में सभी वस्तुओं पर पुनरावृत्ति होती है, इसलिए आप 10 के बजाय 10 से अधिक लूप करते हैं 10.000।
रॉय टी।

1
बहुत सच है - मुझे लगता है कि "केवल" एक कठोर शब्द था। निश्चित रूप से पास-पड़ोस की खोजों में क्वाडट्रैक्स को समेटने के तरीके हैं, इस पर निर्भर करता है कि आप उन्हें कैसे लागू करते हैं, लेकिन यदि आप उन्हें पहले से ही अन्य कारणों से उपयोग नहीं कर रहे हैं (जैसे टकराव का पता लगाना), तो मैं अधिक अनुकूलित केडी-ट्री के साथ रहना चाहूंगा।
dlras2

मैं यह नोट करना चाहता था कि मैंने एक कार्यान्वयन किया है जो काले हरे नीले समस्या से संबंधित है। नीचे की जाँच करें।
clankill3r

18

sqrt() गैर-नकारात्मक तर्कों के लिए मोनोटोनिक या ऑर्डर-प्रोटेक्शन है:

sqrt(x) < sqrt(y) iff x < y

और इसके विपरीत।

इसलिए यदि आप केवल दो दूरियों की तुलना करना चाहते हैं, लेकिन उनके वास्तविक मूल्यों में कोई दिलचस्पी नहीं है, तो आप sqrt()अपने पाइथागोरस-सामान से केवल -स्टेप को काट सकते हैं :

pseudoDistanceB = (A.x - B.x + (A.y - B.y
pseudoDistanceC = (A.x - C.x + (A.y - C.y
if (pseudoDistanceB < pseudoDistanceC)
{
    A is closest to B!
}
else
{
    A is closest to C!
}

यह ऑक्ट-ट्री चीज़ जितना कुशल नहीं है, लेकिन इसे लागू करना आसान है और कम से कम थोड़ी सी गति को बढ़ा देता है


1
उस मीट्रिक को वर्गीय यूक्लिडियन दूरी के रूप में भी जाना जाता है ।
मूओइप जूल

10

आपको स्थानिक विभाजन करना होगा, इस मामले में आप एक कुशल डेटा संरचना (आमतौर पर एक ओक्ट्री) बनाते हैं। इस स्थिति में प्रत्येक ऑब्जेक्ट एक या अधिक रिक्त स्थान (क्यूब्स) के अंदर होता है और यदि आप जानते हैं कि आप किन स्थानों में हैं तो आप O (1) को देख सकते हैं कि आपके पड़ोसी कौन से स्थान हैं।

इस मामले में निकटतम वस्तु को अपने स्वयं के अंतरिक्ष में सभी वस्तुओं पर सबसे पहले पुनरावृत्त करके पाया जा सकता है कि कौन सा सबसे निकटतम है। यदि कोई नहीं है, तो आप अपने पहले पड़ोसियों की जांच कर सकते हैं, यदि कोई नहीं है तो आप उनके पड़ोसियों की जांच कर सकते हैं, आदि ...

इस तरह से आप अपनी दुनिया की सभी वस्तुओं के माध्यम से आसानी से निकटतम वस्तु को आसानी से पा सकते हैं। हमेशा की तरह इस गति लाभ के लिए बहीखाता पद्धति की आवश्यकता होती है, लेकिन यह वास्तव में सभी प्रकार के सामानों के लिए उपयोगी है, इसलिए यदि आपके पास एक बड़ी दुनिया है तो यह निश्चित रूप से स्थानिक विभाजन और एक ऑक्ट्री को लागू करने के लायक है।

हमेशा की तरह, विकिपीडिया लेख भी देखें: http://en.wikipedia.org/wiki/Octree


7
@ultifinitus इसे जोड़ने के लिए: यदि आपका गेम 2D है तो आप Octrees के बजाय QuadTrees का उपयोग कर सकते हैं।
ट्रैविसग

1

हो सकता है कि अपने स्थानिक डेटा को आरट्री में व्यवस्थित करने का प्रयास करें, जो अंतरिक्ष में सामान के लिए बीट्री की तरह है और "निकटतम एन पड़ोसियों" आदि जैसे प्रश्नों की अनुमति देता है ... http://en.wikipedia.org/wiki/Rtree


0

यहाँ एक क्वाडट्री से निकटतम प्राप्त करने के लिए मेरा जावा कार्यान्वयन है। यह समस्या का वर्णन करता है dlras2 वर्णन कर रहा है:

यहाँ छवि विवरण दर्ज करें

मुझे लगता है कि ऑपरेशन वास्तव में कुशल है। यह एक क्वाड की दूरी पर आधारित है ताकि आगे के निकटतम रास्ते में खोज की जा सके।

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

public T getClosest(float x, float y) {

    Closest closest = new Closest();
    getClosest(x, y, closest);

    return closest.item;
}

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

protected void getClosest(float x, float y, Closest closestInfo) {


    if (hasQuads) {

        // we have no starting point yet
        // so get one
        if (closestInfo.item == null) {
            // check all 4 cause there could be a empty one
            for (int i = 0; i < 4; i++) {
                quads[i].getClosest(x, y, closestInfo);
                if (closestInfo.item != null) {
                    // now we have a starting point
                    getClosest(x, y, closestInfo);
                    return;
                }

            }
        }
        else {

            // we have a item set as closest
            // we should check if this quad is
            // closer then the current closest distance
            // let's start with the closest from index

            int closestIndex = getIndex(x, y);

            float d = quads[closestIndex].bounds.distToPointSQ(x, y);

            if (d < closestInfo.dist) {
                quads[closestIndex].getClosest(x, y, closestInfo);
            }

            // check the others
            for (int i = 0; i < 4; i++) {
                if (i == closestIndex) continue;

                d = quads[i].bounds.distToPointSQ(x, y);

                if (d < closestInfo.dist) {
                    quads[i].getClosest(x, y, closestInfo);
                }

            }

        }

    }
    else {

        for (int i = 0; i < items.size(); i++) {

            T item = items.get(i);

            float dist = distSQ(x, y, getXY.x(item), getXY.y(item));

            if (dist < closestInfo.dist) {
                closestInfo.dist = dist;
                closestInfo.item = item;
                closestInfo.tree = this;
            }

        }
    }

}

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .


class Closest {

    QuadTree<T> tree;
    T item;
    float dist = Float.MAX_VALUE;

}

पीएस मुझे अभी भी लगता है कि केडी-ट्री या कुछ और का उपयोग करना बेहतर है, लेकिन इससे लोगों को मदद मिल सकती है।
clankill3r

इसे भी देखें: bl.ocks.org/llb4ll/8709363
clankill3r
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.