লাইন সেগমেন্টের অন্য দুটি পয়েন্টের মধ্যে একটি বিন্দুটি আপনি কীভাবে নির্ধারণ করতে পারেন?


96

ধরা যাক যে আপনার কাছে একটি দুটি মাত্রিক সমতল রয়েছে যার উপরে 2 পয়েন্ট রয়েছে (একে এবং বি বলা হয়) প্রতিটি পয়েন্টের জন্য একটি x পূর্ণসংখ্যা এবং আইয়ের পূর্ণসংখ্যা দ্বারা প্রতিনিধিত্ব করা হয়।

আপনি কীভাবে নির্ধারণ করতে পারবেন যে অন্য বিন্দু সি এবং বি দ্বারা সংজ্ঞায়িত রেখাংশে রয়েছে?

আমি অজগরটি বেশিরভাগ ক্ষেত্রেই ব্যবহার করি তবে যে কোনও ভাষায় উদাহরণগুলি সহায়ক হবে।


4
আমি দেখতে পাই যে এই উত্তরগুলিতে প্রচুর দৈর্ঘ্য = স্কয়ার্ট (এক্স) স্টাফ চলছে; তারা কাজ করতে পারে, কিন্তু তারা দ্রুত হয় না। দৈর্ঘ্য-বর্গক্ষেত্র ব্যবহার বিবেচনা করুন; যদি আপনি কেবল একে অপরের সাথে স্কোয়ার দৈর্ঘ্যের মানগুলি তুলনা করেন তবে নির্ভুলতার কোনও ক্ষতি হয় না এবং আপনি ধীর কলগুলি স্কয়ার্ট () এ সংরক্ষণ করেন save
ojrac

4
বিন্দু সিটি 2 টি পূর্ণসংখ্যা দ্বারাও প্রতিনিধিত্ব করে? যদি তাই হয় তবে আপনি কি জানতে চান যে সিটি একটি এবং খ এর মধ্যে সত্যিকারের সরলরেখার সাথে ঠিক আছে কিনা বা ক এবং খ এর মধ্যবর্তী সরল রেখার রাস্টার সান্নিধ্যের উপর রয়েছে? এটি একটি গুরুত্বপূর্ণ ব্যাখ্যা।
রবস

অনুরূপ প্রশ্ন এখানে জিজ্ঞাসা করা হয়েছিল: স্ট্যাকওভারফ্লো.com / q / 31346862 / 1914034 যখন সমাধানের সাথে যখন লাইন থেকে একটি বাফার দূরত্ব প্রয়োজন হয়
রাডার নীচে


4
ভবিষ্যতের পাঠকদের জন্য সতর্কতা: মোটামুটি উত্তরগুলি ভুল বা অসম্পূর্ণ। কয়েকটি প্রান্তের ক্ষেত্রে যা ঘন ঘন কাজ করে না সেগুলি হ'রে অনুভূমিক এবং উল্লম্ব লাইন।
স্টেফনচ

উত্তর:


129

পরীক্ষা করে দেখুন ক্রস পণ্য(বা) এবং (সিএ) 0 হয় কিনা তা দারিয়াস বেকন বলছে যে, বিন্দু a, b এবং c প্রান্তিক হয়েছে কিনা তা আপনাকে পরীক্ষা করে দেখুন।

তবে, আপনি যেমনটি জানতে চান যে সিটি a এবং b এর মধ্যে রয়েছে কিনা, আপনাকে এটিও পরীক্ষা করে দেখতে হবে যে (বা) এবং (সিএ) এর ডট পণ্যটি ইতিবাচক এবং a এবং b এর মধ্যকার দূরত্বের বর্গক্ষেত্রের চেয়ে কম

অপ-অপ্টিমাইজড সিউডোকোডে:

def isBetween(a, b, c):
    crossproduct = (c.y - a.y) * (b.x - a.x) - (c.x - a.x) * (b.y - a.y)

    # compare versus epsilon for floating point values, or != 0 if using integers
    if abs(crossproduct) > epsilon:
        return False

    dotproduct = (c.x - a.x) * (b.x - a.x) + (c.y - a.y)*(b.y - a.y)
    if dotproduct < 0:
        return False

    squaredlengthba = (b.x - a.x)*(b.x - a.x) + (b.y - a.y)*(b.y - a.y)
    if dotproduct > squaredlengthba:
        return False

    return True

4
-epsilon < crossproduct < epsilon and min(a.x, b.x) <= c.x <= max(a.x, b.x) and min(a.y, b.y) <= c.y <= max(a.y, b.y)যথেষ্ট, তাই না?
jfs

9
ক্রস প্রোডাক্টের পরম মান তিনটি পয়েন্ট দ্বারা গঠিত ত্রিভুজের ক্ষেত্রের দ্বিগুণ (পাশের তৃতীয় পয়েন্টটি নির্দেশ করে) সুতরাং আইএমএইচও আপনার একটি এপসিলন ব্যবহার করা উচিত যা দুটি প্রান্তের মধ্যবর্তী দূরত্বের সমানুপাতিক is
বার্ট

4
আপনি আমাদের বলতে পারেন কেন এটি পূর্ণসংখ্যার সাথে কাজ করবে না? অ্যাপসিলন চেকটি "! = 0" দ্বারা প্রতিস্থাপন করা হয়েছে তবে আমি সমস্যাটি দেখছি না।
সাইরিল কা

4
হ্যাঁ, অতিরিক্ত বন্ধনী কেবল একটি টাইপো। কেউ কিছু বলার আগে 4 বছর কেটে গেছে। :)
সিরিল কা

4
বিভাগটি শেষের পয়েন্টগুলি এবং কোয়েরি পয়েন্টটি কোনটি পরিষ্কার করার জন্য আপনার একটি, বি, সি নাম পরিবর্তন করতে হবে।
ক্রেগ গিডনি

50

আমি এটি কীভাবে করব তা এখানে:

def distance(a,b):
    return sqrt((a.x - b.x)**2 + (a.y - b.y)**2)

def is_between(a,c,b):
    return distance(a,c) + distance(c,b) == distance(a,b)

7
এটির সাথে একমাত্র সমস্যা হ'ল সংখ্যাসূচক স্থায়িত্ব - সংখ্যার পার্থক্য নেওয়া এবং আরও অনেক কিছু যথাযথতা হারাতে সক্ষম।
জোনাথন লেফলার

29
-epsilon < (distance(a, c) + distance(c, b) - distance(a, b)) < epsilon
jfs

4
@jfs আপনি এর অর্থ কি? অ্যাপসিলনের সাথে চেক কী?
নিওন ওয়ার্জ

4
@ নিওন ওয়ার্জ: স্কয়ার্ট () একটি ফ্ল্যাট ফেরত দেয়। ==বেশিরভাগ ক্ষেত্রে ভাসমানদের জন্য একটি ভুল জিনিসmath.isclose()পরিবর্তে ব্যবহার করা যেতে পারে। কোন ছিল math.isclose()2008 সালে এবং সেইজন্য আমি স্পষ্ট বৈষম্য প্রদান করেছেন epsilon( abs_tolমধ্যে math.isclose()কথা বলা)।
jfs

এটি একেবারে সঠিক, তবে এই পদ্ধতিটি ম্যাথ.আইক্লোস () দিয়েও খুব ভাল নয়। স্থানাঙ্কগুলি যখন পূর্ণসংখ্যা হয় তখন আপনি একটি সঠিক পরীক্ষা করতে চান। আমার অন্য উত্তরটি এর জন্য একটি সূত্র দেয়: stackoverflow.com/a/29301940/40078
জুলাই

36

ক্রস পণ্যটি কিনা b-aএবং c-aতা পরীক্ষা করে দেখুন 0: এর অর্থ সমস্ত পয়েন্ট কল্যানারি। যদি তা হয় তবে cএর স্থানাঙ্কগুলি a's এবং b' এর মধ্যে রয়েছে কিনা তা পরীক্ষা করুন । এক্স বা y স্থানাঙ্কগুলি ব্যবহার করুন, যতক্ষণ না সেই অক্ষরে পৃথক aএবং b(বা তারা উভয় ক্ষেত্রে সমান)।

def is_on(a, b, c):
    "Return true iff point c intersects the line segment from a to b."
    # (or the degenerate case that all 3 points are coincident)
    return (collinear(a, b, c)
            and (within(a.x, c.x, b.x) if a.x != b.x else 
                 within(a.y, c.y, b.y)))

def collinear(a, b, c):
    "Return true iff a, b, and c all lie on the same line."
    return (b.x - a.x) * (c.y - a.y) == (c.x - a.x) * (b.y - a.y)

def within(p, q, r):
    "Return true iff q is between p and r (inclusive)."
    return p <= q <= r or r <= q <= p

এই উত্তরটি তিনটি আপডেটের বিশৃঙ্খলা করত। তাদের কাছ থেকে উপযুক্ত তথ্য: ব্রায়ান হায়েজ এর অধ্যায় মধ্যে সুন্দর কোড - দরকারী পটভূমি একটি সমরৈখিকতা পরীক্ষার ফাংশন জন্য নকশা স্থান জুড়ে। ভিনসেন্টের উত্তর এটির উন্নতি করতে সহায়তা করেছিল। এবং এটি হেইস যিনি কেবলমাত্র x বা y স্থানাঙ্কগুলির মধ্যে একটির পরীক্ষা করার পরামর্শ দিয়েছিলেন; মূলত কোডটি ছিলand জায়গায় ছিল if a.x != b.x else


যেহেতু দ্রুত পরিসীমা চেক করা ভাল চেকের জন্য প্রথমে রেঞ্জ করা ভাল তবে বাউন্ডিং বাক্সে কলিনারি পরীক্ষা করুন।
অনুদান এম

4
ফাংশনটি হল_অন (এ, বি, সি) যেখানে মামলার ক্ষেত্রে a == খ! = সি। সেক্ষেত্রে এটি সত্য হবে, যদিও সি একটি থেকে বি পর্যন্ত কোনও রেখাংশকে ছেদ করে না।
মিক্কো ভাইর্ক্কিল

@ সুপারফ্লাক্স, আমি এটি চালানোর চেষ্টা করেছি, এবং মিথ্যা পেয়েছি।
দারিয়াস বেকন

4
আমি মনে করি বর্তমান উত্তর গৃহীত উত্তরের চেয়ে এই উত্তরটি বেশ পরিষ্কারভাবে উচ্চতর superior
রিক

4
কলিনারি (ক, খ, সি) সমতা অনুসারে ভাসমান পয়েন্ট সংখ্যাগুলি পরীক্ষা করছে। এটি একটি অ্যাপসিলন / সহনশীলতা ব্যবহার করা উচিত নয়?
jwezorek

7

এখানে অন্য পদ্ধতির:

  • দুটি বিন্দু A (x1, y1) এবং বি (x2, y2) ধরে নেওয়া যাক
  • এই বিন্দুগুলির মধ্য দিয়ে যাওয়ার রেখার সমীকরণটি হ'ল (x-x1) / (y-y1) = (x2-x1) / (y2-y1) .. (কেবল theালু সমান করে দেওয়া)

পয়েন্ট সি (x3, y3) এ এবং বি এর মধ্যে থাকবে যদি:

  • x3, y3 উপরের সমীকরণটিকে সন্তুষ্ট করে।
  • x3 x1 এবং x2 এর মধ্যে এবং y3 y1 এবং y2 এর মধ্যে রয়েছে (তুচ্ছ পরীক্ষা)

এটি রাউন্ডিং ত্রুটিগুলি (স্থানাঙ্কের অক্ষমতা) বিবেচনা করে না।
বার্ট

এটি সঠিক ধারণা, আমি মনে করি, তবে বিস্তারিতভাবে সংক্ষেপে (আমরা অনুশীলনে এই সমীকরণটি কীভাবে পরীক্ষা করব?) এবং কিছুটা বগি: শেষ y3টি y2 হওয়া উচিত।
দারিয়াস বেকন

@ দারিয়াস: টাইপোটি ঠিক করেছেন
হারলে হলকম্ব 0

7

বিভাগটির দৈর্ঘ্য গুরুত্বপূর্ণ নয়, সুতরাং বর্গমূল ব্যবহারের প্রয়োজন হয় না এবং এড়ানো উচিত কারণ আমরা কিছুটা নির্ভুলতা হারাতে পারি।

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

class Segment:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def is_between(self, c):
        # Check if slope of a to c is the same as a to b ;
        # that is, when moving from a.x to c.x, c.y must be proportionally
        # increased than it takes to get from a.x to b.x .

        # Then, c.x must be between a.x and b.x, and c.y must be between a.y and b.y.
        # => c is after a and before b, or the opposite
        # that is, the absolute value of cmp(a, b) + cmp(b, c) is either 0 ( 1 + -1 )
        #    or 1 ( c == a or c == b)

        a, b = self.a, self.b             

        return ((b.x - a.x) * (c.y - a.y) == (c.x - a.x) * (b.y - a.y) and 
                abs(cmp(a.x, c.x) + cmp(b.x, c.x)) <= 1 and
                abs(cmp(a.y, c.y) + cmp(b.y, c.y)) <= 1)

ব্যবহারের কয়েকটি এলোমেলো উদাহরণ:

a = Point(0,0)
b = Point(50,100)
c = Point(25,50)
d = Point(0,8)

print Segment(a,b).is_between(c)
print Segment(a,b).is_between(d)

4
CX বা CY ভাসা তারপর প্রথম হন ==সালে is_between()ব্যর্থ হতে পারে (BTW এটা ছদ্মবেশে একটি crossproduct যায়)।
jfs

যোগ করুন is_between():a, b = self.a, self.b
jfs

দেখে মনে হচ্ছে এটি তিনটি পয়েন্ট একই হলে (সত্য যা সঠিক, তবে সত্য) ফিরে আসবে তবে মিথ্যা যদি ঠিক দুটি পয়েন্ট একই হয় - তবে মধ্যবর্তীতা নির্ধারণের জন্য একটি দুর্দান্ত অসঙ্গতিপূর্ণ উপায়। আমি আমার উত্তরে একটি বিকল্প পোস্ট করেছি।
দারিয়াস বেকন

এটি অন্য সিএমপি ট্রিক দ্বারা স্থির করা হয়েছে, তবে এই কোডটি গন্ধ পেতে শুরু করে ;-)
ভিনসেন্ট

5

সি ++ এ দেওয়া কোড সহ এটি সম্পর্কে আরও একটি আলাদা উপায়। দুটি পয়েন্ট দেওয়া, l1 এবং l2 এটি তাদের মধ্যে লাইন বিভাগটি হিসাবে প্রকাশ করার জন্য এটি তুচ্ছ

l1 + A(l2 - l1)

যেখানে 0 <= এ <= 1. আপনি যদি এই সমস্যার জন্য ব্যবহার না করে আরও আগ্রহী হন তবে এটি কোনও লাইনের ভেক্টর উপস্থাপনা হিসাবে পরিচিত। আমরা এর x এবং y উপাদানগুলি বিভক্ত করতে পারি:

x = l1.x + A(l2.x - l1.x)
y = l1.y + A(l2.y - l1.y)

একটি বিন্দু (x, y) নিন এবং এ এর ​​x এবং y উপাদানগুলি এ দুটি সমাধান করার জন্য এই দুটি এক্সপ্রেশনে প্রতিস্থাপন করুন বিন্দুটি লাইনটিতে রয়েছে যদি উভয় এক্সপ্রেশনটিতে A এর সমাধানগুলি সমান হয় এবং 0 <= এ <= 1 হয় কারণ এ এর সমাধান করার জন্য বিভাগের প্রয়োজন, লাইন বিভাগটি অনুভূমিক বা উল্লম্ব হয়ে গেলে বিভাগগুলি শূন্য দ্বারা বন্ধ করতে হ্যান্ডলিংয়ের বিশেষ ক্ষেত্রে প্রয়োজন। চূড়ান্ত সমাধানটি নিম্নরূপ:

// Vec2 is a simple x/y struct - it could very well be named Point for this use

bool isBetween(double a, double b, double c) {
    // return if c is between a and b
    double larger = (a >= b) ? a : b;
    double smaller = (a != larger) ? a : b;

    return c <= larger && c >= smaller;
}

bool pointOnLine(Vec2<double> p, Vec2<double> l1, Vec2<double> l2) {
    if(l2.x - l1.x == 0) return isBetween(l1.y, l2.y, p.y); // vertical line
    if(l2.y - l1.y == 0) return isBetween(l1.x, l2.x, p.x); // horizontal line

    double Ax = (p.x - l1.x) / (l2.x - l1.x);
    double Ay = (p.y - l1.y) / (l2.y - l1.y);

    // We want Ax == Ay, so check if the difference is very small (floating
    // point comparison is fun!)

    return fabs(Ax - Ay) < 0.000001 && Ax >= 0.0 && Ax <= 1.0;
}

4

আরও জ্যামিতিক পদ্ধতির ব্যবহার করে নিম্নলিখিত দূরত্বগুলি গণনা করুন:

ab = sqrt((a.x-b.x)**2 + (a.y-b.y)**2)
ac = sqrt((a.x-c.x)**2 + (a.y-c.y)**2)
bc = sqrt((b.x-c.x)**2 + (b.y-c.y)**2)

এবং পরীক্ষা কিনা AC + BC সমান AB :

is_on_segment = abs(ac + bc - ab) < EPSILON

কারণ তিনটি সম্ভাবনা রয়েছে:

  • 3 টি পয়েন্ট একটি ত্রিভুজ গঠন করে => এসি + বিসি> আব
  • এগুলি কলিনারি এবং সি আব বিভাগের বাইরে => এসি + বিসি> আবের বাইরে
  • তারা সমরৈখিক এবং ভিতরে AB সেগমেন্ট => AC + BC = AB

জোনাথন লেফলার অন্য মন্তব্যে যেমন উল্লেখ করেছেন, এর মধ্যে এমন সংখ্যাসঙ্গিক সমস্যা রয়েছে যা ক্রস-প্রোডাক্টের মতো অন্যান্য পন্থাগুলি এড়ানো যায়। আমার উত্তরে আমি যে অধ্যায়ের সাথে লিঙ্ক করেছি তা ব্যাখ্যা করে।
দারিয়াস বেকন

3

ঠিক আছে, লিনিয়ার বীজগণিতের প্রচুর উল্লেখ (ভেক্টরের ক্রস প্রোডাক্ট) এবং এটি একটি আসল (অর্থাত্ ধারাবাহিক বা ভাসমান পয়েন্ট) স্পেসে কাজ করে তবে প্রশ্নটি নির্দিষ্টভাবে উল্লেখ করেছে যে দুটি পয়েন্টটি পূর্ণসংখ্যা হিসাবে প্রকাশ করা হয়েছিল এবং সুতরাং ক্রস পণ্যটি সঠিক নয় সমাধান যদিও এটি একটি আনুমানিক সমাধান দিতে পারে।

সঠিক সমাধানটি হ'ল দুটি পয়েন্টের মধ্যে ব্রেনহ্যামের লাইন অ্যালগরিদম ব্যবহার করা এবং তৃতীয় বিন্দুটি লাইনের একটি বিন্দুর মধ্যে একটি কিনা তা দেখতে। যদি পয়েন্টগুলি পর্যাপ্ত পরিমাণে দূরে থাকে যে অ্যালগরিদম গণনা করা অ-পারফরম্যান্ট (এবং এটি হওয়ার জন্য এটি সত্যই বড় হতে হবে) আমি নিশ্চিত আপনি আশেপাশে খনন করতে এবং অপ্টিমাইজেশন খুঁজে পেতে পারেন।


এটি দুটি স্বেচ্ছাসেবী পয়েন্ট এবং এর গাণিতিকভাবে সঠিকের মধ্যে দ্বি-মাত্রিক পূর্ণসংখ্যার স্থানের মধ্য দিয়ে কীভাবে একটি লাইন আঁকবে তা সমাধান করে। তৃতীয় বিন্দু যদি সেই লাইনের একটি বিন্দুর হয় তবে এটি হয় সংজ্ঞা অনুসারে, এই দুটি পয়েন্টের মধ্যে।
ক্লিটাস

4
না, Bresenham এর লাইন অ্যালগরিদম একটি তৈরি করার পদ্ধতি solves পড়তা একটি দ্বি-মাত্রিক পূর্ণসংখ্যা স্থান একটি লাইন বিভাগটির। মূল পোস্টারের বার্তাটি থেকে আমি দেখতে পাচ্ছি না যে এটি রাস্টারাইজেশন সম্পর্কিত একটি প্রশ্ন ছিল।
সাইরিল কা

"আসুন আমরা বলি যে আপনার কাছে একটি দুটি মাত্রিক বিমান রয়েছে যার উপরে দুটি পয়েন্ট রয়েছে (একে এবং বি বলা হয়) প্রতিটি পয়েন্টের জন্য একটি এক্স আইএনটিগের এবং আইআই ইনটিগারের প্রতিনিধিত্ব করে।" (আমার দ্বারা জোর দেওয়া)।
ক্লিটাস

4
আমার মনে হয় ব্রেসেনহ্যামের লাইন অ্যালগোরিদম একটি লাইনে পায়খানা পূর্ণসংখ্যার পয়েন্ট দেয়, তারপরে লাইনটি আঁকতে ব্যবহার করা যেতে পারে। তারা লাইনে নাও থাকতে পারে। উদাহরণস্বরূপ যদি (0,0) থেকে (11,13) অ্যালগোরিদম অঙ্কনের জন্য একটি সংখ্যা পিক্সেল দেয় তবে শেষ পয়েন্টগুলি ছাড়া কোনও পূর্ণসংখ্য পয়েন্ট থাকে না, কারণ 11 এবং 13 টি কপিরাইট হয়।
অনুদান এম

রিয়েল স্পেসের (ℝ × ℝ) সঠিক সমাধানটি কীভাবে পূর্ণসংখ্যা স্পেসের (ℕ × ℕ), ℕ∈ℝ হিসাবে সঠিক হতে পারে না ℕ∈ℝ অথবা আপনার অর্থ: "এর চেয়ে অনুকূল নয় ..." এর পরিবর্তে 'সঠিক নয়?
আইডিয়াগ্রাম

2

(সিএ) এবং (বা) এর মধ্যে স্কেলার পণ্য অবশ্যই তাদের দৈর্ঘ্যের পণ্যের সমান হতে হবে (এর অর্থ হল ভেক্টর (সিএ) এবং (বা) সারিবদ্ধ এবং একই দিকের)) অধিকন্তু, (সিএ) দৈর্ঘ্য (বা) এর চেয়ে কম বা সমান হতে হবে। সুডোকোড:

# epsilon = small constant

def isBetween(a, b, c):
    lengthca2  = (c.x - a.x)*(c.x - a.x) + (c.y - a.y)*(c.y - a.y)
    lengthba2  = (b.x - a.x)*(b.x - a.x) + (b.y - a.y)*(b.y - a.y)
    if lengthca2 > lengthba2: return False
    dotproduct = (c.x - a.x)*(b.x - a.x) + (c.y - a.y)*(b.y - a.y)
    if dotproduct < 0.0: return False
    if abs(dotproduct*dotproduct - lengthca2*lengthba2) > epsilon: return False 
    return True

শেষ শর্তটি আরও বেশি হওয়া উচিত নয়: ABS (পণ্য - দৈর্ঘ্য * দৈর্ঘ্য) <অ্যাপসিলন?
জোনাথন লেফলার

পরিবর্তে আপনি স্কোয়ার দৈর্ঘ্যের তুলনা করা উচিত নয়? বর্গাকার শিকড় এড়ানো হয়। এছাড়াও, যদি এটি অতিরিক্ত প্রবাহের কারণে অপ্রয়োজনীয় হয়, আপনি math.sqrt এর পরিবর্তে math.hypot ব্যবহার করতে পারেন (যুক্তিগুলির যথাযথ পরিবর্তন সহ)।
দারিয়াস বেকন

আমিও এপিসিলনের বিষয়ে ভাবছি। তুমি কি এটা ব্যাখ্যা করতে পারবে? অবশ্যই, যদি আমাদের অবশ্যই ভাসমান বিষয়গুলি মোকাবেলা করতে হয় তবে আমাদের তুলনা সম্পর্কে সতর্ক থাকতে হবে, তবে কোনও অ্যাপসিলন কেন এই বিশেষ তুলনাটি আরও নির্ভুল করে তোলে তা আমার কাছে স্পষ্ট নয়।
দারিয়াস বেকন

আমি সম্মতি জ্ঞাপন করি. এই প্রশ্নের বেশ কয়েকটি ভাল উত্তর রয়েছে, এবং এটি ঠিক আছে। তবে স্কয়ারটি না ব্যবহার করার জন্য এই কোডটি সংশোধন করা দরকার এবং শেষের তুলনাটি স্থির হয়েছে।
সিরিল কা

@ জোনাথন: প্রকৃতপক্ষে কোডটি অ্যাবস ব্যবহার করে আরও পরিচিত এবং মার্জিত। ধন্যবাদ
ফেডেরিকো এ। রাম্পনি

2

এইচটিএমএল 5 ক্যানভাসে জাভাস্ক্রিপ্ট ব্যবহারের জন্য এটি ব্যবহারকারীর কার্সার নির্দিষ্ট রেখার উপরে বা কাছাকাছি ছিল কিনা তা সনাক্ত করার জন্য আমার এটি প্রয়োজন ছিল needed সুতরাং আমি দারিয়াস বেকন দ্বারা প্রদত্ত উত্তরটি কফিস্ক্রিপ্টে পরিবর্তিত করেছি:

is_on = (a,b,c) ->
    # "Return true if point c intersects the line segment from a to b."
    # (or the degenerate case that all 3 points are coincident)
    return (collinear(a,b,c) and withincheck(a,b,c))

withincheck = (a,b,c) ->
    if a[0] != b[0]
        within(a[0],c[0],b[0]) 
    else 
        within(a[1],c[1],b[1])

collinear = (a,b,c) ->
    # "Return true if a, b, and c all lie on the same line."
    ((b[0]-a[0])*(c[1]-a[1]) < (c[0]-a[0])*(b[1]-a[1]) + 1000) and ((b[0]-a[0])*(c[1]-a[1]) > (c[0]-a[0])*(b[1]-a[1]) - 1000)

within = (p,q,r) ->
    # "Return true if q is between p and r (inclusive)."
    p <= q <= r or r <= q <= p

2

আপনি কীলক এবং বিন্দু পণ্য ব্যবহার করতে পারেন:

def dot(v,w): return v.x*w.x + v.y*w.y
def wedge(v,w): return v.x*w.y - v.y*w.x

def is_between(a,b,c):
   v = a - b
   w = b - c
   return wedge(v,w) == 0 and dot(v,w) > 0

1

আমি স্কুলে এটি কীভাবে করেছি তা এখানে। আমি ভুলে গেছি কেন এটি ভাল ধারণা নয়।

সম্পাদনা:

@ ড্যারিয়াস বেকন: একটি "বিউটিফুল কোড" বইয়ের উদ্ধৃতি দিয়েছেন যাতে নীচের কোডটি কেন ভাল ধারণা নয় তা ব্যাখ্যা রয়েছে।

#!/usr/bin/env python
from __future__ import division

epsilon = 1e-6

class Point:
    def __init__(self, x, y):
        self.x, self.y = x, y

class LineSegment:
    """
    >>> ls = LineSegment(Point(0,0), Point(2,4))
    >>> Point(1, 2) in ls
    True
    >>> Point(.5, 1) in ls
    True
    >>> Point(.5, 1.1) in ls
    False
    >>> Point(-1, -2) in ls
    False
    >>> Point(.1, 0.20000001) in ls
    True
    >>> Point(.1, 0.2001) in ls
    False
    >>> ls = LineSegment(Point(1, 1), Point(3, 5))
    >>> Point(2, 3) in ls
    True
    >>> Point(1.5, 2) in ls
    True
    >>> Point(0, -1) in ls
    False
    >>> ls = LineSegment(Point(1, 2), Point(1, 10))
    >>> Point(1, 6) in ls
    True
    >>> Point(1, 1) in ls
    False
    >>> Point(2, 6) in ls 
    False
    >>> ls = LineSegment(Point(-1, 10), Point(5, 10))
    >>> Point(3, 10) in ls
    True
    >>> Point(6, 10) in ls
    False
    >>> Point(5, 10) in ls
    True
    >>> Point(3, 11) in ls
    False
    """
    def __init__(self, a, b):
        if a.x > b.x:
            a, b = b, a
        (self.x0, self.y0, self.x1, self.y1) = (a.x, a.y, b.x, b.y)
        self.slope = (self.y1 - self.y0) / (self.x1 - self.x0) if self.x1 != self.x0 else None

    def __contains__(self, c):
        return (self.x0 <= c.x <= self.x1 and
                min(self.y0, self.y1) <= c.y <= max(self.y0, self.y1) and
                (not self.slope or -epsilon < (c.y - self.y(c.x)) < epsilon))

    def y(self, x):        
        return self.slope * (x - self.x0) + self.y0

if __name__ == '__main__':
    import  doctest
    doctest.testmod()

1

লাইন বিভাগের যে কোনও বিন্দু ( , ) (যেখানে a এবং b ভেক্টর) দুটি ভেক্টর a এবং b এর রৈখিক সংমিশ্রণ হিসাবে প্রকাশ করা যেতে পারে :

অন্য কথায়, যদি লাইন বিভাগে থাকে ( , ):

c = ma + (1 - m)b, where 0 <= m <= 1

মিটার জন্য সমাধান , আমরা পাই:

m = (c.x - b.x)/(a.x - b.x) = (c.y - b.y)/(a.y - b.y)

সুতরাং, আমাদের পরীক্ষাটি (পাইথনে) হয়ে যায়:

def is_on(a, b, c):
    """Is c on the line segment ab?"""

    def _is_zero( val ):
        return -epsilon < val < epsilon

    x1 = a.x - b.x
    x2 = c.x - b.x
    y1 = a.y - b.y
    y2 = c.y - b.y

    if _is_zero(x1) and _is_zero(y1):
        # a and b are the same point:
        # so check that c is the same as a and b
        return _is_zero(x2) and _is_zero(y2)

    if _is_zero(x1):
        # a and b are on same vertical line
        m2 = y2 * 1.0 / y1
        return _is_zero(x2) and 0 <= m2 <= 1
    elif _is_zero(y1):
        # a and b are on same horizontal line
        m1 = x2 * 1.0 / x1
        return _is_zero(y2) and 0 <= m1 <= 1
    else:
        m1 = x2 * 1.0 / x1
        if m1 < 0 or m1 > 1:
            return False
        m2 = y2 * 1.0 / y1
        return _is_zero(m2 - m1)

1

সি # থেকে http://www.faqs.org/faqs/ographicics/algorithms-faq/ -> বিষয় 1.02: আমি কীভাবে একটি বিন্দু থেকে একটি রেখার দূরত্ব খুঁজে পেতে পারি?

Boolean Contains(PointF from, PointF to, PointF pt, double epsilon)
        {

            double segmentLengthSqr = (to.X - from.X) * (to.X - from.X) + (to.Y - from.Y) * (to.Y - from.Y);
            double r = ((pt.X - from.X) * (to.X - from.X) + (pt.Y - from.Y) * (to.Y - from.Y)) / segmentLengthSqr;
            if(r<0 || r>1) return false;
            double sl = ((from.Y - pt.Y) * (to.X - from.X) - (from.X - pt.X) * (to.Y - from.Y)) / System.Math.Sqrt(segmentLengthSqr);
            return -epsilon <= sl && sl <= epsilon;
        }

অন্যান্য বেশিরভাগ পদ্ধতির যথার্থ সমস্যাগুলি এড়ানোর সঠিক উপায়। অন্যান্য উল্লেখযোগ্যতার সাথে উল্লেখযোগ্যভাবে আরও দক্ষ।
রবিন ডেভিস

1

এখানে কিছু জাভা কোড যা আমার পক্ষে কাজ করেছে:

boolean liesOnSegment(Coordinate a, Coordinate b, Coordinate  c) {

    double dotProduct = (c.x - a.x) * (c.x - b.x) + (c.y - a.y) * (c.y - b.y);
    if (dotProduct < 0) return true;
    return false;
}

4
ডটপ্রডাক্ট কেবলমাত্র অ্যালিজেনমেন্ট সম্পর্কে বলতে পারে। আপনার কোড অসম্পূর্ণ !!! একটি (0,0), বি (4,0), সি (1,1) দিয়ে আপনার ডটপ্রডাক্ট = (1-0) * (1-4) + (1-0) * (1-0) = - 3 + 1 = -3
ব্যবহারকারী 43968

0

justাল একই এবং পয়েন্টটি অন্যদের মধ্যে রয়েছে তা নিশ্চিত করার বিষয়ে কীভাবে?

প্রদত্ত পয়েন্টগুলি (x1, y1) এবং (x2, y2) (x2> x1 সহ) এবং প্রার্থী পয়েন্ট (ক, খ)

যদি (খ-y1) / (a-x1) = (y2-y2) / (x2-x1) এবং x1 <a <x2

তারপরে (ক, খ) অবশ্যই (x1, y1) এবং (x2, y2) এর মধ্যে থাকবে


কিছু স্থানাঙ্ক নিকট বা অভিন্ন হলে পাগল ভাসমান পয়েন্ট যথার্থ সমস্যা সম্পর্কে কীভাবে?
রবিন ডেভিস

কম্পিউটারগুলি ভাসমান পয়েন্টগুলি ভালভাবে করে না। একটি কম্পিউটারে অসীম ধারাবাহিকভাবে সামঞ্জস্যযোগ্য মানগুলির মতো কোনও জিনিস নেই। সুতরাং আপনি যদি ভাসমান পয়েন্টগুলি ব্যবহার করছেন, আপনাকে নির্ধারক হিসাবে কিছু ছোট অ্যাপসিলন মান নির্ধারণ করতে হবে এবং এপিসিলনের চেয়ে আরও দুটি পয়েন্ট একই পয়েন্ট হিসাবে বিবেচনা করা উচিত। একই পংক্তিতে যে বিন্দুটি হয় এবং শেষ বিন্দু থেকে একই দূরত্ব নির্ধারণ করুন। যদি আপনার প্রার্থী পয়েন্টটি সেই গণিত পয়েন্টের আপনার অ্যাপসিলনের মধ্যে থাকে, তবে এটিকে অভিন্ন বলুন।
চার্লস ব্রেটানা

আমার বক্তব্যটি হ'ল এই উত্তরটি যথার্থ সমস্যার কারণে অকার্যকর কারণ আপনি যখন কোডটিতে বাস্তবে এটি প্রয়োগ করেন। সুতরাং এটি ব্যবহার করা উচিত নয়। গণিত পরীক্ষায় একটি সুন্দর উত্তর। তবে একটি কম্প-সায়েন্স কোর্সে প্রতিযোগিতা ব্যর্থতা। আমি এখানে বিন্দু-পণ্য পদ্ধতির সন্ধান করতে এসেছি (যা সঠিক); সুতরাং আমি ভেবেছিলাম যে আমি এই থ্রেডের অনেকগুলি উত্তর পতাকাঙ্কিত করতে কয়েক মুহুর্ত নেব যাতে সঠিক যেগুলি সঠিক সমাধানের সাথে পরিচিত অন্যগুলি সেগুলি ব্যবহার করার জন্য প্রলোভিত হবে না।
রবিন ডেভিস

কম্পিউটারগুলি একটি লাইনে প্রতিটি সম্ভাব্য আসল সংখ্যা উপস্থাপন করতে অক্ষমতার কারণে উত্থাপিত সমস্যাগুলি সম্পর্কে আপনি সঠিক। আপনি ভুল যে কোনও সমাধান (ডট পণ্য পদ্ধতি সহ) এই সমস্যাগুলির জন্য অনাক্রম্য হতে পারে। যে কোনও সমাধান এই সমস্যায় ভুগতে পারে। আপনি গ্রহণযোগ্য এপসিলনের জন্য কিছু ভাতা না দিলে একটি পয়েন্ট যা হুবহু লাইনে থাকে (তবে যার স্থানাংকগুলি যেমন ফ্লাইটিং পয়েন্ট বাইনারি উপস্থাপনায় প্রতিনিধিত্বযোগ্য নয়) ডট পণ্য পরীক্ষায়ও ব্যর্থ হবে, যেহেতু কম্পিউটার পয়েন্টের স্থানাঙ্কগুলি সঠিকভাবে উপস্থাপন করবে কিছু পরিমাণে
চার্লস বেতানা

0

ভেক্টর 2 ডি ক্লাস ব্যবহার করে সি # তে একটি উত্তর

public static bool IsOnSegment(this Segment2D @this, Point2D c, double tolerance)
{
     var distanceSquared = tolerance*tolerance;
     // Start of segment to test point vector
     var v = new Vector2D( @this.P0, c ).To3D();
     // Segment vector
     var s = new Vector2D( @this.P0, @this.P1 ).To3D();
     // Dot product of s
     var ss = s*s;
     // k is the scalar we multiply s by to get the projection of c onto s
     // where we assume s is an infinte line
     var k = v*s/ss;
     // Convert our tolerance to the units of the scalar quanity k
     var kd = tolerance / Math.Sqrt( ss );
     // Check that the projection is within the bounds
     if (k <= -kd || k >= (1+kd))
     {
        return false;
     }
     // Find the projection point
     var p = k*s;
     // Find the vector between test point and it's projection
     var vp = (v - p);
     // Check the distance is within tolerance.
     return vp * vp < distanceSquared;
}

মনে রাখবেন যে

s * s

সি # তে অপারেটর ওভারলোডিংয়ের মাধ্যমে বিভাগের ভেক্টরের বিন্দু পণ্য

কীটি অসীম রেখায় বিন্দুটির প্রক্ষেপণের সুযোগ নিয়েছে এবং পর্যবেক্ষণটির স্কেলারের পরিমাণ আমাদের তুচ্ছভাবে বলে দেয় যদি প্রজেকশনটি সেগমেন্টে থাকে বা না থাকে। একটি অস্পষ্ট সহনশীলতা ব্যবহার করতে আমরা স্কেলারের পরিমাণের সীমানা সামঞ্জস্য করতে পারি।

যদি প্রক্ষেপণ সীমানার মধ্যে থাকে তবে আমরা কেবল পরীক্ষার বিন্দু থেকে প্রক্ষেপণের দূরত্ব সীমাতে থাকলে পরীক্ষা করি।

ক্রস পণ্য পদ্ধতির উপর সুবিধা হ'ল সহনশীলতার একটি অর্থপূর্ণ মূল্য রয়েছে value


0

ইউনিটিতে সি # সহ আমার সমাধানটি এখানে।

private bool _isPointOnLine( Vector2 ptLineStart, Vector2 ptLineEnd, Vector2 ptPoint )
{
    bool bRes = false;
    if((Mathf.Approximately(ptPoint.x, ptLineStart.x) || Mathf.Approximately(ptPoint.x, ptLineEnd.x)))
    {
        if(ptPoint.y > ptLineStart.y && ptPoint.y < ptLineEnd.y)
        {
            bRes = true;
        }
    }
    else if((Mathf.Approximately(ptPoint.y, ptLineStart.y) || Mathf.Approximately(ptPoint.y, ptLineEnd.y)))
    {
        if(ptPoint.x > ptLineStart.x && ptPoint.x < ptLineEnd.x)
        {
            bRes = true;
        }
    }
    return bRes;
}

দেখে মনে হচ্ছে এই কোডটি কেবল উল্লম্ব এবং অনুভূমিক রেখাংশগুলির সাথে কাজ করবে। পিটিলাইনস্টার্টটি যদি (0,0) হয়, পিটিলাইন ইন্ড (2,2) এবং পিটিপয়েন্টটি (1, 1) হয় তবে কী হবে?
ভ্যাক

0

সি # জুলেসের উত্তরের সংস্করণ:

public static double CalcDistanceBetween2Points(double x1, double y1, double x2, double y2)
{
    return Math.Sqrt(Math.Pow (x1-x2, 2) + Math.Pow (y1-y2, 2));
}

public static bool PointLinesOnLine (double x, double y, double x1, double y1, double x2, double y2, double allowedDistanceDifference)
{
    double dist1 = CalcDistanceBetween2Points(x, y, x1, y1);
    double dist2 = CalcDistanceBetween2Points(x, y, x2, y2);
    double dist3 = CalcDistanceBetween2Points(x1, y1, x2, y2);
    return Math.Abs(dist3 - (dist1 + dist2)) <= allowedDistanceDifference;
}

0

আপনি পয়েন্ট স্থানাঙ্কের সাহায্যে লাইন সেগমেন্টের জন্য লাইন সমীকরণটি সমাধান করে এটি জানতে পারবেন যে আপনি যে বিন্দুটি লাইনে রয়েছে কিনা এবং তারপরে সেগমেন্টের সীমানা পরীক্ষা করে এটি এর ভিতরে বা বাইরে রয়েছে কিনা তা জানতে পারবেন। আপনি কিছু থ্রেশহোল্ড প্রয়োগ করতে পারেন কারণ ভাল এটি কোথাও কোথাও সম্ভবত ফ্লোটিং পয়েন্ট মান দ্বারা সংজ্ঞায়িত করা হয় এবং আপনাকে অবশ্যই সঠিকটিকে আঘাত করতে হবে না। পিএইচপি মধ্যে উদাহরণ

function getLineDefinition($p1=array(0,0), $p2=array(0,0)){
    
    $k = ($p1[1]-$p2[1])/($p1[0]-$p2[0]);
    $q = $p1[1]-$k*$p1[0];
    
    return array($k, $q);
    
}

function isPointOnLineSegment($line=array(array(0,0),array(0,0)), $pt=array(0,0)){
    
    // GET THE LINE DEFINITION y = k.x + q AS array(k, q) 
    $def = getLineDefinition($line[0], $line[1]);
    
    // use the line definition to find y for the x of your point
    $y = $def[0]*$pt[0]+$def[1];

    $yMin = min($line[0][1], $line[1][1]);
    $yMax = max($line[0][1], $line[1][1]);

    // exclude y values that are outside this segments bounds
    if($y>$yMax || $y<$yMin) return false;
    
    // calculate the difference of your points y value from the reference value calculated from lines definition 
    // in ideal cases this would equal 0 but we are dealing with floating point values so we need some threshold value not to lose results
    // this is up to you to fine tune
    $diff = abs($pt[1]-$y);
    
    $thr = 0.000001;
    
    return $diff<=$thr;
    
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.