मैं यह कैसे निर्धारित करूं कि दो रेखाएं प्रतिच्छेदन हैं या नहीं, और यदि वे करते हैं, तो x, y बिंदु पर क्या होगा?
मैं यह कैसे निर्धारित करूं कि दो रेखाएं प्रतिच्छेदन हैं या नहीं, और यदि वे करते हैं, तो x, y बिंदु पर क्या होगा?
जवाबों:
इस समस्या का एक अच्छा तरीका है जो वेक्टर क्रॉस उत्पादों का उपयोग करता है। 2-आयामी वेक्टर क्रॉस उत्पाद v × w को v x w y - v y w x में परिभाषित करें ।
मान लीजिए कि दो पंक्ति खंड p से p + r तक और q से q + s तक चलते हैं । तब पहली पंक्ति का कोई भी बिंदु p + t r (एक स्केलर पैरामीटर t के लिए ) और दूसरी पंक्ति पर q + u s (एक स्केलर पैरामीटर u के रूप में ) के रूप में किसी भी बिंदु के रूप में प्रतिनिधित्व करने योग्य होता है ।
यदि हम t और u को खोज सकें तो दो पंक्तियाँ प्रतिच्छेद करती हैं:
p + t r = q + u s
एस के साथ दोनों पक्षों को पार करना , प्राप्त करना
( p + t r ) × s = ( q + u s ) × s
और चूंकि s × s = 0, इसका मतलब है
t ( r × s ) = ( q - p ) × s
और इसलिए, टी के लिए हल :
t = ( q - p ) × s / ( r × s )
उसी तरह, हम यू के लिए हल कर सकते हैं :
( p + t r ) × r = ( q + u s ) × r
u ( s × r ) = ( p - q ) × r
u = ( p - q ) × r / ( s × r )
गणना के चरणों की संख्या को कम करने के लिए, इसे इस तरह से फिर से लिखना सुविधाजनक है (यह याद रखना कि s × r = - r / s ):
u = ( q - p ) × r / ( r × s )
अब चार मामले हैं:
यदि r × s = 0 और ( q - p ) × r = 0 हो, तो दो रेखाएं आपस में टकराती हैं।
इस स्थिति में, पहली पंक्ति खंड ( p + t r ) के समीकरण के संदर्भ में दूसरे खंड ( q और q + s ) के अंतिम बिंदुओं को व्यक्त करें :
t 0 = ( q - p ) · r / ( r · r )
t 1 = ( q + s - p ) · r / ( r · r ) = t 0 + s · r / ( r · r )
यदि टी 0 और टी 1 के बीच का अंतराल अंतराल को नष्ट कर देता है [0, 1] तो लाइन सेगमेंट टकराते हैं और अतिव्यापी होते हैं; अन्यथा वे टकरा रहे हैं और असंतुष्ट हैं।
ध्यान दें कि यदि s और r विपरीत दिशाओं में इंगित करते हैं, तो s · r <0 और इसलिए चेक किया जाने वाला अंतराल [ t 0 , t 1 ] के बजाय [ t 1 , t 0 ] है।
यदि r × s = 0 और ( q - p ) × r then 0 है, तो दो रेखाएं समानांतर और गैर-प्रतिच्छेदन हैं।
यदि r × s and 0 और 0 × t 0 1 और 0 ≤ u s 1 है, तो दो पंक्ति खंड बिंदु p + t r = q + u s पर मिलते हैं ।
अन्यथा, दो लाइन सेगमेंट समानांतर नहीं हैं, लेकिन प्रतिच्छेद नहीं करते हैं।
क्रेडिट: यह विधि ग्राफिक्स रत्न , पेज 304 में प्रकाशित रोनाल्ड गोल्डमैन द्वारा प्रकाशित लेख "थ्री-स्पेस में दो लाइनों का अंतर" से 3 डी लाइन चौराहे एल्गोरिथ्म का 2-आयामी विशेषज्ञता है । तीन आयामों में, सामान्य स्थिति यह है कि लाइनें तिरछी होती हैं (न तो समानांतर और न ही इंटरसेक्टिंग) जिस स्थिति में विधि दो लाइनों के निकटतम दृष्टिकोण के बिंदु देती है।
/ (r × s)
, लेकिन (r × s)
एक वेक्टर है, है ना? एक वेक्टर (0, 0, rx * sy - ry * sx)
। और बाएं हाथ की तरफ इसी तरह एक वेक्टर है जो z अक्ष के समानांतर है। तो ... क्या मैं z घटक को अन्य z घटक से विभाजित करता हूं? टी के लिए सूत्र वास्तव में है |(q − p) × s| / |(r × s)|
?
FWIW, निम्न फ़ंक्शन (C में) दोनों लाइन चौराहों का पता लगाता है और प्रतिच्छेदन बिंदु निर्धारित करता है। यह आंद्रे लेमोटे के " ट्रिक्स ऑफ़ द विंडोज गेम प्रोग्रामिंग गुरु " में एक एल्गोरिथ्म पर आधारित है । यह एल्गोरिथ्म के कुछ अन्य उत्तरों (जैसे गारेथ) में भिन्न नहीं है। LeMothe तो Cramer के नियम का उपयोग करता है (मुझे मत पूछो) खुद समीकरणों को हल करने के लिए।
मैं यह जान सकता हूं कि यह मेरे कमजोर क्षुद्रग्रहों के क्लोन में काम करता है, और एलीमेंटल, डैन और वोडज़ू द्वारा अन्य उत्तरों में वर्णित किनारे के मामलों के साथ सही ढंग से व्यवहार करता है। यह शायद KingNestor द्वारा पोस्ट किए गए कोड से भी तेज़ है क्योंकि यह सभी गुणा और भाग है, कोई वर्गमूल नहीं!
मुझे लगता है कि वहाँ शून्य से विभाजित करने के लिए कुछ क्षमता है, हालांकि यह मेरे मामले में एक मुद्दा नहीं रहा है। वैसे भी दुर्घटना से बचने के लिए संशोधित करना काफी आसान है।
// Returns 1 if the lines intersect, otherwise 0. In addition, if the lines
// intersect the intersection point may be stored in the floats i_x and i_y.
char get_line_intersection(float p0_x, float p0_y, float p1_x, float p1_y,
float p2_x, float p2_y, float p3_x, float p3_y, float *i_x, float *i_y)
{
float s1_x, s1_y, s2_x, s2_y;
s1_x = p1_x - p0_x; s1_y = p1_y - p0_y;
s2_x = p3_x - p2_x; s2_y = p3_y - p2_y;
float s, t;
s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);
if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
{
// Collision detected
if (i_x != NULL)
*i_x = p0_x + (t * s1_x);
if (i_y != NULL)
*i_y = p0_y + (t * s1_y);
return 1;
}
return 0; // No collision
}
BTW, मुझे कहना होगा कि LeMothe की पुस्तक में, हालांकि वह स्पष्ट रूप से एल्गोरिथ्म को सही पाता है, लेकिन ठोस उदाहरण वह गलत संख्या में प्लग दिखाता है और गणना गलत करता है। उदाहरण के लिए:
(4 * (4 - 1) + 12 * (7 - 1)) / (17 * 4 + 12 * 10)
= 844 / 0.88
= 0.44
इसने मुझे घंटों तक भ्रमित किया । :(
s
और t
सीधे करने के बजाय , दो संख्यात्मक और भाजक के बीच संबंधों का परीक्षण करें। केवल अगर लाइनों को पुष्टि करने की पुष्टि की जाती है तो क्या आपको वास्तव में t
(लेकिन नहीं s
) के मूल्य की गणना करने की आवश्यकता है ।
समस्या इस प्रश्न को कम करती है: A से B तक और C से D प्रतिच्छेदन तक दो रेखाएँ हैं? फिर आप इसे चार बार पूछ सकते हैं (रेखा के बीच और आयत के चार पक्षों में से प्रत्येक)।
यहाँ यह करने के लिए वेक्टर गणित है। मैं मान रहा हूं कि A से B तक की रेखा प्रश्न में रेखा है और C से D तक की रेखा आयत रेखाओं में से एक है। मेरी धारणा यह है कि Ax
"ए का x- समन्वय" और Cy
"सी का y- समन्वय" है। और " *
" का अर्थ है डॉट-प्रोडक्ट, इसलिए जैसे A*B = Ax*Bx + Ay*By
।
E = B-A = ( Bx-Ax, By-Ay )
F = D-C = ( Dx-Cx, Dy-Cy )
P = ( -Ey, Ex )
h = ( (A-C) * P ) / ( F * P )
यह h
नंबर कुंजी है। यदि h
बीच में है 0
और 1
, रेखाएं प्रतिच्छेद करती हैं, अन्यथा वे नहीं करते हैं। यदि F*P
शून्य है, तो निश्चित रूप से आप गणना नहीं कर सकते हैं, लेकिन इस मामले में लाइनें समानांतर हैं और इसलिए केवल स्पष्ट मामलों में अंतर करती हैं।
चौराहे का सटीक बिंदु है C + F*h
।
ज्यादा मस्ती:
अगर h
है वास्तव में 0
या 1
लाइनों एक अंत बिंदु पर स्पर्श करें। आप इस पर विचार कर सकते हैं "चौराहे" या नहीं जैसा कि आप फिट देखते हैं।
विशेष रूप से, h
यह है कि आपको दूसरी पंक्ति को छूने के लिए लाइन की लंबाई कितनी गुणा करनी होगी।
इसलिए, यदि h<0
, इसका मतलब है कि आयत रेखा "दी गई" रेखा से "पीछे" है (ए से बी तक "दिशा" होने के नाते), और यदि h>1
आयत रेखा दी गई रेखा के "सामने" है।
व्युत्पत्ति:
ए और सी वैक्टर हैं जो लाइन की शुरुआत को इंगित करते हैं; ई और एफ ए और सी के छोर से वैक्टर हैं जो लाइन बनाते हैं।
विमान में किसी भी दो गैर-समानांतर रेखाओं के लिए, स्केलर की एक जोड़ी g
और h
इस तरह की समीकरण होनी चाहिए :
A + E*g = C + F*h
क्यों? क्योंकि दो गैर-समानांतर रेखाओं को एक दूसरे से सटना चाहिए, जिसका अर्थ है कि आप दोनों रेखाओं को कुछ मात्रा में माप सकते हैं और एक-दूसरे को स्पर्श कर सकते हैं।
( कम दो अज्ञात के साथ एक एकल समीकरण की तरह इस दिखता है! लेकिन यह जब आप समझते हैं कि यह एक 2 डी वेक्टर समीकरण है, जिसका अर्थ यह वास्तव में समीकरणों की एक जोड़ी है नहीं है x
और y
।)
हमें इनमें से एक वैरिएबल को खत्म करना होगा। एक आसान तरीका यह है कि E
शून्य शब्द बनाया जाए। ऐसा करने के लिए, समीकरण के दोनों पक्षों के डॉट-उत्पाद को वेक्टर के उपयोग से ले लीजिए, जो कि ई के साथ शून्य पर डॉट जाएगा। उस वेक्टर को मैंने P
ऊपर बुलाया , और मैंने ई का स्पष्ट परिवर्तन किया।
अब आपके पास है:
A*P = C*P + F*P*h
(A-C)*P = (F*P)*h
( (A-C)*P ) / (F*P) = h
A + E*g = C + F*h
दो पंक्तियाँ अगर और केवल उस समीकरण का हल मानती हैं (मान लें कि वे समानांतर नहीं हैं) दोनों हैं, g
औरh
0 और 1 के बीच (या- या अनन्य, इस बात पर निर्भर करता है कि आप एक अंतिम बिंदु पर छूते हैं)।
मैंने एल्गोरिथ्म को लागू करने की कोशिश की है ताकि ऊपर जेसन द्वारा वर्णित सुरुचिपूर्ण ढंग से; दुर्भाग्य से काम करते हुए हालांकि डिबगिंग में गणित मुझे कई मामले मिले जिनके लिए यह काम नहीं करता है।
उदाहरण के लिए अंक A (10,10) B (20,20) C (10,1) D (1,10) h = .5 देता है पर विचार करें और फिर भी परीक्षा से यह स्पष्ट है कि ये खंड प्रत्येक के पास नहीं हैं। अन्य।
इसे रेखांकन करने से यह स्पष्ट हो जाता है कि 0 <h <1 मानदंड केवल यह दर्शाता है कि अवरोधन बिंदु सीडी पर झूठ होगा यदि यह अस्तित्व में है, लेकिन उस बिंदु पर एबी में से कोई भी नहीं बताता है। यह सुनिश्चित करने के लिए कि एक क्रॉस पॉइंट है जिसे आपको चर g के लिए सममित गणना करनी चाहिए और अवरोधन की आवश्यकता है: 0 <g <1 और 0 <h <1
यहाँ गेविन के उत्तर में सुधार है। marcp का समाधान भी समान है, लेकिन न तो विभाजन को स्थगित करें।
यह वास्तव में गैरेथ रीस के उत्तर के व्यावहारिक अनुप्रयोग के रूप में अच्छी तरह से पता चलता है, क्योंकि 2 डी में क्रॉस-उत्पाद का समकक्ष प्रति-डॉट-उत्पाद है, जो कि यह कोड तीन का उपयोग करता है। 3 डी पर स्विच करना और क्रॉस-उत्पाद का उपयोग करना, अंत में एस और टी दोनों को प्रक्षेपित करना, 3 डी में लाइनों के बीच दो निकटतम बिंदुओं का परिणाम है। वैसे भी, 2 डी समाधान:
int get_line_intersection(float p0_x, float p0_y, float p1_x, float p1_y,
float p2_x, float p2_y, float p3_x, float p3_y, float *i_x, float *i_y)
{
float s02_x, s02_y, s10_x, s10_y, s32_x, s32_y, s_numer, t_numer, denom, t;
s10_x = p1_x - p0_x;
s10_y = p1_y - p0_y;
s32_x = p3_x - p2_x;
s32_y = p3_y - p2_y;
denom = s10_x * s32_y - s32_x * s10_y;
if (denom == 0)
return 0; // Collinear
bool denomPositive = denom > 0;
s02_x = p0_x - p2_x;
s02_y = p0_y - p2_y;
s_numer = s10_x * s02_y - s10_y * s02_x;
if ((s_numer < 0) == denomPositive)
return 0; // No collision
t_numer = s32_x * s02_y - s32_y * s02_x;
if ((t_numer < 0) == denomPositive)
return 0; // No collision
if (((s_numer > denom) == denomPositive) || ((t_numer > denom) == denomPositive))
return 0; // No collision
// Collision detected
t = t_numer / denom;
if (i_x != NULL)
*i_x = p0_x + (t * s10_x);
if (i_y != NULL)
*i_y = p0_y + (t * s10_y);
return 1;
}
मूल रूप से यह अंतिम क्षण तक विभाजन को स्थगित कर देता है, और कुछ गणनाओं को पूरा करने से पहले तक अधिकांश परीक्षणों को स्थानांतरित कर देता है, जिससे शुरुआती-बाहरी को जोड़ा जाता है। अंत में, यह विभाजन को शून्य मामले से भी बचाता है जो तब होता है जब लाइनें समानांतर होती हैं।
आप शून्य के मुकाबले तुलना करने के बजाय एप्सिलॉन परीक्षण का उपयोग करने पर विचार कर सकते हैं। रेखाएं जो समानांतर के बेहद समीप हैं, वे परिणाम उत्पन्न कर सकती हैं जो थोड़े से बंद हैं। यह एक बग नहीं है, यह फ्लोटिंग पॉइंट गणित के साथ एक सीमा है।
s32_y
जो किसी चीज़ के बजाय इसका वर्णन करते हैं कि यह कैसा है point2YDifference
?
मैंने एक ही विषय की खोज की है, और मैं उत्तरों से खुश नहीं था। इसलिए मैंने एक लेख लिखा है जिसमें बताया गया है कि दो लाइन खंडों को बहुत सारी छवियों के साथ जोड़ने पर कैसे जांच की जाए । जावा-कोड का पूरा (और परीक्षण किया हुआ) है।
यहाँ लेख है, सबसे महत्वपूर्ण भागों में फसली:
एल्गोरिथ्म, जो यह जाँचता है कि लाइन सेगमेंट के साथ एक खंड खंड b, इस तरह दिखता है:
बाउंडिंग बॉक्स क्या हैं? यहां दो पंक्ति खंडों के दो बाउंडिंग बॉक्स हैं:
यदि दोनों बाउंडिंग बॉक्स में एक चौराहा है, तो आप लाइन सेगमेंट को स्थानांतरित करते हैं ताकि एक बिंदु पर (0 | 0) हो। अब आपके पास a द्वारा परिभाषित मूल के माध्यम से एक पंक्ति है। अब उसी तरह से लाइन सेगमेंट बी को आगे बढ़ाएं और चेक करें कि क्या लाइन सेगमेंट के नए पॉइंट्स लाइन ए के अलग-अलग तरफ हैं। यदि यह मामला है, तो इसे दूसरे तरीके से जांचें। यदि यह भी है, तो रेखा सेगमेंट प्रतिच्छेद करते हैं। यदि नहीं, तो वे प्रतिच्छेद नहीं करते हैं।
आप जानते हैं कि दो पंक्ति खंड एक और बी प्रतिच्छेद हैं। यदि आप यह नहीं जानते हैं, तो मुझे "प्रश्न C" में दिए गए टूल से इसकी जांच करें।
अब आप कुछ मामलों से गुजर सकते हैं और 7 वीं कक्षा के गणित के साथ हल प्राप्त कर सकते हैं ( कोड और इंटरैक्टिव उदाहरण देखें )।
के अपनी बात मान लीजिए A = (x1, y1)
, बिंदु B = (x2, y2)
, C = (x_3, y_3)
, D = (x_4, y_4)
। आपकी पहली पंक्ति AB (A! = B) के साथ परिभाषित की गई है, और CD (C! = D) के साथ आपकी दूसरी पंक्ति है।
function doLinesIntersect(AB, CD) {
if (x1 == x2) {
return !(x3 == x4 && x1 != x3);
} else if (x3 == x4) {
return true;
} else {
// Both lines are not parallel to the y-axis
m1 = (y1-y2)/(x1-x2);
m2 = (y3-y4)/(x3-x4);
return m1 != m2;
}
}
प्रश्न B के साथ जांचें कि क्या वे बिल्कुल इंटरसेक्ट करते हैं।
प्रत्येक रेखा के लिए दो बिंदुओं द्वारा रेखाओं को a और b परिभाषित किया जाता है। आप मूल रूप से उसी तर्क को लागू कर सकते हैं जिसका उपयोग प्रश्न ए में किया गया था।
यहाँ एक बार स्वीकार किया गया उत्तर गलत है (यह तब से अस्वीकार्य है, इसलिए हुर्रे!)। यह सभी गैर-चौराहों को सही ढंग से समाप्त नहीं करता है। तुच्छ रूप से यह काम करने के लिए प्रकट हो सकता है लेकिन यह विफल हो सकता है, विशेष रूप से इस मामले में कि 0 और 1 को h के लिए वैध माना जाता है।
निम्नलिखित मामले पर विचार करें:
(4,1) - (5,1) और (0,0) - (0,2) पर लाइनें
ये लंबवत रेखाएं हैं जो स्पष्ट रूप से ओवरलैप नहीं होती हैं।
A = (4,1)
B = (5,1)
C = (0,0)
D = (0,2)
E = (5,1) - (4,1) = (- 1,0)
F = (0,2) - (0,0) = (0, -2)
P = (0,1)
h = ((4,1) - (0,0)) डॉट (0,1) / (0 , -2) डॉट (0,1)) = 0
उपरोक्त उत्तर के अनुसार, ये दो लाइन खंड एक समापन बिंदु (0 और 1 के मान) पर मिलते हैं। वह समापन बिंदु होगा:
(0,0) + (0, -2) * 0 = (0,0)
तो, स्पष्ट रूप से दो लाइन खंड मिलते हैं (0,0), जो लाइन सीडी पर है, लेकिन लाइन एबी पर नहीं। तो क्या गलत हो रहा है? इसका उत्तर यह है कि 0 और 1 के मान मान्य नहीं हैं और केवल कभी-कभी HAPPEN अंत बिंदु चौराहे की सही भविष्यवाणी करने के लिए। जब एक लाइन का विस्तार (लेकिन अन्य नहीं) लाइन सेगमेंट को पूरा करेगा, तो एल्गोरिथ्म लाइन सेगमेंट के एक चौराहे की भविष्यवाणी करता है, लेकिन यह सही नहीं है। मैं कल्पना करता हूं कि एबी बनाम सीडी के साथ परीक्षण शुरू करने और फिर सीडी बनाम एबी के साथ परीक्षण करने से यह समस्या समाप्त हो जाएगी। केवल अगर दोनों 0 और 1 के बीच में आते हैं, तो उन्हें प्रतिच्छेद कहा जा सकता है।
यदि आप अंत बिंदुओं की भविष्यवाणी करना चाहते हैं तो मैं वेक्टर क्रॉस उत्पाद विधि का उपयोग करने की सलाह देता हूं।
-Dan
IMalc के उत्तर का पायथन संस्करण:
def find_intersection( p0, p1, p2, p3 ) :
s10_x = p1[0] - p0[0]
s10_y = p1[1] - p0[1]
s32_x = p3[0] - p2[0]
s32_y = p3[1] - p2[1]
denom = s10_x * s32_y - s32_x * s10_y
if denom == 0 : return None # collinear
denom_is_positive = denom > 0
s02_x = p0[0] - p2[0]
s02_y = p0[1] - p2[1]
s_numer = s10_x * s02_y - s10_y * s02_x
if (s_numer < 0) == denom_is_positive : return None # no collision
t_numer = s32_x * s02_y - s32_y * s02_x
if (t_numer < 0) == denom_is_positive : return None # no collision
if (s_numer > denom) == denom_is_positive or (t_numer > denom) == denom_is_positive : return None # no collision
# collision detected
t = t_numer / denom
intersection_point = [ p0[0] + (t * s10_x), p0[1] + (t * s10_y) ]
return intersection_point
denom = float(...)
दो लाइन खंडों का सही चौराहा ढूंढना एक गैर-तुच्छ कार्य है जिसमें बहुत सारे किनारे हैं। यहाँ जावा में एक अच्छी तरह से प्रलेखित, काम और परीक्षण किया गया समाधान है।
संक्षेप में, दो लाइन खंडों के प्रतिच्छेदन को खोजने पर तीन चीजें हो सकती हैं:
खंड खंड नहीं करते हैं
एक अनूठा चौराहा बिंदु है
चौराहा एक और खंड है
नोट : कोड में, मैं मानता हूं कि X1 = x2 और y1 = y2 के साथ एक लाइन खंड (X1, y1), (x2, y2) एक मान्य रेखाखंड है। गणितीय रूप से, एक पंक्ति खंड में अलग-अलग बिंदु होते हैं, लेकिन मैं पूर्णता के लिए इस कार्यान्वयन में खंडों को अंक देने की अनुमति देता हूं।
कोड मेरे जीथब रेपो से लिया गया है
/**
* This snippet finds the intersection of two line segments.
* The intersection may either be empty, a single point or the
* intersection is a subsegment there's an overlap.
*/
import static java.lang.Math.abs;
import static java.lang.Math.max;
import static java.lang.Math.min;
import java.util.ArrayList;
import java.util.List;
public class LineSegmentLineSegmentIntersection {
// Small epsilon used for double value comparison.
private static final double EPS = 1e-5;
// 2D Point class.
public static class Pt {
double x, y;
public Pt(double x, double y) {
this.x = x;
this.y = y;
}
public boolean equals(Pt pt) {
return abs(x - pt.x) < EPS && abs(y - pt.y) < EPS;
}
}
// Finds the orientation of point 'c' relative to the line segment (a, b)
// Returns 0 if all three points are collinear.
// Returns -1 if 'c' is clockwise to segment (a, b), i.e right of line formed by the segment.
// Returns +1 if 'c' is counter clockwise to segment (a, b), i.e left of line
// formed by the segment.
public static int orientation(Pt a, Pt b, Pt c) {
double value = (b.y - a.y) * (c.x - b.x) -
(b.x - a.x) * (c.y - b.y);
if (abs(value) < EPS) return 0;
return (value > 0) ? -1 : +1;
}
// Tests whether point 'c' is on the line segment (a, b).
// Ensure first that point c is collinear to segment (a, b) and
// then check whether c is within the rectangle formed by (a, b)
public static boolean pointOnLine(Pt a, Pt b, Pt c) {
return orientation(a, b, c) == 0 &&
min(a.x, b.x) <= c.x && c.x <= max(a.x, b.x) &&
min(a.y, b.y) <= c.y && c.y <= max(a.y, b.y);
}
// Determines whether two segments intersect.
public static boolean segmentsIntersect(Pt p1, Pt p2, Pt p3, Pt p4) {
// Get the orientation of points p3 and p4 in relation
// to the line segment (p1, p2)
int o1 = orientation(p1, p2, p3);
int o2 = orientation(p1, p2, p4);
int o3 = orientation(p3, p4, p1);
int o4 = orientation(p3, p4, p2);
// If the points p1, p2 are on opposite sides of the infinite
// line formed by (p3, p4) and conversly p3, p4 are on opposite
// sides of the infinite line formed by (p1, p2) then there is
// an intersection.
if (o1 != o2 && o3 != o4) return true;
// Collinear special cases (perhaps these if checks can be simplified?)
if (o1 == 0 && pointOnLine(p1, p2, p3)) return true;
if (o2 == 0 && pointOnLine(p1, p2, p4)) return true;
if (o3 == 0 && pointOnLine(p3, p4, p1)) return true;
if (o4 == 0 && pointOnLine(p3, p4, p2)) return true;
return false;
}
public static List<Pt> getCommonEndpoints(Pt p1, Pt p2, Pt p3, Pt p4) {
List<Pt> points = new ArrayList<>();
if (p1.equals(p3)) {
points.add(p1);
if (p2.equals(p4)) points.add(p2);
} else if (p1.equals(p4)) {
points.add(p1);
if (p2.equals(p3)) points.add(p2);
} else if (p2.equals(p3)) {
points.add(p2);
if (p1.equals(p4)) points.add(p1);
} else if (p2.equals(p4)) {
points.add(p2);
if (p1.equals(p3)) points.add(p1);
}
return points;
}
// Finds the intersection point(s) of two line segments. Unlike regular line
// segments, segments which are points (x1 = x2 and y1 = y2) are allowed.
public static Pt[] lineSegmentLineSegmentIntersection(Pt p1, Pt p2, Pt p3, Pt p4) {
// No intersection.
if (!segmentsIntersect(p1, p2, p3, p4)) return new Pt[]{};
// Both segments are a single point.
if (p1.equals(p2) && p2.equals(p3) && p3.equals(p4))
return new Pt[]{p1};
List<Pt> endpoints = getCommonEndpoints(p1, p2, p3, p4);
int n = endpoints.size();
// One of the line segments is an intersecting single point.
// NOTE: checking only n == 1 is insufficient to return early
// because the solution might be a sub segment.
boolean singleton = p1.equals(p2) || p3.equals(p4);
if (n == 1 && singleton) return new Pt[]{endpoints.get(0)};
// Segments are equal.
if (n == 2) return new Pt[]{endpoints.get(0), endpoints.get(1)};
boolean collinearSegments = (orientation(p1, p2, p3) == 0) &&
(orientation(p1, p2, p4) == 0);
// The intersection will be a sub-segment of the two
// segments since they overlap each other.
if (collinearSegments) {
// Segment #2 is enclosed in segment #1
if (pointOnLine(p1, p2, p3) && pointOnLine(p1, p2, p4))
return new Pt[]{p3, p4};
// Segment #1 is enclosed in segment #2
if (pointOnLine(p3, p4, p1) && pointOnLine(p3, p4, p2))
return new Pt[]{p1, p2};
// The subsegment is part of segment #1 and part of segment #2.
// Find the middle points which correspond to this segment.
Pt midPoint1 = pointOnLine(p1, p2, p3) ? p3 : p4;
Pt midPoint2 = pointOnLine(p3, p4, p1) ? p1 : p2;
// There is actually only one middle point!
if (midPoint1.equals(midPoint2)) return new Pt[]{midPoint1};
return new Pt[]{midPoint1, midPoint2};
}
/* Beyond this point there is a unique intersection point. */
// Segment #1 is a vertical line.
if (abs(p1.x - p2.x) < EPS) {
double m = (p4.y - p3.y) / (p4.x - p3.x);
double b = p3.y - m * p3.x;
return new Pt[]{new Pt(p1.x, m * p1.x + b)};
}
// Segment #2 is a vertical line.
if (abs(p3.x - p4.x) < EPS) {
double m = (p2.y - p1.y) / (p2.x - p1.x);
double b = p1.y - m * p1.x;
return new Pt[]{new Pt(p3.x, m * p3.x + b)};
}
double m1 = (p2.y - p1.y) / (p2.x - p1.x);
double m2 = (p4.y - p3.y) / (p4.x - p3.x);
double b1 = p1.y - m1 * p1.x;
double b2 = p3.y - m2 * p3.x;
double x = (b2 - b1) / (m1 - m2);
double y = (m1 * b2 - m2 * b1) / (m1 - m2);
return new Pt[]{new Pt(x, y)};
}
}
यहाँ एक सरल उपयोग उदाहरण दिया गया है:
public static void main(String[] args) {
// Segment #1 is (p1, p2), segment #2 is (p3, p4)
Pt p1, p2, p3, p4;
p1 = new Pt(-2, 4); p2 = new Pt(3, 3);
p3 = new Pt(0, 0); p4 = new Pt(2, 4);
Pt[] points = lineSegmentLineSegmentIntersection(p1, p2, p3, p4);
Pt point = points[0];
// Prints: (1.636, 3.273)
System.out.printf("(%.3f, %.3f)\n", point.x, point.y);
p1 = new Pt(-10, 0); p2 = new Pt(+10, 0);
p3 = new Pt(-5, 0); p4 = new Pt(+5, 0);
points = lineSegmentLineSegmentIntersection(p1, p2, p3, p4);
Pt point1 = points[0], point2 = points[1];
// Prints: (-5.000, 0.000) (5.000, 0.000)
System.out.printf("(%.3f, %.3f) (%.3f, %.3f)\n", point1.x, point1.y, point2.x, point2.y);
}
बस यह उल्लेख करना चाहता था कि न्यूमेरिक रेसिपी श्रृंखला में एक अच्छी व्याख्या और स्पष्ट समाधान पाया जा सकता है। मुझे तीसरा संस्करण मिला है और उत्तर पृष्ठ 1117, धारा 21.4 पर है। एक अलग नामकरण के साथ एक अन्य समाधान मरीना गवरिलोवा विश्वसनीय लाइन सेक्शन इंटरसेक्शन परीक्षण द्वारा एक पेपर में पाया जा सकता है । उसका समाधान है, मेरे दिमाग में, थोड़ा सरल है।
मेरा कार्यान्वयन नीचे है:
bool NuGeometry::IsBetween(const double& x0, const double& x, const double& x1){
return (x >= x0) && (x <= x1);
}
bool NuGeometry::FindIntersection(const double& x0, const double& y0,
const double& x1, const double& y1,
const double& a0, const double& b0,
const double& a1, const double& b1,
double& xy, double& ab) {
// four endpoints are x0, y0 & x1,y1 & a0,b0 & a1,b1
// returned values xy and ab are the fractional distance along xy and ab
// and are only defined when the result is true
bool partial = false;
double denom = (b0 - b1) * (x0 - x1) - (y0 - y1) * (a0 - a1);
if (denom == 0) {
xy = -1;
ab = -1;
} else {
xy = (a0 * (y1 - b1) + a1 * (b0 - y1) + x1 * (b1 - b0)) / denom;
partial = NuGeometry::IsBetween(0, xy, 1);
if (partial) {
// no point calculating this unless xy is between 0 & 1
ab = (y1 * (x0 - a1) + b1 * (x1 - x0) + y0 * (a1 - x1)) / denom;
}
}
if ( partial && NuGeometry::IsBetween(0, ab, 1)) {
ab = 1-ab;
xy = 1-xy;
return true;
} else return false;
}
समाधान के बहुत सारे उपलब्ध हैं, लेकिन मुझे लगता है कि नीचे समाधान बहुत सरल और समझने में आसान है।
दो सेगमेंट सदिश AB और सदिश CD प्रतिच्छेद यदि और केवल यदि
अधिक विशेष रूप से एक और ख खंड सीडी के विपरीत दिशा में हैं यदि और केवल अगर दो तीनों में से एक ए, सी, डी और बी, सी, डी काउंटरक्लॉकवाइज ऑर्डर में है।
Intersect(a, b, c, d)
if CCW(a, c, d) == CCW(b, c, d)
return false;
else if CCW(a, b, c) == CCW(a, b, d)
return false;
else
return true;
यहाँ CCW वामावर्त का प्रतिनिधित्व करता है जो अंकों के उन्मुखीकरण के आधार पर सही / गलत रिटर्न देता है।
स्रोत: http://compgeom.cs.uiuc.edu/~Jffe/teaching/373/notes/x06-sweepline.pdf पेज 2
CCW
परीक्षण कैसे परिभाषित किया गया है? बाहरी उत्पाद के संकेत के साथ?
गैरेथ रीस के जवाब पर आधारित
const AGKLine AGKLineZero = (AGKLine){(CGPoint){0.0, 0.0}, (CGPoint){0.0, 0.0}};
AGKLine AGKLineMake(CGPoint start, CGPoint end)
{
return (AGKLine){start, end};
}
double AGKLineLength(AGKLine l)
{
return CGPointLengthBetween_AGK(l.start, l.end);
}
BOOL AGKLineIntersection(AGKLine l1, AGKLine l2, CGPoint *out_pointOfIntersection)
{
// http://stackoverflow.com/a/565282/202451
CGPoint p = l1.start;
CGPoint q = l2.start;
CGPoint r = CGPointSubtract_AGK(l1.end, l1.start);
CGPoint s = CGPointSubtract_AGK(l2.end, l2.start);
double s_r_crossProduct = CGPointCrossProductZComponent_AGK(r, s);
double t = CGPointCrossProductZComponent_AGK(CGPointSubtract_AGK(q, p), s) / s_r_crossProduct;
double u = CGPointCrossProductZComponent_AGK(CGPointSubtract_AGK(q, p), r) / s_r_crossProduct;
if(t < 0 || t > 1.0 || u < 0 || u > 1.0)
{
if(out_pointOfIntersection != NULL)
{
*out_pointOfIntersection = CGPointZero;
}
return NO;
}
else
{
if(out_pointOfIntersection != NULL)
{
CGPoint i = CGPointAdd_AGK(p, CGPointMultiply_AGK(r, t));
*out_pointOfIntersection = i;
}
return YES;
}
}
CGFloat CGPointCrossProductZComponent_AGK(CGPoint v1, CGPoint v2)
{
return v1.x * v2.y - v1.y * v2.x;
}
CGPoint CGPointSubtract_AGK(CGPoint p1, CGPoint p2)
{
return (CGPoint){p1.x - p2.x, p1.y - p2.y};
}
CGPoint CGPointAdd_AGK(CGPoint p1, CGPoint p2)
{
return (CGPoint){p1.x + p2.x, p1.y + p2.y};
}
CGFloat CGPointCrossProductZComponent_AGK(CGPoint v1, CGPoint v2)
{
return v1.x * v2.y - v1.y * v2.x;
}
CGPoint CGPointMultiply_AGK(CGPoint p1, CGFloat factor)
{
return (CGPoint){p1.x * factor, p1.y * factor};
}
फ़ंक्शंस और स्ट्रक्चर्स में से कई निजी हैं, लेकिन आपको पता होना चाहिए कि क्या चल रहा है। यह इस रेपो https://github.com/hfossli/AGGeometryKit/ पर सार्वजनिक है
यह मेरे लिए अच्छा काम कर रहा है। यहां से ले गए ।
// calculates intersection and checks for parallel lines.
// also checks that the intersection point is actually on
// the line segment p1-p2
Point findIntersection(Point p1,Point p2,
Point p3,Point p4) {
float xD1,yD1,xD2,yD2,xD3,yD3;
float dot,deg,len1,len2;
float segmentLen1,segmentLen2;
float ua,ub,div;
// calculate differences
xD1=p2.x-p1.x;
xD2=p4.x-p3.x;
yD1=p2.y-p1.y;
yD2=p4.y-p3.y;
xD3=p1.x-p3.x;
yD3=p1.y-p3.y;
// calculate the lengths of the two lines
len1=sqrt(xD1*xD1+yD1*yD1);
len2=sqrt(xD2*xD2+yD2*yD2);
// calculate angle between the two lines.
dot=(xD1*xD2+yD1*yD2); // dot product
deg=dot/(len1*len2);
// if abs(angle)==1 then the lines are parallell,
// so no intersection is possible
if(abs(deg)==1) return null;
// find intersection Pt between two lines
Point pt=new Point(0,0);
div=yD2*xD1-xD2*yD1;
ua=(xD2*yD3-yD2*xD3)/div;
ub=(xD1*yD3-yD1*xD3)/div;
pt.x=p1.x+ua*xD1;
pt.y=p1.y+ua*yD1;
// calculate the combined length of the two segments
// between Pt-p1 and Pt-p2
xD1=pt.x-p1.x;
xD2=pt.x-p2.x;
yD1=pt.y-p1.y;
yD2=pt.y-p2.y;
segmentLen1=sqrt(xD1*xD1+yD1*yD1)+sqrt(xD2*xD2+yD2*yD2);
// calculate the combined length of the two segments
// between Pt-p3 and Pt-p4
xD1=pt.x-p3.x;
xD2=pt.x-p4.x;
yD1=pt.y-p3.y;
yD2=pt.y-p4.y;
segmentLen2=sqrt(xD1*xD1+yD1*yD1)+sqrt(xD2*xD2+yD2*yD2);
// if the lengths of both sets of segments are the same as
// the lenghts of the two lines the point is actually
// on the line segment.
// if the point isn’t on the line, return null
if(abs(len1-segmentLen1)>0.01 || abs(len2-segmentLen2)>0.01)
return null;
// return the valid intersection
return pt;
}
class Point{
float x,y;
Point(float x, float y){
this.x = x;
this.y = y;
}
void set(float x, float y){
this.x = x;
this.y = y;
}
}
मैंने इनमें से कुछ उत्तरों की कोशिश की, लेकिन उन्होंने मेरे लिए काम नहीं किया (क्षमा करें दोस्तों); कुछ और नेट सर्चिंग के बाद मुझे यह मिला ।
उनके कोड में थोड़ा संशोधन करके अब मेरे पास यह फ़ंक्शन है जो चौराहे के बिंदु को वापस कर देगा या यदि कोई चौराहा नहीं मिला है तो यह -1, -1 वापस आ जाएगा।
Public Function intercetion(ByVal ax As Integer, ByVal ay As Integer, ByVal bx As Integer, ByVal by As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal dx As Integer, ByVal dy As Integer) As Point
'// Determines the intersection point of the line segment defined by points A and B
'// with the line segment defined by points C and D.
'//
'// Returns YES if the intersection point was found, and stores that point in X,Y.
'// Returns NO if there is no determinable intersection point, in which case X,Y will
'// be unmodified.
Dim distAB, theCos, theSin, newX, ABpos As Double
'// Fail if either line segment is zero-length.
If ax = bx And ay = by Or cx = dx And cy = dy Then Return New Point(-1, -1)
'// Fail if the segments share an end-point.
If ax = cx And ay = cy Or bx = cx And by = cy Or ax = dx And ay = dy Or bx = dx And by = dy Then Return New Point(-1, -1)
'// (1) Translate the system so that point A is on the origin.
bx -= ax
by -= ay
cx -= ax
cy -= ay
dx -= ax
dy -= ay
'// Discover the length of segment A-B.
distAB = Math.Sqrt(bx * bx + by * by)
'// (2) Rotate the system so that point B is on the positive X axis.
theCos = bx / distAB
theSin = by / distAB
newX = cx * theCos + cy * theSin
cy = cy * theCos - cx * theSin
cx = newX
newX = dx * theCos + dy * theSin
dy = dy * theCos - dx * theSin
dx = newX
'// Fail if segment C-D doesn't cross line A-B.
If cy < 0 And dy < 0 Or cy >= 0 And dy >= 0 Then Return New Point(-1, -1)
'// (3) Discover the position of the intersection point along line A-B.
ABpos = dx + (cx - dx) * dy / (dy - cy)
'// Fail if segment C-D crosses line A-B outside of segment A-B.
If ABpos < 0 Or ABpos > distAB Then Return New Point(-1, -1)
'// (4) Apply the discovered position to line A-B in the original coordinate system.
'*X=Ax+ABpos*theCos
'*Y=Ay+ABpos*theSin
'// Success.
Return New Point(ax + ABpos * theCos, ay + ABpos * theSin)
End Function
गेविन के उत्तर में कुछ रुचि प्रतीत होती है जिसके लिए कॉर्टिजॉन ने टिप्पणियों में एक जावास्क्रिप्ट संस्करण प्रस्तावित किया और iMalc ने थोड़ा कम कम्प्यूटेशन के साथ एक संस्करण प्रदान किया । कुछ ने विभिन्न कोड प्रस्तावों के साथ कमियों को इंगित किया है और कुछ ने कुछ कोड प्रस्तावों की दक्षता पर टिप्पणी की है।
गाविन के जवाब के माध्यम से iMalc द्वारा प्रदान की गई एल्गोरिथ्म वह है जो मैं वर्तमान में एक जावास्क्रिप्ट परियोजना में उपयोग कर रहा हूं और मैं सिर्फ यहां एक साफ किया गया संस्करण प्रदान करना चाहता था अगर यह किसी की मदद कर सकता है।
// Some variables for reuse, others may do this differently
var p0x, p1x, p2x, p3x, ix,
p0y, p1y, p2y, p3y, iy,
collisionDetected;
// do stuff, call other functions, set endpoints...
// note: for my purpose I use |t| < |d| as opposed to
// |t| <= |d| which is equivalent to 0 <= t < 1 rather than
// 0 <= t <= 1 as in Gavin's answer - results may vary
var lineSegmentIntersection = function(){
var d, dx1, dx2, dx3, dy1, dy2, dy3, s, t;
dx1 = p1x - p0x; dy1 = p1y - p0y;
dx2 = p3x - p2x; dy2 = p3y - p2y;
dx3 = p0x - p2x; dy3 = p0y - p2y;
collisionDetected = 0;
d = dx1 * dy2 - dx2 * dy1;
if(d !== 0){
s = dx1 * dy3 - dx3 * dy1;
if((s <= 0 && d < 0 && s >= d) || (s >= 0 && d > 0 && s <= d)){
t = dx2 * dy3 - dx3 * dy2;
if((t <= 0 && d < 0 && t > d) || (t >= 0 && d > 0 && t < d)){
t = t / d;
collisionDetected = 1;
ix = p0x + t * dx1;
iy = p0y + t * dy1;
}
}
}
};
t = dx2 * dy3 - dx3 * dy2;
...
t/d
आता है।
crossProduct = (line1XDifference * line2YDifference) - (line2XDifference * line1YDifference)
और scaledResult = crossProduct / dotProduct
?
p1x, p1y
आदि, उनके x और y मूल्यों से अंक का वर्णन करने के लिए हैं तो p1x
के लिए एक संक्षिप्त नाम है point1x
, वैसे ही d1x
, में मेरे मन ग्रीक अक्षर के लिए एक संक्षिप्त नाम है deltaX
या आप कह सकते हैं differenceInX
। (अधिक)
मुझे लगता है कि इस समस्या का बहुत सरल समाधान है। मैं आज एक और विचार के साथ आया और यह ठीक काम करने के लिए लगता है (कम से कम अब के लिए 2 डी में)। आपको बस इतना करना है कि दो लाइनों के बीच चौराहे की गणना करना है, फिर जांचें कि क्या गणना की गई चौराहा बिंदु दोनों पंक्ति खंडों के सीमा बक्से के भीतर है। यदि यह है, तो रेखा सेगमेंट प्रतिच्छेद करते हैं। बस।
संपादित करें:
यह है कि मैं चौराहे की गणना कैसे करता हूं (मुझे नहीं पता कि मुझे यह कोड स्निपेट कहां मिला)
Point3D
से आता है
System.Windows.Media.Media3D
public static Point3D? Intersection(Point3D start1, Point3D end1, Point3D start2, Point3D end2) {
double a1 = end1.Y - start1.Y;
double b1 = start1.X - end1.X;
double c1 = a1 * start1.X + b1 * start1.Y;
double a2 = end2.Y - start2.Y;
double b2 = start2.X - end2.X;
double c2 = a2 * start2.X + b2 * start2.Y;
double det = a1 * b2 - a2 * b1;
if (det == 0) { // lines are parallel
return null;
}
double x = (b2 * c1 - b1 * c2) / det;
double y = (a1 * c2 - a2 * c1) / det;
return new Point3D(x, y, 0.0);
}
और यह मेरा (उत्तर के उद्देश्य के लिए सरलीकृत) बाउंडिंगबॉक्स वर्ग है:
public class BoundingBox {
private Point3D min = new Point3D();
private Point3D max = new Point3D();
public BoundingBox(Point3D point) {
min = point;
max = point;
}
public Point3D Min {
get { return min; }
set { min = value; }
}
public Point3D Max {
get { return max; }
set { max = value; }
}
public bool Contains(BoundingBox box) {
bool contains =
min.X <= box.min.X && max.X >= box.max.X &&
min.Y <= box.min.Y && max.Y >= box.max.Y &&
min.Z <= box.min.Z && max.Z >= box.max.Z;
return contains;
}
public bool Contains(Point3D point) {
return Contains(new BoundingBox(point));
}
}
यह समाधान मदद कर सकता है
public static float GetLineYIntesept(PointF p, float slope)
{
return p.Y - slope * p.X;
}
public static PointF FindIntersection(PointF line1Start, PointF line1End, PointF line2Start, PointF line2End)
{
float slope1 = (line1End.Y - line1Start.Y) / (line1End.X - line1Start.X);
float slope2 = (line2End.Y - line2Start.Y) / (line2End.X - line2Start.X);
float yinter1 = GetLineYIntesept(line1Start, slope1);
float yinter2 = GetLineYIntesept(line2Start, slope2);
if (slope1 == slope2 && yinter1 != yinter2)
return PointF.Empty;
float x = (yinter2 - yinter1) / (slope1 - slope2);
float y = slope1 * x + yinter1;
return new PointF(x, y);
}
मैंने Kris के उपरोक्त उत्तर को जावास्क्रिप्ट में चित्रित किया। कई अलग-अलग उत्तरों की कोशिश करने के बाद, उन्होंने सही अंक प्रदान किए। मुझे लगा कि मैं पागल हो रहा हूं कि मुझे उन बिंदुओं की आवश्यकता नहीं है जो मुझे चाहिए।
function getLineLineCollision(p0, p1, p2, p3) {
var s1, s2;
s1 = {x: p1.x - p0.x, y: p1.y - p0.y};
s2 = {x: p3.x - p2.x, y: p3.y - p2.y};
var s10_x = p1.x - p0.x;
var s10_y = p1.y - p0.y;
var s32_x = p3.x - p2.x;
var s32_y = p3.y - p2.y;
var denom = s10_x * s32_y - s32_x * s10_y;
if(denom == 0) {
return false;
}
var denom_positive = denom > 0;
var s02_x = p0.x - p2.x;
var s02_y = p0.y - p2.y;
var s_numer = s10_x * s02_y - s10_y * s02_x;
if((s_numer < 0) == denom_positive) {
return false;
}
var t_numer = s32_x * s02_y - s32_y * s02_x;
if((t_numer < 0) == denom_positive) {
return false;
}
if((s_numer > denom) == denom_positive || (t_numer > denom) == denom_positive) {
return false;
}
var t = t_numer / denom;
var p = {x: p0.x + (t * s10_x), y: p0.y + (t * s10_y)};
return p;
}
मैंने बहुत तरीके आजमाए और फिर मैंने खुद लिखने का फैसला किया। तो यहाँ है:
bool IsBetween (float x, float b1, float b2)
{
return ( ((x >= (b1 - 0.1f)) &&
(x <= (b2 + 0.1f))) ||
((x >= (b2 - 0.1f)) &&
(x <= (b1 + 0.1f))));
}
bool IsSegmentsColliding( POINTFLOAT lineA,
POINTFLOAT lineB,
POINTFLOAT line2A,
POINTFLOAT line2B)
{
float deltaX1 = lineB.x - lineA.x;
float deltaX2 = line2B.x - line2A.x;
float deltaY1 = lineB.y - lineA.y;
float deltaY2 = line2B.y - line2A.y;
if (abs(deltaX1) < 0.01f &&
abs(deltaX2) < 0.01f) // Both are vertical lines
return false;
if (abs((deltaY1 / deltaX1) -
(deltaY2 / deltaX2)) < 0.001f) // Two parallel line
return false;
float xCol = ( ( (deltaX1 * deltaX2) *
(line2A.y - lineA.y)) -
(line2A.x * deltaY2 * deltaX1) +
(lineA.x * deltaY1 * deltaX2)) /
((deltaY1 * deltaX2) - (deltaY2 * deltaX1));
float yCol = 0;
if (deltaX1 < 0.01f) // L1 is a vertical line
yCol = ((xCol * deltaY2) +
(line2A.y * deltaX2) -
(line2A.x * deltaY2)) / deltaX2;
else // L1 is acceptable
yCol = ((xCol * deltaY1) +
(lineA.y * deltaX1) -
(lineA.x * deltaY1)) / deltaX1;
bool isCol = IsBetween(xCol, lineA.x, lineB.x) &&
IsBetween(yCol, lineA.y, lineB.y) &&
IsBetween(xCol, line2A.x, line2B.x) &&
IsBetween(yCol, line2A.y, line2B.y);
return isCol;
}
इन दो सूत्रों के आधार पर: (मैंने उन्हें लाइनों और अन्य सूत्रों के समीकरण से सरल बनाया)
यह गैरेथ री के जवाब पर आधारित है। यदि वे करते हैं तो यह रेखा खंडों के ओवरलैप को भी लौटाता है। C ++ में Coded, V एक साधारण वेक्टर क्लास है। जहां 2 डी में दो वैक्टर का क्रॉस उत्पाद एकल स्केलर लौटाता है। यह मेरे स्कूलों द्वारा स्वचालित परीक्षण प्रणाली द्वारा परीक्षण और पारित किया गया था।
//Required input point must be colinear with the line
bool on_segment(const V& p, const LineSegment& l)
{
//If a point is on the line, the sum of the vectors formed by the point to the line endpoints must be equal
V va = p - l.pa;
V vb = p - l.pb;
R ma = va.magnitude();
R mb = vb.magnitude();
R ml = (l.pb - l.pa).magnitude();
R s = ma + mb;
bool r = s <= ml + epsilon;
return r;
}
//Compute using vector math
// Returns 0 points if the lines do not intersect or overlap
// Returns 1 point if the lines intersect
// Returns 2 points if the lines overlap, contain the points where overlapping start starts and stop
std::vector<V> intersect(const LineSegment& la, const LineSegment& lb)
{
std::vector<V> r;
//http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
V oa, ob, da, db; //Origin and direction vectors
R sa, sb; //Scalar values
oa = la.pa;
da = la.pb - la.pa;
ob = lb.pa;
db = lb.pb - lb.pa;
if (da.cross(db) == 0 && (ob - oa).cross(da) == 0) //If colinear
{
if (on_segment(lb.pa, la) && on_segment(lb.pb, la))
{
r.push_back(lb.pa);
r.push_back(lb.pb);
dprintf("colinear, overlapping\n");
return r;
}
if (on_segment(la.pa, lb) && on_segment(la.pb, lb))
{
r.push_back(la.pa);
r.push_back(la.pb);
dprintf("colinear, overlapping\n");
return r;
}
if (on_segment(la.pa, lb))
r.push_back(la.pa);
if (on_segment(la.pb, lb))
r.push_back(la.pb);
if (on_segment(lb.pa, la))
r.push_back(lb.pa);
if (on_segment(lb.pb, la))
r.push_back(lb.pb);
if (r.size() == 0)
dprintf("colinear, non-overlapping\n");
else
dprintf("colinear, overlapping\n");
return r;
}
if (da.cross(db) == 0 && (ob - oa).cross(da) != 0)
{
dprintf("parallel non-intersecting\n");
return r;
}
//Math trick db cross db == 0, which is a single scalar in 2D.
//Crossing both sides with vector db gives:
sa = (ob - oa).cross(db) / da.cross(db);
//Crossing both sides with vector da gives
sb = (oa - ob).cross(da) / db.cross(da);
if (0 <= sa && sa <= 1 && 0 <= sb && sb <= 1)
{
dprintf("intersecting\n");
r.push_back(oa + da * sa);
return r;
}
dprintf("non-intersecting, non-parallel, non-colinear, non-overlapping\n");
return r;
}
यहां समान चौराहे का पता लगाने के कोड के साथ, C # में एक लाइन सेगमेंट का एक बुनियादी कार्यान्वयन है। इसके लिए 2 डी वेक्टर / पॉइंट स्ट्रक्चर की आवश्यकता होती है Vector2f
, जिसे आप एक्स / वाई गुणों वाले किसी अन्य प्रकार से बदल सकते हैं। तुम भी बदल सकते float
के साथ double
करता है, तो यह है कि सूट आपकी आवश्यकताओं।
इस कोड का उपयोग मेरे .NET फिजिक्स लाइब्रेरी, बोइंग में किया जाता है ।
public struct LineSegment2f
{
public Vector2f From { get; }
public Vector2f To { get; }
public LineSegment2f(Vector2f @from, Vector2f to)
{
From = @from;
To = to;
}
public Vector2f Delta => new Vector2f(To.X - From.X, To.Y - From.Y);
/// <summary>
/// Attempt to intersect two line segments.
/// </summary>
/// <remarks>
/// Even if the line segments do not intersect, <paramref name="t"/> and <paramref name="u"/> will be set.
/// If the lines are parallel, <paramref name="t"/> and <paramref name="u"/> are set to <see cref="float.NaN"/>.
/// </remarks>
/// <param name="other">The line to attempt intersection of this line with.</param>
/// <param name="intersectionPoint">The point of intersection if within the line segments, or empty..</param>
/// <param name="t">The distance along this line at which intersection would occur, or NaN if lines are collinear/parallel.</param>
/// <param name="u">The distance along the other line at which intersection would occur, or NaN if lines are collinear/parallel.</param>
/// <returns><c>true</c> if the line segments intersect, otherwise <c>false</c>.</returns>
public bool TryIntersect(LineSegment2f other, out Vector2f intersectionPoint, out float t, out float u)
{
var p = From;
var q = other.From;
var r = Delta;
var s = other.Delta;
// t = (q − p) × s / (r × s)
// u = (q − p) × r / (r × s)
var denom = Fake2DCross(r, s);
if (denom == 0)
{
// lines are collinear or parallel
t = float.NaN;
u = float.NaN;
intersectionPoint = default(Vector2f);
return false;
}
var tNumer = Fake2DCross(q - p, s);
var uNumer = Fake2DCross(q - p, r);
t = tNumer / denom;
u = uNumer / denom;
if (t < 0 || t > 1 || u < 0 || u > 1)
{
// line segments do not intersect within their ranges
intersectionPoint = default(Vector2f);
return false;
}
intersectionPoint = p + r * t;
return true;
}
private static float Fake2DCross(Vector2f a, Vector2f b)
{
return a.X * b.Y - a.Y * b.X;
}
}
एक C ++ प्रोग्राम यह जांचने के लिए कि क्या दो दिए गए खंड खंड प्रतिच्छेद करते हैं
#include <iostream>
using namespace std;
struct Point
{
int x;
int y;
};
// Given three colinear points p, q, r, the function checks if
// point q lies on line segment 'pr'
bool onSegment(Point p, Point q, Point r)
{
if (q.x <= max(p.x, r.x) && q.x >= min(p.x, r.x) &&
q.y <= max(p.y, r.y) && q.y >= min(p.y, r.y))
return true;
return false;
}
// To find orientation of ordered triplet (p, q, r).
// The function returns following values
// 0 --> p, q and r are colinear
// 1 --> Clockwise
// 2 --> Counterclockwise
int orientation(Point p, Point q, Point r)
{
// See 10th slides from following link for derivation of the formula
// http://www.dcs.gla.ac.uk/~pat/52233/slides/Geometry1x1.pdf
int val = (q.y - p.y) * (r.x - q.x) -
(q.x - p.x) * (r.y - q.y);
if (val == 0) return 0; // colinear
return (val > 0)? 1: 2; // clock or counterclock wise
}
// The main function that returns true if line segment 'p1q1'
// and 'p2q2' intersect.
bool doIntersect(Point p1, Point q1, Point p2, Point q2)
{
// Find the four orientations needed for general and
// special cases
int o1 = orientation(p1, q1, p2);
int o2 = orientation(p1, q1, q2);
int o3 = orientation(p2, q2, p1);
int o4 = orientation(p2, q2, q1);
// General case
if (o1 != o2 && o3 != o4)
return true;
// Special Cases
// p1, q1 and p2 are colinear and p2 lies on segment p1q1
if (o1 == 0 && onSegment(p1, p2, q1)) return true;
// p1, q1 and p2 are colinear and q2 lies on segment p1q1
if (o2 == 0 && onSegment(p1, q2, q1)) return true;
// p2, q2 and p1 are colinear and p1 lies on segment p2q2
if (o3 == 0 && onSegment(p2, p1, q2)) return true;
// p2, q2 and q1 are colinear and q1 lies on segment p2q2
if (o4 == 0 && onSegment(p2, q1, q2)) return true;
return false; // Doesn't fall in any of the above cases
}
// Driver program to test above functions
int main()
{
struct Point p1 = {1, 1}, q1 = {10, 1};
struct Point p2 = {1, 2}, q2 = {10, 2};
doIntersect(p1, q1, p2, q2)? cout << "Yes\n": cout << "No\n";
p1 = {10, 0}, q1 = {0, 10};
p2 = {0, 0}, q2 = {10, 10};
doIntersect(p1, q1, p2, q2)? cout << "Yes\n": cout << "No\n";
p1 = {-5, -5}, q1 = {0, 0};
p2 = {1, 1}, q2 = {10, 10};
doIntersect(p1, q1, p2, q2)? cout << "Yes\n": cout << "No\n";
return 0;
}
@ गैरेथ रीस उत्तर के आधार पर, पायथन के लिए संस्करण:
import numpy as np
def np_perp( a ) :
b = np.empty_like(a)
b[0] = a[1]
b[1] = -a[0]
return b
def np_cross_product(a, b):
return np.dot(a, np_perp(b))
def np_seg_intersect(a, b, considerCollinearOverlapAsIntersect = False):
# /programming/563198/how-do-you-detect-where-two-line-segments-intersect/565282#565282
# http://www.codeproject.com/Tips/862988/Find-the-intersection-point-of-two-line-segments
r = a[1] - a[0]
s = b[1] - b[0]
v = b[0] - a[0]
num = np_cross_product(v, r)
denom = np_cross_product(r, s)
# If r x s = 0 and (q - p) x r = 0, then the two lines are collinear.
if np.isclose(denom, 0) and np.isclose(num, 0):
# 1. If either 0 <= (q - p) * r <= r * r or 0 <= (p - q) * s <= * s
# then the two lines are overlapping,
if(considerCollinearOverlapAsIntersect):
vDotR = np.dot(v, r)
aDotS = np.dot(-v, s)
if (0 <= vDotR and vDotR <= np.dot(r,r)) or (0 <= aDotS and aDotS <= np.dot(s,s)):
return True
# 2. If neither 0 <= (q - p) * r = r * r nor 0 <= (p - q) * s <= s * s
# then the two lines are collinear but disjoint.
# No need to implement this expression, as it follows from the expression above.
return None
if np.isclose(denom, 0) and not np.isclose(num, 0):
# Parallel and non intersecting
return None
u = num / denom
t = np_cross_product(v, s) / denom
if u >= 0 and u <= 1 and t >= 0 and t <= 1:
res = b[0] + (s*u)
return res
# Otherwise, the two line segments are not parallel but do not intersect.
return None
यदि आयत का प्रत्येक पक्ष एक लाइन खंड है, और उपयोगकर्ता द्वारा खींचा गया भाग एक लाइन खंड है, तो आपको बस चार साइड लाइन खंडों के साथ चौराहे के लिए उपयोगकर्ता द्वारा खींचे गए खंड की जांच करने की आवश्यकता है। यह प्रत्येक खंड के आरंभ और अंत बिंदुओं को देखते हुए एक काफी सरल अभ्यास होना चाहिए।
T3chb0t के उत्तर पर आधारित:
int intersezione_linee(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int& p_x, int& p_y)
{
//L1: estremi (x1,y1)(x2,y2) L2: estremi (x3,y3)(x3,y3)
int d;
d = (x1-x2)*(y3-y4) - (y1-y2)*(x3-x4);
if(!d)
return 0;
p_x = ((x1*y2-y1*x2)*(x3-x4) - (x1-x2)*(x3*y4-y3*x4))/d;
p_y = ((x1*y2-y1*x2)*(y3-y4) - (y1-y2)*(x3*y4-y3*x4))/d;
return 1;
}
int in_bounding_box(int x1, int y1, int x2, int y2, int p_x, int p_y)
{
return p_x>=x1 && p_x<=x2 && p_y>=y1 && p_y<=y2;
}
int intersezione_segmenti(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int& p_x, int& p_y)
{
if (!intersezione_linee(x1,y1,x2,y2,x3,y3,x4,y4,p_x,p_y))
return 0;
return in_bounding_box(x1,y1,x2,y2,p_x,p_y) && in_bounding_box(x3,y3,x4,y4,p_x,p_y);
}
मैंने इन एल्गोरिथ्म को "मल्टीपल व्यू ज्योमेट्री" पुस्तक से पढ़ा।
निम्नलिखित पाठ का उपयोग कर
'संक्रमण संकेत के रूप में
* डॉट उत्पाद के रूप में
एक्स को पार उत्पाद के रूप में, जब ऑपरेटर के रूप में उपयोग किया जाता है
एक बिंदु x_vec = (x, y) 'लाइन कुल्हाड़ी + पर + c = 0 द्वारा निहित है
हम L = (a, b, c) ', बिंदु को (x, y, 1)' के रूप में सजातीय निर्देशांक के रूप में दर्शाते हैं।
रेखा समीकरण के रूप में लिखा जा सकता है
(x, y, 1) (a, b, c) '= 0 या x' * L = 0
हमारी दो पंक्तियाँ हैं L1 = (a1, b1, c1) ', L2 = (a2, b2, c2)
मान लें कि एक बिंदु एक वेक्टर है, और x = L1 x L2 (L1 क्रॉस उत्पाद L2)।
सावधान रहें, x हमेशा एक 2D बिंदु है, कृपया समरूप निर्देशांक पढ़ें यदि आप भ्रमित हैं (L1xL2) एक तीन तत्व वेक्टर है, और x एक 2D निर्देशांक है।
ट्रिपल उत्पाद के अनुसार, हम जानते हैं कि
L1 * (L1 x L2) = 0, और L2 * (L1 x L2) = 0, L1, L2 के सह-विमान के कारण
हम वेक्टर x के साथ (L1xL2) स्थानापन्न करते हैं, तो हमारे पास L1 * x = 0, L2 * x = 0 है, जिसका अर्थ है कि L1 और L2 दोनों पर x झूठ चौराहा बिंदु है।
सावधान रहें, यहां x समरूप निर्देशांक है, यदि x का अंतिम तत्व शून्य है, तो इसका मतलब है कि L1 और L2 समानांतर हैं।
कई जवाबों ने सभी गणनाओं को एक ही फ़ंक्शन में लपेट दिया है। यदि आपको अपने कोड में कहीं और लाइन स्लोप्स, y- इंटरसेप्ट्स या एक्स-इंटरसेप्ट्स का उपयोग करने के लिए गणना करने की आवश्यकता है, तो आप उन गणनाओं को अनावश्यक रूप से कर रहे होंगे। मैंने संबंधित कार्यों को अलग कर दिया है, स्पष्ट चर नामों का उपयोग किया है, और मेरे कोड का अनुसरण करते हुए इसे आसान बनाने के लिए टिप्पणी की है। मुझे यह जानने की जरूरत है कि क्या लाइनें उनके समापन बिंदुओं से परे अनंत रूप से प्रतिच्छेद करती हैं, इसलिए जावास्क्रिप्ट में:
http://jsfiddle.net/skibulk/evmqq00u/
var point_a = {x:0, y:10},
point_b = {x:12, y:12},
point_c = {x:10, y:0},
point_d = {x:0, y:0},
slope_ab = slope(point_a, point_b),
slope_bc = slope(point_b, point_c),
slope_cd = slope(point_c, point_d),
slope_da = slope(point_d, point_a),
yint_ab = y_intercept(point_a, slope_ab),
yint_bc = y_intercept(point_b, slope_bc),
yint_cd = y_intercept(point_c, slope_cd),
yint_da = y_intercept(point_d, slope_da),
xint_ab = x_intercept(point_a, slope_ab, yint_ab),
xint_bc = x_intercept(point_b, slope_bc, yint_bc),
xint_cd = x_intercept(point_c, slope_cd, yint_cd),
xint_da = x_intercept(point_d, slope_da, yint_da),
point_aa = intersect(slope_da, yint_da, xint_da, slope_ab, yint_ab, xint_ab),
point_bb = intersect(slope_ab, yint_ab, xint_ab, slope_bc, yint_bc, xint_bc),
point_cc = intersect(slope_bc, yint_bc, xint_bc, slope_cd, yint_cd, xint_cd),
point_dd = intersect(slope_cd, yint_cd, xint_cd, slope_da, yint_da, xint_da);
console.log(point_a, point_b, point_c, point_d);
console.log(slope_ab, slope_bc, slope_cd, slope_da);
console.log(yint_ab, yint_bc, yint_cd, yint_da);
console.log(xint_ab, xint_bc, xint_cd, xint_da);
console.log(point_aa, point_bb, point_cc, point_dd);
function slope(point_a, point_b) {
var i = (point_b.y - point_a.y) / (point_b.x - point_a.x);
if (i === -Infinity) return Infinity;
if (i === -0) return 0;
return i;
}
function y_intercept(point, slope) {
// Horizontal Line
if (slope == 0) return point.y;
// Vertical Line
if (slope == Infinity)
{
// THE Y-Axis
if (point.x == 0) return Infinity;
// No Intercept
return null;
}
// Angled Line
return point.y - (slope * point.x);
}
function x_intercept(point, slope, yint) {
// Vertical Line
if (slope == Infinity) return point.x;
// Horizontal Line
if (slope == 0)
{
// THE X-Axis
if (point.y == 0) return Infinity;
// No Intercept
return null;
}
// Angled Line
return -yint / slope;
}
// Intersection of two infinite lines
function intersect(slope_a, yint_a, xint_a, slope_b, yint_b, xint_b) {
if (slope_a == slope_b)
{
// Equal Lines
if (yint_a == yint_b && xint_a == xint_b) return Infinity;
// Parallel Lines
return null;
}
// First Line Vertical
if (slope_a == Infinity)
{
return {
x: xint_a,
y: (slope_b * xint_a) + yint_b
};
}
// Second Line Vertical
if (slope_b == Infinity)
{
return {
x: xint_b,
y: (slope_a * xint_b) + yint_a
};
}
// Not Equal, Not Parallel, Not Vertical
var i = (yint_b - yint_a) / (slope_a - slope_b);
return {
x: i,
y: (slope_a * i) + yint_a
};
}