অনুমান করুন যে প্রতিটি বাক্সের অবজেক্টের x, y, প্রস্থ, উচ্চতা বৈশিষ্ট্য রয়েছে এবং তাদের কেন্দ্রস্থলে এর উত্স রয়েছে এবং অবজেক্ট বা সীমানা বাক্স দুটিই ঘোরান না।
অনুমান করুন যে প্রতিটি বাক্সের অবজেক্টের x, y, প্রস্থ, উচ্চতা বৈশিষ্ট্য রয়েছে এবং তাদের কেন্দ্রস্থলে এর উত্স রয়েছে এবং অবজেক্ট বা সীমানা বাক্স দুটিই ঘোরান না।
উত্তর:
(সি-ইশ সিউডোকোড - উপযুক্ত ভাষা হিসাবে অনুকূলিতকরণ)
bool DoBoxesIntersect(Box a, Box b) {
return (abs(a.x - b.x) * 2 < (a.width + b.width)) &&
(abs(a.y - b.y) * 2 < (a.height + b.height));
}
ইংরাজীতে: প্রতিটি অক্ষের উপর, বাক্সগুলির কেন্দ্রগুলি এমনভাবে খুব কাছাকাছি রয়েছে যেগুলি তারা ছেদ করবে see যদি তারা উভয় অক্ষকে ছেদ করে তবে বাক্সগুলি ছেদ করে। যদি তারা না করে, তবে তারা তা করে না।
আপনি যদি প্রান্ত-স্পর্শকে ছেদক হিসাবে গণনা করতে চান তবে আপনি <'s << এ পরিবর্তন করতে পারেন। আপনি যদি একটি নির্দিষ্ট প্রান্ত-টাচ-কেবল সূত্র চান তবে আপনি == ব্যবহার করতে পারবেন না - এটি আপনাকে কোণগুলি স্পর্শ করে কিনা তা বলবে, প্রান্তগুলি স্পর্শ না করে নয়। আপনি যুক্তিযুক্তভাবে সমতুল্য কিছু করতে চাইবেন return DoBoxesIntersectOrTouch(a, b) && !DoBoxesIntersect(a, b)
।
এটি উল্লেখ করার মতো যে আপনি অর্ধ-প্রস্থ এবং অর্ধ-উচ্চতা সম্পূর্ণ প্রস্থ এবং সম্পূর্ণ উচ্চতা ছাড়াও (বা পরিবর্তে) সংরক্ষণ করে একটি ছোট তবে উল্লেখযোগ্য গতির বৃদ্ধি পেতে পারেন। অন্যদিকে, 2 ডি বাউন্ডিং বক্সের ছেদটি বিরল যা পারফরম্যান্সের বাধা।
abs(5 - 10) * 2 < (10 + 4)
=> দিয়ে শেষ করেন 10 < 14
। টপলফিট-কর্নার এবং মাপের সাথে এটি কাজ করার জন্য আপনাকে কিছু সাধারণ টুইট করতে হবে।
এটি এক্স এবং ওয়াই অক্ষের সাথে সংযুক্ত দুটি আয়তক্ষেত্রের জন্য কাজ করে।
প্রতিটি আয়তক্ষেত্রের বৈশিষ্ট্য রয়েছে:
"বাম", এর বাম পাশের x স্থানাঙ্ক,
"শীর্ষ", এর শীর্ষ দিকের y স্থানাঙ্ক,
"ডান", তার ডান পাশের x স্থানাঙ্ক,
"নীচে", এর y স্থানাঙ্ক এর নীচের দিক,
function IntersectRect(r1:Rectangle, r2:Rectangle):Boolean {
return !(r2.left > r1.right
|| r2.right < r1.left
|| r2.top > r1.bottom
|| r2.bottom < r1.top);
}
নোট করুন যে এটি একটি স্থানাঙ্ক ব্যবস্থার জন্য ডিজাইন করা হয়েছে যেখানে + y অক্ষটি নীচে এবং + x অক্ষটি ডানদিকে নির্দেশ করা হয়েছে (যেমন টিপিক্যাল স্ক্রিন / পিক্সেল স্থানাঙ্ক)। এটি একটি সাধারণ কার্তেসিয়ান সিস্টেমের সাথে মানিয়ে নিতে যেখানে + y উপরের দিকে নির্দেশিত হয়, উল্লম্ব অক্ষের সাথে তুলনাগুলি বিপরীত হবে, যেমন:
return !(r2.left > r1.right
|| r2.right < r1.left
|| r2.top < r1.bottom
|| r2.bottom > r1.top);
ধারণা সব সম্ভব অবস্থার যার উপর আয়তক্ষেত্র হবে ক্যাপচার হয় না ওভারল্যাপ, এবং তারপর উত্তর অস্বীকার দেখতে যদি তারা হয় overlapped। অক্ষগুলির দিক নির্বিশেষে, এটি সহজেই দেখতে পাওয়া যায় যে দুটি আয়তক্ষেত্র ওভারল্যাপ হবে না যদি:
আর 2 এর বাম প্রান্তটি আর 1 এর ডান প্রান্তের চেয়ে আরও ডান
________ ________
| | | |
| r1 | | r2 |
| | | |
|________| |________|
অথবা r2 এর ডান প্রান্তটি আর 1 এর বাম প্রান্তের চেয়ে আরও বাম দিকে রয়েছে
________ ________
| | | |
| r2 | | r1 |
| | | |
|________| |________|
অথবা r2 এর শীর্ষ প্রান্তটি R1 এর নীচের প্রান্তের নীচে
________
| |
| r1 |
| |
|________|
________
| |
| r2 |
| |
|________|
অথবা r2 এর নীচের প্রান্তটি R1 এর শীর্ষ প্রান্তের উপরে
________
| |
| r2 |
| |
|________|
________
| |
| r1 |
| |
|________|
আসল ফাংশন - এবং এটি কেন কাজ করে তার একটি বিকল্প বিবরণ এখানে পাওয়া যাবে: http://tekpool.wordpress.com/2006/10/11/rectangle-intersication-determine-if-two-given-rectangles-intersect- প্রতিটি-অন্যান্য-অর-না /
আপনি যদি অবজেক্ট- অ্যালাইন্টেড বাউন্ডিং বাক্সগুলি চান তবে মেটানেট দ্বারা পৃথকীকরণ অক্ষের উপপাদ্যটিতে এই টিউটোরিয়ালটি ব্যবহার করে দেখুন : http://www.metanetsoftware.com/technique/tutorialA.html
স্যাট দ্রুততম সমাধান নয়, তবে এটি তুলনামূলকভাবে সহজ। আপনি এমন একটি একক লাইন (বা 3 ডি যদি একটি প্লেন) সন্ধান করার চেষ্টা করছেন যা আপনার অবজেক্টগুলিকে আলাদা করবে। যদি এই লাইনটি বিদ্যমান থাকে তবে এটি আপনার বাক্সগুলির একটির প্রান্তে প্যারালেল হওয়ার গ্যারান্টিযুক্ত, সুতরাং আপনি বাক্সগুলি পৃথক করে কিনা তা পরীক্ষার জন্য সমস্ত প্রান্তটি দিয়ে পুনরাবৃত্তি করুন।
এটি কেবল এক্স / ওয়াই অক্ষকে সীমাবদ্ধ করে অক্ষ-সংযুক্ত বাক্সগুলির জন্যও কাজ করে।
উপরের DoBoxesIntersect একটি ভাল যুগল সমাধান। তবে আপনার যদি অনেকগুলি বাক্স থাকে তবে আপনার কাছে এখনও একটি ও (এন ^ 2) সমস্যা রয়েছে এবং আপনাকে সম্ভবত কাজাজের দ্বারা উল্লিখিত মতো কিছু করার দরকার হতে পারে। (3 ডি সংঘর্ষ শনাক্তকরণের সাহিত্যে, এটি ব্রড-ফেজ এবং একটি সরু-পর্যায়ের অ্যালগরিদম উভয় হিসাবেই পরিচিত। আমরা ওভারল্যাপের সমস্ত সম্ভাব্য জোড়া খুঁজে পেতে খুব দ্রুত কিছু করব, এবং আমাদের সম্ভাব্য কিনা তা দেখার জন্য আরও ব্যয়বহুল কিছু করব something জোড়া প্রকৃত জোড়া হয়।)
ব্রড-ফেজ অ্যালগরিদম আমি এর আগে ব্যবহার করেছি "ঝাড়ু এবং ছাঁটাই"; 2 ডি এর জন্য, আপনি প্রতিটি বাক্সের শুরু এবং শেষের দুটি সাজানো তালিকা বজায় রাখতে চান। যতক্ষণ না বাক্স চলাচল না হয় >> ফ্রেম থেকে ফ্রেমে বক্স স্কেল না হওয়া পর্যন্ত এই তালিকাগুলির ক্রমটি খুব বেশি পরিবর্তন ঘটবে না এবং তাই এটি বজায় রাখতে আপনি বুদ্বুদ বা সন্নিবেশ সাজানোর ব্যবহার করতে পারেন। "রিয়েল-টাইম রেন্ডারিং" বইটিতে আপনি করতে পারেন এমন অপ্টিমাইজেশনের উপর একটি দুর্দান্ত রচনাআপ রয়েছে তবে এটি এন বাক্সের জন্য কে, ওভারল্যাপে দুর্দান্ত ও বাস্তব রিয়েল ওয়ার্ল্ড সহ ও (এন + কে) সময় পর্যন্ত বিস্তৃত হয় bo পারফরম্যান্স যদি আপনি ফ্রেম থেকে ফ্রেমে কোনও জোড়া বাক্স ছেদ করে চলেছে তা পরীক্ষা করে রাখতে N ^ 2 বুলিয়ান সাধ্যের মধ্যে রাখতে পারেন। তারপরে আপনার কাছে সামগ্রিকভাবে ও (এন + কে overall 2) সময় রয়েছে, যা আপনার << ও (এন ^ 2) অনেকগুলি বাক্স থাকলে তবে কেবল কয়েকটি ওভারল্যাপ থাকে।
খুব সাধারণ সমস্যার জন্য এখানে প্রচুর গণিত, ধরে নিই যে আমাদের একটি রেট, শীর্ষ, বাম, নীচে, ডানদিকে 4 পয়েন্ট নির্ধারিত আছে ...
২ টি পুনরায় সংঘর্ষ সংঘটিত হয়েছে কিনা তা নির্ধারণের ক্ষেত্রে আমাদের কেবলমাত্র দেখতে হবে যে সমস্ত সম্ভাব্য চূড়ান্ততা যা সংঘর্ষগুলি রোধ করবে, যদি এর কোনওটিই পূরণ না হয় তবে 2 টি পুনরায় সংঘর্ষ হওয়া উচিত, যদি আপনি সীমানা সংঘর্ষগুলি অন্তর্ভুক্ত করতে চান তবে কেবল> এবং < উপযুক্ত> = এবং = <সহ with
struct aRect{
float top;
float left;
float bottom;
float right;
};
bool rectCollision(rect a, rect b)
{
return ! ( b.left > a.right || b.right < a.left || b.top < a.bottom || b.bottom > a.top);
}
জোর্বাথুতের উত্তরের বিকল্প সংস্করণ:
bool DoBoxesIntersect(Box a, Box b) {
return (abs(a.x - b.x) < (a.width + b.width) / 2) &&
(abs(a.y - b.y) < (a.height + b.height) / 2);
}
আপনি যে সমস্যার সমাধান করার চেষ্টা করেছেন তার উপর নির্ভর করে আপনি যখন আপনার স্থানটি সরানোর সময় আপনার ট্র্যাক রাখা ঠিক তত ভাল হতে পারেন, অর্থাৎ, বাছাই হওয়া x সূচনা এবং শেষের অবস্থানগুলির একটি তালিকা রাখুন এবং শুরু এবং শেষের y পজিশনের জন্য একটি। যদি আপনাকে প্রচুর ওভারল্যাপ চেক করতে হয় এবং অতএব অনুকূলিতকরণের প্রয়োজন হয় তবে আপনি এটি আপনার সুবিধার্থে ব্যবহার করতে পারেন, আপনি তত্ক্ষণাত দেখতে পারেন যে কে আপনার বাম দিকে বন্ধ করে চলেছে, যার যার প্রান্তটি রয়েছে তার বাম দিকে ছাঁটাই করা যেতে পারে অবিলম্বে। উপরে, নীচে এবং ডানদিকে একই প্রয়োগ করুন।
বুককিপিংয়ের অবশ্যই সময় ব্যয় হয়, সুতরাং এটি কয়েকটি চলমান বস্তুর সাথে প্রচুর ওভারল্যাপ চেকগুলির সাথে একটি পরিস্থিতির জন্য আরও উপযুক্ত।
আর একটি বিকল্প স্থানিক হ্যাশিং, যেখানে আপনি আনুমানিক অবস্থানের উপর ভিত্তি করে বস্তুগুলি বালতি করেন (আকারটি একাধিক বালতিতে এম ফেলতে পারে), তবে আবার সেখানে কেবলমাত্র যদি প্রচুর পরিমাণে অবজেক্ট থাকে, যার মধ্যে তুলনামূলকভাবে কয়েকটি বইয়ের ব্যয়ের কারণে পুনরাবৃত্তি প্রতি চলমান থাকে।
মূলত যে কোনও কিছুই (এন * এন) / ২ এড়ায় না (আপনি যদি বি এর বিপরীতে কোন বিষয় পরীক্ষা করে থাকেন তবে আপনাকে অবশ্যই বি এর বিরুদ্ধে বি পরীক্ষা করতে হবে না) সীমাবদ্ধ বক্স চেকগুলি অনুকূলিতকরণের চেয়ে আরও বেশি সহায়তা করে। যদি বাউন্ডিং বক্সের চেকগুলি কোনও বাধা হয় তবে আমি সমস্যার বিকল্প সমাধানগুলি সন্ধানের জন্য গুরুত্ব সহকারে পরামর্শ দেব।
কেন্দ্রগুলির মধ্যে দূরত্ব কোণার মধ্যকার দূরত্বের সমান নয় (যখন একটি বাক্স অন্যটির অভ্যন্তরে থাকে উদাহরণস্বরূপ), সুতরাং সাধারণ ক্ষেত্রে, এই সমাধানটি সঠিক (আমার মনে হয়)।
কেন্দ্রগুলির মধ্যে দূরত্ব (যেমন, বলুন, এক্স): abs(x1+1/2*w1 - x2+1/2*w2)
বা1/2 * abs(2*(x1-x2)+(w1-w2)
ন্যূনতম দূরত্ব 1/2 w1 + 1/2 w2 or 1/2 (w1+w2)
। অর্ধেক বাতিল তাই ..
return
ABS(2*(x1 - x2) + (w1-w2) ) < (w1+w2)) &&
ABS(2*(y1 - y2) + (h1-h2) ) < (h1+h2));
এখানে জাভা আমার বাস্তবায়নের এর একটি দুই দুই-সম্পূরক স্থাপত্য অভিমানী । আপনি যদি দ্বিগুণ-পরিপূরক না হয়ে থাকেন তবে পরিবর্তে একটি মানক ম্যাথ.এবস ফাংশন কল ব্যবহার করুন:
boolean intersects(IntAxisAlignedBox left, IntAxisAlignedBox right) {
return
(
lineDeltaFactor(left.min.x, left.max.x, right.min.x, right.max.x) |
lineDeltaFactor(left.min.y, left.max.y, right.min.y, right.max.y) |
lineDeltaFactor(left.min.z, left.max.z, right.min.z, right.max.z)
) == 0;
}
int lineDeltaFactor(int leftMin, int leftMax, int rightMin, int rightMax) {
final int
leftWidth = leftMax - leftMin,
rightWidth = rightMax - rightMin,
leftMid = leftMin + ((leftMax - leftMin) >> 1),
rightMid = rightMin + ((rightMax - rightMin) >> 1);
return (abs(leftMid - rightMid) << 1) / (leftWidth + rightWidth + 1);
}
int abs(int value) {
final int mask = value >> (Integer.SIZE - 1);
value ^= mask;
value += mask & 1;
return value;
}
অর্ধ-শালীন সংকলক / এলএলভিএম ইনলাইন ধরে নেওয়া ব্যয়বহুল স্ট্যাক জাগলিং এবং ভি-টেবিল বর্ণনগুলি এড়াতে এই ফাংশনগুলি প্রসারিত করে। এটি ইনপুট মানগুলির জন্য ব্যর্থ হবে যা 32-বিট চূড়ান্ত (যেমন Integer.MAX_VALUE
এবং Integer.MIN_VALUE
) এর কাছাকাছি।
দ্রুততম উপায়ে একক ভেক্টর রেজিস্টারে সমস্ত 4 টি মানকে একত্রিত করা হয়।
বাক্সগুলিকে একটি ভেক্টরে নিম্নলিখিত মান সহ সংরক্ষণ করুন [ min.x, min.y, -max.x, -max.y ]
। আপনি যদি এই জাতীয় বাক্সগুলি সংরক্ষণ করেন তবে ছেদ পরীক্ষাটি কেবল 3 সিপিইউ নির্দেশনা নেয়:
_mm_shuffle_ps
দ্বিতীয় বাক্সটি মিনিট এবং সর্বাধিক অর্ধে ফ্লিপিংকে পুনরায় অর্ডার করতে।
_mm_xor_ps
_mm_set1_ps(-0.0f)
দ্বিতীয় বাক্সে সমস্ত 4 টির মান চিহ্ন ফ্লিপ করতে যাদু নম্বর সহ
_mm_cmple_ps
নিম্নলিখিত দুটি রেজিস্টারের সাথে তুলনা করে একে অপরের সাথে সমস্ত 4 টি মানকে তুলনা করতে:
[ a.min.x, a.min.y, -a.max.x, -a.max.y ] < [ b.max.x, b.max.y, -b.min.x, -b.min.y ]
পরিশেষে, যদি প্রয়োজন হয় তবে _mm_movemask_ps
ভেক্টর ইউনিট থেকে স্কেলার রেজিস্টারে ফলাফল আনতে। মান 0 এর অর্থ বাক্সগুলি ছেদ করা। অথবা আপনার যদি 2 টিরও বেশি বাক্সের প্রয়োজন হয় না তবে ভেক্টর রেজিস্টারগুলিতে মানগুলি ছেড়ে দিন এবং একাধিক বাক্স থেকে ফলাফল একত্রিত করতে বিটওয়াইজ ক্রিয়াকলাপগুলি ব্যবহার করুন।
আপনি ভাষা বা প্ল্যাটফর্ম নির্দিষ্ট করেন নি, তবে এই জাতীয় সিমডের জন্য সমর্থন বা খুব অনুরূপ, সমস্ত প্ল্যাটফর্ম এবং ভাষায় উপলব্ধ। মোবাইলে, এআরএম-তে খুব অনুরূপ স্টাফ সহ নিওন সিমড রয়েছে। .NET এর সিস্টেমে ভেক্টর 128 রয়েছে un রুনটাইম.আইন্ট্রিনসিকস নেমস্পেস এবং আরও অনেক কিছু।