2 ডি পয়েন্ট একটি বহুভুজের মধ্যে রয়েছে কিনা তা আমি কীভাবে নির্ধারণ করতে পারি?


497

হিট-টেস্টিংয়ে (উদাহরণস্বরূপ ) ব্যবহারের জন্য বহুভুজ অ্যালগরিদমের অভ্যন্তরে একটি দ্রুত 2D পয়েন্ট তৈরি করার চেষ্টা করছি Polygon.contains(p:Point)। কার্যকর কৌশলগুলির জন্য পরামর্শগুলি প্রশংসা করা হবে।


আপনি ডান বা বাম হাতের প্রশ্ন সম্পর্কে আপনার উপলব্ধি সম্পর্কে আমাদের বলতে ভুলে গিয়েছিলেন - যা "ভিতরে" বনাম "বাইরে" হিসাবেও ব্যাখ্যা করা যেতে পারে - আরটি
রিচার্ড টি

13
হ্যাঁ, আমি বুঝতে পেরেছি যে প্রশ্নটি অনেকগুলি বিবরণ ছাড়িয়ে গেছে, তবে এই মুহুর্তে আমি বিভিন্ন প্রতিক্রিয়া দেখতে আগ্রহী।
স্কট এভারেনডেন

4
একটি 90 পার্শ্বযুক্ত বহুভুজকে এনিয়েএকন্টাগন এবং 10,000 পার্শ্বযুক্ত বহুভুজকে মেরিয়্যাগোন বলা হয়।

"সর্বাধিক মার্জিত" লক্ষ্যমাত্রার বাইরে, যেহেতু একটি "মোটেও কাজ" -ালগরিদম খুঁজে পেতে আমার সমস্যা হয়েছিল। : আমি নিজেকে বের করে চিন্তা করতে হবে stackoverflow.com/questions/14818567/...
davidkonrad

উত্তর:


731

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

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

যেমন আপনার পয়েন্ট আছে (9/1), (4/3), (2/7), (8/2), (3/6)। এর অর্থ এক্সিনটি 2, এক্সম্যাক্স 9, ইয়ামিন 1 এবং ইয়াম্যাক্স 7 হয়। দুটি প্রান্ত (2/1) এবং (9/7) আয়তক্ষেত্রের বাইরে একটি বিন্দু বহুভুজের মধ্যে থাকতে পারে না।

// p is your point, p.x is the x coord, p.y is the y coord
if (p.x < Xmin || p.x > Xmax || p.y < Ymin || p.y > Ymax) {
    // Definitely not within the polygon!
}

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

গর্ত ছাড়াই বহুভুজ

এবং এখানে একটি গর্তযুক্ত রয়েছে:

গর্ত সঙ্গে বহুভুজ

সবুজটির মাঝে একটা গর্ত আছে!

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

একটি বহুভুজের মাধ্যমে কীভাবে রশ্মি কেটে যায় তা প্রদর্শন করে

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

আপনার এখনও উপরে বাউন্ডিং বক্স আছে, মনে আছে? সীমাবদ্ধ বাক্সের বাইরে কেবল একটি পয়েন্ট বাছাই করুন এবং এটি আপনার রশ্মির প্রারম্ভিক পয়েন্ট হিসাবে ব্যবহার করুন। উদাহরণস্বরূপ পয়েন্টটি (Xmin - e/p.y)অবশ্যই বহুভুজের বাইরে।

তবে কী e? ওয়েল, e(আসলে এপসিলন) বাউন্ডিং বক্সকে কিছু প্যাডিং দেয় । যেমনটি আমি বলেছিলাম, যদি আমরা একটি বহুভুজ রেখার খুব কাছাকাছি শুরু করি তবে রে ট্রেসিং ব্যর্থ হয়। যেহেতু সীমানা বাক্সটি বহুভুজের সমান হতে পারে (যদি বহুভুজটি অক্ষরেখাগুলি আয়তক্ষেত্র হয় তবে সীমাবদ্ধ বাক্সটি বহুভুজের সমান!), এই নিরাপদ করার জন্য আমাদের কিছু প্যাডিং দরকার that's আপনার কত বড় নির্বাচন করা উচিত e? খুব বড় নয়. এটি অঙ্কনের জন্য আপনি যে সমন্বয় ব্যবস্থা ব্যবহার করছেন তা নির্ভর করে। যদি আপনার পিক্সেল ধাপের প্রস্থটি 1.0 হয়, তবে কেবলমাত্র 1.0 বেছে নিন (তবুও 0.1 কাজ করবে)

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

side 1: (X1/Y1)-(X2/Y2)
side 2: (X2/Y2)-(X3/Y3)
side 3: (X3/Y3)-(X4/Y4)
:

আপনার চারপাশে রশ্মির পরীক্ষা করা দরকার। রশ্মিকে ভেক্টর হিসাবে বিবেচনা করুন এবং প্রতিটি পক্ষকে ভেক্টর হিসাবে বিবেচনা করুন। রশ্মিকে একেবারে একবারে আঘাত করতে হয় বা কখনই নয়। এটি একই দিকে দু'বার আঘাত করতে পারে না। 2 ডি স্পেসে দুটি রেখা সর্বদা ঠিক একবার ছেদ করবে, যদি না তারা সমান্তরাল হয়, তবে যদি তারা কখনও ছেদ করে না। তবে যেহেতু ভেক্টরগুলির দৈর্ঘ্য সীমিত, দুটি ভেক্টর সমান্তরাল নাও হতে পারে এবং এখনও কখনও ছেদ করতে পারে না কারণ তারা একে অপরের সাথে দেখা করার পক্ষে খুব কম।

// Test the ray against all sides
int intersections = 0;
for (side = 0; side < numberOfSides; side++) {
    // Test if current side intersects with ray.
    // If yes, intersections++;
}
if ((intersections & 1) == 1) {
    // Inside of polygon
} else {
    // Outside of polygon
}

এতদূর ভাল, তবে দুটি ভেক্টর ছেদ করলে আপনি কীভাবে পরীক্ষা করবেন? এখানে কিছু সি কোড দেওয়া আছে (পরীক্ষিত নয়) এটি কৌশলটি করা উচিত:

#define NO 0
#define YES 1
#define COLLINEAR 2

int areIntersecting(
    float v1x1, float v1y1, float v1x2, float v1y2,
    float v2x1, float v2y1, float v2x2, float v2y2
) {
    float d1, d2;
    float a1, a2, b1, b2, c1, c2;

    // Convert vector 1 to a line (line 1) of infinite length.
    // We want the line in linear equation standard form: A*x + B*y + C = 0
    // See: http://en.wikipedia.org/wiki/Linear_equation
    a1 = v1y2 - v1y1;
    b1 = v1x1 - v1x2;
    c1 = (v1x2 * v1y1) - (v1x1 * v1y2);

    // Every point (x,y), that solves the equation above, is on the line,
    // every point that does not solve it, is not. The equation will have a
    // positive result if it is on one side of the line and a negative one 
    // if is on the other side of it. We insert (x1,y1) and (x2,y2) of vector
    // 2 into the equation above.
    d1 = (a1 * v2x1) + (b1 * v2y1) + c1;
    d2 = (a1 * v2x2) + (b1 * v2y2) + c1;

    // If d1 and d2 both have the same sign, they are both on the same side
    // of our line 1 and in that case no intersection is possible. Careful, 
    // 0 is a special case, that's why we don't test ">=" and "<=", 
    // but "<" and ">".
    if (d1 > 0 && d2 > 0) return NO;
    if (d1 < 0 && d2 < 0) return NO;

    // The fact that vector 2 intersected the infinite line 1 above doesn't 
    // mean it also intersects the vector 1. Vector 1 is only a subset of that
    // infinite line 1, so it may have intersected that line before the vector
    // started or after it ended. To know for sure, we have to repeat the
    // the same test the other way round. We start by calculating the 
    // infinite line 2 in linear equation standard form.
    a2 = v2y2 - v2y1;
    b2 = v2x1 - v2x2;
    c2 = (v2x2 * v2y1) - (v2x1 * v2y2);

    // Calculate d1 and d2 again, this time using points of vector 1.
    d1 = (a2 * v1x1) + (b2 * v1y1) + c2;
    d2 = (a2 * v1x2) + (b2 * v1y2) + c2;

    // Again, if both have the same sign (and neither one is 0),
    // no intersection is possible.
    if (d1 > 0 && d2 > 0) return NO;
    if (d1 < 0 && d2 < 0) return NO;

    // If we get here, only two possibilities are left. Either the two
    // vectors intersect in exactly one point or they are collinear, which
    // means they intersect in any number of points from zero to infinite.
    if ((a1 * b2) - (a2 * b1) == 0.0f) return COLLINEAR;

    // If they are not collinear, they must intersect in exactly one point.
    return YES;
}

ইনপুট মানগুলি ভেক্টর 1 ( এবং ) এবং ভেক্টর 2 ( এবং ) এর দুটি শেষ বিন্দু । সুতরাং আপনার কাছে 2 টি ভেক্টর, 4 পয়েন্ট, 8 টি স্থানাঙ্ক রয়েছে। এবং পরিষ্কার। ছেদ বাড়ায়, কিছুই করে না।v1x1/v1y1v1x2/v1y2v2x1/v2y1v2x2/v2y2YESNOYESNO

COLLINEAR সম্পর্কে কি? এর অর্থ উভয় ভেক্টর একই সীমাহীন লাইনে অবস্থান করে, অবস্থান এবং দৈর্ঘ্যের উপর নির্ভর করে এগুলি একেবারে ছেদ করে না বা অবিরাম সংখ্যায় তারা ছেদ করে। আমি কীভাবে এই কেসটি পরিচালনা করব তা পুরোপুরি নিশ্চিত নই, আমি একে অন্যভাবে ছেদ হিসাবে গণনা করব না। ভাল, ভাসমান পয়েন্ট গোলাকার ত্রুটির কারণে এই কেসটি বাস্তবে বাস্তবে বিরল; আরও ভাল কোড সম্ভবত এটির পরিবর্তে এমন কোনও কিছুর == 0.0fজন্য পরীক্ষা করবে না < epsilonযেখানে অ্যাপসিলন বরং একটি ছোট সংখ্যা।

আপনার যদি বৃহত সংখ্যক পয়েন্ট পরীক্ষা করার দরকার হয় তবে আপনি বহুভুজ পক্ষের রৈখিক সমীকরণের স্ট্যান্ডার্ড ফর্মগুলিকে মেমরির মধ্যে রেখে অবশ্যই পুরো জিনিসটি কিছুটা গতি বাড়িয়ে তুলতে পারেন, সুতরাং আপনাকে প্রতিবার এগুলি পুনরায় গণনা করতে হবে না। এটি আপনাকে মেমোরিতে বহুভুজ পার্শ্বে প্রতি ভাসমান পয়েন্টের মানগুলি সংরক্ষণের পরিবর্তে প্রতিটি পরীক্ষায় দুটি ফ্লোটিং পয়েন্ট গুণ এবং তিনটি ভাসমান পয়েন্ট বিয়োগগুলি সংরক্ষণ করবে। এটি একটি সাধারণ মেমরি বনাম গণনার সময় বাণিজ্য বন্ধ।

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

অবশ্যই এই পদ্ধতিটি কেবলমাত্র ব্যবহারযোগ্য যদি আপনার অঙ্কনের পৃষ্ঠটি বিশাল হতে না হয়। যদি এটি জিপিইউ মেমরির সাথে ফিট না করতে পারে তবে এই পদ্ধতিটি সিপিইউ-তে করার চেয়ে ধীর। যদি এটি বিশাল হতে হয় এবং আপনার জিপিইউ আধুনিক ছায়া গো সমর্থন করে, আপনি এখনও GPU শ্যাডার হিসাবে উপরে প্রদর্শিত রশ্মির ingালাই প্রয়োগ করে GPU ব্যবহার করতে পারেন, যা একেবারেই সম্ভব। বহুবিধ সংখ্যা বা পরীক্ষার জন্য বৃহত সংখ্যক পয়েন্টের জন্য, এটি প্রদান করবে, কিছু জিপিইউ সমান্তরালে to৪ থেকে ২৫ 25 পয়েন্ট পরীক্ষা করতে সক্ষম হবে তা বিবেচনা করুন। তবে নোট করুন যে সিপিইউ থেকে জিপিইউ এবং পিছনে ডেটা স্থানান্তর সবসময় ব্যয়বহুল, সুতরাং কেবলমাত্র কয়েকটি বহুভুজের বিরুদ্ধে কয়েকটি পয়েন্ট পরীক্ষা করার জন্য যেখানে পয়েন্টগুলি বা বহুভুজগুলি গতিশীল এবং ঘন ঘন পরিবর্তিত হয়, জিপিইউ পদ্ধতির খুব কমই অর্থ প্রদান করা হবে বন্ধ।


26
+1 চমত্কার উত্তর। এটি করার জন্য হার্ডওয়্যারটি ব্যবহার করার সময়, আমি অন্য জায়গায় পড়েছি যে এটি ধীর হতে পারে কারণ আপনাকে গ্রাফিক্স কার্ড থেকে ডেটা ফিরে পেতে হবে। তবে আমি সিপিইউকে প্রচুর পরিমাণে বোঝা নেওয়ার নীতিটি পছন্দ করি। কীভাবে ওপেনজিএলে এটি করা যেতে পারে তার জন্য কারও কোনও ভাল রেফারেন্স রয়েছে?
গ্যাভিন

3
+1 কারণ এটি এত সহজ! প্রধান সমস্যাটি হ'ল যদি আপনার বহুভুজ এবং পরীক্ষার পয়েন্টটি কোনও গ্রিডে দাঁড়িয়ে থাকে (অস্বাভাবিক নয়) তবে আপনাকে "সদৃশ" ছেদগুলি মোকাবেলা করতে হবে, উদাহরণস্বরূপ, সরাসরি বহুভুজের মাধ্যমে! (একের পরিবর্তে দু'জনের সমতা ফলন)। এই অদ্ভুত অঞ্চলে পান: স্ট্যাকওভারফ্লো . com / প্রশ্নগুলি / ২২৫৫84৪২/২ । কম্পিউটার গ্রাফিকগুলি এই বিশেষ ক্ষেত্রে পূর্ণ: তত্ত্বের ক্ষেত্রে সহজ, অনুশীলনে লোমশ।
জ্যারেড আপডেটিকে

7
@ আরএমরিসি: আপনারা কেন এমন ভাবছেন? এটি অবতল বহুভুজের জন্য কীভাবে ব্যর্থ হবে তা দেখতে আমি ব্যর্থ। বহুভুজ অবতল হওয়ার সময় রশ্মি বহুভুজটি ছেড়ে বহুবার প্রবেশ করতে পারে, তবে শেষদিকে, হিট কাউন্টারটি বিন্দুটির মধ্যে এবং এমনকি বাইরে থাকলেও অবতল বহুভুজগুলির জন্য বিজোড় হবে।
মক্কি

6
'দ্রুত উইন্ডিং নম্বর অ্যালগরিদম', সফ্টসারফার / আর্কাইভ / অ্যালগোরিদম_0103/algorithm_0103.htm এ বর্ণিত খুব দ্রুত কাজ করে ...
এসপি

10
এক্স এবং y স্থানাঙ্ককে আলাদা করতে আপনার / ব্যবহার বিভ্রান্তিকর, এটি y এর দ্বারা বিভক্ত x হিসাবে পড়ে। এটি x, y (অর্থাত্ x কমা y) ব্যবহার করা আরও পরিষ্কার। সামগ্রিকভাবে একটি দরকারী উত্তর।
অ্যাশ

583

আমি মনে করি নিম্নলিখিত কোডের টুকরোটি সেরা সমাধান ( এখান থেকে নেওয়া ):

int pnpoly(int nvert, float *vertx, float *verty, float testx, float testy)
{
  int i, j, c = 0;
  for (i = 0, j = nvert-1; i < nvert; j = i++) {
    if ( ((verty[i]>testy) != (verty[j]>testy)) &&
     (testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )
       c = !c;
  }
  return c;
}

যুক্তি

  • ন্যাভার্ট : বহুভুজের মধ্যে শীর্ষে অবস্থিত সংখ্যা শেষে প্রথম শীর্ষটি পুনরাবৃত্তি করবেন কিনা তা উপরে উল্লিখিত নিবন্ধে আলোচনা করা হয়েছে।
  • উল্লম্ব, ভার্টি : বহুভুজের অনুভূমিকের x- এবং y- স্থানাঙ্কযুক্ত অ্যারে
  • টেস্টেক্স, টেস্টি : এক্স পয়েন্টের এক্স এবং y- সমন্বিত inate

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

এর পিছনে ধারণাটি বেশ সহজ। লেখক এটিকে বর্ণনা করেছেন:

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

ভেরিয়েবল সি প্রতিবার অনুভূমিক রশ্মিটি কোনও প্রান্ত অতিক্রম করে 0 থেকে 1 এবং 1 থেকে 0 থেকে স্যুইচ করছে। সুতরাং মূলত এটি নির্ধারিত প্রান্তগুলির সংখ্যাটি সমান বা বিজোড় কিনা তা খতিয়ে রাখছে। 0 এর অর্থ সম এবং 1 এর অর্থ বিজোড়।


5
প্রশ্ন। আমি যে ভেরিয়েবলগুলি পাস করি তা কী? তারা কী উপস্থাপন করে?
tekknolagi

9
@ মিক এটি যাচাই করে verty[i]এবং verty[j]এর উভয় পাশে থাকে testy, তাই তারা কখনই সমান হয় না।
পিটার উড

4
এই কোডটি শক্তিশালী নয় এবং আমি এটি ব্যবহার করার পরামর্শ দেব না। এখানে একটি বিশদ বিশ্লেষণ দেওয়ার জন্য একটি লিঙ্ক এখানে দেওয়া হয়েছে: www-ma2.upc.es/geoc/Schirra-PointPolygon.pdf
মিকোলা

13
এই পদ্ধতির আসলে সীমাবদ্ধতা রয়েছে (এজ-কেস): বহুভুজের মধ্যে পয়েন্ট (15,20) চেক করা [[(10,10), (10,20), (20,20), (20,10)] ফিরে আসবে) মিথ্যা পরিবর্তে সত্য। (10,20) বা (20,15) এর সাথে একই। অন্যান্য সমস্ত ক্ষেত্রে, অ্যালগরিদম পুরোপুরি সূক্ষ্মভাবে কাজ করে এবং প্রান্ত-কেসগুলিতে ভুয়া-নেতিবাচকগুলি আমার আবেদনের জন্য ঠিক আছে।
আলেকজান্ডার পাচা

10
@ আলেকজান্দার, এটি আসলে নকশার দ্বারা: বিপরীত অর্থে বাম এবং নীচের সীমানা উপরের এবং ডান সীমানায় পরিচালনা করে, দুটি স্বতন্ত্র বহুভুজ একটি কিনারা ভাগ করে নিতে পারে, এই প্রান্তের যে কোনও বিন্দু এক এবং কেবল একটি বহুভুজের মধ্যে অবস্থিত হবে। .. একটি দরকারী সম্পত্তি।
ওয়ার্ডপু

69

নির্গের দেওয়া উত্তরের একটি সি # সংস্করণ এখানে দেওয়া হয়েছে , যা এই আরপিআই অধ্যাপক থেকে এসেছে । নোট করুন যে আরপিআই উত্স থেকে কোড ব্যবহারের জন্য অ্যাট্রিবিউশন প্রয়োজন।

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

public bool IsPointInPolygon( Point p, Point[] polygon )
{
    double minX = polygon[ 0 ].X;
    double maxX = polygon[ 0 ].X;
    double minY = polygon[ 0 ].Y;
    double maxY = polygon[ 0 ].Y;
    for ( int i = 1 ; i < polygon.Length ; i++ )
    {
        Point q = polygon[ i ];
        minX = Math.Min( q.X, minX );
        maxX = Math.Max( q.X, maxX );
        minY = Math.Min( q.Y, minY );
        maxY = Math.Max( q.Y, maxY );
    }

    if ( p.X < minX || p.X > maxX || p.Y < minY || p.Y > maxY )
    {
        return false;
    }

    // https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html
    bool inside = false;
    for ( int i = 0, j = polygon.Length - 1 ; i < polygon.Length ; j = i++ )
    {
        if ( ( polygon[ i ].Y > p.Y ) != ( polygon[ j ].Y > p.Y ) &&
             p.X < ( polygon[ j ].X - polygon[ i ].X ) * ( p.Y - polygon[ i ].Y ) / ( polygon[ j ].Y - polygon[ i ].Y ) + polygon[ i ].X )
        {
            inside = !inside;
        }
    }

    return inside;
}

5
দুর্দান্ত কাজ করে, ধন্যবাদ, আমি জাভাস্ক্রিপ্টে রূপান্তর করেছি। stackoverflow.com/questions/217578/...
ফিলিপ Lenssen

2
এটি গ্রাফিকসপথ ব্যবহারের চেয়ে 1000x দ্রুত। সীমানা বাক্স চেকটি ফাংশনটি প্রায় 70% ধীর করে দেয়।
জেমস ব্রাউন 3

কেবল গ্রাফিকসপথই নয়। আইসভিজিবল () বেশ ধীরে ধীরে তবে 0.01f রেঞ্জের সাথে খুব ছোট বহুভুজগুলির সাথেও এটি ভাল কাজ করে না
এনডিপেন্ডের দল থেকে প্যাট্রিক

50

নির্গের পদ্ধতির উপর ভিত্তি করে এম। কাট্জের উত্তরের একটি জাভাস্ক্রিপ্ট বৈকল্পিক:

function pointIsInPoly(p, polygon) {
    var isInside = false;
    var minX = polygon[0].x, maxX = polygon[0].x;
    var minY = polygon[0].y, maxY = polygon[0].y;
    for (var n = 1; n < polygon.length; n++) {
        var q = polygon[n];
        minX = Math.min(q.x, minX);
        maxX = Math.max(q.x, maxX);
        minY = Math.min(q.y, minY);
        maxY = Math.max(q.y, maxY);
    }

    if (p.x < minX || p.x > maxX || p.y < minY || p.y > maxY) {
        return false;
    }

    var i = 0, j = polygon.length - 1;
    for (i, j; i < polygon.length; j = i++) {
        if ( (polygon[i].y > p.y) != (polygon[j].y > p.y) &&
                p.x < (polygon[j].x - polygon[i].x) * (p.y - polygon[i].y) / (polygon[j].y - polygon[i].y) + polygon[i].x ) {
            isInside = !isInside;
        }
    }

    return isInside;
}

32

পয়েন্ট পি এবং প্রতিটি বহুভুজ apices এর মধ্যবর্তী কোণগুলির ওরিয়েন্টড সমষ্টিটি গণনা করুন। যদি মোট ওরিয়েন্টেড কোণটি 360 ডিগ্রি হয় তবে বিন্দুটি ভিতরে রয়েছে। যদি মোট 0 হয় তবে বিন্দুটি বাইরে।

আমি এই পদ্ধতিটি আরও ভাল পছন্দ করি কারণ এটি আরও দৃust় এবং সংখ্যার নির্ভুলতার উপর কম নির্ভরশীল।

ছেদগুলির সংখ্যার সমানতা গণনা করার পদ্ধতিগুলি সীমিত কারণ আপনি ছেদ সংখ্যার গণনার সময় একটি শীর্ষকে 'হিট' করতে পারেন।

সম্পাদনা: দ্য ওয়ে, এই পদ্ধতিটি অবতল এবং উত্তল বহুভুজগুলির সাথে কাজ করে।

সম্পাদনা: আমি সম্প্রতি এই বিষয়টিতে একটি সম্পূর্ণ উইকিপিডিয়া নিবন্ধ পেয়েছি ।


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

2
@ ড্যারেনডাব্লু: প্রতি ভার্টেক্সে কেবল একটি একো; অন্যদিকে, এই অ্যালগরিদমটি সিমডে প্রয়োগ করা সবচেয়ে সহজ হওয়া উচিত কারণ এর কোনও শাখা নেই।
জ্যাস্পার বেকার্স

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

2
"পয়েন্ট ইজ দুর" কেস সমাধান করতে প্রথমে বাউন্ডিং বক্স চেক ব্যবহার করুন। ট্রিগের জন্য, আপনি পূর্বজাত টেবিলগুলি ব্যবহার করতে পারেন।
জেএম

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

24

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

এক্স টার্গেট পয়েন্ট হতে দিন। অ্যারে [0, 1, .... n] ক্ষেত্রের সমস্ত পয়েন্ট হতে দিন। একটি লাইন দিয়ে প্রতিটি সীমানা বিন্দুর সাথে লক্ষ্য বিন্দুটি সংযুক্ত করুন। টার্গেট পয়েন্টটি যদি এই অঞ্চলের অভ্যন্তরে থাকে। সমস্ত কোণগুলির যোগফল 360 ডিগ্রি হবে। কোণ না থাকলে 360 এর কম হবে than

ধারণাটির প্রাথমিক বোঝার জন্য এই চিত্রটি দেখুন: এখানে চিত্র বর্ণনা লিখুন

আমার অ্যালগরিদম ধরেছে ঘড়ির কাঁটার দিকটি ইতিবাচক দিক। এখানে একটি সম্ভাব্য ইনপুট দেওয়া হয়েছে:

[[-122.402015, 48.225216], [-117.032049, 48.999931], [-116.919132, 45.995175], [-124.079107, 46.267259], [-124.717175, 48.377557], [-122.92315, 47.047963], [-122.402015, 48.225216]]

নীচে পাইথন কোড যা ধারণাটি কার্যকর করে:

def isInside(self, border, target):
degree = 0
for i in range(len(border) - 1):
    a = border[i]
    b = border[i + 1]

    # calculate distance of vector
    A = getDistance(a[0], a[1], b[0], b[1]);
    B = getDistance(target[0], target[1], a[0], a[1])
    C = getDistance(target[0], target[1], b[0], b[1])

    # calculate direction of vector
    ta_x = a[0] - target[0]
    ta_y = a[1] - target[1]
    tb_x = b[0] - target[0]
    tb_y = b[1] - target[1]

    cross = tb_y * ta_x - tb_x * ta_y
    clockwise = cross < 0

    # calculate sum of angles
    if(clockwise):
        degree = degree + math.degrees(math.acos((B * B + C * C - A * A) / (2.0 * B * C)))
    else:
        degree = degree - math.degrees(math.acos((B * B + C * C - A * A) / (2.0 * B * C)))

if(abs(round(degree) - 360) <= 3):
    return True
return False

21

এরিক হেইন্সের নিবন্ধ bobobobo দ্বারা উদাহৃত সত্যিই চমৎকার। বিশেষত আকর্ষণীয় হ'ল অ্যালগরিদমের পারফরম্যান্সের তুলনা করার টেবিলগুলি; অন্যের তুলনায় কোণ সমষ্টি পদ্ধতিটি খুব খারাপ is এছাড়াও মজার বিষয় হ'ল বহুভুজকে "ইন" এবং "আউট" সেক্টরে আরও উপ-বিভাজন করার জন্য লুকিং গ্রিড ব্যবহার করার মতো অপ্টিমাইজেশনগুলি> 1000 টি পক্ষের বহুভুজগুলিতেও পরীক্ষাকে অবিশ্বাস্যভাবে দ্রুততর করে তুলতে পারে।

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

যাইহোক, এরিড হেইনিসের নিবন্ধ থেকে আগ্রহের জন্য, এলোমেলো বহুভুজগুলির উপর পরীক্ষা করার জন্য এখানে পারফরম্যান্সের একটি সারণী রয়েছে।

                       number of edges per polygon
                         3       4      10      100    1000
MacMartin               2.9     3.2     5.9     50.6    485
Crossings               3.1     3.4     6.8     60.0    624
Triangle Fan+edge sort  1.1     1.8     6.5     77.6    787
Triangle Fan            1.2     2.1     7.3     85.4    865
Barycentric             2.1     3.8    13.8    160.7   1665
Angle Summation        56.2    70.4   153.6   1403.8  14693

Grid (100x100)          1.5     1.5     1.6      2.1      9.8
Grid (20x20)            1.7     1.7     1.9      5.7     42.2
Bins (100)              1.8     1.9     2.7     15.1    117
Bins (20)               2.1     2.2     3.7     26.3    278

11

উত্তরের উত্তরটির দ্রুততম সংস্করণ :

extension CGPoint {
    func isInsidePolygon(vertices: [CGPoint]) -> Bool {
        guard !vertices.isEmpty else { return false }
        var j = vertices.last!, c = false
        for i in vertices {
            let a = (i.y > y) != (j.y > y)
            let b = (x < (j.x - i.x) * (y - i.y) / (j.y - i.y) + i.x)
            if a && b { c = !c }
            j = i
        }
        return c
    }
}

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

11

সত্যিই নির্গ পোস্ট করা সমাধান এবং বোবোবোবো সম্পাদিত পছন্দ করুন like আমি কেবল এটি জাভাস্ক্রিপ্ট বান্ধব এবং আমার ব্যবহারের জন্য আরও একটু সুস্পষ্টভাবে তৈরি করেছি:

function insidePoly(poly, pointx, pointy) {
    var i, j;
    var inside = false;
    for (i = 0, j = poly.length - 1; i < poly.length; j = i++) {
        if(((poly[i].y > pointy) != (poly[j].y > pointy)) && (pointx < (poly[j].x-poly[i].x) * (pointy-poly[i].y) / (poly[j].y-poly[i].y) + poly[i].x) ) inside = !inside;
    }
    return inside;
}

8

আমি যখন মাইকেল স্টোনব্রেকারের অধীনে একজন গবেষক ছিলাম তখন আমি এই পিছনে কিছু কাজ করেছি - আপনি কি জানেন যে প্রফেসর যিনি ইনগ্রেস , পোস্টগ্র্যাস এসকিউএল নিয়ে এসেছিলেন? ইত্যাদি

আমরা বুঝতে পারি যে দ্রুততম উপায়টি ছিল প্রথমে একটি বাউন্ডিং বাক্স করা কারণ এটি দুর্দান্ত। এটি যদি বাউন্ডিং বক্সের বাইরে থাকে তবে এটি বাইরে outside অন্যথায়, আপনি আরও কঠোর পরিশ্রম করেন ...

আপনি যদি একটি দুর্দান্ত অ্যালগরিদম চান তবে জিও কাজের জন্য ওপেন সোর্স প্রকল্প পোস্টগ্রেএসকিউএল উত্স কোডটি দেখুন ...

আমি উল্লেখ করতে চাই, আমরা কখনই ডান বনাম বাম হাতের বিষয়ে কোনও অন্তর্দৃষ্টি পাইনি ("ভিতরে" বনাম "বাইরে" সমস্যা হিসাবেও স্পষ্টতই ...


হালনাগাদ

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

এছাড়াও, আমার কাজটি "অন লাইনে" পরীক্ষার জন্য পৃথক ফাংশন ব্যবহার করে।

... যেহেতু কেউ জিজ্ঞাসা করেছেন: আমরা বুঝতে পেরেছিলাম যে যখন চৌম্বক সংখ্যাটি কিছু সংখ্যার অতিক্রম করে তখন বাউন্ডিং বক্স পরীক্ষাগুলি সেরা ছিল - প্রয়োজনে দীর্ঘতর পরীক্ষা করার আগে খুব দ্রুত পরীক্ষা করুন ... কেবলমাত্র একটি বেইন্ডিং বাক্স তৈরি করে তৈরি করা হয়েছে বৃহত্তম x, ক্ষুদ্রতম x, বৃহত্তম y এবং ক্ষুদ্রতম y এবং এগুলি একসাথে রেখে বাক্সের চারটি পয়েন্ট তৈরি করুন ...

তাদের অনুসরণকারীদের জন্য আরও একটি পরামর্শ: আমরা আমাদের আরও পরিশীলিত এবং "হালকা-ম্লান" কম্পিউটারটি একটি গ্রিডে সমস্ত সমতলের পজিটিভ পয়েন্টগুলিতে করেছিলাম এবং তারপরে পুনরায় "প্রকৃত" দ্রাঘিমাংশ / অক্ষাংশে প্রত্যাশা করি, ফলে সম্ভাব্য ত্রুটিগুলি এড়ানো যায় we যখন এক দ্রাঘিমাংশের 180 রেখাটি অতিক্রম করেছে এবং যখন মেরু অঞ্চলগুলি পরিচালনা করবেন তখন চারদিকে মোড়ানো। দুর্দান্ত কাজ করেছেন!


আমার যদি বাউন্ডিং বাক্সটি না থাকে তবে কী হবে? :)
স্কট এভারেনডেন

8
আপনি সহজেই একটি বাউন্ডিং বাক্স তৈরি করতে পারেন - এটি কেবলমাত্র চারটি পয়েন্ট যা সর্বশ্রেষ্ঠ এবং ন্যূনতম এক্স এবং সর্বাধিক এবং সর্বনিম্ন y ব্যবহার করে। আরো শীঘ্রই.
রিচার্ড টি

"... যখন দ্রাঘিমাংশের 180 রেখাটি অতিক্রম করা হয়েছে এবং মেরু অঞ্চলগুলি পরিচালনা করার সময় চারদিকে মোড়ানো সম্ভাব্য ত্রুটিগুলি এড়ানো হচ্ছে" " আপনি সম্ভবত আরও বিস্তারিতভাবে এটি বর্ণনা করতে পারেন? আমি মনে করি যে আমার বহুভুজকে 0 দ্রাঘিমাংশ অতিক্রম করার জন্য আমি কীভাবে সমস্ত কিছু "উপরে" সরিয়ে নিয়ে যেতে পারি তা বুঝতে পারি, তবে যে মেরুগুলির মধ্যে রয়েছে এমন বহুভুজগুলি কীভাবে পরিচালনা করতে হবে সে সম্পর্কে আমি পরিষ্কার নই ...
তিরিটি

6

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

অনেকগুলি অপ্টিমাইজেশনের মতো, এগুলি সাধারণ কেসের পরিবর্তে নির্দিষ্ট ভিত্তিতে হয় এবং একক ব্যবহারের পরিবর্তে সূক্ষ্ম সময়ের ভিত্তিতে উপদান দেয় yield

এই ক্ষেত্রে কাজ করে, আমি জোস্ফ ও'রউর্কেস 'গণনা জ্যামিতি সি' আইএসবিএন 0-521-44034-3 এ পেয়েছি একটি দুর্দান্ত সহায়ক হতে পেরেছি।


4

তুচ্ছ সমাধানটি হ'ল বহুভুজকে ত্রিভুজগুলিতে বিভক্ত করা এবং এখানে বর্ণিত ত্রিভুজগুলিকে পরীক্ষা করতে হবে

যদি আপনার বহুভুজটি কনভেক্স হয় তবে এর চেয়ে আরও ভাল উপায় থাকতে পারে। বহুভুজকে অসীম রেখার সংগ্রহ হিসাবে দেখুন Look প্রতিটি লাইন স্পেসকে দুটি ভাগে ভাগ করে। প্রতিটি পয়েন্টের জন্য এটি একদিকে বা লাইনের অন্য দিকে থাকলে তা বলা সহজ। যদি কোনও বিন্দু সমস্ত লাইনের একই দিকে থাকে তবে এটি বহুভুজের অভ্যন্তরে।


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

1
এই বক্ররেখার উপর কোন রেফারেন্স পেয়েছেন?
শুশ করুন

আমি খুব বক্রতা জন্য একটি রেফ চাই।
জোয়েল

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

4

আমি বুঝতে পারি যে এটি পুরানো, তবে এখানে কোকোয় প্রয়োগ করা একটি রে কাস্টিং অ্যালগরিদম, যদি কেউ আগ্রহী হন interested নিশ্চিত না যে এটি কাজ করার সবচেয়ে কার্যকর উপায়, তবে এটি কাউকে সাহায্য করতে পারে।

- (BOOL)shape:(NSBezierPath *)path containsPoint:(NSPoint)point
{
    NSBezierPath *currentPath = [path bezierPathByFlatteningPath];
    BOOL result;
    float aggregateX = 0; //I use these to calculate the centroid of the shape
    float aggregateY = 0;
    NSPoint firstPoint[1];
    [currentPath elementAtIndex:0 associatedPoints:firstPoint];
    float olderX = firstPoint[0].x;
    float olderY = firstPoint[0].y;
    NSPoint interPoint;
    int noOfIntersections = 0;

    for (int n = 0; n < [currentPath elementCount]; n++) {
        NSPoint points[1];
        [currentPath elementAtIndex:n associatedPoints:points];
        aggregateX += points[0].x;
        aggregateY += points[0].y;
    }

    for (int n = 0; n < [currentPath elementCount]; n++) {
        NSPoint points[1];

        [currentPath elementAtIndex:n associatedPoints:points];
        //line equations in Ax + By = C form
        float _A_FOO = (aggregateY/[currentPath elementCount]) - point.y;  
        float _B_FOO = point.x - (aggregateX/[currentPath elementCount]);
        float _C_FOO = (_A_FOO * point.x) + (_B_FOO * point.y);

        float _A_BAR = olderY - points[0].y;
        float _B_BAR = points[0].x - olderX;
        float _C_BAR = (_A_BAR * olderX) + (_B_BAR * olderY);

        float det = (_A_FOO * _B_BAR) - (_A_BAR * _B_FOO);
        if (det != 0) {
            //intersection points with the edges
            float xIntersectionPoint = ((_B_BAR * _C_FOO) - (_B_FOO * _C_BAR)) / det;
            float yIntersectionPoint = ((_A_FOO * _C_BAR) - (_A_BAR * _C_FOO)) / det;
            interPoint = NSMakePoint(xIntersectionPoint, yIntersectionPoint);
            if (olderX <= points[0].x) {
                //doesn't matter in which direction the ray goes, so I send it right-ward.
                if ((interPoint.x >= olderX && interPoint.x <= points[0].x) && (interPoint.x > point.x)) {  
                    noOfIntersections++;
                }
            } else {
                if ((interPoint.x >= points[0].x && interPoint.x <= olderX) && (interPoint.x > point.x)) {
                     noOfIntersections++;
                } 
            }
        }
        olderX = points[0].x;
        olderY = points[0].y;
    }
    if (noOfIntersections % 2 == 0) {
        result = FALSE;
    } else {
        result = TRUE;
    }
    return result;
}

5
মনে রাখবেন যে আপনি যদি কোকোতে সত্যই এটি করে থাকেন তবে আপনি [এনএসবেজারপথ রয়েছে পয়েন্টপয়েন্ট:] পদ্ধতিটি ব্যবহার করতে পারেন।
টমাসডাব্লু

4

পরীক্ষার পয়েন্টগুলির জন্য নমুনা পদ্ধতি সহ নীরগের উত্তরের ওবজে-সি সংস্করণ। নির্গ এর উত্তর আমার পক্ষে ভাল কাজ করেছে।

- (BOOL)isPointInPolygon:(NSArray *)vertices point:(CGPoint)test {
    NSUInteger nvert = [vertices count];
    NSInteger i, j, c = 0;
    CGPoint verti, vertj;

    for (i = 0, j = nvert-1; i < nvert; j = i++) {
        verti = [(NSValue *)[vertices objectAtIndex:i] CGPointValue];
        vertj = [(NSValue *)[vertices objectAtIndex:j] CGPointValue];
        if (( (verti.y > test.y) != (vertj.y > test.y) ) &&
        ( test.x < ( vertj.x - verti.x ) * ( test.y - verti.y ) / ( vertj.y - verti.y ) + verti.x) )
            c = !c;
    }

    return (c ? YES : NO);
}

- (void)testPoint {

    NSArray *polygonVertices = [NSArray arrayWithObjects:
        [NSValue valueWithCGPoint:CGPointMake(13.5, 41.5)],
        [NSValue valueWithCGPoint:CGPointMake(42.5, 56.5)],
        [NSValue valueWithCGPoint:CGPointMake(39.5, 69.5)],
        [NSValue valueWithCGPoint:CGPointMake(42.5, 84.5)],
        [NSValue valueWithCGPoint:CGPointMake(13.5, 100.0)],
        [NSValue valueWithCGPoint:CGPointMake(6.0, 70.5)],
        nil
    ];

    CGPoint tappedPoint = CGPointMake(23.0, 70.0);

    if ([self isPointInPolygon:polygonVertices point:tappedPoint]) {
        NSLog(@"YES");
    } else {
        NSLog(@"NO");
    }
}

নমুনা বহুভুজ


2
অবশ্যই, অবজেক্টিভ-সিতে CGPathContainsPoint()আপনার বন্ধু।
জেভ আইজেনবার্গ

@ জাভেইজেনবার্গ কিন্তু এটি খুব সহজ হবে! নোটের জন্য ধন্যবাদ। আমি কেন একটি কাস্টম সমাধান ব্যবহার করেছি তা দেখার জন্য আমি এই প্রকল্পটি কোনও এক সময় খনন করব। আমি সম্ভবত সম্পর্কে জানেন নাCGPathContainsPoint()
জন

4

কোনও সমস্যার ইন্ডাকটিভ সংজ্ঞা ব্যতিরেকে সুন্দর কিছু আর নেই। সম্পূর্ণতার জন্য এখানে আপনার কাছে প্রোলগের একটি সংস্করণ রয়েছে যা রে কাস্টিংয়ের পিছনে চিন্তাভাবনাগুলিও স্পষ্ট করতে পারে :

Http://www.ecse.rpi.edu/ Homepages/wrf/Research/Short_Notes/pnpoly.html- তে সরলতা অ্যালগরিদমের অনুকরণের ভিত্তিতে

কিছু সহায়ক ভবিষ্যদ্বাণী করেছেন:

exor(A,B):- \+A,B;A,\+B.
in_range(Coordinate,CA,CB) :- exor((CA>Coordinate),(CB>Coordinate)).

inside(false).
inside(_,[_|[]]).
inside(X:Y, [X1:Y1,X2:Y2|R]) :- in_range(Y,Y1,Y2), X > ( ((X2-X1)*(Y-Y1))/(Y2-Y1) +      X1),toggle_ray, inside(X:Y, [X2:Y2|R]); inside(X:Y, [X2:Y2|R]).

get_line(_,_,[]).
get_line([XA:YA,XB:YB],[X1:Y1,X2:Y2|R]):- [XA:YA,XB:YB]=[X1:Y1,X2:Y2]; get_line([XA:YA,XB:YB],[X2:Y2|R]).

2 পয়েন্ট A এবং B (রেখা (A, B)) দেওয়া রেখার সমীকরণটি হ'ল:

                    (YB-YA)
           Y - YA = ------- * (X - XA) 
                    (XB-YB) 

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

               (XB-XA)
           X < ------- * (Y - YA) + XA
               (YB-YA) 

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

is_left_half_plane(_,[],[],_).
is_left_half_plane(X:Y,[XA:YA,XB:YB], [[X1:Y1,X2:Y2]|R], Test) :- [XA:YA, XB:YB] =  [X1:Y1, X2:Y2], call(Test, X , (((XB - XA) * (Y - YA)) / (YB - YA) + XA)); 
                                                        is_left_half_plane(X:Y, [XA:YA, XB:YB], R, Test).

in_y_range_at_poly(Y,[XA:YA,XB:YB],Polygon) :- get_line([XA:YA,XB:YB],Polygon),  in_range(Y,YA,YB).
all_in_range(Coordinate,Polygon,Lines) :- aggregate(bag(Line),    in_y_range_at_poly(Coordinate,Line,Polygon), Lines).

traverses_ray(X:Y, Lines, Count) :- aggregate(bag(Line), is_left_half_plane(X:Y, Line, Lines, <), IntersectingLines), length(IntersectingLines, Count).

% This is the entry point predicate
inside_poly(X:Y,Polygon,Answer) :- all_in_range(Y,Polygon,Lines), traverses_ray(X:Y, Lines, Count), (1 is mod(Count,2)->Answer=inside;Answer=outside).

3

সি # এর নীরগের উত্তরটির সংস্করণটি এখানে রয়েছে: আমি কেবল কোডটি ভাগ করব। এটি কারও কিছু সময় সাশ্রয় করতে পারে।

public static bool IsPointInPolygon(IList<Point> polygon, Point testPoint) {
            bool result = false;
            int j = polygon.Count() - 1;
            for (int i = 0; i < polygon.Count(); i++) {
                if (polygon[i].Y < testPoint.Y && polygon[j].Y >= testPoint.Y || polygon[j].Y < testPoint.Y && polygon[i].Y >= testPoint.Y) {
                    if (polygon[i].X + (testPoint.Y - polygon[i].Y) / (polygon[j].Y - polygon[i].Y) * (polygon[j].X - polygon[i].X) < testPoint.X) {
                        result = !result;
                    }
                }
                j = i;
            }
            return result;
        }

এটি বেশিরভাগ ক্ষেত্রে কাজ করে তবে এটি ভুল এবং সর্বদা সঠিকভাবে কাজ করে না! এম ক্যাটজ থেকে সমাধানটি ব্যবহার করুন যা সঠিক
লুকাশ হানাসেক

3

জাভা সংস্করণ:

public class Geocode {
    private float latitude;
    private float longitude;

    public Geocode() {
    }

    public Geocode(float latitude, float longitude) {
        this.latitude = latitude;
        this.longitude = longitude;
    }

    public float getLatitude() {
        return latitude;
    }

    public void setLatitude(float latitude) {
        this.latitude = latitude;
    }

    public float getLongitude() {
        return longitude;
    }

    public void setLongitude(float longitude) {
        this.longitude = longitude;
    }
}

public class GeoPolygon {
    private ArrayList<Geocode> points;

    public GeoPolygon() {
        this.points = new ArrayList<Geocode>();
    }

    public GeoPolygon(ArrayList<Geocode> points) {
        this.points = points;
    }

    public GeoPolygon add(Geocode geo) {
        points.add(geo);
        return this;
    }

    public boolean inside(Geocode geo) {
        int i, j;
        boolean c = false;
        for (i = 0, j = points.size() - 1; i < points.size(); j = i++) {
            if (((points.get(i).getLongitude() > geo.getLongitude()) != (points.get(j).getLongitude() > geo.getLongitude())) &&
                    (geo.getLatitude() < (points.get(j).getLatitude() - points.get(i).getLatitude()) * (geo.getLongitude() - points.get(i).getLongitude()) / (points.get(j).getLongitude() - points.get(i).getLongitude()) + points.get(i).getLatitude()))
                c = !c;
        }
        return c;
    }

}

2

। নেট বন্দর:

    static void Main(string[] args)
    {

        Console.Write("Hola");
        List<double> vertx = new List<double>();
        List<double> verty = new List<double>();

        int i, j, c = 0;

        vertx.Add(1);
        vertx.Add(2);
        vertx.Add(1);
        vertx.Add(4);
        vertx.Add(4);
        vertx.Add(1);

        verty.Add(1);
        verty.Add(2);
        verty.Add(4);
        verty.Add(4);
        verty.Add(1);
        verty.Add(1);

        int nvert = 6;  //Vértices del poligono

        double testx = 2;
        double testy = 5;


        for (i = 0, j = nvert - 1; i < nvert; j = i++)
        {
            if (((verty[i] > testy) != (verty[j] > testy)) &&
             (testx < (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + vertx[i]))
                c = 1;
        }
    }

2

ভিবিএ সংস্করণ:

দ্রষ্টব্য: মনে রাখবেন যে যদি আপনার বহুভুজটি মানচিত্রের মধ্যে এমন একটি অঞ্চল থাকে যেটি X / Y (অক্ষাংশ = ওয়াই, দ্রাঘিমাংশ = এক্স) এর বিপরীতে অক্ষাংশ / দ্রাঘিমাংশ Y / X মান হয় তবে আমি বুঝতে পেরেছি backতিহাসিক জাল দ্রাঘিমাংশ একটি পরিমাপ ছিল না।

ক্লাস মডিউল: নিয়োগ করুন

Private pXValue As Double
Private pYValue As Double

'''''X Value Property'''''

Public Property Get X() As Double
    X = pXValue
End Property

Public Property Let X(Value As Double)
    pXValue = Value
End Property

'''''Y Value Property'''''

Public Property Get Y() As Double
    Y = pYValue
End Property

Public Property Let Y(Value As Double)
    pYValue = Value
End Property

মডিউল:

Public Function isPointInPolygon(p As CPoint, polygon() As CPoint) As Boolean

    Dim i As Integer
    Dim j As Integer
    Dim q As Object
    Dim minX As Double
    Dim maxX As Double
    Dim minY As Double
    Dim maxY As Double
    minX = polygon(0).X
    maxX = polygon(0).X
    minY = polygon(0).Y
    maxY = polygon(0).Y

    For i = 1 To UBound(polygon)
        Set q = polygon(i)
        minX = vbMin(q.X, minX)
        maxX = vbMax(q.X, maxX)
        minY = vbMin(q.Y, minY)
        maxY = vbMax(q.Y, maxY)
    Next i

    If p.X < minX Or p.X > maxX Or p.Y < minY Or p.Y > maxY Then
        isPointInPolygon = False
        Exit Function
    End If


    ' SOURCE: http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html

    isPointInPolygon = False
    i = 0
    j = UBound(polygon)

    Do While i < UBound(polygon) + 1
        If (polygon(i).Y > p.Y) Then
            If (polygon(j).Y < p.Y) Then
                If p.X < (polygon(j).X - polygon(i).X) * (p.Y - polygon(i).Y) / (polygon(j).Y - polygon(i).Y) + polygon(i).X Then
                    isPointInPolygon = True
                    Exit Function
                End If
            End If
        ElseIf (polygon(i).Y < p.Y) Then
            If (polygon(j).Y > p.Y) Then
                If p.X < (polygon(j).X - polygon(i).X) * (p.Y - polygon(i).Y) / (polygon(j).Y - polygon(i).Y) + polygon(i).X Then
                    isPointInPolygon = True
                    Exit Function
                End If
            End If
        End If
        j = i
        i = i + 1
    Loop   
End Function

Function vbMax(n1, n2) As Double
    vbMax = IIf(n1 > n2, n1, n2)
End Function

Function vbMin(n1, n2) As Double
    vbMin = IIf(n1 > n2, n2, n1)
End Function


Sub TestPointInPolygon()

    Dim i As Integer
    Dim InPolygon As Boolean

'   MARKER Object
    Dim p As CPoint
    Set p = New CPoint
    p.X = <ENTER X VALUE HERE>
    p.Y = <ENTER Y VALUE HERE>

'   POLYGON OBJECT
    Dim polygon() As CPoint
    ReDim polygon(<ENTER VALUE HERE>) 'Amount of vertices in polygon - 1
    For i = 0 To <ENTER VALUE HERE> 'Same value as above
       Set polygon(i) = New CPoint
       polygon(i).X = <ASSIGN X VALUE HERE> 'Source a list of values that can be looped through
       polgyon(i).Y = <ASSIGN Y VALUE HERE> 'Source a list of values that can be looped through
    Next i

    InPolygon = isPointInPolygon(p, polygon)
    MsgBox InPolygon

End Sub

2

আমি একটি পাইথন বাস্তবায়ন করেছি nirg এর C ++ কোড :

ইনপুট

  • বাউন্ডিং_পয়েন্টস: বহুভুজ তৈরি করে এমন নোড
  • সীমানা_বক্স_পজিশন: ফিল্টার করতে প্রার্থী পয়েন্ট। (আমার বাস্তবায়নে বাউন্ডিং বক্স থেকে তৈরি করা হয়েছে।

    (ইনপুটগুলি ফর্ম্যাটে টিপলগুলির তালিকা [(xcord, ycord), ...]:)

রিটার্নস

  • বহুভুজের ভিতরে থাকা সমস্ত পয়েন্ট।
def polygon_ray_casting(self, bounding_points, bounding_box_positions):
    # Arrays containing the x- and y-coordinates of the polygon's vertices.
    vertx = [point[0] for point in bounding_points]
    verty = [point[1] for point in bounding_points]
    # Number of vertices in the polygon
    nvert = len(bounding_points)
    # Points that are inside
    points_inside = []

    # For every candidate position within the bounding box
    for idx, pos in enumerate(bounding_box_positions):
        testx, testy = (pos[0], pos[1])
        c = 0
        for i in range(0, nvert):
            j = i - 1 if i != 0 else nvert - 1
            if( ((verty[i] > testy ) != (verty[j] > testy))   and
                    (testx < (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + vertx[i]) ):
                c += 1
        # If odd, that means that we are inside the polygon
        if c % 2 == 1: 
            points_inside.append(pos)


    return points_inside

আবার, ধারণাটি এখান থেকে নেওয়া হয়েছে


2

অবাক বিস্মিত কেউ এটিকে আগে আনেনি, তবে ব্যবহারবাদীদের জন্য একটি ডাটাবেসের প্রয়োজন: মঙ্গোডিবির এই সহ জিও অনুসন্ধানগুলির জন্য দুর্দান্ত সমর্থন রয়েছে।

আপনি যা সন্ধান করছেন তা হ'ল:

db.neighborhoods.findOne ({জ্যামিতি: {$ geoIntersects: {$ জ্যামিতি: {প্রকার: "পয়েন্ট", স্থানাঙ্ক: ["দ্রাঘিমাংশ", "অক্ষাংশ"]}}}})

Neighborhoodsএটি হ'ল সংগ্রহ যা স্ট্যান্ডার্ড জিওজেসন ফর্ম্যাটে এক বা একাধিক বহুভুজ সঞ্চয় করে। যদি ক্যোয়ারী নাল ফেরায় তবে এটি ছেদ করা হবে না অন্যথায়।

এখানে খুব ভাল নথিভুক্ত করা হয়েছে: https://docs.mongodb.com/manual/tutorial/geospatial-tutorial/

330 অনিয়মিত বহুভুজ গ্রিডে শ্রেণিবদ্ধ 6,০০০ এরও বেশি পয়েন্টের জন্য পারফরম্যান্সটি এক মিনিটেরও কম ছিল এবং কোনও অপ্টিমাইজেশন ছাড়াই এবং স্ব স্ব বহুভুজ সহ নথি আপডেট করার সময় সহ এক মিনিটেরও কম ছিল।


1

সি এর বহুভুজ পরীক্ষার একটি বিন্দু যা রে-কাস্টিং ব্যবহার করে না। এবং এটি ওভারল্যাপিং অঞ্চলগুলির (স্ব-ছেদগুলি) কাজ করতে পারে, use_holesযুক্তিটি দেখুন।

/* math lib (defined below) */
static float dot_v2v2(const float a[2], const float b[2]);
static float angle_signed_v2v2(const float v1[2], const float v2[2]);
static void copy_v2_v2(float r[2], const float a[2]);

/* intersection function */
bool isect_point_poly_v2(const float pt[2], const float verts[][2], const unsigned int nr,
                         const bool use_holes)
{
    /* we do the angle rule, define that all added angles should be about zero or (2 * PI) */
    float angletot = 0.0;
    float fp1[2], fp2[2];
    unsigned int i;
    const float *p1, *p2;

    p1 = verts[nr - 1];

    /* first vector */
    fp1[0] = p1[0] - pt[0];
    fp1[1] = p1[1] - pt[1];

    for (i = 0; i < nr; i++) {
        p2 = verts[i];

        /* second vector */
        fp2[0] = p2[0] - pt[0];
        fp2[1] = p2[1] - pt[1];

        /* dot and angle and cross */
        angletot += angle_signed_v2v2(fp1, fp2);

        /* circulate */
        copy_v2_v2(fp1, fp2);
        p1 = p2;
    }

    angletot = fabsf(angletot);
    if (use_holes) {
        const float nested = floorf((angletot / (float)(M_PI * 2.0)) + 0.00001f);
        angletot -= nested * (float)(M_PI * 2.0);
        return (angletot > 4.0f) != ((int)nested % 2);
    }
    else {
        return (angletot > 4.0f);
    }
}

/* math lib */

static float dot_v2v2(const float a[2], const float b[2])
{
    return a[0] * b[0] + a[1] * b[1];
}

static float angle_signed_v2v2(const float v1[2], const float v2[2])
{
    const float perp_dot = (v1[1] * v2[0]) - (v1[0] * v2[1]);
    return atan2f(perp_dot, dot_v2v2(v1, v2));
}

static void copy_v2_v2(float r[2], const float a[2])
{
    r[0] = a[0];
    r[1] = a[1];
}

দ্রষ্টব্য: এটি একটি atan2fস্বল্পতর সর্বোত্তম পদ্ধতিগুলির মধ্যে এটির জন্য প্রচুর কল অন্তর্ভুক্ত রয়েছে তবে এটি থ্রেডটি পড়তে বিকাশকারীদের পক্ষে আগ্রহী হতে পারে (আমার পরীক্ষাগুলিতে লাইন ছেদ পদ্ধতিটি ব্যবহার করে এর ~ 23x ধীর করে))


0

বহুভুজের উপর আঘাত হিট সনাক্ত করার জন্য আমাদের দুটি জিনিস পরীক্ষা করতে হবে:

  1. পয়েন্ট যদি বহুভুজ অঞ্চলের ভিতরে থাকে। (রে-কাস্টিং অ্যালগরিদম দ্বারা সম্পন্ন করা যেতে পারে)
  2. যদি পয়েন্টটি বহুভুজের সীমানায় থাকে (একই অ্যালগরিদম দ্বারা সম্পন্ন করা যায় যা পললাইন (লাইন) এ পয়েন্ট সনাক্তকরণের জন্য ব্যবহৃত হয়)।

0

রে কাস্টিং অ্যালগরিদমে নিম্নলিখিত বিশেষ ক্ষেত্রে মোকাবিলা করতে :

  1. রশ্মি বহুভুজের একটি দিককে ওভারল্যাপ করে।
  2. বিন্দুটি বহুভুজের অভ্যন্তরে এবং রশ্মি বহুভুজের একটি শীর্ষবিন্দু দিয়ে যায়।
  3. বিন্দুটি বহুভুজের বাইরে এবং রশ্মি বহুভুজের একটি কোণকে স্পর্শ করে।

কমপ্লেক্স বহুভুজের ভিতরে একটি পয়েন্ট রয়েছে কিনা তা নির্ধারণ করে দেখুন । নিবন্ধটি তাদের সমাধানের সহজ উপায় সরবরাহ করে যাতে উপরের কেসগুলির জন্য কোনও বিশেষ চিকিত্সার প্রয়োজন হয় না।


0

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

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

আমি জানি না যে যদি আপনার বহুভুজের ভিতরে কোনও গর্ত থাকে তবে কী হয় তবে আমার কাছে মনে হয় যে মূল ধারণাটি এই পরিস্থিতিতে মানিয়ে নিতে পারে

আপনি গণিত সম্প্রদায়ে প্রশ্নটি পোস্ট করতে পারেন। আমি বাজি ধরেছিলাম যে তাদের এটি করার এক মিলিয়ন উপায় রয়েছে


0

আপনি যদি জাভা-স্ক্রিপ্ট লাইব্রেরির সন্ধান করছেন তবে বহুভুজ শ্রেণীর জন্য একটি জাভাস্ক্রিপ্ট গুগল ম্যাপস ভি 3 এক্সটেনশান রয়েছে যাতে এটিতে কোনও বিন্দু রয়েছে কিনা তা সনাক্ত করতে পারে।

var polygon = new google.maps.Polygon([], "#000000", 1, 1, "#336699", 0.3);
var isWithinPolygon = polygon.containsLatLng(40, -90);

গুগল এক্সটেনশন গিথুব


0

ব্যবহার করার সময় (Qt 4.3+), যে কেউ QPolygon এর ফাংশন ধারণ পয়েন্ট ব্যবহার করতে পারে


0

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

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

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

http://geomalgorithms.com/a03-_inclusion.html


0

নীর্গ দ্বারা সমাধানের স্কেল সংস্করণ (অনুমান করা আবদ্ধ আয়তক্ষেত্রের প্রাক-চেক পৃথকভাবে সম্পন্ন করা হয়েছে):

def inside(p: Point, polygon: Array[Point], bounds: Bounds): Boolean = {

  val length = polygon.length

  @tailrec
  def oddIntersections(i: Int, j: Int, tracker: Boolean): Boolean = {
    if (i == length)
      tracker
    else {
      val intersects = (polygon(i).y > p.y) != (polygon(j).y > p.y) && p.x < (polygon(j).x - polygon(i).x) * (p.y - polygon(i).y) / (polygon(j).y - polygon(i).y) + polygon(i).x
      oddIntersections(i + 1, i, if (intersects) !tracker else tracker)
    }
  }

  oddIntersections(0, length - 1, tracker = false)
}

0

এখানে @nirg উত্তরের গোলং সংস্করণ রয়েছে (এম এম-কেটজ দ্বারা সি # কোড দ্বারা অনুপ্রাণিত)

func isPointInPolygon(polygon []point, testp point) bool {
    minX := polygon[0].X
    maxX := polygon[0].X
    minY := polygon[0].Y
    maxY := polygon[0].Y

    for _, p := range polygon {
        minX = min(p.X, minX)
        maxX = max(p.X, maxX)
        minY = min(p.Y, minY)
        maxY = max(p.Y, maxY)
    }

    if testp.X < minX || testp.X > maxX || testp.Y < minY || testp.Y > maxY {
        return false
    }

    inside := false
    j := len(polygon) - 1
    for i := 0; i < len(polygon); i++ {
        if (polygon[i].Y > testp.Y) != (polygon[j].Y > testp.Y) && testp.X < (polygon[j].X-polygon[i].X)*(testp.Y-polygon[i].Y)/(polygon[j].Y-polygon[i].Y)+polygon[i].X {
            inside = !inside
        }
        j = i
    }

    return inside
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.