नेत्रहीन अपील और सहज तरीके से लेबल फैलाने के लिए एल्गोरिदम


24

लघु संस्करण

क्या एक गैर-अतिव्यापी फैशन में वाहन के लेबल को वितरित करने के लिए एक डिज़ाइन पैटर्न है, उन्हें उस वाहन के जितना संभव हो उतना निकट रखना? यदि नहीं, तो क्या कोई ऐसी विधि है जो मैं व्यवहार्य होने का सुझाव दूं? आप इसे खुद कैसे लागू करेंगे?

विस्तारित संस्करण

खेल में मैं लिख रहा हूँ मैं अपने हवाई वाहनों की एक पक्षी-दृष्टि है। मेरे पास प्रत्येक वाहन के पास एक छोटा लेबल है जिसमें वाहन के बारे में कुंजी-डेटा है। यह एक वास्तविक स्क्रीनशॉट है:

उनके लेबल वाले दो वाहन

अब, चूंकि वाहन विभिन्न ऊंचाई पर उड़ सकते हैं, इसलिए उनके आइकन ओवरलैप हो सकते हैं। हालाँकि मैं कभी भी उनके लेबल को ओवरलैप नहीं करना चाहूंगा (या वाहन 'ए' का लेबल वाहन 'बी' के आइकन को ओवरलैप कर सकता हूं)।

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

  B - label
A -----------label
  C - label

जहां बेहतर होगा (= वाहन के करीब लेबल) पाने के लिए:

          B - label
label - A
          C - label

संपादित करें: यह भी माना जाता है कि ओवरलैपिंग वाहनों के मामले के अलावा, ऐसे अन्य कॉन्फ़िगरेशन हो सकते हैं जिनमें वाहन ओवरलैप हो सकते हैं (उदाहरण के लिए ASCII- कला उदाहरण तीन बहुत करीबी वाहन दिखाते हैं जिसमें लेबल का Aआइकन ओवरलैप होता है। Bऔर C)।

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

इसके लायक क्या है, यहाँ दो विचार मैं सोच रहा था:

लेबल स्थान का स्लॉट-अलगाव

इस परिदृश्य में मैं सभी स्क्रीन को "स्लॉट" में लेबल के लिए विभाजित करूंगा। फिर, प्रत्येक वाहन के पास हमेशा उसका लेबल निकटतम खाली एक में रखा जाता है (खाली = उस स्थान पर कोई अन्य छिड़काव नहीं होता है)।

सर्पिल खोज

स्क्रीन पर वाहन के स्थान से, मैं लेबल को बढ़ते कोणों पर और फिर बढ़ते त्रिज्याओं में रखने की कोशिश करूंगा, जब तक कि एक गैर-अतिव्यापी स्थान न मिल जाए। की लाइन के नीचे कुछ:

try 0°, 10px
try 10°, 10px
try 20°, 10px
...
try 350°, 10px
try 0°, 20px
try 10°, 20px
...

1
एक समय में कितने विमान ओवरलैप हो सकते हैं?
wangburger

1
@ वैंगबर्गर - कभी नहीं सोचा था कि यह प्रासंगिक होगा (विचार की अपनी पंक्ति के बारे में अधिक जानने के लिए दिलचस्पी होगी), लेकिन जवाब है: यह खिलाड़ी की खेल रणनीति से निर्भर करता है। तकनीकी रूप से दुनिया में 24 वाहन ओवरलैपिंग हो सकते हैं, लेकिन अधिकांश गेम की स्थिति में यथार्थवादी आंकड़ा 3-4 है।
मैक

3
यह समय के एक उचित राशि के लिए अतिव्यापी लेकिन स्थिर लोगों की तुलना में विमान के सापेक्ष चलती लेबल होने के लिए अधिक भ्रमित नहीं है?
माईक सेमर

3
आपको en.wikipedia.org/wiki/… में रुचि हो सकती है - यह हल करने के लिए एक सरल समस्या नहीं है। एक सही समाधान खोजने की उम्मीद मत करो।
ब्लेकी

2
ग्राफविज़ , नेत्रहीन मनभावन तरीके से ग्राफ़ बिछाने के लिए उपकरणों का एक सूट है, जिसमें लेबल में ओवरलैप से बचने की प्रवृत्ति है। हालांकि यह सीधे प्रयोग करने योग्य नहीं हो सकता है, आप अपने प्रलेखन या स्रोत कोड से कुछ जानकारी को चमकाने में सक्षम हो सकते हैं कि वे अपने ग्राफ़ को लेआउट करने के लिए किस तरह के एल्गोरिदम का उपयोग करते हैं। वे उदाहरण के लिए, ऊर्जा-आधारित मॉडल और स्प्रिंग-आधारित मॉडल दोनों हैं।
लार्स विकलंड

जवाबों:


14

अनिवार्य रूप से यह मुद्दा टकराव से बचने की समस्या के समान है। हां, विमान अलग-अलग ऊंचाई पर उड़ान भर सकते हैं, लेकिन उनके लेबल समान "ऊंचाई" पर हैं।

Unaligned Collision Avoidance जैसे एल्गोरिदम हैं , जो आपके लिए सही दिशा में एक कदम होगा। बेशक आपकी स्थिति के लिए, लेबल अपने विमानों के लिए "टेथर" होते हैं, इसलिए उनके पास सीमित सीमा होती है।

यदि आप फ्लॉकिंग बिहेवियर को देखते हैं , तो आप फ्लॉकिंग के पहले "नियम" को लागू करना चाहते हैं: शॉर्ट रेंज रेपल्शन। हालांकि, निकटतम पड़ोसियों से दूर होने वाली दिशा में "स्टीयरिंग" के बजाय, आप अपने लेबल पर प्लेसमेंट स्थान के रूप में "दूर" वेक्टर का उपयोग करेंगे।

उदाहरण के लिए:

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

बड़ा ब्लैक सर्कल आपके प्रभाव क्षेत्र का प्रतिनिधित्व करता है, ग्रीन सर्कल लेबल के लिए मान्य प्लेसमेंट का प्रतिनिधित्व करता है, केंद्र ग्रीन डॉट आपके वर्तमान में विचार कर रहा विमान है, छोटा ग्रीन डॉट लेबल प्लेसमेंट के लिए चुने गए सर्कल पर बिंदु है।

अब काले डॉट्स अन्य लेबल, या अन्य विमानों का प्रतिनिधित्व कर सकते हैं। मुझे यकीन नहीं है कि कौन सा सबसे अच्छा काम करेगा, यदि आप अन्य लेबल थे, तो आप बेहतर परहेज कर सकते हैं, लेकिन मुझे यकीन नहीं है। स्पष्ट रूप से "बल" तीर आपके वर्तमान विमान और "प्रभाव की वस्तुओं" के बीच दिशा वैक्टर हैं। अंत में, बॉक्स लेबल है।

इसलिए ऊपर दिए गए अपने उदाहरण का उपयोग करते हुए, मुझे लगता है कि यह कुछ ऐसा उत्पन्न करेगा:

            - label
           / 
          B 
label - A
          C 
           \
            - label

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

          - label       label -
          |                   |
          B                   B
  label - A                   A - label
          C                   C
          |                   |
          - label       label -

आपके लेबल के कोनों को कैसे परिभाषित किया गया है, इस पर निर्भर करते हुए, सभी तीन लेबल दाईं ओर से बाईं ओर फ़्लॉप हो सकते हैं। असल में, आपको बस उस सर्कल के चारों ओर के कोणों के लिए बाहर देखना होगा जहां आपके लेबल स्विच कर सकते हैं कि वे किस कोने से खींचे गए हैं: 0, 90, 180, 270।

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

मुझे लगता है कि अंत में, यह एक प्रकार का साफ-सुथरा दिखेगा, लेबल देखने से एक-दूसरे से बचते हैं। यदि यह बहुत अधिक विचलित करता है, तो शायद आप कम लगातार आवाजाही के लिए निकटतम 10 डिग्री तक चक्कर लगा सकते हैं।

अजीब विवरण के लिए क्षमा करें, इस सामान के बारे में मैंने सोचा था कि जब मैं अपने खेल के लिए एक रेडियल मेनू बना रहा था, लेकिन मुझे लगता है कि इस "गतिशील" रूप में यह बहुत अच्छा काम करेगा।


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

1
ओह, ऐसा प्रतीत होता है कि आपने अपनी टिप्पणी हटा दी है?
MichaelHouse

1
मेरे पूर्व के साथ मेरा क्या मतलब था [खराब रूप से तैयार और इस प्रकार अब हटा दी गई] टिप्पणी, यह था कि आपके पास एक ऐसा परिदृश्य हो सकता है जिसमें अन्य गैर-जंगम (यानी वाहनों) द्वारा एक लेबल "फंसा / घिरा हुआ" हो। इस मामले में लेबल को शायद एनक्लोजिंग सर्कल के बाहर "कूद" चाहिए, लेकिन यह मेरे लिए बिल्कुल स्पष्ट नहीं है कि यह कैसे होना चाहिए। BTW: मैं मूल रूप से हालांकि आपकी तस्वीर की हरी बिंदी कई हवाई जहाज एक दूसरे के ऊपर खड़ी थी, लेकिन आपकी टिप्पणी के बाद मुझे एहसास हुआ कि मैं गलत था ... क्षमा करें!)।
मैक

1
ओह समझा। तो आप काले डॉट्स को विमानों और लेबल दोनों के रूप में मानेंगे। यदि पहली पुनरावृत्ति द्वारा पायी गई स्थिति अच्छी नहीं है, तो त्रिज्या को दोगुना करें और फिर से जांचें। या आपके पास पहले से ही एक वेक्टर है जो भीड़ के बहुमत से दूर की ओर इशारा करता है, आप इसे तब तक फॉलो कर सकते हैं जब तक कि आप कहीं काम न करें। हालाँकि मुझे लगता है कि पहली विधि के बेहतर परिणाम होंगे।
MichaelHouse

9

कुछ विचार करने के बाद, मैंने आखिरकार सर्पलिंग खोज विधि को लागू करने का फैसला किया, जिसे मैंने मूल प्रश्न में संक्षेप में वर्णित किया था।

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

हालाँकि कृपया अपने उत्तर को जारी रखें, क्योंकि यह न केवल उपयोगी है, यह बहुत अच्छी तरह से लिखा गया है!

यहाँ आवर्त कोड के साथ प्राप्त परिणाम का स्क्रीनशॉट है:

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

और यहाँ कोड है जो - हालांकि स्व-निहित नहीं है - यह एक विचार देता है कि कार्यान्वयन कितना सरल है:

def place_tags(self):
    for tag in self.tags:
        start_angle = tag.angle
        while not tag.place() or is_colliding(tag):  #See note n.1
            tag.angle = (tag.angle + angle_step) % 360
            if tag.angle == start_angle:
                tag.radius += radius_step
        tag.connector.update()                       #See note n.2

नोट 1 - यह tag.place()सच है अगर टैग पूरी तरह से स्क्रीन / रडार के दृश्य क्षेत्र पर है। तो वह पंक्ति इस तरह पढ़ती है, "यदि लॉगर रडार के बाहर है तो उसे लूप करते रहें या वह कुछ और ओवरलैप करता है ..."

नोट 2 - tag.connector.updateवह विधि है जो पाठ सूचना के साथ हवाई जहाज के आइकन को लेबल / टैग से जोड़ने वाली रेखा खींचती है।


अच्छा किया, यह वास्तव में बहुत कॉम्पैक्ट है। प्रशंसा के लिए धन्यवाद। आपने जो काम किया, उसके बारे में पोस्ट करने के लिए भी धन्यवाद, जो बाद में जवाब खोजने वाले लोगों के लिए हमेशा उपयोगी होता है। स्क्रीनशॉट से ऐसा लगता है कि यह बहुत अच्छा काम कर रहा है! अपने उत्तर को स्वीकार करना सुनिश्चित करें, क्योंकि यह वही है जो आपने समाप्त किया है।
MichaelHouse

@ बाइटे56 - "रेट्रो-प्रशंसा" के लिए धन्यवाद;) मुझे उत्तर स्वीकार करने के लिए इंतजार है क्योंकि मैं अभी भी आपके समाधान को कोड करना चाहूंगा और परिणाम की तुलना करूंगा। एक के लिए, मुझे संदेह है कि आपके समाधान को निष्पादित करने के लिए लंबे समय तक लेकिन साथ ही तेज़ कोड हो सकता है। इसके अलावा, मैं यह देखना चाहूंगा कि दोनों की तुलना बहुत ही कम हवाई जहाजों में कैसे होती है ... इसलिए अभी भी एक मौका है कि मैं आपके एल्गोरिथ्म के साथ कोड जारी कर सकता हूं। इस जगह को देखो! ;)
मैक

@ बाइटे 56 - मैं आपके एल्गोरिथ्म को लागू करने में एक गया था। इसने कम घनत्व में ठीक और तेजी से काम किया, लेकिन जैसे ही अंतरिक्ष में गड्ढा हो गया, मुझे एक सीधा कार्यान्वयन खोजने में समस्या थी जो विशिष्ट स्थितियों का प्रबंधन करेगी जिसमें एक लेबल अन्य लेबल के ब्लॉक को "कूद" या गैर-फंसाना चाहिए। जंगम (यानी विमान आइकन) स्प्राइट। मैं इस उत्तर को तब चयनित के रूप में चिह्नित कर रहा हूं, लेकिन फिर से: समय और योगदान के लिए बहुत बहुत धन्यवाद! :)
मैक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.