अनियमित बहुभुज केन्द्रक (लेबल बिंदु) खोजने के लिए एल्गोरिथम


13

मुझे Google मानचित्र में अनियमित आकार के बहुभुजों के लिए एक केन्द्रक (या लेबल बिंदु) खोजने की आवश्यकता है। मैं पार्सल के लिए InfoWindows दिखा रहा हूं और InfoWindow को लंगर डालने के लिए एक जगह की आवश्यकता है जो सतह पर होने की गारंटी है। नीचे चित्र देखें

वैकल्पिक शब्द वैकल्पिक शब्द

हकीकत में मुझे कुछ भी गूगल मैप्स की जरूरत नहीं है, बस इस बात का अंदाजा लगाना है कि इस बिंदु को स्वचालित रूप से कैसे पाया जाए।

मेरा पहला विचार औसत लेट और लैंग्स को ले कर "असत्य" सेंट्रोइड का पता लगाना था और बेतरतीब ढंग से पॉइंटिंग पॉइंट्स को वहाँ से तब तक बाहर निकालता था जब तक कि मुझे एक ऐसा न मिल जाए जो बहुभुज को काटता हो। मेरे पास पहले से ही बहुभुज कोड है। यह बस भयानक रूप से मुझे "हैकी" लगता है।

मुझे ध्यान देना चाहिए कि मेरे पास किसी भी सर्वर साइड कोड की ज्यामिति का उपयोग करने की पहुंच नहीं है, इसलिए मैं ST_PointOnSurface (the_geom) जैसा कुछ भी नहीं कर सकता।

जवाबों:


6

त्वरित और गंदा: यदि "झूठी" सेंट्रोइड बहुभुज में नहीं है, तो उस बिंदु पर निकटतम शीर्ष का उपयोग करें।


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

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

@ जेसन यदि आप वास्तविक केन्द्रक का उपयोग करते हैं तो आपको इस समस्या का सामना करने की संभावना कम हो सकती है। जावास्क्रिप्ट में जल्दी से कुछ अनुवाद करने के लिए बहुत कठिन नहीं होना चाहिए: github.com/cartesiananalytics/Pipra/blob/master/src/…
Dandy

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

3

आप इसे देखना चाह सकते हैं: http://github.com/tparkin/Google-Maps-Point-in-Polygon

यह रे कास्टिंग एल्गोरिथ्म का उपयोग करने के लिए प्रतीत होता है जो आपके द्वारा प्रस्तुत मामले से मेल खाना चाहिए।

यहाँ इसके बारे में एक ब्लॉग पोस्ट है। http://appdelegateinc.com/blog/2010/05/16/point-in-polygon-checking/


यदि आप इसे सर्वर साइड पर लागू करना चाहते हैं, तो JTS (Java) और Geos (C) दोनों इस कार्यक्षमता को लागू करते हैं।
डेविड एफएपी

हाँ, मुझे शायद यह जोड़ना चाहिए कि मेरे पास पहले से ही यह निर्धारित करने के लिए कोड है कि मेरी "गणना" सेंट्रोइड बहुभुज के भीतर है या नहीं। जो मैं वास्तव में चाहता हूं वह सेंट्रोइड बनाने का कुछ तरीका है जो बहुभुज के भीतर है।
जेसन

3

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


1

मैंने http://econym.org.uk/gmap से लोकप्रिय एपिसोड कोड का विस्तार करके अपनी समस्या को हल किया । मूल रूप से मैंने जो किया, वह था:

  • किरणों की एक श्रृंखला बनाएं जो "झूठी सेंट्रोइड" से शुरू होती है और हर कोने और तरफ (8 कुल) तक विस्तारित होती है
  • आकस्मिक रूप से एक बिंदु बनाएं 10,20,30 ... प्रत्येक किरण का प्रतिशत नीचे देखें और देखें कि क्या यह बिंदु हमारे मूल बहुभुज में है

नीचे दिया गया विस्तृत कोड:

google.maps.Polygon.prototype.Centroid = function() {
var p = this;
var b = this.Bounds();
var c = new google.maps.LatLng((b.getSouthWest().lat()+b.getNorthEast().lat())/2,(b.getSouthWest().lng()+b.getNorthEast().lng())/2);
if (!p.Contains(c)){
    var fc = c; //False Centroid
    var percentages = [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9]; //We'll check every 10% down each ray and see if we're inside our polygon
    var rays = [
        new google.maps.Polyline({path:[fc,new google.maps.LatLng(b.getNorthEast().lat(),fc.lng())]}),
        new google.maps.Polyline({path:[fc,new google.maps.LatLng(fc.lat(),b.getNorthEast().lng())]}),
        new google.maps.Polyline({path:[fc,new google.maps.LatLng(b.getSouthWest().lat(),fc.lng())]}),
        new google.maps.Polyline({path:[fc,new google.maps.LatLng(fc.lat(),b.getSouthWest().lng())]}),
        new google.maps.Polyline({path:[fc,b.getNorthEast()]}),
        new google.maps.Polyline({path:[fc,new google.maps.LatLng(b.getSouthWest().lat(),b.getNorthEast().lng())]}),
        new google.maps.Polyline({path:[fc,b.getSouthWest()]}),
        new google.maps.Polyline({path:[fc,new google.maps.LatLng(b.getNorthEast().lat(),b.getSouthWest().lng())]})
    ];
    var lp;
    for (var i=0;i<percentages.length;i++){
        var percent = percentages[i];
        for (var j=0;j<rays.length;j++){
            var ray = rays[j];
            var tp = ray.GetPointAtDistance(percent*ray.Distance()); //Test Point i% down the ray
            if (p.Contains(tp)){
                lp = tp; //It worked, store it
                break;
            }
        }
        if (lp){
            c = lp;
            break;
        }
    }
}
return c;}

अभी भी थोड़ा हैकी है लेकिन यह काम करने लगता है।


यह विधि कुछ यातनापूर्ण बहुभुजों के लिए विफल हो जाएगी। उदाहरण के लिए, पॉलीलाइन {{0, 9}, {10, 20}, {9, 9}, {20, 10}, {9, 0}, {20, -10}, {9, -9} बफर करें। , {10, -20}, {0, -9}, {-10, -20}, {-9, -9}, {-20, -10}, {-9, 0}, {-20 10}, {-9, 9}, {-10, 20}, {0,9}} 1/2 से कम। उदाहरण के लिए, यह बांका की QAD विधि की तुलना में अक्षम है।
व्हिबर

1

ऐसा करने के लिए एक और 'गंदा' एल्गोरिथ्म:

  • ज्यामिति के बाउंडिंग बॉक्स को लें (Xmax, Ymax, Xmin, Ymin)

  • ( Xmin+rand*(Xmax-Xmin), Ymin+rand*(Ymax-Ymin) ) ज्यामिति के भीतर एक यादृच्छिक बिंदु मिलने तक लूप करें ( Google-मैप्स-पॉइंट-इन-पॉलीगॉन का उपयोग करके )


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

1
@ कैंडी: वास्तव में, कुछ मामलों में यह वास्तव में खराब एल्गोरिथम हो सकता है। उदाहरण के लिए एक संकीर्ण विकर्ण ज़ुल्फ़ पर विचार करें। ये व्यवहार में मौजूद हैं (उदाहरण के लिए, रोड फ्रंटेज के लंबे पार्सल) और बाउंडिंग बॉक्स (कभी-कभी बहुत कम) के 0.1% से कम पर आसानी से कब्जा कर सकते हैं। इस तकनीक के साथ इस तरह के बहुभुज को मारने के लिए (95% आश्वस्त) निश्चित रूप से सुनिश्चित करने के लिए लगभग 3,000 पुनरावृत्तियों की आवश्यकता होगी।
whuber

@Whuber: यदि आप एक बुरा शुरुआती स्थान चुनते हैं, जो पूरा होने के लिए कुछ समय ले सकता है। यदि आप यह भी मानते हैं कि काल्पनिक रूप से 95% क्लिक अधिक वांछनीय ज्यामितीय होंगे तो यह केवल 5% समस्या हो सकती है। एक और GIS.se प्रश्न के साथ भी अगर प्रदर्शन का उद्देश्य एक ही समाधान नहीं है, तो यह आँकड़ों के आधार पर रणनीति को बदलना सबसे अच्छा है। 3000 पुनरावृत्तियों के लिए इसे चलाने का कोई कारण नहीं है। आप हमेशा 10. के बाद मेरी क्यूएडी को जमानत दे सकते हैं। मुझे लगता है कि यह कुछ पुनरावृत्तियों के लिए इसे आज़माने के लिए लायक होगा क्योंकि स्थान अधिक वांछनीय हो सकता है।
डेंडी

@ कैंडी: लेकिन आपके क्यूएडी समाधान के साथ क्या बात है? बहुभुज के कुछ आंतरिक बफर में मूल परीक्षण लेबल बिंदु से निकटतम शीर्ष पर ले जाकर आप इसे थोड़ा सा भी संशोधित कर सकते हैं: फिर भी QAD लेकिन अब मूल विशेषता के आंतरिक स्थान पर उतरने की गारंटी है। BTW, जल्द ही बाहर चलने की आपकी रणनीति एक अच्छी है। जब भी मैं इस तरह एक यादृच्छिक जांच को कोड करता हूं, तो मैं फीचर के क्षेत्र के अनुपात को उसके बाउंडिंग बॉक्स से जोड़ देता हूं, इसका उपयोग सफलता के लिए अपेक्षित समय खोजने के लिए करता हूं, और उपयोगकर्ता को तुरंत चेतावनी देता हूं कि अगर यह लंबा हो सकता है।
whuber

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

1

आपके हाल के स्पष्टीकरण के प्रकाश में कि आप एक कड़ाई से आंतरिक स्थान पसंद करेंगे, आप किसी भी बिंदु का चयन कर सकते हैं जो कि औसत दर्जे का एक्सिस ट्रांसफॉर्म है जो कि बहुभुज की सीमा पर भी नहीं है। (यदि आपके पास MAT के लिए कोड नहीं है, तो आप बहुभुज को नकारात्मक रूप से बफर करके इसे लगभग अनुमानित कर सकते हैं। एक बाइनरी या सेकेंट खोज जल्दी से एक छोटे आंतरिक बहुभुज का उत्पादन करेगी जो MAT के हिस्से का अनुमान लगाती है; इसकी सीमा पर किसी भी बिंदु का उपयोग करें।)


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

@ डंडी: जो इसके दिल में उतर जाती है। इसके बारे में जाने के कई तरीके हैं जो आपके जीआईएस मूल रूप से करता है। उदाहरण के लिए, एक बार जब आपको एक किरण मिल जाती है जो सकारात्मक लंबाई के एक सेट में मूल विशेषता को काटती है, तो वह अंतर रेखा खंडों का एक असंतुष्ट संघ होगा। उन खंडों में से किसी एक के केंद्र का उपयोग करें। एक और तरीका है कि आप किसी भी बिंदु पर शुरू करें (विशेष रूप से इसके मध्य के पास, जो कि आपका QED तरीका पूरा हो चुका है), वहां केंद्रित एक छोटा सा साधारण बहुभुज (जैसे, वर्ग) बनाएं, इसे मूल सुविधा के साथ प्रतिच्छेद करें, अद्वितीय जुड़ा हुआ चुनें घटक ...
whuber

(निरंतरता) ... प्रारंभिक बिंदु से युक्त, और पुनरावर्ती रूप से उस घटक के लिए एक केंद्र चुनें। जब आपके जीआईएस आपको सुविधा की सीमा का वर्णन करने वाले कोने के अनुक्रमों पर लूप देता है, तो तरीकों का भार उपलब्ध होगा। यदि नकारात्मक बफ़र्स का समर्थन किया जाता है, तो आप अधिकतम दूरी वाले आंतरिक बिंदुओं ("कंकाल", जो MAT का सबसेट है) का एक सेट खोज सकते हैं। यह थोड़ा महंगा है लेकिन प्रोग्राम के लिए काफी आसान है और उत्कृष्ट लेबल पॉइंट का उत्पादन करता है।
whuber

0

केवल ऊर्ध्वाधर (अक्षांश) स्थिति के लिए केन्द्रक का उपयोग क्यों नहीं किया जाता है? फिर, आप उस अक्षांश पर औसत देशांतर उठाकर लेबल को क्षैतिज रूप से रख सकते हैं । (इसके लिए आपको एक विशिष्ट अक्षांश पर बहुभुज किनारे के लिए देशांतर मान खोजने की आवश्यकता होगी, जिससे आपको कोई परेशानी न हो)।

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

यह आपको स्थिति पर थोड़ा और नियंत्रण देता है; उदाहरण के लिए, जानकारी विंडो को 66 या 75% पर लंबवत रूप से स्थिति में रखना अच्छा हो सकता है, ताकि बहुभुज दिखाई देने पर अधिक छोड़ सके। (या यह नहीं हो सकता है! लेकिन आपके पास ट्विन करने के लिए घुंडी है।)


0

केवल उस बिंदु का उपयोग करने के बारे में जिसे उपयोगकर्ता ने इसे चुनने के लिए क्लिक किया है, अगर यह उपयोगकर्ता द्वारा चुना गया है।


यह एक माउस क्लिक या गैर-स्थानिक क्वेरी द्वारा चुना जा सकता है, इसलिए यह हमेशा काम नहीं करेगा।
जेसन

0

मैं इसे भी हल करने की कोशिश कर रहा हूं। मैंने अपने पॉलीगोन पर एक शर्त लगाई है कि उनके पास क्रॉसिंग लाइनें नहीं हो सकती हैं जो कि मैं जो वर्णन करता हूं उसमें प्रवेश करता है।

इसलिए, मेरा दृष्टिकोण त्रिकोणासन का उपयोग करता है। एक यादृच्छिक वर्टेक्स लें (संभवतः चरम एन, ई, डब्ल्यू, या एस चीजों को सरल बना सकता है)।

इस शीर्ष से, एक शीर्ष पर दूर की ओर रेखाएँ खींचें, यानी यदि आपका शीर्ष 3 है, तो शीर्ष 3 या 2 देखें।

अपने मूल शीर्ष से इस शीर्ष तक एक रेखा बनाएँ। यदि निर्मित लाइन:

  1. कोई अन्य रेखा पार नहीं करता है और
  2. इसका मध्य बिंदु बहुभुज के बाहर नहीं है

फिर आपने एक त्रिकोण का निर्माण किया है जो बहुभुज के भीतर है। यदि सफल शीर्ष स्थान n + 2 था, तो आपका त्रिकोण {n, n + 1, n + 2} है, जिसे हम {v, v1, v2} के रूप में संदर्भित करेंगे। यदि नहीं, तो अगले शीर्ष को आज़माएं, और तब तक जारी रखें जब तक कि सभी कोने की कोशिश न की गई हो।

जब आप एक त्रिभुज पाते हैं, तो शीर्ष v से v1 और v2 के मध्य बिंदु तक एक रेखा लेकर उस का केंद्र ढूंढें। उस रेखा के मध्य बिंदु को त्रिकोण के अंदर और बहुभुज के अंदर होने की गारंटी है।

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


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