मैं एक 2D मानचित्र में पानी से जुड़े (लेकिन तार्किक रूप से अलग) निकायों का पता कैसे लगा सकता हूं?


17

मेरे पास 2 डी हेक्सागोनल ग्रिड मैप है। प्रत्येक हेक्स सेल में एक ऊंचाई मूल्य होता है जो यह निर्धारित करता है कि यह पानी या महासागर है। मैं पानी के निकायों को निर्धारित करने और लेबल करने के लिए एक अच्छा तरीका सोचने की कोशिश कर रहा हूं। महासागरों और अंतर्देशीय समुद्रों में आसानी होती है (बाढ़ भराव एल्गोरिथ्म का उपयोग करके)।

लेकिन भूमध्य सागर जैसे पानी के निकायों के बारे में क्या ? पानी की हड्डियां जो बड़े लोगों से जुड़ी होती हैं (जहां "समुद्र" और "गलफड़े" केवल उद्घाटन के आकार से भिन्न होते हैं)?

यहां एक उदाहरण दिया गया है कि मैं क्या पता लगाने की कोशिश कर रहा हूं (छवि के बीच में पानी का नीला शरीर, जिसे तकनीकी रूप से जुड़े होने के बावजूद समुद्र के बड़े शरीर से अलग तरह से लेबल किया जाना चाहिए): दुनिया का नक्शा

कोई विचार?

जवाबों:


10

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

अनिवार्य रूप से, आप सभी वाटर टाइल्स को एक ग्राफ में जोड़ते हैं। ग्राफ़ में किनारों को वज़न निर्दिष्ट करें जो आसन्न जल टाइलों के बीच अंतर के अनुरूप है। मुझे लगता है कि आपके मामले में, सभी भार 1. हो सकते हैं। वांछनीय परिणाम प्राप्त करने के लिए आपको विभिन्न भार योजनाओं के साथ खेलना होगा। उदाहरण के लिए, आपको कुछ वज़न जोड़ना होगा, जिसमें समीपवर्ती सम्‍मिलित सम्‍मिलित सम्‍मिलित हो सकते हैं।

फिर, ग्राफ़ के सभी जुड़े हुए घटकों को खोजें। ये स्पष्ट समुद्र / झीलें आदि हैं।

अंत में, प्रत्येक जुड़े घटक के लिए, पुनरावर्ती रूप से घटक को उप-विभाजित करें जैसे कि दो नए उप-घटकों को जोड़ने वाले किनारों का न्यूनतम वजन होता है । जब तक सभी उप-घटक न्यूनतम आकार (जैसे कि समुद्र के अधिकतम आकार) तक नहीं पहुंच जाते, या यदि दो घटकों को काटने वाले किनारों का वजन बहुत अधिक न हो जाए, तो पुनरावर्ती उप-विभाजन रखें। अंत में, जुड़े हुए सभी घटकों को लेबल करें।

व्यवहार में यह क्या करेगा कि चैनलों पर समुद्रों को एक-दूसरे से काट दिया जाता है, लेकिन महासागरों के बड़े फैलाव नहीं।

यहाँ यह छद्मकोड में है:

function SegmentGraphCut(Map worldMap, int minimumSeaSize, int maximumCutSize)
    Graph graph = new Graph();
    // First, build the graph from the world map.
    foreach Cell cell in worldMap:
        // The graph only contains water nodes
        if not cell.IsWater():
            continue;

        graph.AddNode(cell);

        // Connect every water node to its neighbors
        foreach Cell neighbor in cell.neighbors:
            if not neighbor.IsWater():
                continue;
            else:  
                // The weight of an edge between water nodes should be related 
                // to how "similar" the waters are. What that means is up to you. 
                // The point is to avoid dividing bodies of water that are "similar"
                graph.AddEdge(cell, neighbor, ComputeWeight(cell, neighbor));

   // Now, subdivide all of the connected components recursively:
   List<Graph> components = graph.GetConnectedComponents();

   // The seas will be added to this list
   List<Graph> seas = new List<Graph>();
   foreach Graph component in components:
       GraphCutRecursive(component, minimumSeaSize, maximumCutSize, seas);


// Recursively subdivides a component using graph cut until all subcomponents are smaller 
// than a minimum size, or all cuts are greater than a maximum cut size
function GraphCutRecursive(Graph component, int minimumSeaSize, int maximumCutSize, List<Graph> seas):
    // If the component is too small, we're done. This corresponds to a small lake,
    // or a small sea or bay
    if(component.size() <= minimumSeaSize):
        seas.Add(component);
        return;

    // Divide the component into two subgraphs with a minimum border cut between them
    // probably using the Ford-Fulkerson algorithm
    [Graph subpartA, Graph subpartB, List<Edge> cut] = GetMinimumCut(component);

    // If the cut is too large, we're done. This corresponds to a huge, bulky ocean
    // that can't be further subdivided
    if (GetTotalWeight(cut) > maximumCutSize):
        seas.Add(component);
        return;
    else:
        // Subdivide each of the new subcomponents
        GraphCutRecursive(subpartA, minimumSeaSize, maximumCutSize);
        GraphCutRecursive(subpartB, minimumSeaSize, maximumCutSize);

संपादित करें : वैसे, यहाँ एल्गोरिथ्म आपके उदाहरण के साथ न्यूनतम समुद्र के आकार के साथ लगभग 40 तक सेट करेगा, अधिकतम 1 के कट आकार के साथ, यदि सभी किनारे का वजन 1 है:

Imgur

मापदंडों के साथ खेलकर, आप विभिन्न परिणाम प्राप्त कर सकते हैं। उदाहरण के लिए, 3 के एक अधिकतम कट आकार का परिणाम होगा कि मुख्य समुद्रों से कई और खण्ड निकले हैं, और समुद्र # 1 उत्तर और दक्षिण में आधा विभाजित हो जाएगा। 20 के न्यूनतम समुद्री आकार के परिणामस्वरूप केंद्रीय समुद्र आधे में भी विभाजित हो जाएगा।


शक्तिशाली लगता है। निश्चित रूप से प्रेरित।
v.oddou

इस पोस्ट के लिए आपका बहुत - बहुत धन्यवाद। मैं आपके उदाहरण से कुछ उचित पाने में कामयाब रहा
केलन कोटेर

6

पानी के एक अलग लेकिन जुड़े शरीर की पहचान करने का एक त्वरित और गंदा तरीका सभी जल निकायों को सिकोड़ना और देखना होगा कि क्या अंतराल दिखाई देते हैं।

ऊपर दिए गए उदाहरण में, मुझे लगता है कि सभी पानी की टाइलें, जिनमें 2 या उससे कम पानी की टाइलें हैं, को हटाने (लाल रंग से चिह्नित) को हटाने से आपको वांछित परिणाम और कुछ बढ़त शोर के साथ प्रदान किया जाएगा। आपके द्वारा निकायों को चिह्नित करने के बाद, आप पानी को उसकी मूल स्थिति में "प्रवाह" कर सकते हैं और अब अलग किए गए निकायों के लिए हटाए गए टाइल को पुनः प्राप्त कर सकते हैं।

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

फिर से, यह एक त्वरित और गंदा समाधान है, यह उत्पादन के बाद के चरणों के लिए पर्याप्त अच्छा नहीं हो सकता है लेकिन यह "अभी के लिए यह काम करना" होगा और किसी अन्य सुविधा पर आगे बढ़ेगा।


5

यहाँ एक पूर्ण एल्गोरिथ्म है जो मुझे लगता है कि अच्छे परिणाम उत्पन्न करने चाहिए।

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

    (यह आपके अंतर्देशीय समुद्र के बाएं हिस्से में नदियों के पानी के द्वीपों पर विचार करेगा। यदि यह एक समस्या है, तो आप एक अलग नियम का उपयोग कर सकते हैं जैसे कि एक vrinek का उत्तर इसके बजाय प्रस्तावित करता है; निम्नलिखित चरण अभी भी तब तक काम करेंगे जब तक आप करेंगे; यहाँ किसी प्रकार की "नदियों को हटाओ" कदम है।

  2. मिट गए नक्शे के जुड़े पानी के घटकों का पता लगाएं और हर एक को एक अनूठा लेबल दें। (मुझे लगता है कि आप पहले से ही जानते हैं कि यह कैसे करना है।) यह अब सब कुछ लेबल करता है, लेकिन नदियों और किनारे के पानी (जहां कटाव का प्रभाव था)।

  3. मूल मानचित्र में प्रत्येक पानी की टाइल के लिए , मिटे हुए नक्शे में पड़ोसी पानी की टाइलों पर मौजूद लेबल को ढूंढें और फिर:

    • यदि टाइल में मिट गए नक्शे में स्वयं एक लेबल है, तो यह मध्य समुद्र का पानी है; इसे मूल नक्शे में लेबल दें।
    • यदि आपको केवल एक अलग पड़ोसी लेबल मिलता है, तो यह किनारे या नदी का मुंह है; इसे वह लेबल दें।
    • यदि आप कोई लेबल नहीं पाते हैं, तो यह एक नदी है; इसे अकेला छोड़ दो।
    • यदि आपको कई लेबल मिलते हैं, तो यह दो बड़े निकायों के बीच की छोटी अड़चन है; आप या तो इसे नदी की तरह मान सकते हैं, या एक लेबल के तहत दोनों निकायों को मिला सकते हैं।

    (ध्यान दें कि इस चरण के लिए आपको इरोड्ड मैप के लिए लेबल के अलग-अलग ग्रिड (या एक संरचना में दो लेबल फ़ील्ड) रखने होंगे (जो आप पढ़ते हैं) और मूल (जो आप लिखते हैं), या पुनरावृत्ति होगी- आदेश-निर्भर त्रुटियाँ।)

  4. यदि आप अलग-अलग नदियों को विशिष्ट रूप से लेबल करना चाहते हैं, तो उपरोक्त चरणों के बाद, अनबेल्ड-वॉटर के सभी शेष जुड़े घटकों को ढूंढें और उन्हें लेबल करें।


1

व्रिंक के विचार के बाद, भूमि के बढ़ने (या पानी के सिकुड़ने) के बारे में कैसे आप मूल रूप से जुड़े होंगे, भूमि के बड़े होने के बाद डिस्कनेक्ट हो जाएगी?

ऐसा किया जा सकता है:

  1. परिभाषित करें कि आप भूमि को कितना विकसित करना चाहते हैं: 1 हेक्स? 2 हेक्सेज़? यह मान हैn

  2. सभी लैंड नोड पर जाएं, और अपने सभी पड़ोसियों nको लैंड नोड्स की गहराई तक सेट करें (एक कॉपी लिखें, जैसा कि अनंत लूप नहीं मिलता है)

  3. यह निर्धारित करने के लिए कि अब क्या जुड़ा हुआ है और क्या नहीं है, अपने मूल फ़्लफ़िल एल्गोरिथ्म को फिर से चलाएँ


0

क्या आपको लगता है कि खाड़ी कहाँ है? यदि ऐसा है, तो आप अपने बाढ़ भरण को पड़ोसी लेकिन अस्पष्टीकृत कोशिकाओं की संख्या को ट्रैक करने के लिए संशोधित कर सकते हैं (साथ में देखी गई कोशिकाओं की सूची)। यह एक हेक्स मैप में 6 से शुरू होता है और जब भी यह मूल्य एक निश्चित बिंदु से नीचे चला जाता है, तो आप जानते हैं कि आप एक "ओपनिंग" मार रहे हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.