आर्कपी का उपयोग करके एक उन्मुख बफर कैसे बनाएं?


9

मैं आर्कपी का उपयोग करके अपने आकार में हर बहुभुज के लिए एक उन्मुख बफर बनाना चाहता हूं। उन्मुख होने से मेरा मतलब है कि मेरे पास दो कोण हैं a1 और a2 जो बफर की दिशा में बाधा डालते हैं। यह नीचे दिए गए ग्राफ में दर्शाया गया है: यहां छवि विवरण दर्ज करें

कोई विचार?


3
कोणों के बारे में अधिक जानकारी की आवश्यकता होगी। आप कोणों को किस अक्ष से माप रहे हैं? CW या CCW? आप बहुभुज पर प्रत्येक कोण का पता कैसे लगाते हैं? किस प्रकार के बहुभुज के साथ हम काम कर रहे हैं? (एक वृत्त बहुभुज नहीं है।)
पॉल 16

1
+1 @Paul लेकिन मैं करने के लिए सोचा एक चक्र एक बहुभुज था जब तक मैंने पढ़ा है यह
PolyGeo

+1 भी करें! मैंने आसानी से समस्या का वर्णन करने के लिए सर्कल का उपयोग किया। बहुविवाह एक वर्ग में एक वर्ग की पहचान करने के लिए वर्गीकरण के बाद मान्यता में विभाजन के परिणाम हैं। कोण a1 और a2 खंडित उपग्रह छवि के रोशनी अज़ीमुथ कोण से निकलते हैं। उदाहरण में, अज़ीमुथ कोण 0, a1 और a2 के बराबर 0 +/- 15 ° (मनमाने ढंग से 15 ° तक तय) के बराबर होगा।
WAF

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

जवाबों:


20

सारांश

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

पृष्ठभूमि

यह एक रूपात्मक फैलाव का एक उदाहरण है पूर्ण सामान्यता में, एक फैलाव एक क्षेत्र के बिंदुओं को उनके पड़ोस में "फैलाता है"; बिंदुओं का संग्रह जहां वे हवा करते हैं वह "फैलाव" है। जीआईएस में आवेदन कई हैं: आग के प्रसार, सभ्यताओं के आंदोलन, पौधों के प्रसार, और बहुत कुछ मॉडलिंग।

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

किसी विशेषता का "बफरिंग" इस तरह के फैलाव के सबसे सरल उदाहरणों में से एक है: फीचर के प्रत्येक बिंदु के आसपास निरंतर त्रिज्या (बफर त्रिज्या) की एक डिस्क (कम से कम वैचारिक रूप से) बनाई जाती है। इन डिस्क का संघ बफर है।

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

निम्नलिखित परिस्थितियों में फैलाव की गणना करना अपेक्षाकृत आसान है:

  • विमान में सुविधा है (यानी हम सुविधा के नक्शे को पतला कर रहे हैं और उम्मीद है कि नक्शा काफी सटीक है)।

  • फैलाव स्थिर होगा : सुविधा के प्रत्येक बिंदु पर प्रसार समान अभिविन्यास के पड़ोस के भीतर होगा।

  • यह आम पड़ोस उत्तल है। उत्तलता गणना को सरल और गति प्रदान करती है।

यह प्रश्न ऐसी विशिष्ट परिस्थितियों में फिट बैठता है: यह परिपत्र क्षेत्रों द्वारा मूल बहुभुजों के फैलाव की मांग करता है जिनकी उत्पत्ति (डिस्क के केंद्र जहां से वे आए थे) आधार बिंदुओं पर स्थित हैं। बशर्ते कि उन क्षेत्रों में 180 डिग्री से अधिक की अवधि न हो, वे उत्तल होंगे। (बड़े क्षेत्रों को हमेशा आधे में दो उत्तल क्षेत्रों में विभाजित किया जा सकता है; दो छोटे फैलाव का मिलन वांछित परिणाम देगा।)


कार्यान्वयन

क्योंकि हम यूक्लिडियन गणना कर रहे हैं - विमान में फैलने का काम - हम केवल उस बिंदु तक फैलाव पड़ोस का अनुवाद करके एक बिंदु को पतला कर सकते हैं । (ऐसा करने में सक्षम होने के लिए, पड़ोस को एक मूल की आवश्यकता हैजो आधार बिंदु के अनुरूप होगा। उदाहरण के लिए, इस प्रश्न में क्षेत्रों की उत्पत्ति उस चक्र का केंद्र है, जहां से वे बने हैं। यह उत्पत्ति क्षेत्र की सीमा पर झूठ बोलने के लिए होती है। मानक जीआईएस बफरिंग ऑपरेशन में पड़ोस अपने केंद्र में मूल के साथ एक चक्र है; अब मूल चक्र के आंतरिक भाग में स्थित है। एक उत्पत्ति का चयन करना कम्प्यूटेशनल रूप से कोई बड़ी बात नहीं है, क्योंकि उत्पत्ति के परिवर्तन से केवल पूरे फैलाव को बदल दिया जाता है, लेकिन यह प्राकृतिक घटनाओं की मॉडलिंग के संदर्भ में एक बड़ी बात हो सकती है। sectorकोड में समारोह नीचे दर्शाता है कि एक मूल निर्दिष्ट किया जा सकता है।)

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

खंड प्रसार

समांतर चतुर्भुज गुलाबी बिंदुओं का पता लगाकर पाए जाते हैं जो कि ऊर्ध्वाधर दिशा में खंड से यथासंभव दूर हैं । यह दो निचले बिंदुओं और दो ऊपरी बिंदुओं को लाइनों के साथ देता है जो कि खंड के समानांतर हैं। हमें बस चार बिंदुओं को समांतर चतुर्भुज (नीले रंग में दिखाया गया है) में शामिल होना है। ध्यान दें, दाईं ओर, यह तब भी कैसे समझ में आता है जब सेक्टर केवल एक लाइन सेगमेंट (और एक सच्चा बहुभुज) नहीं है: वहाँ, खंड पर हर बिंदु को दिशा में 171 डिग्री पूर्व में उत्तर की ओर दूरी के लिए अनुवाद किया गया है 0 से 1. इन समापन बिंदुओं का सेट दिखाया गया समांतर चतुर्भुज है। इस गणना का विवरण नीचे दिए गए कोड में bufferनिर्धारित फ़ंक्शन में दिखाई देता है dilate.edges

एक पॉलीलाइन को पतला करने के लिए , हम इसे बनाने वाले बिंदुओं और खंडों के फैलाव का संघ बनाते हैं। dilate.edgesइस लूप के प्रदर्शन की अंतिम दो पंक्तियाँ ।

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

आइए कुछ उदाहरणों पर गौर करें कि यह कैसे काम करता है, पहले एक नॉनगन (विस्तार प्रकट करने के लिए चुना गया) और फिर एक सर्कल के साथ (प्रश्न में चित्रण से मेल खाने के लिए चुना गया)। उदाहरण वही तीन पड़ोस का उपयोग करना जारी रखेंगे, लेकिन 1/3 के दायरे तक सिकुड़ते रहेंगे।

एक गैर के फैलाव

इस आंकड़े में बहुभुज का आंतरिक भाग ग्रे है, बिंदु फैलाव (क्षेत्र) गुलाबी है, और किनारे फैलाव (समांतर चतुर्भुज) नीले हैं।

एक वृत्त की ह्रास

"सर्कल" वास्तव में सिर्फ एक 60-गॉन है, लेकिन यह अच्छी तरह से एक सर्कल का अनुमान लगाता है।


प्रदर्शन

जब आधार सुविधा को एन बिंदुओं द्वारा और एम बिंदुओं द्वारा फैलाव पड़ोस का प्रतिनिधित्व किया जाता है, तो इस एल्गोरिथ्म में ओ (एन एम) प्रयास की आवश्यकता होती है संघ में कोने और किनारों की गंदगी को सरल करके इसका पालन किया जाना चाहिए, जिसमें ओ (एन एम लॉग (एन एम)) प्रयास की आवश्यकता हो सकती है: जो कि जीआईएस को करने के लिए कहने के लिए कुछ है; हमें वह प्रोग्राम नहीं करना चाहिए।

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

जब बेस पड़ोस में धीरे-धीरे परिवर्तन पड़ोस और / या अभिविन्यास बदल जाता है, तो आधार के फैलाव को इसके समापन बिंदुओं के संघनन के उत्तल पतवार से बारीकी से लगाया जा सकता है। यदि दो फैलाव पड़ोस में एम 1 और एम 2 बिंदु हैं, तो यह शमोस और प्रिपेटा, कम्प्यूटेशनल ज्यामिति में वर्णित एल्गोरिदम का उपयोग करके ओ (एम 1 + एम 2) प्रयास के साथ पाया जा सकता है । इसलिए, K = M1 + M2 + ... + M (N) N फैलाव पड़ोस में कुल संख्याओं का होना, हम O (K * log (K)) समय में फैलाव की गणना कर सकते हैं।

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


कोड

इस Rप्रोटोटाइप के साथ उदाहरण पेश किए गए , जो आसानी से आपकी पसंदीदा भाषा (पायथन, सी ++, आदि) में पोर्ट किए जा सकते हैं। संरचना में यह इस उत्तर में बताए गए विश्लेषण को समानता देता है और इसलिए इसे अलग से स्पष्टीकरण की आवश्यकता नहीं है। टिप्पणियाँ कुछ विवरणों को स्पष्ट करती हैं।

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

#
# Dilate the vertices of a polygon/polyline by a shape.
#
dilate.points <- function(p, q) {
  # Translate a copy of `q` to each vertex of `p`, resulting in a list of polygons.
  pieces <- apply(p, 1, function(x) list(t(t(q)+x)))
  lapply(pieces, function(z) z[[1]]) # Convert to a list of matrices
}
#
# Dilate the edges of a polygon/polyline `p` by a shape `q`. 
# `p` must have at least two rows.
#
dilate.edges <- function(p, q) {
  i <- matrix(c(0,-1,1,0), 2, 2)       # 90 degree rotation
  e <- apply(rbind(p, p[1,]), 2, diff) # Direction vectors of the edges
  # Dilate a single edge from `x` to `x+v` into a parallelogram
  # bounded by parts of the dilation shape that are at extreme distances
  # from the edge.
  buffer <- function(x, v) {
    y <- q %*% i %*% v # Signed distances orthogonal to the edge
    k <- which.min(y)  # Find smallest distance, then the largest *after* it
    l <- (which.max(c(y[-(1:k)], y[1:k])) + k-1) %% length(y)[1] + 1
    list(rbind(x+q[k,], x+v+q[k,], x+v+q[l,], x+q[l,])) # A parallelogram
  }
  # Apply `buffer` to every edge.
  quads <- apply(cbind(p, e), 1, function(x) buffer(x[1:2], x[3:4]))
  lapply(quads, function(z) z[[1]]) # Convert to a list of matrices
}
#----------------------- (This ends the dilation code.) --------------------------#
#
# Display a polygon and its point and edge dilations.
# NB: In practice we would submit the polygon, its point dilations, and edge 
#     dilations to the GIS to create and simplify their union, producing a single
#     polygon.  We keep the three parts separate here in order to illustrate how
#     that polygon is constructed.
#
display <- function(p, d.points, d.edges, ...) {
  # Create a plotting region covering the extent of the dilated figure.
  x <- c(p[,1], unlist(lapply(c(d.points, d.edges), function(x) x[,1])))
  y <- c(p[,2], unlist(lapply(c(d.points, d.edges), function(x) x[,2])))
  plot(c(min(x),max(x)), c(min(y),max(y)), type="n", asp=1, xlab="x", ylab="y", ...)
  # The polygon itself.
  polygon(p, density=-1, col="#00000040")
  # The dilated points and edges.
  plot.list <- function(l, c) lapply(l, function(p) 
                  polygon(p, density=-1, col=c, border="#00000040"))
  plot.list(d.points, "#ff000020")
  plot.list(d.edges, "#0000ff20")
  invisible(NULL) # Doesn't return anything
}
#
# Create a sector of a circle.
# `n` is the number of vertices to use for approximating its outer arc.
#
sector <- function(radius, arg1, arg2, n=1, origin=c(0,0)) {
  t(cbind(origin, radius*sapply(seq(arg1, arg2, length.out=n), 
                  function(a) c(cos(a), sin(a)))))
}
#
# Create a polygon represented as an array of rows.
#
n.vertices <- 60 # Inscribes an `n.vertices`-gon in the unit circle.
angles <- seq(2*pi, 0, length.out=n.vertices+1)
angles <- angles[-(n.vertices+1)]
polygon.the <- cbind(cos(angles), sin(angles))
if (n.vertices==1) polygon.the <- rbind(polygon.the, polygon.the)
#
# Dilate the polygon in various ways to illustrate.
#
system.time({
  radius <- 1/3
  par(mfrow=c(1,3))
  q <- sector(radius, pi/12, 2*pi/3, n=120)
  d.points <- dilate.points(polygon.the, q)
  d.edges <- dilate.edges(polygon.the, q)
  display(polygon.the, d.points, d.edges, main="-30 to 75 degrees")

  q <- sector(radius, pi/3, 4*pi/3, n=180)
  d.points <- dilate.points(polygon.the, q)
  d.edges <- dilate.edges(polygon.the, q)
  display(polygon.the, d.points, d.edges, main="-150 to 30 degrees")

  q <- sector(radius, -9/20*pi, -9/20*pi)
  d.points <- dilate.points(polygon.the, q)
  d.edges <- dilate.edges(polygon.the, q)
  display(polygon.the, d.points, d.edges, main="171 degrees")
})

इस उदाहरण के लिए कम्प्यूटिंग समय (अंतिम आंकड़े से), एन = 60 और एम = 121 (बाएं), एम = 181 (मध्य), और एम = 2 (दाएं) के साथ, एक चौथाई दूसरा था। हालाँकि, इसमें से अधिकांश डिस्प्ले के लिए था। आमतौर पर, यह Rकोड N M = 1.5 मिलियन प्रति सेकंड (केवल 0.002 सेकंड या इतने पर दिखाए गए सभी उदाहरण गणना करने के लिए) संभाल लेगा फिर भी, उत्पाद एम एन की उपस्थिति का अर्थ है एक विस्तृत पड़ोस के माध्यम से कई आंकड़े या जटिल आंकड़े का फैलाव काफी समय लग सकता है, इसलिए सावधान रहें! एक बड़ी समस्या से निपटने से पहले छोटी समस्याओं के लिए बेंचमार्क। ऐसी परिस्थितियों में कोई भी एक रेखापुंज आधारित समाधान को देख सकता है (जो लागू करने के लिए बहुत आसान है, अनिवार्य रूप से सिर्फ एक पड़ोस गणना की आवश्यकता है।)


वाह, यह बहुत विस्तृत और आकर्षक है। मैं किसी भी कम की उम्मीद नहीं थी।
पॉल

1

यह बहुत व्यापक है, लेकिन आप यह कर सकते हैं:

  1. मूल बहुभुज बफर
  2. बहुभुज सीमा पर बनाए जाने वाली "उन्मुख" किरणों का मूल बिंदु खोजें (किसी प्रकार की स्पर्शरेखा का बिंदु?)
  3. प्रश्न से टिप्पणियों में चर्चा किए गए कोण का उपयोग करके बफर से परे उस बिंदु से दूरी तक एक लाइन बनाएं / विस्तारित करें।
  4. बफर और मूल बहुभुज के साथ उस रेखा को काटना। यह शायद 3 के रूप में एक ही समय में किया जा सकता है) विस्तार करने के लिए उचित args के साथ।
  5. बहुभुज के परिणामी सेट से नया "उन्मुख बफर" बहुभुज निकालें

मेरा मानना ​​है कि ओपी का मतलब एक सर्कल के सेक्टर द्वारा प्रत्येक आकृति के रूपात्मक फैलाव के अर्थ में "उन्मुख बफर" है । , (लेकिन जब से शेपफ़ाइलें वेक्टर प्रारूप में हैं, एक वेक्टर समाधान वांछनीय होगा यह करने के लिए मुश्किल है इस विवरण तुरंत एक रेखापुंज समाधान देता है।।)
whuber

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

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

फोकलस्टैट्स के बारे में सोचते हुए , लेकिन यह निश्चित नहीं था कि अगर ओपी का आकार + कोण एक ही पड़ोस में संयोजित करना कठिन होगा ।
रोलैंड

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