मैं एक बिंदु और एक अक्ष-संरेखित आयत के बीच की दूरी की गणना कैसे करूं?


29

मेरे पास x, y स्थिति, ऊंचाई और चौड़ाई के साथ 2D आयत है, और पास में एक बेतरतीब ढंग से स्थित बिंदु है।

क्या यह जांचने का कोई तरीका है कि क्या यह बिंदु आयत से टकरा सकता है यदि यह एक निश्चित दूरी से अधिक निकट है? उस आयत के बाहर एक अदृश्य त्रिज्या की कल्पना करें जो उक्त आयत से टकरा रही है। मुझे इस से समस्या है क्योंकि यह एक वर्ग नहीं है!

जवाबों:


26

यदि (x,y)आयत का केंद्र है, तो एक बिंदु (px,py)से आयत की सीमा तक की वर्ग दूरी की गणना इस प्रकार की जा सकती है:

dx = max(abs(px - x) - width / 2, 0);
dy = max(abs(py - y) - height / 2, 0);
return dx * dx + dy * dy;

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


6
किसी और के लिए, जो सोच रहा है, (x, y) आयत का केंद्र है, न कि कोने का
ग्रेग रोज़मिरियनज़ेक

2
पुरानी टिप्पणी के लिए खेद है, लेकिन क्या यह समीकरण मानता है कि आयत अक्ष-संरेखित है?
बिटिनजा

1
@BitNinja हाँ, यही सवाल है। यदि यह अक्ष-संरेखित नहीं है, तो सबसे तेज़ / सरल एल्गोरिथ्म इस बात पर निर्भर करेगा कि आयत की जानकारी कैसे संग्रहीत की जाती है।
सैम होसेवर

कहते हैं, बिंदु (4: 4) है, आयत चौड़ाई / ऊँचाई (5: 5) के साथ (5: 5) है। आपका कोड यह दावा करेगा कि बिंदु स्पर्श करता है या आयत के अंदर है, लेकिन यह स्पष्ट रूप से बाहर है
LRN

@LRN चौड़ाई (ऊंचाई (5: 5) (2.5: 2.5) से (7.5: 7.5) तक फैला हुआ है। बिंदु (4: 4) उस आयत के अंदर है।
सैम होसेवर

11

मुझे लगता है कि आपकी आयत एक्सिस-संरेखित है।

आपको बस बिंदु को आयत में "दबाना" पड़ता है और फिर दबे हुए बिंदु से दूरी की गणना करनी होती है।

बिंदु = (px, py), आयत = (rx, ry, rwidth, rheight) // (शीर्ष बाएं कोने, आयाम)

function pointRectDist (px, py, rx, ry, rwidth, rheight)
{
    var cx = Math.max(Math.min(px, rx+rwidth ), rx);
    var cy = Math.max(Math.min(py, ry+rheight), ry);
    return Math.sqrt( (px-cx)*(px-cx) + (py-cy)*(py-cy) );
}

3

आपको इसके लिए सर्कल-आयत टकराव का उपयोग करना होगा। स्टैक ओवरफ्लो पर एक समान प्रश्न है।

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


3

यदि आप एक आयत के किनारे पर एक बिंदु से दूरी जानने की कोशिश कर रहे हैं, तो आयत द्वारा बनाए गए नौ क्षेत्रों में से प्रत्येक के साथ काम करना सबसे तेज़ तरीका हो सकता है:

function pointRectangleDistance(x, y, x1, y1, x2, y2) {
    var dx, dy;
    if (x < x1) {
        dx = x1 - x;
        if (y < y1) {
            dy = y1 - y;
            return Math.sqrt(dx * dx + dy * dy);
        }
        else if (y > y2) {
            dy = y - y2;
            return Math.sqrt(dx * dx + dy * dy);
        }
        else {
            return dx;
        }
    }
    else if (x > x2) {
        dx = x - x2;
        if (y < y1) {
            dy = y1 - y;
            return Math.sqrt(dx * dx + dy * dy);
        }
        else if (y > y2) {
            dy = y - y2;
            return Math.sqrt(dx * dx + dy * dy);
        }
        else {
            return dx;
        }
    }
    else {
        if (y < y1) {
            return y1 - y;
        }
        else if (y > y2) {
            return y - y2;
        }
        else {
            return 0.0; // inside the rectangle or on the edge
        }
    }
}

2

[टिप्पणियों के आधार पर संशोधित उत्तर]

यदि आप यह देखना चाहते हैं कि बिंदु 10 इकाइयों के भीतर है या नहीं, यदि नीचे दी गई छवि में ग्रे आयत है, तो आप जांचते हैं कि बिंदु किसी में है या नहीं

  1. लाल आयत
  2. नीली आयत
  3. हरे घेरे में से कोई एक (त्रिज्या 10)

enter image description here

inside=false;

bluerect.x=oldrect.x-10;
bluerect.y=oldrect.y;
bluerect.width=oldrect.width;
bluerect.height=oldrect.height+20;

if(  point.x >=bluerect && point.x <=redrect.x+bluerect.width &&
     point.y >=bluerect && point.y <=redrect.y+bluerect.height){
         //now point is side the blue rectangle
         inside=true;
}

redrect.x=oldrect.x;
redrect.y=oldrect.y-10;
redrect.width=oldrect.width+20;
redrect.height=oldrect.height;

if(  point.x >=redrect&& point.x <=redrect.x+redrect.width &&
     point.y >=redrect&& point.y <=redrect.y+redrect.height){
         //now point is side the redrectangle
         inside=true;
}


d1= distance(point, new point(oldrect.x, oldrect.y)) //calculate distance between point and (oldrect.x, oldrect.y)
d2= distance(point, new point(oldrect.x+10, oldrect.y))
d3= distance(point, new point(oldrect.x, oldrect.y+10))
d4= distance(point, new point(oldrect.x+10, oldrect.y+10))
if (d1 < 10 || d2 <10 || d3 < 10 || d4 <10){
    inside=true;
}

//inside is now true if the point is within 10 units of rectangle

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


विकर्ण दिशा में, यह उन बिंदुओं को गलत सकारात्मक देगा जो उदाहरण के लिए हैं। 11 इकाइयाँ दूर।
एरिक बी

अपडेट की गई तस्वीर स्पष्ट रूप से गलत है, वास्तव में यह वास्तव में त्रुटि मामले को दिखाता है और इसे सही दिखाता है। वह हरा बिंदु आसानी से 10 यूनिट से अधिक दूर हो सकता है और उस बाहरी आयत के अंदर हो सकता है।
एरिक बी

अरे @ EricB, मैंने आपके द्वारा बताई गई त्रुटि को ठीक कर दिया है, आपके डाउनवोट को पूर्ववत् कैसे करें?
केन

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

यह उत्तर ईमानदारी से भयानक है। 12 अतिरिक्त, 4 ऑब्जेक्ट निर्माण, 12 परीक्षण, 4 कार्य के लिए 4 वर्गमूल जो वास्तव में कोड की 3 लाइनों की आवश्यकता होती है?
सैम होसेवर

-2

आप कुछ इस तरह का उपयोग कर सकते हैं: enter image description here


यह विधि अनावश्यक रूप से जटिल लगती है। इस समस्या को हल करने के लिए X1 और y1 ढूँढना आवश्यक नहीं है।
एरिक बी

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

दूरी की एक माप पहले से ही निहित है। अगर (d2 <10 * 10) {/ * नाप की 10 इकाइयों के भीतर * /}
अलेक्जेंडर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.