पॉलीगनों को फुलाते / अपस्फीति (ऑफसेट, बफरिंग) के लिए एक एल्गोरिथ्म


202

मैं एक बहुभुज को "कैसे" फुलाऊंगा? यही है, मैं ऐसा ही कुछ करना चाहता हूं:

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

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

जो मैं देख रहा हूँ, उसके लिए गणितीय शब्द वास्तव में आवक / जावक बहुभुज ऑफसेट है । इसे इंगित करने के लिए +1 से बैलेंट। वैकल्पिक नामकरण बहुभुज बफरिंग है

मेरी खोज के परिणाम:

यहाँ कुछ लिंक दिए गए हैं:


17
यह बिल्कुल तुच्छ सवाल नहीं है: यदि अपस्फीति / मुद्रास्फीति छोटी है, तो कुछ भी गंभीर नहीं होता है, लेकिन कुछ बिंदु पर, कोने गायब हो जाएंगे। संभवतः यह पहले किया गया है, इसलिए मैं कहूंगा: किसी और के एल्गोरिथ्म का उपयोग करें, अपना खुद का निर्माण न करें।
Martijn

1
वास्तव में, अगर आपके बहुभुज के साथ शुरू करने के लिए अवतल है (ऊपर के उदाहरण के रूप में) आप तय करने के लिए क्या बिंदु है जहां अनुभवहीन एल्गोरिथ्म एक स्वयं का प्रतिच्छेदन 'बहुभुज' बनाना चाहता है ... पर होना चाहिए है
AakashM

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

हैलो, यह भी मेरी समस्या है, सिवाय इसके कि मुझे 3 डी में ऐसा करने की आवश्यकता है। क्या कागज में वर्णित त्रि-आयामी पॉलीहेड्रा के सीधे कंकाल का एक विकल्प है arxiv.org/pdf/0805.0022.pdf ?
Stephanmg

जवाबों:


138

मैंने सोचा कि मैं अपनी खुद की बहुभुज क्लिपिंग और ऑफसेट लाइब्रेरी का उल्लेख कर सकता हूं - क्लिपर

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

बहुभुज ऑफसेटिंग को तीन ऑफसेट शैलियों में से एक का उपयोग करके किया जा सकता है - चुकता, गोल और मिट्ट।

बहुभुज ऑफसेट शैलियों


2
बहुत ही शांत! आप 2 साल पहले कहां थे? :) अंत में मुझे अपने स्वयं के ऑफसेट तर्क को लागू करना पड़ा (और उस पर बहुत समय खो दिया)। बहुभुज ऑफसेट, BTW के लिए आप किस एल्गोरिथ्म का उपयोग कर रहे हैं? मैंने घासफूस का इस्तेमाल किया। क्या आप बहुभुज में छेद संभालते हैं?
इगोर ब्रेजक

2
2 साल पहले मैं बहुभुज कतरन के लिए एक सभ्य समाधान की तलाश कर रहा था जो मुश्किल लाइसेंस मुद्दों के साथ संलग्न नहीं था :)। एज ऑफसेटिंग सभी किनारों के लिए यूनिट मानदंड बनाकर हासिल की जाती है। एज जॉइन्ट्स मेरे बहुभुज क्लिपर द्वारा तंग किए जाते हैं क्योंकि इन ओवरलैप्ड चौराहों के झुकाव पॉलीगोन के ओरिएंटेशन के विपरीत हैं। छिद्रों को सबसे निश्चित रूप से नियंत्रित किया जाता है जैसे कि स्व-प्रतिच्छेदन बहुभुज आदि। उनके प्रकार या संख्या पर कोई प्रतिबंध नहीं है। यहाँ भी देखें "पॉलीगॉन ऑफ़सेटिंग बाय कम्प्यूटिंग वाइंडिंग नंबर्स" यहाँ: me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf
Angus Johnson

वाह! एक दूसरे के लिए मत सोचो कि यह सवाल "भूल" है! मैंने पिछले हफ्ते यहाँ देखा - मैं इस पर वापस आने की उम्मीद नहीं कर रहा था! बहुत बहुत धन्यवाद!
क्रिस बर्ट-ब्राउन

पॉली बफ़रिंग पर क्लिपर के डॉक्स यहाँ हैं: angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/…
ड्रू नोक

5
जो कोई भी ऐसा करना चाहता है, उसके लिए एक और विकल्प है GEOS का उपयोग करना, और यदि आपका उपयोग अजगर, GEOS के रैपर, Shapely। एक बहुत सुंदर उदाहरण: Toblerity.github.com/shapely/manual.html#object.buffer
pelson

40

आप जिस बहुभुज की तलाश कर रहे हैं उसे कम्प्यूटेशनल ज्यामिति में आवक / जावक ऑफसेट बहुभुज कहा जाता है और यह सीधे कंकाल से संबंधित है ।

एक जटिल बहुभुज के लिए ये कई ऑफसेट बहुभुज हैं:

और यह एक और बहुभुज के लिए सीधा कंकाल है:

जैसा कि अन्य टिप्पणियों में कहा गया है, साथ ही, इस बात पर निर्भर करता है कि आप अपने बहुभुज को "फुलाए / टालने" की योजना बनाते हैं, आप आउटपुट के लिए विभिन्न कनेक्टिविटी के साथ समाप्त हो सकते हैं।

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

पैकेज के मैनुअल आप एक अच्छी कैसे इन संरचनाओं भले ही आप CGAL उपयोग करने के लिए नहीं जा रहे हैं का निर्माण करने पर बात शुरू करने देते हैं, और गणितीय परिभाषा और गुणों के साथ कागजात के संदर्भ हैं चाहिए:

CGAL मैनुअल: 2D सीधे कंकाल और बहुभुज ऑफसेट


12

इस प्रकार की चीजों के लिए मैं आमतौर पर जेटीएस का उपयोग करता हूं । प्रदर्शन प्रयोजनों के लिए मैंने इस jsFiddle को बनाया जो JSTS (JTS का जावास्क्रिप्ट पोर्ट) का उपयोग करता है । आपको बस उन निर्देशांक को परिवर्तित करना होगा जो आपको JSTS निर्देशांक में करने हैं:

function vectorCoordinates2JTS (polygon) {
  var coordinates = [];
  for (var i = 0; i < polygon.length; i++) {
    coordinates.push(new jsts.geom.Coordinate(polygon[i].x, polygon[i].y));
  }
  return coordinates;
}

परिणाम कुछ इस प्रकार है:

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

अतिरिक्त जानकारी : मैं आमतौर पर इस तरह के फुलाते / अपस्फीति (अपने उद्देश्यों के लिए थोड़ा संशोधित) का उपयोग करता हूं, जो कि पॉलीगोन पर त्रिज्या के साथ सीमाएं स्थापित करने के लिए होता है जो एक मानचित्र (जीआरबी या Google मानचित्र के साथ) पर खींची जाती हैं। आप बस JSTS निर्देशांक के लिए (lat, lng) जोड़े को रूपांतरित करते हैं और बाकी सब समान है। उदाहरण:

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


9

मुझे लगता है कि तुम क्या चाहते हो:

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

परिणामस्वरूप बहुभुज पुराने बहुभुज से आवश्यक दूरी पर स्थित है "कोने से काफी"। एक शीर्ष के पास, dपुराने बहुभुज से दूरी पर बिंदुओं का सेट है, जैसा कि आप कहते हैं, बहुभुज नहीं है, इसलिए कहा गया आवश्यकता पूरी नहीं की जा सकती है।

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


6

जीआईएस दुनिया में इस कार्य के लिए नकारात्मक बफरिंग का उपयोग करता है: http://www-users.cs.umn.edu/~npramod/enc_pdf.pdf

जेटीएस पुस्तकालय आप के लिए यह करना चाहिए। बफ़र ऑपरेशन के लिए दस्तावेज़ देखें: http://tsusiatsoftware.net/jts/javadoc/com/vividsolutions/jts/operation/buffer/package-summary.html

किसी मोटे अवलोकन के लिए डेवलपर गाइड भी देखें: http://www.vividsolutions.com/jts/bin/JTS%20Developer%20Guide.pdf


5

प्रत्येक पंक्ति को विमान को "अंदर" और "रूपरेखा" से विभाजित करना चाहिए; आप सामान्य आंतरिक-उत्पाद विधि का उपयोग करके यह पता लगा सकते हैं।

कुछ दूरी से सभी लाइनों को बाहर की ओर ले जाएं।

पड़ोसी रेखाओं के सभी जोड़े पर विचार करें (रेखाएं, रेखा खंड नहीं), चौराहे को ढूंढें। ये नए शिखर हैं।

किसी भी अन्तर्विभाजक भागों को हटाकर नए शीर्ष को साफ करें। - हमारे यहां कुछ मामला है

(ए) केस 1:

 0--7  4--3
 |  |  |  |
 |  6--5  |
 |        |
 1--------2

यदि आप इसे एक द्वारा खर्च करते हैं, तो आपको यह मिला:

0----a----3
|    |    |
|    |    |
|    b    |
|         |
|         |
1---------2

7 और 4 ओवरलैप .. यदि आप इसे देखते हैं, तो आप इस बिंदु और सभी बिंदुओं को बीच में हटा देते हैं।

(b) केस २

 0--7  4--3
 |  |  |  |
 |  6--5  |
 |        |
 1--------2

यदि आप इसे दो खर्च करते हैं, तो आपको यह मिला:

0----47----3
|    ||    |
|    ||    |
|    ||    |
|    56    |
|          |
|          |
|          |
1----------2

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

(c) केस 3

       4--3
 0--X9 |  |
 |  78 |  |
 |  6--5  |
 |        |
 1--------2

व्यय 1 से। यह केस 1 के लिए अधिक सामान्य मामला है।

(d) केस 4

केस 3 के समान, लेकिन दो द्वारा व्यय।

वास्तव में, यदि आप मामले को संभाल सकते हैं 4. अन्य सभी मामले किसी लाइन या शीर्ष ओवरलैपिंग के साथ इसके विशेष मामले हैं।

केस 4 करने के लिए, आप वर्टेक्स का एक स्टैक रखते हैं .. आप पुश करते हैं जब आप बाद वाली लाइन के साथ अतिव्यापी पाते हैं, तो बाद वाली लाइन मिलने पर इसे पॉप करें। - जैसे आप उत्तल-पतवार में क्या करते हैं।


क्या आप इसके लिए कोई psedo एल्गोरिथ्म जानते हैं।
17

5

यहां एक वैकल्पिक समाधान है, देखें कि क्या आपको यह बेहतर लगता है।

  1. एक त्रिकोणासन करें , इसमें विलंब नहीं होना चाहिए - कोई भी त्रिकोणासन करेगा।

  2. प्रत्येक त्रिकोण को फुलाएं - यह तुच्छ होना चाहिए। यदि आप त्रिकोण को एंटी-क्लॉकवाइज ऑर्डर में स्टोर करते हैं, तो लाइनों को दाहिने-हाथ की ओर ले जाएं और चौराहा करें।

  3. एक संशोधित वेइलर-एथरटन कतरन एल्गोरिथ्म का उपयोग करके उन्हें मिलाएं


आप त्रिकोणों को कैसे फुलाते हैं? क्या आपका आउटपुट त्रिकोणासन पर निर्भर करता है? इस दृष्टिकोण के साथ आप बहुभुज को सिकोड़ते समय मामले को संभाल सकते हैं?
बाल्टि.मिक्लोस

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

1
इगोर: वीलर-एथरटन कतरन एल्गोरिथ्म "कुछ कोने को समाप्त करना होगा" मामले को सही ढंग से संभाल सकता है;
J-16 SDiZ

@balint: एक त्रिभुज को फुलाया जाना तुच्छ है: यदि आप लंबर को सामान्य क्रम में संग्रहीत करते हैं, तो दायाँ हाथ हमेशा "बाहरी" होता है। बस उन रेखाखंडों को रेखाओं के रूप में मानते हैं, उन्हें बाहर की ओर ले जाते हैं, और इंटरैक्शन ढूंढते हैं - वे नए शीर्ष हैं। त्रिकोणासन के लिए, दूसरे विचार पर, delaunay triangulation बेहतर परिणाम दे सकता है।
J-16 SDiZ

4
मुझे लगता है कि यह दृष्टिकोण आसानी से खराब परिणाम दे सकता है। यहां तक ​​कि एक साधारण उदाहरण के लिए, जैसा कि तिरछे तिरछे का उपयोग करके त्रिकोणित किया गया है। दो बढ़े हुए त्रिकोण के लिए आपको मिलता है: img200.imageshack.us/img200/2640/counterm.png और उनका मिलन सिर्फ वही नहीं है जिसकी आपको तलाश है। मैं नहीं देखता कि यह विधि कैसे उपयोगी है।
बाल्टि.मिक्लोस

3

अपनी क्लिपर लाइब्रेरी के लिए एंगस जॉनसन का बड़ा धन्यवाद। Http://www.angusj.com/delphi/clipper.php#code पर क्लिपर होमपेज पर क्लिपिंग सामान करने के लिए अच्छे कोड के नमूने हैं, लेकिन मैंने बहुभुज ऑफसेट के लिए एक उदाहरण नहीं देखा। इसलिए मैंने सोचा कि शायद यह किसी के लिए उपयोग हो, अगर मैं अपना कोड पोस्ट करूं:

    public static List<Point> GetOffsetPolygon(List<Point> originalPath, double offset)
    {
        List<Point> resultOffsetPath = new List<Point>();

        List<ClipperLib.IntPoint> polygon = new List<ClipperLib.IntPoint>();
        foreach (var point in originalPath)
        {
            polygon.Add(new ClipperLib.IntPoint(point.X, point.Y));
        }

        ClipperLib.ClipperOffset co = new ClipperLib.ClipperOffset();
        co.AddPath(polygon, ClipperLib.JoinType.jtRound, ClipperLib.EndType.etClosedPolygon);

        List<List<ClipperLib.IntPoint>> solution = new List<List<ClipperLib.IntPoint>>();
        co.Execute(ref solution, offset);

        foreach (var offsetPath in solution)
        {
            foreach (var offsetPathPoint in offsetPath)
            {
                resultOffsetPath.Add(new Point(Convert.ToInt32(offsetPathPoint.X), Convert.ToInt32(offsetPathPoint.Y)));
            }
        }

        return resultOffsetPath;
    }

2

एक और विकल्प बढ़ावा का उपयोग करने के लिए है :: बहुभुज - प्रलेखन में कुछ हद तक कमी है, लेकिन आपको यह पता लगाना चाहिए कि तरीकों resizeऔर bloat, और अतिभारित +=ऑपरेटर, जो वास्तव में बफरिंग को लागू करते हैं। इसलिए उदाहरण के लिए कुछ मूल्य से बहुभुज (या बहुभुजों का एक सेट) के आकार को बढ़ाना सरल हो सकता है:

poly += 2; // buffer polygon by 2

मुझे समझ में नहीं आता है कि आप कैसे बढ़ावा देने के साथ कुछ भी करने वाले हैं :: बहुभुज चूंकि यह केवल पूर्णांक निर्देशांक का समर्थन करता है? कहो कि मेरे पास एक सामान्य (फ्लोटिंग पॉइंट निर्देशांक) बहुभुज है और मैं इसका विस्तार करना चाहता हूं - मैं क्या करूंगा?
डेविड डोरिया

@DavidDoria: यह इस बात पर निर्भर करता है कि आपको अपने निर्देशांक के लिए किस रिज़ॉल्यूशन / सटीकता और डायनेमिक रेंज की आवश्यकता है, लेकिन आप एक उचित स्केलिंग फैक्टर के साथ 32 बिट या 64 बिट इंट का उपयोग कर सकते हैं। संयोग से मेरे पास (दुर्घटनावश) बूस्ट का इस्तेमाल किया गया है: अतीत में फ्लोट निर्देशांक के साथ बहुभुज और यह ठीक काम करने लगता है, लेकिन यह 100% मजबूत नहीं हो सकता है (डॉक्स इसके खिलाफ चेतावनी देता है!)।
पॉल आर

मैं इसके साथ ठीक हो जाऊंगा "यह ज्यादातर समय काम करेगा" :)। मैंने यह कोशिश की: ideone.com/XbZeBf लेकिन यह संकलित नहीं करता है - कोई विचार?
डेविड डोरिया

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

ठीक है - यह अब मेरे पास वापस आ रहा है - आप केवल +=बहुभुज सेट के साथ उपयोग कर सकते हैं , व्यक्तिगत बहुभुज के साथ नहीं। इसे एक std :: बहुभुज के वेक्टर के साथ आज़माएं। (बेशक वेक्टर को केवल एक बहुभुज की आवश्यकता होती है)।
पॉल आर

1

@ जोश'ब्रायन की सलाह के आधार पर, यह इस एल्गोरिथ्म rGeosको Rभाषा में लागू करता है। देख लो rGeos::gBuffer


0

पुस्तकालयों के एक जोड़े का उपयोग कर सकते हैं (3 डी डेटा सेट के लिए भी प्रयोग करने योग्य)।

  1. https://github.com/otherlab/openmesh
  2. https://github.com/alecjacobson/nested_cages
  3. http://homepage.tudelft.nl/h05k3/Projects/MeshThickeningProj.htm

एल्गोरिदम को और अधिक विस्तार से समझने के लिए इन पुस्तकालयों के लिए एक ही प्रकाशन भी मिल सकता है।

आखिरी में सबसे कम निर्भरता होती है और यह आत्म-निहित होती है और .obj फाइलों में पढ़ सकती है।

शुभकामनाएं, स्टीफ़न


0

मैं सरल ज्यामिति का उपयोग करता हूं: वैक्टर और / या त्रिकोणमिति

  1. प्रत्येक कोने पर मध्य वेक्टर और मध्य कोण पाते हैं। मध्य वेक्टर कोने के किनारों द्वारा परिभाषित दो यूनिट वैक्टर का अंकगणितीय औसत है। मिड एंगल किनारों द्वारा परिभाषित कोण का आधा हिस्सा है।

  2. यदि आपको प्रत्येक किनारे से d की मात्रा से अपने बहुभुज का विस्तार (या अनुबंध) करना है; आपको नया कोने बिंदु प्राप्त करने के लिए राशि d / sin (midAngle) द्वारा बाहर (में) जाना चाहिए।

  3. सभी कोनों के लिए इसे दोहराएं

*** अपनी दिशा के बारे में सावधान रहें। कोने को परिभाषित करने वाले तीन बिंदुओं का उपयोग करके काउंटरकॉलवाइज टेस्ट बनाएं; यह पता लगाने के लिए कि कौन सा रास्ता बाहर है, या अंदर है।

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