যদি আপনার কাছে 2 ডি ভেক্টর এক্স এবং ওয়াই হিসাবে প্রকাশিত হয় তবে এটি নিকটতম কম্পাসের দিকে রূপান্তর করার একটি ভাল উপায় কী?
যেমন
x:+1, y:+1 => NE
x:0, y:+3 => N
x:+10, y:-2 => E // closest compass direction
যদি আপনার কাছে 2 ডি ভেক্টর এক্স এবং ওয়াই হিসাবে প্রকাশিত হয় তবে এটি নিকটতম কম্পাসের দিকে রূপান্তর করার একটি ভাল উপায় কী?
যেমন
x:+1, y:+1 => NE
x:0, y:+3 => N
x:+10, y:-2 => E // closest compass direction
উত্তর:
সহজতম উপায় হ'ল সম্ভবত ভেক্টরের কোণটি ব্যবহার করে atan2()
যেমন টেট্রাড মন্তব্যগুলিতে পরামর্শ করেছিলেন এবং তারপরে স্কেল এবং গোল করে, যেমন (সিউডোকোড):
// enumerated counterclockwise, starting from east = 0:
enum compassDir {
E = 0, NE = 1,
N = 2, NW = 3,
W = 4, SW = 5,
S = 6, SE = 7
};
// for string conversion, if you can't just do e.g. dir.toString():
const string[8] headings = { "E", "NE", "N", "NW", "W", "SW", "S", "SE" };
// actual conversion code:
float angle = atan2( vector.y, vector.x );
int octant = round( 8 * angle / (2*PI) + 8 ) % 8;
compassDir dir = (compassDir) octant; // typecast to enum: 0 -> E etc.
string dirStr = headings[octant];
octant = round( 8 * angle / (2*PI) + 8 ) % 8
লাইন কিছু ব্যাখ্যা প্রয়োজন হতে পারে। প্রায় কাছাকাছি সব ভাষার যে আমি যে জানি এটা আছে, ফাংশন রেডিয়ানে কোণ ফেরৎ। এটি 2 by দ্বারা ভাগ করা πatan2()
এটি পরিবর্তন করে একটি পূর্ণ বৃত্ত ভগ্নাংশ থেকে রেডিয়ানে থেকে এবং 8 দ্বারা গুন তারপর একটি বৃত্তের eighths, এর এটি পরিবর্তন করে যা আমরা তারপর নিকটতম পূর্ণসংখ্যা গোলাকার। পরিশেষে, মোড়কের চারপাশের যত্ন নিতে আমরা এটি 8 মডিউল হ্রাস করি, যাতে 0 এবং 8 উভয়ই পূর্ব দিকে সঠিকভাবে ম্যাপ করা হয়।
এর + 8
উপরের কারণটি , যা আমি উপরের দিকে ছেড়ে দিয়েছি, এটি হ'ল কিছু ভাষায় atan2()
নেতিবাচক ফলাফল (যেমন - π থেকে + π 0 থেকে 2 π এর পরিবর্তে ) %
ফিরে আসতে পারে এবং মডিউল অপারেটর ( ) এর জন্য নেতিবাচক মানগুলি ফেরত দিতে সংজ্ঞায়িত করা যেতে পারে নেতিবাচক আর্গুমেন্ট (বা নেতিবাচক তর্কগুলির জন্য এর আচরণের সংজ্ঞা দেওয়া যেতে পারে)। যোগ করার পদ্ধতি8
হ্রাসের আগে (অর্থাত্ একটি সম্পূর্ণ পালা) যুক্ত করা নিশ্চিত করে যে আর্গুমেন্টগুলি সর্বদা ইতিবাচক থাকে, ফলাফলকে অন্য কোনওভাবে প্রভাবিত না করে।
যদি আপনার ভাষাটি কোনও সুবিধাজনক রাউন্ড টু নিকটস্থ ফাংশন সরবরাহ না করে তবে আপনি তার পরিবর্তে একটি কাটা সংখ্যার রূপান্তর ব্যবহার করতে পারেন এবং যুক্তির সাথে কেবল 0.5 টি যুক্ত করতে পারেন:
int octant = int( 8 * angle / (2*PI) + 8.5 ) % 8; // int() rounds down
নোট করুন যে, কিছু ভাষায়, ডিফল্ট ফ্লোট-টু-ইন্টিজার রূপান্তরটি নেমে না গিয়ে শূন্যের দিকে নেতিবাচক ইনপুট দেয়, যা ইনপুটটি সর্বদা ইতিবাচক থাকে তা নিশ্চিত করার আরেকটি কারণ।
অবশ্যই, 8
বৃত্তটিকে বহু দিকগুলিতে বিভক্ত করতে আপনি সেই লাইনের সমস্ত উপস্থিতি অন্য কয়েকটি সংখ্যার (যেমন 4 বা 16, এমনকি আপনি যদি হেক্স মানচিত্রে থাকেন তবে 6 বা 12) দিয়ে প্রতিস্থাপন করতে পারেন । কেবল সেই অনুযায়ী এনাম / অ্যারে সামঞ্জস্য করুন।
atan2(y,x)
না atan2(x,y)
।
atan2(x,y)
কেউ কাজ করবে, যদি কেউ কেবল উত্তর থেকে শুরু করে ক্লকওয়াইজ ক্রমে কম্পাস শিরোনামগুলি তালিকাভুক্ত করে।
octant = round(8 * angle / 360 + 8) % 8
quadtant = round(4 * angle / (2*PI) + 4) % 4
এবং এনাম: ব্যবহার করে { E, N, W, S }
।
আপনার কাছে 8 টি বিকল্প (বা 16 বা ততোধিক সূক্ষ্মতা চাইলে আরও বেশি) থাকতে পারে)
atan2(y,x)
আপনার ভেক্টরের জন্য কোণ পেতে ব্যবহার করুন ।
atan2()
নিম্নলিখিত পদ্ধতিতে কাজ করে:
সুতরাং x = 1, y = 0 এর ফলাফল 0 হবে এবং এটি x = -1, y = 0 এ বিযুক্ত এবং both এবং -π উভয়ই থাকবে π
এখন আমাদের atan2()
উপরে যে কম্পাসটি রয়েছে তার সাথে মেলে আমাদের আউটপুটটি মানচিত্রের প্রয়োজন ।
সম্ভবত বাস্তবায়নের সহজতম হল কোণগুলির বর্ধমান চেক। এখানে কিছু সিউডো কোড যা বর্ধিত নির্ভুলতার জন্য সহজেই সংশোধন করা যেতে পারে:
//start direction from the lowest value, in this case it's west with -π
enum direction {
west,
south,
east,
north
}
increment = (2PI)/direction.count
angle = atan2(y,x);
testangle = -PI + increment/2
index = 0
while angle > testangle
index++
if(index > direction.count - 1)
return direction[0] //roll over
testangle += increment
return direction[index]
এখন আরও নির্ভুলতা যুক্ত করতে, কেবল এনামের দিকে মান যুক্ত করুন।
অ্যালগরিদম কম্পাসের চারপাশে ক্রমবর্ধমান মানগুলি পরীক্ষা করে কাজ করে এটি দেখার জন্য যে আমাদের কোণটি আমরা সর্বশেষে পরীক্ষা করেছিলাম এবং নতুন অবস্থানের মধ্যে কোনও স্থানে রয়েছে কিনা। এজন্য আমরা -PI + ইনক্রিমেন্ট / 2 এ শুরু করি। আমরা প্রতিটি দিকের চারপাশে সমান স্থান অন্তর্ভুক্ত করতে আমাদের চেকগুলি অফসেট করতে চাই। এটার মতো কিছু:
পশ্চিম দুটি ভাঙ্গা হয়েছে কারণ atan2()
পশ্চিমে প্রত্যাবর্তনের মানগুলি বিচ্ছিন্ন।
atan2
, তবে মনে রাখবেন যে 0 ডিগ্রি সম্ভবত উত্তর হবে না বরং পূর্ব হবে east
angle >=
উপরের কোডে আপনার চেকের দরকার নেই ; উদাহরণস্বরূপ যদি কোণ 45 এর কম হয় তবে উত্তরটি ইতিমধ্যে ফিরে আসবে তাই পূর্ব চেকের জন্য আপনার কোণ> = 45 কিনা পরীক্ষা করার দরকার নেই। একইভাবে পশ্চিমে ফিরে যাওয়ার আগে আপনার কোনও চেকের দরকার নেই - এটিই কেবল সম্ভাবনা বাকি।
if
আপনি যদি 16 টি দিক বা তার বেশি যেতে চান তবে এক টন স্টেটমেন্টের কথা বলবেন না ।
যখনই আপনি ভেক্টরগুলির সাথে লেনদেন করছেন, কিছু নির্দিষ্ট ফ্রেমে কোণে রূপান্তরিত না করে মৌলিক ভেক্টর ক্রিয়াকলাপগুলি বিবেচনা করুন।
একটি ক্যোয়ারী ভেক্টর দেওয়া v
এবং ইউনিট ভেক্টর একটি সেট s
, সর্বাধিক প্রান্তিককৃত ভেক্টর ভেক্টর হয় s_i
যে সম্ভব dot(v,s_i)
। এটি প্যারামিটারগুলির জন্য নির্দিষ্ট দৈর্ঘ্যের প্রদত্ত ডট পণ্যটির একই দিকনির্দেশক ভেক্টরগুলির জন্য সর্বাধিক এবং বিরোধী দিকনির্দেশ সহ ভেক্টরগুলির জন্য ন্যূনতম অন্তর্ভুক্ত থাকে, সহজেই অভ্যন্তরীণ অভ্যন্তরে পরিবর্তন হয়।
এটি তুচ্ছভাবে দু'জনের চেয়ে বেশি মাত্রায় বিভক্ত হয়ে যায়, স্বেচ্ছাসেবীর দিকনির্দেশনা সহ প্রসারিত এবং অসীম গ্রেডিয়েন্টের মতো ফ্রেম-নির্দিষ্ট সমস্যা ভোগ করে না।
বাস্তবায়ন অনুসারে, প্রতিটি দিকনির্দেশক ভেক্টরের সাথে সনাক্তকারী (এনাম, স্ট্রিং, আপনার যা প্রয়োজন) সে দিকটি উপস্থাপনের সাথে সংযুক্ত করে ফোটানো হবে। এরপরে আপনি আপনার সর্বোচ্চ দিকের পণ্য সহ একটি সন্ধান করে আপনার নির্দেশিকাগুলির সেটটি লুপ করবেন।
map<float2,Direction> candidates;
candidates[float2(1,0)] = E; candidates[float2(0,1)] = N; // etc.
for each (float2 dir in candidates)
{
float goodness = dot(dir, v);
if (goodness > bestResult)
{
bestResult = goodness;
bestDir = candidates[dir];
}
}
map
সঙ্গে float2
কী-এর মত? এটি খুব সিরিয়াস দেখাচ্ছে না।
এখানে একটি উপায় উল্লেখ করা হয়নি যা ভেক্টরগুলিকে জটিল সংখ্যা হিসাবে বিবেচনা করে। তাদের ত্রিকোণমিতির প্রয়োজন হয় না এবং এগুলি সংখ্যার জোড় হিসাবে উপস্থাপন করে আপনার শিরোনামটি ইতিমধ্যে তৈরি করার কারণে, ঘূর্ণনগুলি যোগ করার, গুণ করার বা গোল করার জন্য বেশ স্বজ্ঞাত হতে পারে।
আপনি যদি তাদের সাথে পরিচিত না হন তবে দিকনির্দেশগুলি একটি + বি (i) আকারে প্রকৃত উপাদান হিসাবে প্রকাশিত হয় এবং খ (i) কাল্পনিক। যদি আপনি কার্টেসিয়ান বিমানটি বাস্তবের সাথে এক্সটি বাস্তব এবং Y কল্পিত হওয়ার কথা কল্পনা করেন, 1 হবে পূর্ব (ডান), আমি উত্তর হবে।
মূল অংশটি এখানে: 8 টি মূল নির্দেশাবলী তাদের আসল এবং কাল্পনিক উপাদানগুলির জন্য 1, -1 বা 0 সংখ্যাগুলির সাথে একচেটিয়াভাবে প্রতিনিধিত্ব করা হয়।সুতরাং আপনাকে যা করতে হবে তা হ'ল আপনার এক্সকে কমিয়ে আনুন, ওয় অনুপাত হিসাবে স্থানাংক করে এবং দিকটি পেতে নিকটতম পুরো সংখ্যায় উভয়কেই গোল করে।
NW (-1 + i) N (i) NE (1 + i)
W (-1) Origin E (1)
SW (-1 - i) S (-i) SE (1 - i)
শিরোনাম থেকে নিকটতম তির্যক রূপান্তর জন্য, X এবং Y উভয়কে আনুপাতিকভাবে হ্রাস করুন যাতে বৃহত্তর মানটি হুবহু 1 বা -1 হয়। সেট
// Some pseudocode
enum xDir { West = -1, Center = 0, East = 1 }
enum yDir { South = -1, Center = 0, North = 1 }
xDir GetXdirection(Vector2 heading)
{
return round(heading.x / Max(heading.x, heading.y));
}
yDir GetYdirection(Vector2 heading)
{
return round(heading.y / Max(heading.x, heading.y));
}
মূলত (10, -2) উভয় উপাদানকেই গোল করা আপনাকে 1 + 0 (i) বা 1. দেয় So সুতরাং নিকটতম দিকটি পূর্ব।
উপরেরটি আসলে জটিল সংখ্যার কাঠামো ব্যবহারের প্রয়োজন হয় না, তবে এগুলি সম্পর্কে চিন্তা করা 8 টি মূল দিকনির্দেশ খুঁজে পাওয়া আরও দ্রুত করে তোলে। আপনি দুই বা ততোধিক ভেক্টরের নেট শিরোনাম পেতে চাইলে আপনি স্বাভাবিকভাবে ভেক্টর গণিত করতে পারেন। (জটিল সংখ্যা হিসাবে, আপনি যোগ করবেন না, তবে ফলাফলটির জন্য গুণ করুন)
Max(x, y)
Max(Abs(x, y))
নেতিবাচক চতুষ্কোণীদের জন্য কাজ করা উচিত । আমি এটি চেষ্টা করেছিলাম এবং izb হিসাবে একই ফলাফল পেয়েছি - এটি ভুল কোণে কম্পাস দিকনির্দেশগুলি স্যুইচ করে। আমি অনুমান করব যে শিরোনাম.y / শিরোনাম.এক্স 0.5 কে অতিক্রম করার সময় এটি পরিবর্তন হবে (সুতরাং গোলাকার মানটি 0 থেকে 1 এর দিকে স্যুইচ), যা আর্টিকান (0.5) = 26.565 ° °
এটি কাজ করে বলে মনে হচ্ছে:
public class So49290 {
int piece(int x,int y) {
double angle=Math.atan2(y,x);
if(angle<0) angle+=2*Math.PI;
int piece=(int)Math.round(n*angle/(2*Math.PI));
if(piece==n)
piece=0;
return piece;
}
void run(int x,int y) {
System.out.println("("+x+","+y+") is "+s[piece(x,y)]);
}
public static void main(String[] args) {
So49290 so=new So49290();
so.run(1,0);
so.run(1,1);
so.run(0,1);
so.run(-1,1);
so.run(-1,0);
so.run(-1,-1);
so.run(0,-1);
so.run(1,-1);
}
int n=8;
static final String[] s=new String[] {"e","ne","n","nw","w","sw","s","se"};
}
ই = 0, উঃপূঃ = 1, এন = 2, উঃপঃ = 3, পঃ = 4, দঃপঃ = 5, এস = 6, ব = 7
f (x, y) = mod ((4-2 * (1 + চিহ্ন (x))) * (1-চিহ্ন (y ^ 2)) - (2 + চিহ্ন (x)) * চিহ্ন (y)
-(1+sign(abs(sign(x*y)*atan((abs(x)-abs(y))/(abs(x)+abs(y))))
-pi()/(8+10^-15)))/2*sign((x^2-y^2)*(x*y))),8)
আপনি যখন একটি স্ট্রিং চান:
h_axis = ""
v_axis = ""
if (x > 0) h_axis = "E"
if (x < 0) h_axis = "W"
if (y > 0) v_axis = "S"
if (y < 0) v_axis = "N"
return v_axis.append_string(h_axis)
এটি আপনাকে বিটফিল্ড ব্যবহার করে ধ্রুবকগুলি দেয়:
// main direction constants
DIR_E = 0x1
DIR_W = 0x2
DIR_S = 0x4
DIR_N = 0x8
// mixed direction constants
DIR_NW = DIR_N | DIR_W
DIR_SW = DIR_S | DIR_W
DIR_NE = DIR_N | DIR_E
DIR_SE = DIR_S | DIR_E
// calculating the direction
dir = 0x0
if (x > 0) dir |= DIR_E
if (x < 0) dir |= DIR_W
if (y > 0) dir |= DIR_S
if (y < 0) dir |= DIR_N
return dir
সামান্য পারফরম্যান্সের উন্নতি <
হ'ল চেকগুলি সংশ্লিষ্ট- >
চেকগুলির অন্য-শাখায় স্থাপন করা হবে, তবে আমি এটি করা থেকে বিরত থেকেছি কারণ এটি পাঠযোগ্যতার ক্ষতি করে।
if (x > 0.9) dir |= DIR_E
এবং অন্যান্য সমস্ত উপর ভিত্তি করে লিখতে পারে । এটি ফিলিপের মূল কোডের চেয়ে ভাল এবং L2 আদর্শ এবং atan2 ব্যবহার করার চেয়ে কিছুটা সস্তা হওয়া উচিত। হতে পারে কিংবা না ও হতে পারে.