लाइन टक्कर पर 2 डी लाइन का पता कैसे लगाएं?


13

मैं एक फ्लैश एक्शनस्क्रिप्ट गेम डेवलपर हूं जो गणित के साथ थोड़ा पीछे है, हालांकि मुझे भौतिकी दिलचस्प और शांत दोनों लगती है।

संदर्भ के लिए यह एक गेम है जिसे मैं बना रहा हूँ: अनटैंगल फ़्लैश गेम

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

यदि आप लाइन सेगमेंट टकराव का पता लगाने के लिए एक एल्गोरिदम का सुझाव दे सकते हैं तो यह वास्तव में आप लोगों की तरह होगा । मैं मूल रूप से एक व्यक्ति हूँ जो 'अंकगणितीय' की तुलना में 'नेत्रहीन' सोचना पसंद करता है :)

संपादित करें: मैं इस विचार को और अधिक स्पष्ट रूप से व्यक्त करने के लिए कुछ आरेख जोड़ना चाहूंगा

कोई चौराहा नहीं कोई चौराहा नहीं चौराहा कोई चौराहा नहीं

पुनश्च मैं एक समारोह के रूप में बनाने की कोशिश कर रहा हूँ

private function isIntersecting(A:Point, B:Point, C:Point, D:Point):Boolean

अग्रिम में धन्यवाद।


6
यह समस्या का एक निराश गैर दृश्य व्याख्या है, लेकिन यह एक एल्गोरिथ्म है और यदि आप अपने गणित पढ़ने के लिए अपने आप को ला सकता है यह कर भावना करता है: local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d यह हो सकता है यदि आपका वेक्टर गणित कमजोर है, तो भारी हो। मैं समझता हूं - मैं दृश्य स्पष्टीकरण भी पसंद करता हूं। मैं इसे डूडल करने के लिए बाद में समय खोजने की कोशिश करूंगा, लेकिन अगर कोई भी कलाकार पूरी तरह से इस लिंक को देखता है और मेरे पास करने से पहले समय है, तो इसे प्राप्त करें!
एको

जवाबों:


18

मैं निम्नलिखित विधि का उपयोग करता हूं जो इस एल्गोरिथ्म के कार्यान्वयन के लिए बहुत अधिक है । यह C # में है, लेकिन ActionScript में इसका अनुवाद तुच्छ होना चाहिए।

bool IsIntersecting(Point a, Point b, Point c, Point d)
{
    float denominator = ((b.X - a.X) * (d.Y - c.Y)) - ((b.Y - a.Y) * (d.X - c.X));
    float numerator1 = ((a.Y - c.Y) * (d.X - c.X)) - ((a.X - c.X) * (d.Y - c.Y));
    float numerator2 = ((a.Y - c.Y) * (b.X - a.X)) - ((a.X - c.X) * (b.Y - a.Y));

    // Detect coincident lines (has a problem, read below)
    if (denominator == 0) return numerator1 == 0 && numerator2 == 0;

    float r = numerator1 / denominator;
    float s = numerator2 / denominator;

    return (r >= 0 && r <= 1) && (s >= 0 && s <= 1);
}

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

संपादित करें

मुझे इस एल्गोरिथम का परिणाम नहीं मिला, क्षमा करें!

यह अजीब है, मैंने इसका परीक्षण किया है और यह मेरे लिए काम कर रहा है सिवाय उस एक मामले के जो मैंने ऊपर वर्णित किया था। जब मैंने इसे टेस्ट ड्राइव के लिए लिया था, तो मैंने जो परिणाम प्राप्त किए थे, उसी सटीक संस्करण का उपयोग करते हुए:

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


मुझे इस एल्गोरिथम का परिणाम नहीं मिला, क्षमा करें!
विष्णु

4
@Vish आपको क्या समस्या थी? मैंने पोस्ट करने से पहले एल्गोरिथ्म की इस सटीक प्रतिलिपि का परीक्षण किया और यह वर्णित एकल मामले को छोड़कर त्रुटिपूर्ण काम किया।
डेविड गाविया

फिर, मुझे फिर से प्रयास करने दें, मैं इसमें कुछ गणित मिला सकता हूं। मैं आपको जल्द ही बता दूँगा। धन्यवाद एक टन, nyways :)
विष्णु

1
मुझे आपसे एल्गोरिथम का वांछित परिणाम मिला, धन्यवाद @DavidGouveia।
विष्णु

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

4

बिना दिव्यांगों के! तो न तो परिशुद्धता के साथ कोई समस्या है और न ही शून्य से विभाजन के द्वारा।

लाइन सेगमेंट 1 ए से बी लाइन सेगमेंट 2 से सी से डी है

एक रेखा एक कभी न खत्म होने वाली रेखा है, रेखा खंड उस रेखा का एक परिभाषित भाग है।

जांचें कि क्या दो बाउंडिंग बॉक्स प्रतिच्छेद करते हैं: यदि कोई प्रतिच्छेदन नहीं है -> कोई क्रॉस नहीं! (गणना की गई, झूठी वापसी करें)

जाँच करें कि क्या लाइन सेग 1 स्ट्रैडल्स लाइन सेग 2 है और यदि लाइन सेग 2 स्ट्रैडल्स लाइन सेग 1 (यानी। लाइन सेगमेंट 1 लाइन सेगमेंट 2 द्वारा परिभाषित लाइन के दोनों किनारों पर है)।

इसे -A द्वारा सभी बिंदुओं का अनुवाद करके बनाया जा सकता है (यानी आप 2 लाइनों को स्थानांतरित करते हैं ताकि A मूल (0,0) में हो)

फिर आप जांचते हैं कि बिंदु C और D 0,0 से B तक परिभाषित रेखा के विभिन्न किनारों पर है या नहीं

//Cross Product (hope I got it right here)
float fC= (B.x*C.y) - (B.y*C.x); //<0 == to the left, >0 == to the right
float fD= (B.x*D.y) - (B.y*D.x);

if( (fc<0) && (fd<0)) //both to the left  -> No Cross!
if( (fc>0) && (fd>0)) //both to the right -> No Cross!

यदि आपको पहले से ही "नो क्रॉस" नहीं मिला है, तो ए, बी बनाम सी, डी लेकिन सी, डी बनाम ए, बी (समान बछड़ों, ए और सी, बी और डी) का उपयोग जारी रखें, यदि कोई नहीं हैं "कोई क्रॉस नहीं!" तो आप एक चौराहा है!

मैंने क्रॉस उत्पाद के लिए सटीक गणना की खोज की और इस ब्लॉग पोस्ट को पाया जो विधि को भी समझाता है।


1
मुझे क्षमा करें, लेकिन मैं वेक्टर गणित के साथ काफी अच्छा नहीं हूं, मैंने इस एल्गोरिथम को इस तरह से लागू किया है, लेकिन कोई परिणाम नहीं मिला, क्षमा करें!
विष्णु

1
यह काम करना चाहिए शायद अगर आप हमें अपना कोड दिखा सकें तो हम आपकी मदद कर सकते हैं?
वेलमंड

अच्छा! हालांकि लिंक टूट गया है
clabe45

चौराहे की बात पाने के लिए क्या आप इसमें कुछ जोड़ सकते हैं?
सीनमेमी

1

मैं सिर्फ यह कहना चाहता हूं, मुझे अपने गेममेकर स्टूडियो गेम के लिए इसकी आवश्यकता थी और यह अच्छी तरह से काम करता है:

///scr_line_collision(x1,y1,x2,y2,x3,y3,x4,y4)

var denominator= ((argument2 - argument0) * (argument7 - argument5)) - ((argument3 - argument1) * (argument6 - argument4));
var numerator1 = ((argument1 - argument5) * (argument6 - argument4)) - ((argument0 - argument4) * (argument7 - argument5));
var numerator2 = ((argument1 - argument5) * (argument2 - argument0)) - ((argument0 - argument4) * (argument3 - argument1));

// Detect coincident lines
if (denominator == 0) {return (numerator1 == 0 && numerator2 == 0)}

var r = numerator1 / denominator;
var s = numerator2 / denominator;

return ((r >= 0 && r <= 1) && (s >= 0 && s <= 1));

मुझे लगता है कि यह उत्तर वास्तव में बेहतर हो सकता है यदि आपने समझाया कि कोड क्या करता है।
टॉमटैग

1

स्वीकृत उत्तर ने इस मामले में गलत उत्तर दिया:

x1 = 0;
y1 = 0;
x2 = 10;
y2 = 10;

x3 = 10.1;
y3 = 10.1;
x4 = 15;
y4 = 15;

ये रेखाएँ स्पष्ट रूप से प्रतिच्छेद नहीं करती हैं, लेकिन "सही उत्तर" में कार्य के अनुसार रेखाएँ प्रतिच्छेद करती हैं।

यही है वह जो मेरे द्वारा उपयोग किया जाता है:

function do_lines_intersect(px1,py1,px2,py2,px3,py3,px4,py4) {
  var ua = 0.0;
  var ub = 0.0;
  var ud = (py4 - py3) * (px2 - px1) - (px4 - px3) * (py2 - py1);


  if (ud != 0) {
    ua = ((px4 - px3) * (py1 - py3) - (py4 - py3) * (px1 - px3)) / ud;
    ub = ((px2 - px1) * (py1 - py3) - (py2 - py1) * (px1 - px3)) / ud;
        if (ua < 0.0 || ua > 1.0 || ub < 0.0 || ub > 1.0) ua = 0.0;
  }

  return ua;
}

रिटर्न 0 = पंक्तियाँ प्रतिच्छेद नहीं करती हैं

रिटर्न> 0 = लाइनें प्रतिच्छेद करती हैं


प्रश्न का उत्तर देने के लिए अपडेट करें:

यह कोड मैंने खुद नहीं बनाया। यह 5 साल से अधिक पुराना है और मुझे नहीं पता कि मूल स्रोत क्या है। परंतु..

मुझे लगता है कि वापसी मूल्य पहली पंक्ति की सापेक्ष स्थिति है जहां वे पार करते हैं (इसे बुरी तरह से समझाने के लिए)। चौराहे के बिंदु की गणना करने के लिए आप संभवतः इस तरह से lerp का उपयोग कर सकते हैं:

l = do_lines_intersect(...)
if (l > 0) {
    intersect_pos_x = l * (px2-px1);
    intersect_pos_y = l * (py2-py1);
} else {
    // lines do not cross
}

(मुझे यह नहीं पता था)


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