मैं एक खींची गई रेखा की सीधीता को कैसे निर्धारित कर सकता हूं?


37

मैं एक ऐसे खेल पर काम कर रहा हूं जिसमें खिलाड़ियों को एक बिंदु ए (एक्स 1, वाई 1) से दूसरे बिंदु बी (एक्स 2, वाई 2) को एक एंड्रॉइड डिवाइस की स्क्रीन पर एक रेखा खींचने की आवश्यकता होती है।

मैं यह जानना चाहता हूं कि ड्राइंग कितनी अच्छी तरह से एक सीधी रेखा में फिट होती है। उदाहरण के लिए, 90% के परिणाम का अर्थ होगा कि रेखा लगभग पूरी तरह से रेखा खींचती है। यदि खिलाड़ी A से B तक घुमावदार रेखा खींचते हैं, तो उसे कम स्कोर प्राप्त करना चाहिए।

अंतिम बिंदु पहले से ज्ञात नहीं हैं। मैं यह कैसे कर सकता हूँ?


1
क्या आप पहले से जानते हैं कि आपके दो अंत बिंदु क्या हैं? या उस समय निर्धारित किया जाता है जब उपयोगकर्ता स्क्रीन को छूना बंद कर देता है?
Vaillancourt

क्षमा करें यदि मेरा विवरण आपके लिए स्पष्ट नहीं है। खैर, शुरुआती बिंदु A (x, y) पहला स्पर्श है और अंतिम बिंदु B (x, y) वह है जब हमने आपके द्वारा टच स्क्रीन से जारी किया था।
user3637362

हमारे पास खिलाड़ी द्वारा तैयार पत्रों से संबंधित प्रश्न हैं ।
एको

3
कृपया भविष्य में स्रोत कोड के लिए चित्र पोस्ट न करें।
जोश

1
@ user3637362 मैं समझता हूं कि आप शुरू कर रहे हैं j=1ताकि आप के touchList[j]साथ तुलना कर सकें touchList[j-1], लेकिन जब touch.phase == TouchPhase.Beganया touch.phase == TouchPhase.Endedपदों को जोड़ा नहीं जाता है touchListऔर बाद में इसमें शामिल नहीं किया जाता है sumLength। यह बग सभी मामलों में मौजूद होगा लेकिन अधिक स्पष्ट होगा जब लाइन में कुछ खंड होंगे।
केली थॉमस

जवाबों:


52

एक पूरी तरह से सीधी रेखा कुल लंबाई के साथ सबसे छोटी संभव रेखा भी होगी sqrt((x1-x2)² + (y1-y2)²)। अधिक परिमार्जन रेखा एक कम आदर्श कनेक्शन होगी और इस प्रकार अनिवार्य रूप से लंबी होगी।

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

यहाँ एक दृश्य है। जब ब्लैक डॉट्स जेस्चर के अंतिम-बिंदु होते हैं और ब्लू पॉइंट इशारे के दौरान आपके द्वारा मापे जाने वाले पॉइंट होते हैं, तो आप हरे रंग की रेखाओं की लंबाई को जोड़ते हैं और इसे लाल रेखा की लंबाई से विभाजित करते हैं:

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

1 का स्कोर या सिनुओसिटी इंडेक्स एकदम सही होगा, कुछ भी अधिक सही होगा, 1 से नीचे कुछ भी बग होगा। जब आप प्रतिशत में स्कोर करना पसंद करते हैं, तो उस संख्या से 100% भाग करें।


34
इस दृष्टिकोण के साथ एक छोटी सी समस्या है कि समान लंबाई के पॉलीइन्स समान रूप से 'सीधे' नहीं हैं। एक ऐसी रेखा जो सीधी रेखा के बारे में कम विचलन (लेकिन कई बार) से टकराती है, समान लंबाई की एक पंक्ति की तुलना में 'स्ट्रैटर' होती है जो एक बिंदु पर और फिर वापस बाहर हो जाती है।
Dancrumb

मैं +1 @Dancrumbs पर्याप्त टिप्पणी नहीं कर सकता - कि इस विधि के साथ एक बहुत ही महत्वपूर्ण सीमा है जैसे कि उपयोगकर्ता एक सीधी रेखा खींच रहा है, वे थोड़ी सी लड़खड़ाएंगे ताकि यह एक सामान्य उपयोग के मामले की तरह महसूस हो।
टी। केली

@ Dancrumb बस लाइन से औसत दूरी में कारक है, या किसी भी बिंदु पर लाइन से "अधिकतम दूरी" में कारक है। फिर आप छोटे विचलन आयामों के साथ और अधिक wobbly लाइनों की ओर एल्गोरिथ्म का वजन कर सकते हैं, और उन पंक्तियों से दूर हो सकते हैं जो अपेक्षित पथ से दूर भटकते हैं।
सुपरडॉगी

2
@ मुझे लगता है कि यह ओपी के उपयोग-मामले के लिए एक लाभ को समाप्त कर सकता है। बेशक, हाथ से तैयार की गई लाइनें छोटी विचलन होंगी। यह दृष्टिकोण वास्तव में इन अपेक्षित अंतरों के प्रभाव को कम करने के लिए काम कर सकता है।

2
@ user3637362 आपके पास अपने कोड में एक बग है। एक संभावित व्याख्या यह है कि आप स्टार्ट-पॉइंट और पहले बिंदु या अंतिम-बिंदु और अंतिम बिंदु के बीच की दूरी को भूल गए, लेकिन आपके कोड को देखे बिना यह बताना असंभव है कि आपकी गलती क्या हो सकती है।
फिलिप

31

यह या तो इसे लागू करने का सबसे अच्छा तरीका नहीं हो सकता है, लेकिन मैं सुझाव देता हूं कि एक RMSD (रूट माध्य वर्ग विचलन) केवल दूरी विधि की तुलना में बेहतर हो सकता है, जो डेंक्रम्ब द्वारा उल्लिखित मामलों में है (नीचे पहले दो पंक्तियाँ देखें)।

RMSD = sqrt(mean(deviation^2))

ध्यान दें:

  • पूर्ण विचलन (अभिन्न-प्रकार) का योग बेहतर हो सकता है, क्योंकि यह नकारात्मक लोगों के साथ सकारात्मक त्रुटियों को औसत नहीं करता है। ( =sum(abs(deviation)))
  • आपको शायद रैखिक रेखा की सबसे छोटी दूरी की खोज करनी होगी यदि कोई ऐसा रास्ता है जो लंबवत छोड़ने की तुलना में कम दूरी बनाता है।

चि त्र का री

(कृपया मेरे ड्राइंग की निम्न गुणवत्ता का बहाना करें)

जैसा कि आप देखते हैं, आपको करना होगा

  1. अपनी लाइन पर एक ऑर्थोगोनल वेक्टर खोजें ( डॉट-उत्पाद बराबर 0 )।
    यदि आपकी लाइन (1, 3) आपको चाहिए (3, -1)(प्रत्येक मूल को गर्तित करती है) की ओर इशारा करती है
  2. hआदर्श रेखा से उपयोगकर्ता के लिए दूरी को मापें , उस वेक्टर के समानांतर।
  3. RMSD या पूर्ण अंतर के योग की गणना करें।

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

1
एक और मामला यह कवर नहीं करता है: कहें कि प्रत्येक मापा बिंदु एक्स अक्ष पर है, लेकिन लाइन कई बार दिशा को उलट देती है। यह
dave mankoff

23

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

हम कैसे बताएं कि वक्र कितना सीधा है? यह मानते हुए कि वक्र पर्याप्त चिकना है, हम जानना चाहते हैं कि औसत पर, वक्र के लिए स्पर्शरेखा कितनी बदल रही है। एक पंक्ति के लिए, यह शून्य होगा (जैसा कि स्पर्शरेखा स्थिर है)।

यदि हम समय पर स्थिति को t (x (t), y (t)) करते हैं, तो स्पर्शरेखा (Dx (t), Dy (t)) है, जहाँ Dx (t) समय t पर x का व्युत्पन्न है। (यह साइट टीईएक्स समर्थन गायब प्रतीत होती है)। यदि वक्र को चाप-लंबाई से परिचालित नहीं किया जाता है, तो हम विभाजित करके सामान्य करते हैं || (Dx (t), Dy (t)) || तो हम समय टी पर वक्र करने के लिए स्पर्शरेखा की एक इकाई वेक्टर (या कोण) है। तो, कोण एक t (t) = (Dx (t), Dy (t)) / || (Dx (t), Dy (t)) है ||

हम फिर से रुचि रखते हैं || Da (t) || ^ 2 वक्र के साथ एकीकृत

यह देखते हुए कि हमारे पास सबसे अधिक संभावना है कि एक वक्र के बजाय असतत डेटा बिंदु हैं, हमें डेरिवेटिव के अनुमानित अंतर का उपयोग करना चाहिए। तो, दा (टी) बन जाता है (a(t+h)-a(t))/h। और, एक (टी) बन जाता है ((x(t+h)-x(t))/h,(y(t+h)-y(t))/h)/||((x(t+h)-x(t))/h,(y(t+h)-y(t))/h)||। फिर हम h||Da(t)||^2सभी डेटा पॉइंट्स के लिए संक्षेप में S प्राप्त करते हैं और संभवतः वक्र की लंबाई से सामान्य करते हैं। सबसे अधिक संभावना है, हम उपयोग करते हैं h=1, लेकिन यह वास्तव में एक मनमाना पैमाने का कारक है।

फिर से कहने के लिए, S एक लाइन के लिए शून्य होगा और जितना अधिक यह एक लाइन से विचलित होगा। आवश्यक प्रारूप में परिवर्तित करने के लिए, का उपयोग करें 1/(1+S)। यह देखते हुए कि पैमाना कुछ हद तक मनमाना है, एस को कुछ सकारात्मक संख्याओं से गुणा करना संभव है (या इसे किसी अन्य तरीके से बदलना, जैसे एस के बजाय बीएस ^ सी का उपयोग करना) यह समायोजित करने के लिए कि कुछ निश्चित वक्र कितने सीधे हैं।


2
यह सीधेपन की सबसे समझदार परिभाषा है।
थॉमस

1
यह अब तक का सबसे समझदार उत्तर है और मुझे यकीन है कि बाकी लोग बहुत निराश होंगे। दुर्भाग्य से, जिस रूप में समाधान प्रस्तुत किया गया है वह दूसरों की तुलना में थोड़ा अधिक अस्पष्ट है, लेकिन मैं ओपी को बनाए रखने की सलाह दूंगा।
डैन शेपर्ड

आम तौर पर मुझे भी लगता है कि यह उत्तर वास्तव में सबसे अच्छा है। हालांकि एक समस्या मुझे परेशान करती है: अगर लाइन "पर्याप्त रूप से चिकनी" नहीं है तो क्या होगा? उदाहरण के लिए, यदि आपके पास कोण के साथ दो बिल्कुल सीधी रेखा खंड हैं, तो 90 ° कहते हैं। क्या मैंने गलती की है या वास्तव में चिकनी रैखिक रेखा की तुलना में यह बहुत कम परिणाम देगा? (मुझे लगता है कि डनक्रम्ब के यूजर केस में एक डब्लू लाइन एक समान समस्या थी) ... स्थानीय रूप से यह निश्चित रूप से सबसे अच्छा तरीका है।
gr4nt3d

3

यह ग्रिड आधारित प्रणाली है, है ना? लाइन के लिए अपने स्वयं के बिंदु खोजें और लाइन की ढलान की गणना करें। अब, उस गणना का उपयोग करते हुए, मान्य बिंदुओं को निर्धारित करें कि सटीक मान से त्रुटि के कुछ मार्जिन को देखते हुए, रेखा गुजरती है।

परीक्षण और त्रुटि परीक्षण की एक छोटी राशि के माध्यम से, निर्धारित करें कि मिलान बिंदुओं की अच्छी और बुरी मात्रा क्या मौजूद होगी और अपने परीक्षण से समान परिणामों के लिए पैमाने का उपयोग करके अपने गेम को सेट करें।

यानी लगभग क्षैतिज ढलान वाली एक छोटी लाइन में 7 बिंदु हो सकते हैं जिन्हें आप खींच सकते हैं। यदि आप लगातार 7 या 6 से अधिक का मिलान कर सकते हैं जो कि सीधी रेखा का हिस्सा होने के लिए निर्धारित थे, तो यह उच्चतम स्कोर होगा। लंबाई और सटीकता के लिए ग्रेडिंग स्कोरिंग का हिस्सा होना चाहिए।


3

एक बहुत ही आसान और सहज उपाय सबसे अच्छी फिटिंग स्ट्रेट लाइन और वास्तविक वक्र के बीच का क्षेत्र है। यह निर्धारित करना काफी सीधा है:

  1. सभी बिंदुओं पर कम से कम-फिट का उपयोग करें (यह जोएल बोसवेल्ड द्वारा उल्लिखित एंड-किंक समस्या को रोकता है)।
  2. वक्र पर सभी बिंदुओं के लिए, लाइन की दूरी निर्धारित करें। यह भी एक मानक समस्या है। (रैखिक बीजगणित, आधार परिवर्तन।)
  3. सभी दूरियों का योग।

यदि आप कुछ पाठ कोडिंग (जेएस, सी #) या छद्म कोड के लिए आपसे पूछें, तो आप बुरा मान सकते हैं, क्योंकि ऊपर दिए गए अधिकांश उत्तर सिद्धांत में वर्णित हैं, मुझे नहीं पता कि कैसे शुरू करें?
user3637362

1
@ user3637362: StackOverflow के पास व्यावहारिक उत्तर हैं: stackoverflow.com/questions/6195335/… stackoverflow.com/questions/849211/-
MSalters

2

यह विचार उपयोगकर्ता द्वारा छपे सभी बिंदुओं को रखने के लिए है, फिर उन बिंदुओं में से प्रत्येक के बीच की दूरी का मूल्यांकन और योग करने के लिए बनाई गई लाइन के लिए जब उपयोगकर्ता स्क्रीन को जारी करता है।

यहाँ आपको छद्म कोड में आरंभ करने के लिए कुछ दिया गया है:

bool mIsRecording = false;
point[] mTouchedPoints = new point[];

function onTouch
  mIsRecording = true

functon update
  if mIsRecording
    mTouchedPoints.append(currentlyTouchedLocation)

function onRelease
  mIsRecording = false

  cumulativeDistance = 0

  line = makeLine( mTouchedPoints.first, mTouchedPoints.last )

  for each point in mTouchedPoints:
    cumulativeDistance = distanceOfPointToLine(point, line)

  mTouchedPoints = new point[]

क्या cumulativeDistanceआप फिटिंग पर एक विचार दे सकता है। 0 की दूरी का मतलब है कि उपयोगकर्ता हर समय लाइन पर सीधा था। अब आपको यह देखने के लिए कुछ परीक्षण करने होंगे कि यह आपके संदर्भ में कैसा व्यवहार करता है। और हो सकता है कि आप distanceOfPointToLineलाइन से दूर बड़ी दूरी को दंडित करने के लिए इसे चुकता करके लौटाए गए मान को बढ़ाना चाहें ।

मैं एकता से परिचित नहीं हूँ, लेकिन updateयहाँ कोड किसी onDragफ़ंक्शन में जा सकता है।

और आप किसी बिंदु को पंजीकृत करने से रोकने के लिए कुछ कोड जोड़ना चाहेंगे, यदि वह पिछले एक पंजीकृत के समान है। जब उपयोगकर्ता स्थानांतरित नहीं करता है तो आप सामान को पंजीकृत नहीं करना चाहते हैं।


5
जब आप प्रत्येक मापा बिंदु के लिए आदर्श रेखा और बिंदु के बीच की दूरी को जोड़ते हैं, तो आपको अपने द्वारा किए गए उपायों की संख्या के लिए खाते की आवश्यकता होती है, अन्यथा जब उपयोगकर्ता धीमी गति से ड्रॉ करता है या एक तेज़ स्कैन-दर के साथ डिवाइस का उपयोग करता है तो वे अधिक पंजीकरण करेंगे अंक जिसका मतलब है कि वे एक बदतर स्कोर प्राप्त करेंगे।
फिलिप

@ फिलिप हां तुम करो! मुझे यह करने के अपने तरीके को स्वीकार करना चाहिए कि यह मेरी तुलना में बेहतर है: पी
वेल्लनकोर्ट

मुझे लगता है कि इस दृष्टिकोण को संचयी व्यवहार के बजाय औसत दूरी लेने से सुधार हुआ है ।
Dancrumb

@ डनक्रंब वास्तव में, यह जरूरतों पर निर्भर करता है, लेकिन हाँ, यह करने का एक तरीका होगा।
Vaillancourt

2

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

संपादित करें:

इसके अलावा, मैं डॉट उत्पाद के अलावा खंड की लंबाई का उपयोग करने पर विचार करूंगा। एक बहुत ही कम लेकिन ऑर्थोगोनल वेक्टर को एक लंबे समय से कम की गणना करनी चाहिए जिसमें विचलन कम होता है।


1

सबसे आसान और त्वरित यह पता लगाने के लिए हो सकता है कि उपयोगकर्ता द्वारा तैयार की गई रेखा के सभी बिंदुओं को कवर करने के लिए लाइन को कितना मोटा होना होगा।

लाइन जितनी मोटी होनी चाहिए, यूजर ने अपनी लाइन खींचने में उतना ही बुरा किया।


0

किसी तरह MSalters उत्तर की चर्चा करते हुए, यहां कुछ और विशिष्ट जानकारी दी गई है।

अपने बिंदुओं के लिए एक पंक्ति फिट करने के लिए कम से कम चौकोर विधि का उपयोग करें। आप मूल रूप से एक फ़ंक्शन y = f (x) की तलाश में हैं जो सबसे अच्छा फिट बैठता है। एक बार जब आप यह कर लेंगे तो आप मतभेदों के वर्ग को योग करने के लिए वास्तविक y मानों का उपयोग कर सकते हैं:

s = योग ओवर ((yf (x)) ^ 2)

योग जितना छोटा, रेखा उतनी ही अधिक।

सबसे अच्छा सन्निकटन कैसे प्राप्त करें, यहाँ बताया गया है: http://math.mit.edu/~gs/linearalgebra/ila0403.pdf

बस "एक सीधी रेखा फिटिंग" से पढ़ें। ध्यान दें कि t का उपयोग x और b के बजाय y के बजाय किया जाता है। C और D को सन्निकटन के रूप में निर्धारित किया जाना है, तो आपके पास f (x) = C + Dx है

अतिरिक्त नोट: जाहिर है, आपको लाइन की लंबाई को भी ध्यान में रखना होगा। 2 पॉइंट्स वाली हर लाइन परफेक्ट होगी। मुझे सटीक संदर्भ नहीं पता है, लेकिन मुझे लगता है कि मैं रेटिंग के रूप में अंकों की संख्या से विभाजित वर्गों के योग का उपयोग करूंगा। इसके अलावा, मैं न्यूनतम लंबाई, न्यूनतम अंक की आवश्यकता को जोड़ूंगा। (शायद अधिकतम लंबाई का लगभग 75%)

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