यथार्थवादी मोड़ जोड़ना
अगला कदम हमारी इकाइयों के लिए यथार्थवादी घुमावदार मोड़ जोड़ना है, ताकि वे हर बार अचानक दिशा बदलने के लिए प्रकट न हों। एक सरल समाधान में अचानक कोने को मोड़ने के लिए एक तख़्ता का उपयोग करना शामिल है। हालांकि यह कुछ सौंदर्य संबंधी चिंताओं को हल करता है, फिर भी अधिकांश इकाइयों के लिए शारीरिक रूप से बहुत अवास्तविक आंदोलन है। उदाहरण के लिए, यह एक टैंक के अचानक मोड़ को एक तंग वक्र में बदल सकता है, लेकिन घुमावदार मोड़ अभी भी टैंक की तुलना में बहुत अधिक सख्त होगा जो वास्तव में प्रदर्शन कर सकता है।
एक बेहतर समाधान के लिए, पहली चीज जो हमें जानने की जरूरत है वह है हमारी इकाई के लिए मोड़ त्रिज्या। टर्निंग त्रिज्या एक काफी सरल अवधारणा है: यदि आप अपनी कार में एक बड़ी पार्किंग में हैं, और पहिया को बाईं ओर मोड़ दें, जहां तक वह जाएगा और एक सर्कल में ड्राइव करने के लिए आगे बढ़ेगा, उस सर्कल की त्रिज्या आपकी मोड़ है। त्रिज्या। वोक्सवैगन बीटल का टर्निंग त्रिज्या एक बड़ी एसयूवी की तुलना में काफी छोटा होगा, और एक व्यक्ति का टर्निंग त्रिज्या एक बड़े, लंबर भालू की तुलना में काफी कम होगा।
मान लें कि आप कुछ बिंदु (मूल) पर हैं और एक निश्चित दिशा में इंगित किया गया है, और आपको कुछ अन्य बिंदु (गंतव्य) पर पहुंचने की आवश्यकता है, जैसा कि चित्र 5 में दिखाया गया है। सबसे छोटा रास्ता या तो बाईं ओर मुड़कर पाया जाता है। कर सकते हैं, एक सर्कल में जा रहा है जब तक आप सीधे गंतव्य पर इशारा कर रहे हैं, और फिर आगे बढ़, या सही मोड़ और एक ही बात कर रही है।
चित्रा 5 में सबसे छोटा मार्ग स्पष्ट रूप से नीचे की ओर हरी रेखा है। चित्रा 6 में चित्रित कुछ ज्यामितीय संबंधों के कारण गणना करने के लिए यह मार्ग काफी सीधा है।
पहले हम बिंदु P के स्थान की गणना करते हैं, जो हमारे मोड़ का केंद्र है, और हमेशा शुरुआती बिंदु से दूर त्रिज्या है। यदि हम अपनी प्रारंभिक दिशा से दाहिनी ओर मुड़ रहे हैं, तो इसका मतलब है कि P मूल से (initial_direction - 90) के कोण पर है, इसलिए:
angleToP = initial_direction - 90
P.x = Origin.x + r * cos(angleToP)
P.y = Origin.y + r * sin(angleToP)
अब जब हम केंद्र बिंदु P का स्थान जानते हैं, तो हम P से गंतव्य तक की दूरी की गणना कर सकते हैं, जिसे चित्र पर h के रूप में दिखाया गया है:
dx = Destination.x - P.x
dy = Destination.y - P.y
h = sqrt(dx*dx + dy*dy)
इस बिंदु पर हम यह भी जांचना चाहते हैं कि गंतव्य सर्कल के भीतर तो नहीं है, क्योंकि अगर यह होता तो हम कभी भी इस तक नहीं पहुँच पाते:
if (h < r)
return false
अब हम खंड d की लंबाई की गणना कर सकते हैं, क्योंकि हम पहले से ही सही त्रिकोण के अन्य दो पक्षों की लंबाई जानते हैं, अर्थात् एच और आर। हम समकोण त्रिभुज संबंध से कोण भी निर्धारित कर सकते हैं:
d = sqrt(h*h - r*r)
theta = arccos(r / h)
अंत में, उस बिंदु Q का पता लगाने के लिए जिस पर वृत्त को छोड़ना और सीधी रेखा पर शुरू करना है, हमें कुल कोण + जानना होगा, और आसानी से P से गंतव्य तक के कोण के रूप में निर्धारित किया जाता है:
phi = arctan(dy / dx) [offset to the correct quadrant]
Q.x = P.x + r * cos(phi + theta)
Q.y = P.y + r * sin(phi + theta)
उपरोक्त गणना सही-मोड़ वाले मार्ग का प्रतिनिधित्व करती है। बाएं हाथ के पथ की गणना ठीक उसी तरह से की जा सकती है, सिवाय इसके कि हम कोण से गणना करने के लिए 90_ initial_direction जोड़ते हैं, और बाद में हम + के बजाय - का उपयोग करते हैं। दोनों की गणना करने के बाद, हम बस देखते हैं कि कौन सा मार्ग छोटा है और उस एक का उपयोग करें।
इस एल्गोरिथ्म के हमारे कार्यान्वयन में और जो अनुसरण करते हैं, हम एक डेटा संरचना का उपयोग करते हैं जो चार अलग-अलग "लाइन सेगमेंट" तक संग्रहीत करता है, प्रत्येक एक या तो सीधा या घुमावदार होता है। यहां वर्णित घुमावदार रास्तों के लिए, केवल दो खंडों का उपयोग किया जाता है: एक चाप जिसके बाद एक सीधी रेखा होती है। डेटा संरचना में ऐसे सदस्य होते हैं जो निर्दिष्ट करते हैं कि क्या खंड एक चाप है या एक सीधी रेखा, खंड की लंबाई और इसकी प्रारंभिक स्थिति। यदि खंड एक सीधी रेखा है, तो डेटा संरचना भी कोण निर्दिष्ट करती है; आर्क्स के लिए, यह सर्कल के केंद्र, सर्कल पर शुरुआती कोण और चाप द्वारा कवर किए गए कुल रेडियंस को निर्दिष्ट करता है।
एक बार जब हमने दो बिंदुओं के बीच पाने के लिए आवश्यक घुमावदार मार्ग की गणना कर ली है, तो हम आसानी से किसी भी समय अपनी स्थिति और दिशा की गणना कर सकते हैं, जैसा कि लिस्टिंग 2 में दिखाया गया है।
सूची 2. किसी विशेष समय पर स्थिति और अभिविन्यास की गणना करना।
distance = unit_speed * elapsed_time
loop i = 0 to 3:
if (distance < LineSegment[i].length)
// Unit is somewhere on this line segment
if LineSegment[i] is an arc
//determine current angle on arc (theta) by adding or
//subtracting (distance / r) to the starting angle
//depending on whether turning to the left or right
position.x = LineSegment[i].center.x + r*cos(theta)
position.y = LineSegment[i].center.y + r*sin(theta)
//determine current direction (direction) by adding or
//subtracting 90 to theta, depending on left/right
else
position.x = LineSegment[i].start.x
+ distance * cos(LineSegment[i].line_angle)
position.y = LineSegment[i].start.y
+ distance * sin(LineSegment[i].line_angle)
direction = theta
break out of loop
else
distance = distance - LineSegment[i].length