হিট-টেস্টিংয়ে (উদাহরণস্বরূপ ) ব্যবহারের জন্য বহুভুজ অ্যালগরিদমের অভ্যন্তরে একটি দ্রুত 2D পয়েন্ট তৈরি করার চেষ্টা করছি Polygon.contains(p:Point)
। কার্যকর কৌশলগুলির জন্য পরামর্শগুলি প্রশংসা করা হবে।
হিট-টেস্টিংয়ে (উদাহরণস্বরূপ ) ব্যবহারের জন্য বহুভুজ অ্যালগরিদমের অভ্যন্তরে একটি দ্রুত 2D পয়েন্ট তৈরি করার চেষ্টা করছি Polygon.contains(p:Point)
। কার্যকর কৌশলগুলির জন্য পরামর্শগুলি প্রশংসা করা হবে।
উত্তর:
গ্রাফিক্সের জন্য, আমি পূর্ণসংখ্যার পছন্দ না করতাম। অনেকগুলি সিস্টেম ইউআই পেইন্টিংয়ের জন্য পূর্ণসংখ্যা ব্যবহার করে (পিক্সেলগুলি সর্বোপরি অন্তর্নিহিত) তবে ম্যাকোস উদাহরণস্বরূপ সমস্ত কিছুর জন্য ভাসমান ব্যবহার করে। ম্যাকোস কেবল পয়েন্টগুলিই জানে এবং একটি বিন্দু একটি পিক্সেলে অনুবাদ করতে পারে তবে মনিটরের রেজোলিউশনের উপর নির্ভর করে এটি অন্য কোনও ক্ষেত্রে অনুবাদ করতে পারে। রেটিনা স্ক্রিনে আধ পয়েন্ট (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/v1y1
v1x2/v1y2
v2x1/v2y1
v2x2/v2y2
YES
NO
YES
NO
COLLINEAR সম্পর্কে কি? এর অর্থ উভয় ভেক্টর একই সীমাহীন লাইনে অবস্থান করে, অবস্থান এবং দৈর্ঘ্যের উপর নির্ভর করে এগুলি একেবারে ছেদ করে না বা অবিরাম সংখ্যায় তারা ছেদ করে। আমি কীভাবে এই কেসটি পরিচালনা করব তা পুরোপুরি নিশ্চিত নই, আমি একে অন্যভাবে ছেদ হিসাবে গণনা করব না। ভাল, ভাসমান পয়েন্ট গোলাকার ত্রুটির কারণে এই কেসটি বাস্তবে বাস্তবে বিরল; আরও ভাল কোড সম্ভবত এটির পরিবর্তে এমন কোনও কিছুর == 0.0f
জন্য পরীক্ষা করবে না < epsilon
যেখানে অ্যাপসিলন বরং একটি ছোট সংখ্যা।
আপনার যদি বৃহত সংখ্যক পয়েন্ট পরীক্ষা করার দরকার হয় তবে আপনি বহুভুজ পক্ষের রৈখিক সমীকরণের স্ট্যান্ডার্ড ফর্মগুলিকে মেমরির মধ্যে রেখে অবশ্যই পুরো জিনিসটি কিছুটা গতি বাড়িয়ে তুলতে পারেন, সুতরাং আপনাকে প্রতিবার এগুলি পুনরায় গণনা করতে হবে না। এটি আপনাকে মেমোরিতে বহুভুজ পার্শ্বে প্রতি ভাসমান পয়েন্টের মানগুলি সংরক্ষণের পরিবর্তে প্রতিটি পরীক্ষায় দুটি ফ্লোটিং পয়েন্ট গুণ এবং তিনটি ভাসমান পয়েন্ট বিয়োগগুলি সংরক্ষণ করবে। এটি একটি সাধারণ মেমরি বনাম গণনার সময় বাণিজ্য বন্ধ।
সর্বশেষে তবে সর্বনিম্ন নয়: আপনি যদি সমস্যাটি সমাধান করতে 3 ডি হার্ডওয়্যার ব্যবহার করতে পারেন তবে একটি আকর্ষণীয় বিকল্প রয়েছে। আপনার জন্য জিপিইউকে সমস্ত কাজ করতে দিন। স্ক্রিনের বাইরে থাকা কোনও চিত্রের পৃষ্ঠ তৈরি করুন। এটি সম্পূর্ণরূপে রঙ কালো দিয়ে পূরণ করুন। এখন ওপেনজিএল বা ডাইরেক্ট 3 ডি আপনার বহুভুজকে আঁকুন (বা আপনার বহুভুজগুলির মধ্যেও যদি আপনি কেবল পরীক্ষা করতে চান তবে বিন্দুগুলির মধ্যে কোনওটির মধ্যে রয়েছে কিনা তবে আপনি কোনটির যত্ন নেন না) এবং বহুভুজ (গুলি) আলাদা দিয়ে পূরণ করুন রঙ, যেমন সাদা। কোন বিন্দু বহুভুজের মধ্যে রয়েছে কিনা তা পরীক্ষা করতে অঙ্কন পৃষ্ঠ থেকে এই বিন্দুর রঙ পান। এটি কেবল একটি ও (1) মেমরি আনয়ন।
অবশ্যই এই পদ্ধতিটি কেবলমাত্র ব্যবহারযোগ্য যদি আপনার অঙ্কনের পৃষ্ঠটি বিশাল হতে না হয়। যদি এটি জিপিইউ মেমরির সাথে ফিট না করতে পারে তবে এই পদ্ধতিটি সিপিইউ-তে করার চেয়ে ধীর। যদি এটি বিশাল হতে হয় এবং আপনার জিপিইউ আধুনিক ছায়া গো সমর্থন করে, আপনি এখনও GPU শ্যাডার হিসাবে উপরে প্রদর্শিত রশ্মির ingালাই প্রয়োগ করে GPU ব্যবহার করতে পারেন, যা একেবারেই সম্ভব। বহুবিধ সংখ্যা বা পরীক্ষার জন্য বৃহত সংখ্যক পয়েন্টের জন্য, এটি প্রদান করবে, কিছু জিপিইউ সমান্তরালে to৪ থেকে ২৫ 25 পয়েন্ট পরীক্ষা করতে সক্ষম হবে তা বিবেচনা করুন। তবে নোট করুন যে সিপিইউ থেকে জিপিইউ এবং পিছনে ডেটা স্থানান্তর সবসময় ব্যয়বহুল, সুতরাং কেবলমাত্র কয়েকটি বহুভুজের বিরুদ্ধে কয়েকটি পয়েন্ট পরীক্ষা করার জন্য যেখানে পয়েন্টগুলি বা বহুভুজগুলি গতিশীল এবং ঘন ঘন পরিবর্তিত হয়, জিপিইউ পদ্ধতির খুব কমই অর্থ প্রদান করা হবে বন্ধ।
আমি মনে করি নিম্নলিখিত কোডের টুকরোটি সেরা সমাধান ( এখান থেকে নেওয়া ):
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;
}
এটি উভয়ই সংক্ষিপ্ত এবং দক্ষ এবং উত্তল এবং অবতল বহুভুজের জন্য উভয়ই কাজ করে। পূর্বে প্রস্তাবিত হিসাবে, আপনার প্রথমে বাউন্ডিং আয়তক্ষেত্রটি পরীক্ষা করা উচিত এবং বহুভুজ গর্তগুলি আলাদাভাবে চিকিত্সা করা উচিত।
এর পিছনে ধারণাটি বেশ সহজ। লেখক এটিকে বর্ণনা করেছেন:
আমি পরীক্ষার বিন্দু থেকে অনুভূমিকভাবে একটি অর্ধ-অসীম রশ্মি চালিয়ে যাচ্ছি (এক্স, ফিক্সড y) বাড়িয়েছি এবং এটি কত প্রান্তটি অতিক্রম করে তা গণনা করছি। প্রতিটি ক্রসিংয়ে, রশ্মিটি ভিতরে এবং বাইরে স্যুইচ করে। একে জর্দান বাঁকানো উপপাদ্য বলা হয়।
ভেরিয়েবল সি প্রতিবার অনুভূমিক রশ্মিটি কোনও প্রান্ত অতিক্রম করে 0 থেকে 1 এবং 1 থেকে 0 থেকে স্যুইচ করছে। সুতরাং মূলত এটি নির্ধারিত প্রান্তগুলির সংখ্যাটি সমান বা বিজোড় কিনা তা খতিয়ে রাখছে। 0 এর অর্থ সম এবং 1 এর অর্থ বিজোড়।
verty[i]
এবং verty[j]
এর উভয় পাশে থাকে testy
, তাই তারা কখনই সমান হয় না।
নির্গের দেওয়া উত্তরের একটি সি # সংস্করণ এখানে দেওয়া হয়েছে , যা এই আরপিআই অধ্যাপক থেকে এসেছে । নোট করুন যে আরপিআই উত্স থেকে কোড ব্যবহারের জন্য অ্যাট্রিবিউশন প্রয়োজন।
শীর্ষে একটি বাউন্ডিং বক্স চেক যুক্ত করা হয়েছে। যাইহোক, জেমস ব্রাউন যেমন উল্লেখ করেছেন, মূল কোডটি বাউন্ডিং বক্সের চেক হিসাবে প্রায় তত দ্রুত, তাই বাউন্ডিং বক্স চেকটি সামগ্রিক ক্রিয়াকে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরেধীরে কমপ্লেক্সে যাবেন। । সুতরাং আপনি বাউন্ডিং বাক্সটি চেক আউট ছেড়ে যেতে পারেন, বা বিকল্প যদি আপনার বহুভুজগুলির সীমানা বাক্সগুলি প্রায়শই আকৃতি পরিবর্তন না করে তবে তা বন্ধ করে দেওয়া।
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;
}
নির্গের পদ্ধতির উপর ভিত্তি করে এম। কাট্জের উত্তরের একটি জাভাস্ক্রিপ্ট বৈকল্পিক:
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;
}
পয়েন্ট পি এবং প্রতিটি বহুভুজ apices এর মধ্যবর্তী কোণগুলির ওরিয়েন্টড সমষ্টিটি গণনা করুন। যদি মোট ওরিয়েন্টেড কোণটি 360 ডিগ্রি হয় তবে বিন্দুটি ভিতরে রয়েছে। যদি মোট 0 হয় তবে বিন্দুটি বাইরে।
আমি এই পদ্ধতিটি আরও ভাল পছন্দ করি কারণ এটি আরও দৃust় এবং সংখ্যার নির্ভুলতার উপর কম নির্ভরশীল।
ছেদগুলির সংখ্যার সমানতা গণনা করার পদ্ধতিগুলি সীমিত কারণ আপনি ছেদ সংখ্যার গণনার সময় একটি শীর্ষকে 'হিট' করতে পারেন।
সম্পাদনা: দ্য ওয়ে, এই পদ্ধতিটি অবতল এবং উত্তল বহুভুজগুলির সাথে কাজ করে।
সম্পাদনা: আমি সম্প্রতি এই বিষয়টিতে একটি সম্পূর্ণ উইকিপিডিয়া নিবন্ধ পেয়েছি ।
এই প্রশ্নটি তাই আকর্ষণীয়। আমার এই পোস্টের অন্যান্য উত্তরগুলির চেয়ে আলাদা একটি কার্যক্ষম ধারণা রয়েছে। লক্ষ্যটি ভিতরে বা বাইরে রয়েছে কিনা তা নির্ধারণের জন্য কোণগুলির সমষ্টিটি ব্যবহার করার ধারণা। বেটার হিসাবে পরিচিত সংখ্যা ঘুর ।
এক্স টার্গেট পয়েন্ট হতে দিন। অ্যারে [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
এরিক হেইন্সের নিবন্ধ 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
উত্তরের উত্তরটির দ্রুততম সংস্করণ :
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
}
}
সত্যিই নির্গ পোস্ট করা সমাধান এবং বোবোবোবো সম্পাদিত পছন্দ করুন 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;
}
আমি যখন মাইকেল স্টোনব্রেকারের অধীনে একজন গবেষক ছিলাম তখন আমি এই পিছনে কিছু কাজ করেছি - আপনি কি জানেন যে প্রফেসর যিনি ইনগ্রেস , পোস্টগ্র্যাস এসকিউএল নিয়ে এসেছিলেন? ইত্যাদি
আমরা বুঝতে পারি যে দ্রুততম উপায়টি ছিল প্রথমে একটি বাউন্ডিং বাক্স করা কারণ এটি দুর্দান্ত। এটি যদি বাউন্ডিং বক্সের বাইরে থাকে তবে এটি বাইরে outside অন্যথায়, আপনি আরও কঠোর পরিশ্রম করেন ...
আপনি যদি একটি দুর্দান্ত অ্যালগরিদম চান তবে জিও কাজের জন্য ওপেন সোর্স প্রকল্প পোস্টগ্রেএসকিউএল উত্স কোডটি দেখুন ...
আমি উল্লেখ করতে চাই, আমরা কখনই ডান বনাম বাম হাতের বিষয়ে কোনও অন্তর্দৃষ্টি পাইনি ("ভিতরে" বনাম "বাইরে" সমস্যা হিসাবেও স্পষ্টতই ...
হালনাগাদ
বিকেবির লিঙ্কটি বেশ কয়েকটি যুক্তিসঙ্গত অ্যালগরিদম সরবরাহ করেছিল। আমি আর্থ সায়েন্স সমস্যার উপর কাজ করছিলাম এবং তাই দ্রষ্টব্য / দ্রাঘিমাংশে কাজ করে এমন একটি সমাধানের প্রয়োজন ছিল এবং এতে হস্তক্ষেপের অদ্ভুত সমস্যা রয়েছে - ছোট অঞ্চলের ক্ষেত্র বা বৃহত্তর অঞ্চল? উত্তরটি হ'ল উল্লম্বের "দিকনির্দেশ" - এটি হয় বাম-হাত বা ডান হাতে এবং এইভাবে আপনি উভয় অঞ্চলকে "প্রদত্ত বহুভুজ" হিসাবে চিহ্নিত করতে পারেন। এর মতো, আমার কাজের সমাধানটিতে পৃষ্ঠায় তিনটি গণনা করা হয়েছে।
এছাড়াও, আমার কাজটি "অন লাইনে" পরীক্ষার জন্য পৃথক ফাংশন ব্যবহার করে।
... যেহেতু কেউ জিজ্ঞাসা করেছেন: আমরা বুঝতে পেরেছিলাম যে যখন চৌম্বক সংখ্যাটি কিছু সংখ্যার অতিক্রম করে তখন বাউন্ডিং বক্স পরীক্ষাগুলি সেরা ছিল - প্রয়োজনে দীর্ঘতর পরীক্ষা করার আগে খুব দ্রুত পরীক্ষা করুন ... কেবলমাত্র একটি বেইন্ডিং বাক্স তৈরি করে তৈরি করা হয়েছে বৃহত্তম x, ক্ষুদ্রতম x, বৃহত্তম y এবং ক্ষুদ্রতম y এবং এগুলি একসাথে রেখে বাক্সের চারটি পয়েন্ট তৈরি করুন ...
তাদের অনুসরণকারীদের জন্য আরও একটি পরামর্শ: আমরা আমাদের আরও পরিশীলিত এবং "হালকা-ম্লান" কম্পিউটারটি একটি গ্রিডে সমস্ত সমতলের পজিটিভ পয়েন্টগুলিতে করেছিলাম এবং তারপরে পুনরায় "প্রকৃত" দ্রাঘিমাংশ / অক্ষাংশে প্রত্যাশা করি, ফলে সম্ভাব্য ত্রুটিগুলি এড়ানো যায় we যখন এক দ্রাঘিমাংশের 180 রেখাটি অতিক্রম করেছে এবং যখন মেরু অঞ্চলগুলি পরিচালনা করবেন তখন চারদিকে মোড়ানো। দুর্দান্ত কাজ করেছেন!
ডেভিড সেগন্ডের উত্তর হ'ল স্ট্যান্ডার্ড সাধারণ উত্তর, এবং রিচার্ড টি'র সর্বাধিক সাধারণ অপ্টিমাইজেশন, যদিও থেরে অন্য কেউ নেই। অন্যান্য শক্তিশালী অপ্টিমাইজেশন কম সাধারণ সমাধানের উপর ভিত্তি করে। উদাহরণস্বরূপ, যদি আপনি প্রচুর পয়েন্ট সহ একই বহুভুজটি যাচাই করতে যাচ্ছেন, বহুভুজকে ট্রায়ানগুলেটেটিং জিনিসগুলিকে প্রচুর পরিমাণে গতি দিতে পারে কারণ সেখানে অনেকগুলি দ্রুত TIN অনুসন্ধানের অ্যালগরিদম রয়েছে। আরেকটি হ'ল যদি বহুভুজ এবং পয়েন্টগুলি কম রেজোলিউশনে সীমিত প্লেনে থাকে তবে একটি স্ক্রিন ডিসপ্লে বলুন, আপনি বহুভুজকে প্রদত্ত রঙে মেমরি ম্যাপযুক্ত ডিসপ্লে বাফারের উপর আঁকতে পারেন এবং প্রদত্ত পিক্সেলের রঙটি পরীক্ষা করে দেখতে পারেন কিনা it বহুভুজ মধ্যে।
অনেকগুলি অপ্টিমাইজেশনের মতো, এগুলি সাধারণ কেসের পরিবর্তে নির্দিষ্ট ভিত্তিতে হয় এবং একক ব্যবহারের পরিবর্তে সূক্ষ্ম সময়ের ভিত্তিতে উপদান দেয় yield
এই ক্ষেত্রে কাজ করে, আমি জোস্ফ ও'রউর্কেস 'গণনা জ্যামিতি সি' আইএসবিএন 0-521-44034-3 এ পেয়েছি একটি দুর্দান্ত সহায়ক হতে পেরেছি।
তুচ্ছ সমাধানটি হ'ল বহুভুজকে ত্রিভুজগুলিতে বিভক্ত করা এবং এখানে বর্ণিত ত্রিভুজগুলিকে পরীক্ষা করতে হবে
যদি আপনার বহুভুজটি কনভেক্স হয় তবে এর চেয়ে আরও ভাল উপায় থাকতে পারে। বহুভুজকে অসীম রেখার সংগ্রহ হিসাবে দেখুন Look প্রতিটি লাইন স্পেসকে দুটি ভাগে ভাগ করে। প্রতিটি পয়েন্টের জন্য এটি একদিকে বা লাইনের অন্য দিকে থাকলে তা বলা সহজ। যদি কোনও বিন্দু সমস্ত লাইনের একই দিকে থাকে তবে এটি বহুভুজের অভ্যন্তরে।
আমি বুঝতে পারি যে এটি পুরানো, তবে এখানে কোকোয় প্রয়োগ করা একটি রে কাস্টিং অ্যালগরিদম, যদি কেউ আগ্রহী হন 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;
}
পরীক্ষার পয়েন্টগুলির জন্য নমুনা পদ্ধতি সহ নীরগের উত্তরের ওবজে-সি সংস্করণ। নির্গ এর উত্তর আমার পক্ষে ভাল কাজ করেছে।
- (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");
}
}
CGPathContainsPoint()
আপনার বন্ধু।
CGPathContainsPoint()
কোনও সমস্যার ইন্ডাকটিভ সংজ্ঞা ব্যতিরেকে সুন্দর কিছু আর নেই। সম্পূর্ণতার জন্য এখানে আপনার কাছে প্রোলগের একটি সংস্করণ রয়েছে যা রে কাস্টিংয়ের পিছনে চিন্তাভাবনাগুলিও স্পষ্ট করতে পারে :
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).
সি # এর নীরগের উত্তরটির সংস্করণটি এখানে রয়েছে: আমি কেবল কোডটি ভাগ করব। এটি কারও কিছু সময় সাশ্রয় করতে পারে।
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;
}
জাভা সংস্করণ:
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;
}
}
। নেট বন্দর:
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;
}
}
ভিবিএ সংস্করণ:
দ্রষ্টব্য: মনে রাখবেন যে যদি আপনার বহুভুজটি মানচিত্রের মধ্যে এমন একটি অঞ্চল থাকে যেটি 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
আমি একটি পাইথন বাস্তবায়ন করেছি 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
অবাক বিস্মিত কেউ এটিকে আগে আনেনি, তবে ব্যবহারবাদীদের জন্য একটি ডাটাবেসের প্রয়োজন: মঙ্গোডিবির এই সহ জিও অনুসন্ধানগুলির জন্য দুর্দান্ত সমর্থন রয়েছে।
আপনি যা সন্ধান করছেন তা হ'ল:
db.neighborhoods.findOne ({জ্যামিতি: {$ geoIntersects: {$ জ্যামিতি: {প্রকার: "পয়েন্ট", স্থানাঙ্ক: ["দ্রাঘিমাংশ", "অক্ষাংশ"]}}}})
Neighborhoods
এটি হ'ল সংগ্রহ যা স্ট্যান্ডার্ড জিওজেসন ফর্ম্যাটে এক বা একাধিক বহুভুজ সঞ্চয় করে। যদি ক্যোয়ারী নাল ফেরায় তবে এটি ছেদ করা হবে না অন্যথায়।
এখানে খুব ভাল নথিভুক্ত করা হয়েছে: https://docs.mongodb.com/manual/tutorial/geospatial-tutorial/
330 অনিয়মিত বহুভুজ গ্রিডে শ্রেণিবদ্ধ 6,০০০ এরও বেশি পয়েন্টের জন্য পারফরম্যান্সটি এক মিনিটেরও কম ছিল এবং কোনও অপ্টিমাইজেশন ছাড়াই এবং স্ব স্ব বহুভুজ সহ নথি আপডেট করার সময় সহ এক মিনিটেরও কম ছিল।
সি এর বহুভুজ পরীক্ষার একটি বিন্দু যা রে-কাস্টিং ব্যবহার করে না। এবং এটি ওভারল্যাপিং অঞ্চলগুলির (স্ব-ছেদগুলি) কাজ করতে পারে, 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 ধীর করে))
বহুভুজের উপর আঘাত হিট সনাক্ত করার জন্য আমাদের দুটি জিনিস পরীক্ষা করতে হবে:
রে কাস্টিং অ্যালগরিদমে নিম্নলিখিত বিশেষ ক্ষেত্রে মোকাবিলা করতে :
কমপ্লেক্স বহুভুজের ভিতরে একটি পয়েন্ট রয়েছে কিনা তা নির্ধারণ করে দেখুন । নিবন্ধটি তাদের সমাধানের সহজ উপায় সরবরাহ করে যাতে উপরের কেসগুলির জন্য কোনও বিশেষ চিকিত্সার প্রয়োজন হয় না।
আপনার বহুভুজের কোণে কাঙ্ক্ষিত বিন্দুটি সংযুক্ত করে গঠিত অঞ্চলটি বহুভুজের ক্ষেত্রের সাথেই মিলছে কিনা তা পরীক্ষা করে আপনি এটি করতে পারেন।
অথবা আপনি পরীক্ষা করতে পারেন আপনার বিন্দু থেকে প্রতিটি জোড় পর্যন্ত আপনার চেক পয়েন্টের পর পর দুটি বহুভুজ উল্লম্বের প্রতিটি জোড়ের যোগফলের যোগফল, তবে আমার অনুভূতি আছে যে প্রথম বিকল্পটি দ্রুততর কারণ এটি বিভাগ বা গণনাগুলিকে জড়িত করে না ত্রিকোণমিত্রিক ফাংশনের বিপরীত।
আমি জানি না যে যদি আপনার বহুভুজের ভিতরে কোনও গর্ত থাকে তবে কী হয় তবে আমার কাছে মনে হয় যে মূল ধারণাটি এই পরিস্থিতিতে মানিয়ে নিতে পারে
আপনি গণিত সম্প্রদায়ে প্রশ্নটি পোস্ট করতে পারেন। আমি বাজি ধরেছিলাম যে তাদের এটি করার এক মিলিয়ন উপায় রয়েছে
আপনি যদি জাভা-স্ক্রিপ্ট লাইব্রেরির সন্ধান করছেন তবে বহুভুজ শ্রেণীর জন্য একটি জাভাস্ক্রিপ্ট গুগল ম্যাপস ভি 3 এক্সটেনশান রয়েছে যাতে এটিতে কোনও বিন্দু রয়েছে কিনা তা সনাক্ত করতে পারে।
var polygon = new google.maps.Polygon([], "#000000", 1, 1, "#336699", 0.3);
var isWithinPolygon = polygon.containsLatLng(40, -90);
উত্তরটি যদি আপনার সাধারণ বা জটিল বহুভুজ থাকে তবে তার উপর নির্ভর করে। সাধারণ বহুভুজের কোনও লাইন বিভাগের ছেদ থাকতে হবে না। সুতরাং তাদের গর্ত থাকতে পারে তবে লাইনগুলি একে অপরকে অতিক্রম করতে পারে না। কমপ্লেক্স অঞ্চলে লাইন ছেদ থাকতে পারে - সুতরাং তাদের ওভারল্যাপিং অঞ্চলগুলি বা অঞ্চলগুলি যা একে অপরের সাথে কেবল একটি বিন্দুতে স্পর্শ করতে পারে।
সাধারণ বহুভুজের জন্য সেরা অ্যালগরিদম হ'ল রে কাস্টিং (ক্রসিং নম্বর) অ্যালগরিদম। জটিল বহুভুজগুলির জন্য, এই অ্যালগরিদম ওভারল্যাপিং অঞ্চলের মধ্যে থাকা পয়েন্টগুলি সনাক্ত করে না। সুতরাং জটিল বহুভুজগুলির জন্য আপনাকে উইন্ডিং নম্বর অ্যালগোরিদম ব্যবহার করতে হবে।
এখানে উভয় অ্যালগরিদমের সি প্রয়োগের সাথে একটি দুর্দান্ত নিবন্ধ। আমি তাদের চেষ্টা করেছিলাম এবং তারা ভাল কাজ করে।
নীর্গ দ্বারা সমাধানের স্কেল সংস্করণ (অনুমান করা আবদ্ধ আয়তক্ষেত্রের প্রাক-চেক পৃথকভাবে সম্পন্ন করা হয়েছে):
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)
}
এখানে @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
}