কোনও পয়েন্টটি ঘোরানো আয়তক্ষেত্রের ভিতরে থাকলে আমি কীভাবে দক্ষতার সাথে পরীক্ষা করব?


11

অপ্টিমাইজেশনের স্বার্থে অংশ, শেখার উদ্দেশ্যে অংশ, আমি জিজ্ঞাসা করার সাহস করব: সি # বা সি ++ ব্যবহার করে, আমি কীভাবে সবচেয়ে দক্ষতার সাথে পরীক্ষা করতে পারি যে 2 ডি পয়েন্ট 2 Pডি ঘোরানো আয়তক্ষেত্রের ভিতরে রয়েছে কিনা XYZW?

বর্তমানে, আমি যা করছি তা হ'ল রিয়েল টাইম কোলিশন সনাক্তকরণ বইটিতে পাওয়া "পয়েন্ট ইন ত্রিভুজ" অ্যালগরিদম ব্যবহার করে এবং এটি দুটিবার চালানো (যে দুটি ত্রিভুজ যা আয়তক্ষেত্রটি তৈরি করে, XYZ এবং XZW বলুন):

bool PointInTriangle(Vector2 A, Vector2 B, Vector2 C, Vector2 P)
{
 // Compute vectors        
 Vector2 v0 = C - A;
 Vector2 v1 = B - A;
 Vector2 v2 = P - A;

 // Compute dot products
 float dot00 = Vector2.Dot(v0, v0);
 float dot01 = Vector2.Dot(v0, v1);
 float dot02 = Vector2.Dot(v0, v2);
 float dot11 = Vector2.Dot(v1, v1);
 float dot12 = Vector2.Dot(v1, v2);

 // Compute barycentric coordinates
 float invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
 float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
 float v = (dot00 * dot12 - dot01 * dot02) * invDenom;

 // Check if point is in triangle
 if(u >= 0 && v >= 0 && (u + v) < 1)
    { return true; } else { return false; }
}


bool PointInRectangle(Vector2 X, Vector2 Y, Vector2 Z, Vector2 W, Vector2 P)
{
 if(PointInTriangle(X,Y,Z,P)) return true;
 if(PointInTriangle(X,Z,W,P)) return true;
 return false;
}

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


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

ভাল যুক্তি. আমার কাছে অনেকগুলি পয়েন্ট থাকবে তবে চেক করার জন্য আরও বেশি আয়তক্ষেত্র রয়েছে।
লুই

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

আপনি কি আয়তক্ষেত্রের রেফারেন্স ফ্রেমে পয়েন্টটি ঘোরানোর বিষয়টি বিবেচনা করেছেন?
রিচার্ড টিঙ্গল

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

উত্তর:


2

চূড়ান্ত শর্তটি এখানে পরিবর্তন করার জন্য একটি সহজ এবং সোজা অপ্টিমাইজেশন হ'ল PointInTriangle:

bool PointInRectangle(Vector2 A, Vector2 B, Vector2 C, Vector2 P) {
  ...
  if(u >= 0 && v >= 0 && u <= 1 && v <= 1)
      { return true; } else { return false; }
  }
}

কোডটি PointInRectangleইতিমধ্যে বেশ ইতিমধ্যে ছিল, এটি শর্তটি (u + v) < 1ছিল যে এটি আয়তক্ষেত্রের "দ্বিতীয়" ত্রিভুজের মধ্যে নেই কিনা তা পরীক্ষা করে দেখার জন্য।

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

float isLeft( Point P0, Point P1, Point P2 )
{
    return ( (P1.x - P0.x) * (P2.y - P0.y) - (P2.x - P0.x) * (P1.y - P0.y) );
}
bool PointInRectangle(Vector2 X, Vector2 Y, Vector2 Z, Vector2 W, Vector2 P)
{
    return (isLeft(X, Y, P) > 0 && isLeft(Y, Z, P) > 0 && isLeft(Z, W, P) > 0 && isLeft(W, X, p) > 0);
}

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

isLeftপদ্ধতির জন্য +1 । এটিতে ট্রিগ ফাংশনগুলির প্রয়োজন হয় না (যেমন Vector2.Dotকরে) যা জিনিসগুলিকে প্রচুর গতি দেয়।
আনকো

বিটিডব্লু, কোডটি টুইট করা যায়নি (পরীক্ষা করা হয়নি; এই কম্পিউটারে কীভাবে হয় না), সরাসরি মূল ফাংশনের মধ্যে আইসেলফিটকে অন্তর্ভুক্ত করে এবং "&" অপারেটরদের "" "দ্বারা প্রতিস্থাপিত করে গর্তটি বিপরীত যুক্তি? public static bool PointInRectangle(Vector2 P, Vector2 X, Vector2 Y, Vector2 Z, Vector2 W) { return !(( (Y.x - X.x) * (P.y - X.y) - (P.x - X.x) * (Y.y - X.y) ) < 0 || ( (Z.x - Y.x) * (P.y - Y.y) - (P.x - Y.x) * (Z.y - Y.y) ) < 0 || ( (W.x - Z.x) * (P.y - Z.y) - (P.x - Z.x) * (W.y - Z.y) ) < 0 || ( (X.x - W.x) * (P.y - W.y) - (P.x - W.x) * (X.y - W.y) ) < 0 ); }
লুই

1
@ লুই 15 আমার মনে হয় না যে আপনার দরকার - দু'টি && এবং || একটি নেতিবাচক / ইতিবাচক পাওয়া গেলে (বা অন্য কোনও কারণ ছিল?) যদি আরও বিবৃতি কার্যকর করা বন্ধ করে দেয়। ইনलाइनরে isLeftসংকলক হিসাবে ঘোষনা করা আপনার জন্য অনুরূপ কিছু করবে (এবং সম্ভবত তখন আপনি আরও ভাল করতে পারেন, কারণ সংকলক লেখার ইঞ্জিনিয়াররা সিপিইউগুলিকে সবচেয়ে ভাল জানতেন, যে কোনও বিকল্পটি দ্রুততম চয়ন করে) আপনার কোডটি একই বা আরও ভাল প্রভাবের সাথে আরও পঠনযোগ্য করে তোলে।
ওয়েজরা

8

সম্পাদনা: ওপস মন্তব্যটি অ্যালগরিদমকে উন্নত করতে প্রস্তাবিত নেতিবাচক বৃত্তাকার বাউন্ড চেকের দক্ষতা সম্পর্কে সন্দেহজনক হয়েছে যাতে একটি নির্বিচার 2D পয়েন্টটি একটি আবর্তিত এবং / অথবা চলমান আয়তক্ষেত্রের মধ্যে রয়েছে কিনা তা পরীক্ষা করে দেখুন। আমার 2 ডি গেম ইঞ্জিন (ওপেনজিএল / সি ++) এর উপরে কিছুটা ফিডিং করে আমি ওপিএস বর্তমান পয়েন্ট-ইন-আয়তক্ষেত্র-চেক অ্যালগরিদম (এবং বিভিন্নতা) এর বিপরীতে আমার অ্যালগরিদমের পারফরম্যান্স বেঞ্চমার্ক সরবরাহ করে আমার উত্তরটি পরিপূরক করছি।

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

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

বন্ধ : ওপি দ্বারা প্রদত্ত সরল অ্যালগরিদমকে বৃত্তের সীমানা নেতিবাচক চেক ছাড়াই

চালু : প্রথম ব্যতিক্রম চেক হিসাবে আয়তক্ষেত্রগুলির চারপাশে প্রতি-প্রক্রিয়াজাত (সীমানা) বৃত্ত ব্যবহার করা

চালু + স্ট্যাক : স্ট্যাকের লুপের মধ্যে রান-টাইমে বৃত্তের সীমা তৈরি করা

চালু + স্কোয়ার দূরত্ব : আরও ব্যয়বহুল বর্গমূলের অ্যালগরিদম (পিটার জেরকেনস) না এড়াতে আরও অনুকূলকরণ হিসাবে বর্গক্ষেত্রের দূরত্ব ব্যবহার করা।

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

এখানে চিত্র বর্ণনা লিখুন

এক্স-অক্ষ আরও ডট যুক্ত করে (এবং এভাবে লুপটি ধীর করে) একটি বর্ধিত জটিলতা দেখায়। (উদাহরণস্বরূপ, ২০ টি আয়তক্ষেত্রের সাথে কনফিডেড স্পেসে এলোমেলোভাবে পয়েন্ট চেক করে 1000 এ, লুপটি পুনরাবৃত্ত হয় এবং 20000 বার অ্যালগরিদমকে কল করে) পারফরম্যান্স টাইমার 20 এমএসেরও বেশি একটি শালীন গেমের জন্য সমস্যাযুক্ত কারণ এটি কোনও মসৃণ অ্যানিমেশনটি ইন্টারপোলেট করার জন্য উচ্চ FPS এর সুবিধা নেবে না এবং গেমটি মাঝে মাঝে 'রাগড' প্রদর্শিত হতে পারে।

ফলাফল 1 : লুপের মধ্যে একটি দ্রুত নেতিবাচক চেক সহ একটি প্রাক-প্রক্রিয়াজাত বিজ্ঞপ্তি বাউন্ড অ্যালগরিদম নিয়মিত অ্যালগরিদমের (চেক ছাড়াই মূল লুপ সময়ের 5%) তুলনায় 1900% দ্বারা কার্যকারিতা উন্নত করে। ফলাফলটি একটি লুপের মধ্যে পুনরাবৃত্তির সংখ্যার আনুপাতিক সমান ধারণ করে, সুতরাং আমরা 10 বা 10000 এলোমেলোভাবে উপস্থিত হওয়া পয়েন্টগুলি পরীক্ষা করি তবে তাতে কিছু আসে যায় না। সুতরাং, এই দৃষ্টান্তটিতে কোনও কর্মক্ষমতা হ্রাস অনুভূত না করে নিরাপদে বস্তুর সংখ্যা 10 কে বাড়িয়ে তুলতে পারে।

ফলাফল 2 : এটি পূর্ববর্তী একটি মন্তব্য দ্বারা প্রস্তাবিত হয়েছে যে অ্যালগরিদম দ্রুত হতে পারে তবে মেমরি নিবিড়। তবে নোট করুন যে প্রাক-প্রক্রিয়াজাতকরণ বৃত্ত আকারের জন্য একটি ফ্লোট সংরক্ষণ করতে কেবল 4 বাইট লাগে। ওপি একই সাথে 100000+ অবজেক্টগুলি চালানোর পরিকল্পনা না করলে এটির কোনও আসল সমস্যা হবে না। একটি বিকল্প এবং মেমরি দক্ষ পন্থা হ'ল লুপের মধ্যে স্ট্যাকের উপরের বৃত্তের সর্বোচ্চ আকারটি গণনা করা এবং প্রতিটি পুনরাবৃত্তির সাথে এটিকে সুযোগের বাইরে যেতে দেওয়া এবং এইভাবে গতির কিছু অজানা দামের জন্য কার্যত কোনও স্মৃতি ব্যবহার না করা। প্রকৃতপক্ষে, ফলাফলটি দেখায় যে প্রাক-প্রক্রিয়াজাতকরণ বৃত্তের আকারের চেয়ে এই পদ্ধতির প্রকৃতপক্ষে ধীর গতি রয়েছে, তবে এটি এখনও প্রায় 1150% (মূল প্রক্রিয়াকরণের সময়কালের 8%) এর যথেষ্ট কার্যকারিতা উন্নতি দেখায়।

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

ফলাফল 4 : আমি আরও চলাচল / চারপাশে আয়তক্ষেত্রগুলির সংঘর্ষে চেক করি; তবে লজিক্যাল চেকটি মূলত একইরকম থাকায় এটি মৌলিক ফলাফলগুলিকে (আশানুরূপ হিসাবে) পরিবর্তন করে না।

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

ফলাফল 6 : আমি এখানে প্রস্তাবিত বিকল্প অ্যালগরিদমগুলি পরীক্ষা করি এবং কার্য সম্পাদনের ক্ষেত্রে খুব সামান্য তবে উল্লেখযোগ্য পার্থক্য খুঁজে পাই না (২%)। আকর্ষণীয় এবং আরও সহজ ইসলেফ্ট অ্যালগরিদম 17% (মূল গণনার সময়কার 85%) দ্বারা পারফরম্যান্স বাড়াতে খুব ভাল পারফর্ম করে তবে দ্রুত নেগেটিভ চেক অ্যালগরিদমের দক্ষতার কাছে কোথাও নেই।

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

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

Rec Points  Iter    OFF     ON     ON_Stack     ON_SqrDist  Ileft Algorithm (Wondra)
            (ms)    (ms)    (ms)    (ms)        (ms)        (ms)
20  10      200     0.29    0.02    0.04        0.02        0.17
20  100     2000    2.23    0.10    0.20        0.09        1.69
20  1000    20000   24.48   1.25    1.99        1.05        16.95
20  10000   200000  243.85  12.54   19.61       10.85       160.58

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

আয়তক্ষেত্রের অবস্থান স্থির করার দরকার নেই। আপেক্ষিক স্থানাঙ্ক ব্যবহার করুন। এটিও এর মতো ভাবুন। ঘূর্ণন যাই হোক না কেন, ব্যাসার্ধ একই থাকে।
মাজতে

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

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

সম্পাদিত + যোগ করা বেঞ্চমার্ক পরীক্ষা।
মাজেতে

2

4 পয়েন্ট সহ একটি আয়তক্ষেত্র নির্ধারণ করা ট্র্যাপিজয়েড তৈরি করা সম্ভব করে। তবে, আপনি এটি x, y, প্রস্থ, উচ্চতা এবং এর মাঝখানে একটি ঘূর্ণন দ্বারা সংজ্ঞায়িত করতে পারেন, আপনি কেবলমাত্র আপনার আয়তক্ষেত্রের বিপরীত ঘূর্ণন (একই উত্সের চারপাশে) দ্বারা পরীক্ষা করছেন এমন পয়েন্টটি ঘোরান এবং তারপরে পরীক্ষা করে দেখুন এটি কিনা মূল আয়তক্ষেত্রে


হুম, পরামর্শের জন্য ধন্যবাদ, তবে ঘোরানো এবং বিপরীত ঘূর্ণনটি পাওয়া কার্যকর বলে মনে হয় না। আসলে এটি আমার সমাধানের মতোই কার্যকর হবে
বিস্ময়ের

আপনি লক্ষ করতে পারেন যে ম্যাট্রিক্সের সাথে 3 ডি পয়েন্ট ঘোরানো 6 গুন এবং 3 সংযোজন এবং একটি ফাংশন কল। @ আশ্চর্যের সমাধানটি সর্বোত্তম সমতুল্য, তবে অভিপ্রায় তুলনায় অনেক কম পরিষ্কার; এবং
ডিআরওয়াই

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

@ ওয়ানড্রা: ডিআরওয়াই = নিজেকে পুনরাবৃত্তি করবেন না। আপনার কোড স্নিপেটটি মেট্রিক্সের বিশদটি ভেক্টর গুণ দ্বারা সর্বত্র কোডিংয়ের পরামর্শ দেয় যে কোডটিতে কার্যকরীতা স্ট্যান্ডার্ড ম্যাট্রিক্স-অ্যাপ্লিকেশন-থেকে-ভেক্টর পদ্ধতির অনুরোধ করার পরিবর্তে কোডটিতে উপস্থিত হয়।
পিটার জেরকেন্স 16

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

1

আমার কাছে এটি বেঞ্চমার্ক করার সময় ছিল না, তবে আমার পরামর্শটি রূপান্তর ম্যাট্রিক্স সংরক্ষণ করবে যা আয়তক্ষেত্রটি অক্ষরেখাযুক্ত স্কোয়ারে x- এবং y- রেঞ্জের মধ্যে 0 থেকে 1 পর্যন্ত সংরক্ষণ করবে। অন্য কথায় ম্যাট্রিক্স সংরক্ষণ করুন যা আয়তক্ষেত্রের একটি কোণকে (0,0) এবং বিপরীতটি একটি (1,1) তে রূপান্তর করে।

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

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

সম্পাদনা: এটি আমার আয়তক্ষেত্র-শ্রেণীর মতো দেখাবে:

class Rectangle
{
public:
    Matrix3x3 _transform;

    Rectangle()
    {}

    void setCorners(Vector2 p_a, Vector2 p_b, Vector2 p_c)
    {
        // create a matrix from the two edges of the rectangle
        Vector2 edgeX = p_b - p_a;
        Vector2 edgeY = p_c - p_a;

        // and then create the inverse of that matrix because we want to 
        // transform points from world coordinates into "rectangle coordinates".
        float scaling = 1/(edgeX._x*edgeY._y - edgeY._x*edgeX._y);

        _transform._columns[0]._x = scaling * edgeY._y;
        _transform._columns[0]._y = - scaling * edgeX._y;
        _transform._columns[1]._x = - scaling * edgeY._x;
        _transform._columns[1]._y = scaling * edgeX._x;

        // the third column is the translation, which also has to be transformed into "rectangle space"
        _transform._columns[2]._x = -p_a._x * _transform._columns[0]._x - p_a._y * _transform._columns[1]._x;
        _transform._columns[2]._y = -p_a._x * _transform._columns[0]._y - p_a._y * _transform._columns[1]._y;
    }

    bool isInside(Vector2 p_point)
    {
        Vector2 test = _transform.transform(p_point);
        return  (test._x>=0)
                && (test._x<=1)
                && (test._y>=0)
                && (test._y<=1);
    }
};

এটি আমার মানদণ্ডের সম্পূর্ণ তালিকা:

#include <cstdlib>
#include <math.h>
#include <iostream>

#include <sys/time.h>

using namespace std;

class Vector2
{
public:
    float _x;
    float _y;

    Vector2()
    :_x(0)
    ,_y(0)
    {}

    Vector2(float p_x, float p_y)
        : _x (p_x)
        , _y (p_y)
        {}

    Vector2 operator-(const Vector2& p_other) const
    {
        return Vector2(_x-p_other._x, _y-p_other._y);
    }

    Vector2 operator+(const Vector2& p_other) const
    {
        return Vector2(_x+p_other._x, _y+p_other._y);
    }

    Vector2 operator*(float p_factor) const
    {
        return Vector2(_x*p_factor, _y*p_factor);
    }

    static float Dot(Vector2 p_a, Vector2 p_b)
    {
        return (p_a._x*p_b._x + p_a._y*p_b._y);
    }
};

bool PointInTriangle(Vector2 A, Vector2 B, Vector2 C, Vector2 P)
{
 // Compute vectors        
 Vector2 v0 = C - A;
 Vector2 v1 = B - A;
 Vector2 v2 = P - A;

 // Compute dot products
 float dot00 = Vector2::Dot(v0, v0);
 float dot01 = Vector2::Dot(v0, v1);
 float dot02 = Vector2::Dot(v0, v2);
 float dot11 = Vector2::Dot(v1, v1);
 float dot12 = Vector2::Dot(v1, v2);

 // Compute barycentric coordinates
 float invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
 float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
 float v = (dot00 * dot12 - dot01 * dot02) * invDenom;

 // Check if point is in triangle
 if(u >= 0 && v >= 0 && (u + v) < 1)
    { return true; } else { return false; }
}


bool PointInRectangle(Vector2 X, Vector2 Y, Vector2 Z, Vector2 W, Vector2 P)
{
 if(PointInTriangle(X,Y,Z,P)) return true;
 if(PointInTriangle(X,Z,W,P)) return true;
 return false;
}

class Matrix3x3
{
public:
    Vector2 _columns[3];

    Vector2 transform(Vector2 p_in)
    {
        return _columns[0] * p_in._x + _columns[1] * p_in._y + _columns[2];
    }
};

class Rectangle
{
public:
    Matrix3x3 _transform;

    Rectangle()
    {}

    void setCorners(Vector2 p_a, Vector2 p_b, Vector2 p_c)
    {
        // create a matrix from the two edges of the rectangle
        Vector2 edgeX = p_b - p_a;
        Vector2 edgeY = p_c - p_a;

        // and then create the inverse of that matrix because we want to 
        // transform points from world coordinates into "rectangle coordinates".
        float scaling = 1/(edgeX._x*edgeY._y - edgeY._x*edgeX._y);

        _transform._columns[0]._x = scaling * edgeY._y;
        _transform._columns[0]._y = - scaling * edgeX._y;
        _transform._columns[1]._x = - scaling * edgeY._x;
        _transform._columns[1]._y = scaling * edgeX._x;

        // the third column is the translation, which also has to be transformed into "rectangle space"
        _transform._columns[2]._x = -p_a._x * _transform._columns[0]._x - p_a._y * _transform._columns[1]._x;
        _transform._columns[2]._y = -p_a._x * _transform._columns[0]._y - p_a._y * _transform._columns[1]._y;
    }

    bool isInside(Vector2 p_point)
    {
        Vector2 test = _transform.transform(p_point);
        return  (test._x>=0)
                && (test._x<=1)
                && (test._y>=0)
                && (test._y<=1);
    }
};

void runTest(float& outA, float& outB)
{
    Rectangle r;
    r.setCorners(Vector2(0,0.5), Vector2(0.5,1), Vector2(0.5,0));

    int numTests = 10000;

    Vector2 points[numTests];

    Vector2 cornerA[numTests];
    Vector2 cornerB[numTests];
    Vector2 cornerC[numTests];
    Vector2 cornerD[numTests];

    bool results[numTests];
    bool resultsB[numTests];

    for (int i=0; i<numTests; ++i)
    {
        points[i]._x = rand() / ((float)RAND_MAX);
        points[i]._y = rand() / ((float)RAND_MAX);

        cornerA[i]._x = rand() / ((float)RAND_MAX);
        cornerA[i]._y = rand() / ((float)RAND_MAX);

        Vector2 edgeA;
        edgeA._x = rand() / ((float)RAND_MAX);
        edgeA._y = rand() / ((float)RAND_MAX);

        Vector2 edgeB;
        edgeB._x = rand() / ((float)RAND_MAX);
        edgeB._y = rand() / ((float)RAND_MAX);

        cornerB[i] = cornerA[i] + edgeA;
        cornerC[i] = cornerA[i] + edgeB;
        cornerD[i] = cornerA[i] + edgeA + edgeB;
    }

    struct timeval start, end;

    gettimeofday(&start, NULL);
    for (int i=0; i<numTests; ++i)
    {
        r.setCorners(cornerA[i], cornerB[i], cornerC[i]);
        results[i] = r.isInside(points[i]);
    }
    gettimeofday(&end, NULL);
    float elapsed = (end.tv_sec - start.tv_sec)*1000;
    elapsed += (end.tv_usec - start.tv_usec)*0.001;
    outA += elapsed;

    gettimeofday(&start, NULL);
    for (int i=0; i<numTests; ++i)
    {
        resultsB[i] = PointInRectangle(cornerA[i], cornerB[i], cornerC[i], cornerD[i], points[i]);
    }
    gettimeofday(&end, NULL);
    elapsed = (end.tv_sec - start.tv_sec)*1000;
    elapsed += (end.tv_usec - start.tv_usec)*0.001;
    outB += elapsed;
}

/*
 * 
 */
int main(int argc, char** argv) 
{
    float a = 0;
    float b = 0;

    for (int i=0; i<5000; i++)
    {
        runTest(a, b);
    }

    std::cout << "Result: " << a << " / " << b << std::endl;

    return 0;
}

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

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


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

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

হ্যাঁ, এরকম কিছু ঘটতে পারে। আমি ভাবছি অ্যালগরিদমের বিরুদ্ধে ঘুরতে মিষ্টি স্পটটি কী। শেষ পর্যন্ত এটি আপনার উদ্দেশ্য পর্যন্ত ফোটে। আপনার যদি সময় থাকে তবে আপনি ওপিএস পোস্টটি ব্যবহার করে আপনার কোড পোস্ট করতে পারেন এবং আমি আপনার অ্যালগরিদমকে বেনমার্ক করতে পারি? আসুন দেখুন আপনার অন্তর্দৃষ্টি ঠিক আছে কিনা। ইসলফ্ট অ্যালগরিদমের বিরুদ্ধে আপনার ধারণার অভিনয় সম্পর্কে আমি কৌতূহলী।
মাজতে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.