আমি কীভাবে ব্রেসেনহ্যামের লাইন অ্যালগরিদমকে ভাসমান-পয়েন্ট শেষের পয়েন্টগুলিতে সাধারণীকরণ করব?


12

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

লাইনের গর্ত গ্রিড

তবুও এটির স্পর্শকারী সমস্ত গ্রিড স্কোয়ারগুলি অন্তর্ভুক্ত করার জন্য আমার এটি প্রয়োজন (যেমন কেবল ব্রেসেনহ্যামের লাইন নয় নীল রঙটি ):

ব্রেনহ্যাম বনাম পুরো ঝাড়ু

কেউ আমাকে কীভাবে এটি করতে পারে সে সম্পর্কে কোনও অন্তর্দৃষ্টি দিতে পারে? স্পষ্ট সমাধান হ'ল নিষ্পাপ লাইন অ্যালগরিদম ব্যবহার করা, তবে আরও কি আরও কিছু অনুকূল (দ্রুত) আছে?


যদি লিঙ্কটি অফলাইনে চলে যায়, কেবল "রেইট্রেসিংয়ের জন্য একটি দ্রুত ভোক্সেল ট্র্যাভারসাল অ্যালগরিদম" এর জন্য গুগল করুন
গুস্তাভো ম্যাকিয়েল

উত্তর:


9

আপনি গ্রিড ট্রভারসাল অ্যালগরিদম সন্ধান করছেন। এই কাগজ একটি ভাল বাস্তবায়ন দেয়;

কাগজে পাওয়া 2D এর মৌলিক বাস্তবায়ন এখানে:

loop {
    if(tMaxX < tMaxY) {
        tMaxX= tMaxX + tDeltaX;
        X= X + stepX;
    } else {
        tMaxY= tMaxY + tDeltaY;
        Y= Y + stepY;
    }
    NextVoxel(X,Y);
}

কাগজে একটি 3D রে-কাস্টিং সংস্করণও রয়েছে।

লিঙ্কটি দাগ দেওয়ার ক্ষেত্রে , আপনি এর নামের সাথে অনেকগুলি আয়না খুঁজে পেতে পারেন: রাইক্র্যাকিংয়ের জন্য একটি দ্রুত ভোক্সেল ট্রভারসাল অ্যালগরিদম


আচ্ছা, বিশ্রী। আমার ধারণা, আমি আপনার কাছে উত্তর সরিয়ে নিয়েছি এবং এলটিজ্যাক্স-আপ করব। কারণ আমি সেই কাগজের আপনার লিঙ্কের ভিত্তিতে সমাধান করেছি।
স্মার্টক 8

5

নীল ধারণাটি ভাল তবে বাস্তবায়নটি কিছুটা আনাড়ি। আসলে, আপনি স্কয়ারটি ছাড়াই এটি সহজেই করতে পারেন। আসুন সেই মুহুর্তের জন্য ধরে নেওয়া যাক আপনি ক্ষয়িষ্ণু কেসগুলি বাদ দেন ( BeginX==EndX || BeginY==EndY) এবং কেবল প্রথম চতুর্ভুজরেখার রেখার দিকনির্দেশগুলিতে ফোকাস করুন, তাই BeginX < EndX && BeginY < EndY। আপনাকে কমপক্ষে অন্য একটি চতুষ্পদার্থের জন্যও একটি সংস্করণ প্রয়োগ করতে হবে, তবে এটি প্রথম চতুর্ভুজটির সংস্করণটির সাথে খুব মিল - আপনি কেবল অন্য প্রান্তটি পরীক্ষা করে দেখেন। সি'স সিউডো কোডে:

int cx = floor(BeginX); // Begin/current cell coords
int cy = floor(BeginY);
int ex = floor(EndX); // End cell coords
int ey = floor(EndY);

// Delta or direction
double dx = EndX-BeginX;
double dy = EndY-BeginY;

while (cx < ex && cy < ey)
{
  // find intersection "time" in x dir
  float t0 = (ceil(BeginX)-BeginX)/dx;
  float t1 = (ceil(BeginY)-BeginY)/dy;

  visit_cell(cx, cy);

  if (t0 < t1) // cross x boundary first=?
  {
    ++cx;
    BeginX += t0*dx;
    BeginY += t0*dy;
  }
  else
  {
    ++cy;
    BeginX += t1*dx;
    BeginY += t1*dy;
  }
}

এখন অন্যান্য অর্ধেই, আপনি শুধু পরিবর্তন ++cxবা ++cyএবং লুপ শর্ত। যদি আপনি এটি সংঘর্ষের জন্য ব্যবহার করেন তবে আপনাকে সম্ভবত সমস্ত 4 টি সংস্করণ প্রয়োগ করতে হবে, অন্যথায় আপনি যথাযথভাবে অদলবদল এবং শেষের পয়েন্টগুলি দুটি দিয়ে পালিয়ে যেতে পারেন।


প্রদত্ত অ্যালগরিদম গুস্তাভো ম্যাকিয়েল কিছুটা বেশি দক্ষ। এটি কেবল প্রথম টিএস নির্ধারণ করে এবং তারপরে কেবল উল্লম্ব বা অনুভূমিকের সাথে 1 যুক্ত করে এবং টিএসকে একটি আকারের ঘর দ্বারা স্থানান্তরিত করে। তবে সে এটিকে কোনও উত্তরে রূপান্তরিত না করায় আমি এটিকে নিকটতম উত্তর হিসাবে গ্রহণ করব।
স্মার্টকে 8

3

আপনার অনুমান কক্ষগুলি সন্ধান করার জন্য অগত্যা নয় তবে এটি এই গ্রিডে যে লাইনগুলি পেরিয়েছে।

উদাহরণস্বরূপ আপনার চিত্র গ্রহণের জন্য আমরা কক্ষগুলি নয়, গ্রিডের রেখাগুলি হাইলাইট করতে পারি:

লাল রেখা

এরপরে এটি দেখায় যে এটি যদি গ্রিড লাইনটি অতিক্রম করে তবে এই লাইনের উভয় পাশের ঘরগুলি ভরাট রয়েছে।

আপনার ভাসমান পয়েন্ট লাইনটি পয়েন্টগুলিতে আপনার পয়েন্টগুলি স্কেল করে এগুলি অতিক্রম করবে কিনা তা জানতে আপনি ছেদটি অ্যালগরিদম ব্যবহার করতে পারেন। আপনার যদি ভাসমান স্থানাঙ্কগুলির একটি 1.0: 1 অনুপাত থাকে: পিক্সেল তখন আপনার বাছাই করা হয় এবং আপনি কেবল এটি সরাসরি অনুবাদ করতে পারেন। লাইন বিভাগটি ছেদ অ্যালগরিদম ব্যবহার করে আপনি নীচের বাম রেখাটি (1,7) (2,7) আপনার লাইনের (1.3,6.2) (6.51,2.9) সাথে ছেদ করেছে কিনা তা পরীক্ষা করতে পারেন। http://alienryderflex.com/intersect/

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

//  public domain function by Darel Rex Finley, 2006

//  Determines the intersection point of the line defined by points A and B with the
//  line defined by points C and D.
//
//  Returns YES if the intersection point was found, and stores that point in X,Y.
//  Returns NO if there is no determinable intersection point, in which case X,Y will
//  be unmodified.

bool lineIntersection(
double Ax, double Ay,
double Bx, double By,
double Cx, double Cy,
double Dx, double Dy,
double *X, double *Y) {

  double  distAB, theCos, theSin, newX, ABpos ;

  //  Fail if either line is undefined.
  if (Ax==Bx && Ay==By || Cx==Dx && Cy==Dy) return NO;

  //  (1) Translate the system so that point A is on the origin.
  Bx-=Ax; By-=Ay;
  Cx-=Ax; Cy-=Ay;
  Dx-=Ax; Dy-=Ay;

  //  Discover the length of segment A-B.
  distAB=sqrt(Bx*Bx+By*By);

  //  (2) Rotate the system so that point B is on the positive X axis.
  theCos=Bx/distAB;
  theSin=By/distAB;
  newX=Cx*theCos+Cy*theSin;
  Cy  =Cy*theCos-Cx*theSin; Cx=newX;
  newX=Dx*theCos+Dy*theSin;
  Dy  =Dy*theCos-Dx*theSin; Dx=newX;

  //  Fail if the lines are parallel.
  if (Cy==Dy) return NO;

  //  (3) Discover the position of the intersection point along line A-B.
  ABpos=Dx+(Cx-Dx)*Dy/(Dy-Cy);

  //  (4) Apply the discovered position to line A-B in the original coordinate system.
  *X=Ax+ABpos*theCos;
  *Y=Ay+ABpos*theSin;

  //  Success.
  return YES; }

আপনার যদি কেবলমাত্র (এবং কোথায়) লাইন বিভাগগুলি ছেদ করে তা খুঁজে বের করতে হবে তবে আপনি ফাংশনটি নিম্নরূপে সংশোধন করতে পারেন:

//  public domain function by Darel Rex Finley, 2006  

//  Determines the intersection point of the line segment defined by points A and B
//  with the line segment defined by points C and D.
//
//  Returns YES if the intersection point was found, and stores that point in X,Y.
//  Returns NO if there is no determinable intersection point, in which case X,Y will
//  be unmodified.

bool lineSegmentIntersection(
double Ax, double Ay,
double Bx, double By,
double Cx, double Cy,
double Dx, double Dy,
double *X, double *Y) {

  double  distAB, theCos, theSin, newX, ABpos ;

  //  Fail if either line segment is zero-length.
  if (Ax==Bx && Ay==By || Cx==Dx && Cy==Dy) return NO;

  //  Fail if the segments share an end-point.
  if (Ax==Cx && Ay==Cy || Bx==Cx && By==Cy
  ||  Ax==Dx && Ay==Dy || Bx==Dx && By==Dy) {
    return NO; }

  //  (1) Translate the system so that point A is on the origin.
  Bx-=Ax; By-=Ay;
  Cx-=Ax; Cy-=Ay;
  Dx-=Ax; Dy-=Ay;

  //  Discover the length of segment A-B.
  distAB=sqrt(Bx*Bx+By*By);

  //  (2) Rotate the system so that point B is on the positive X axis.
  theCos=Bx/distAB;
  theSin=By/distAB;
  newX=Cx*theCos+Cy*theSin;
  Cy  =Cy*theCos-Cx*theSin; Cx=newX;
  newX=Dx*theCos+Dy*theSin;
  Dy  =Dy*theCos-Dx*theSin; Dx=newX;

  //  Fail if segment C-D doesn't cross line A-B.
  if (Cy<0. && Dy<0. || Cy>=0. && Dy>=0.) return NO;

  //  (3) Discover the position of the intersection point along line A-B.
  ABpos=Dx+(Cx-Dx)*Dy/(Dy-Cy);

  //  Fail if segment C-D crosses line A-B outside of segment A-B.
  if (ABpos<0. || ABpos>distAB) return NO;

  //  (4) Apply the discovered position to line A-B in the original coordinate system.
  *X=Ax+ABpos*theCos;
  *Y=Ay+ABpos*theSin;

  //  Success.
  return YES; }

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

তবে তবুও আপনাকে উত্তর দেওয়ার জন্য ধন্যবাদ। প্রযুক্তিগতভাবে এটি কাজ করে এবং সঠিক। তবে আমার পক্ষে ঠিক সম্ভব নয়।
স্মার্টক 8

3
float difX = end.x - start.x;
float difY = end.y - start.y;
float dist = abs(difX) + abs(difY);

float dx = difX / dist;
float dy = difY / dist;

for (int i = 0, int x, int y; i <= ceil(dist); i++) {
    x = floor(start.x + dx * i);
    y = floor(start.y + dy * i);
    draw(x,y);
}
return true;

জেএস ডেমো:

Imgur


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

0

আমি আজ একই সমস্যায় পড়েছি এবং একটি তিল পাহাড়ের বাইরে স্প্যাগেটির একটি দুর্দান্ত বড় পর্বত তৈরি করেছি তবে এটি এমন কিছু কাজ করে শেষ করেছে: https://github.com/SnpM/Pan-Line- অ্যালগোরিদম

রিডম থেকে:

এই অ্যালগরিদমের মূল ধারণাটি ব্রেসেনহ্যামের সাথে সমান যে এটি এক অক্ষতে 1 ইউনিট বৃদ্ধি করে এবং অন্য অক্ষের বৃদ্ধি পরীক্ষা করে। ভগ্নাংশগুলি ইনক্রিমেন্টিংকে আরও বেশি কঠিন করে তোলে, তবে প্রচুর পিজ্জা যুক্ত করতে হয়েছিল For উদাহরণস্বরূপ, 5 এর slাল দিয়ে এক্স = .21 থেকে এক্স = 1.21 বাড়ানো একটি জটিল সমস্যা তৈরি করে (সেই দুষ্টু সংখ্যার মধ্যে নিদর্শন সমন্বয় করে) ভবিষ্যদ্বাণী করা শক্ত) তবে 5 এর slালু 1 দিয়ে 2 থেকে বাড়ানো একটি সহজ সমস্যা তৈরি করে। পূর্ণসংখ্যার মধ্যে সমন্বয়মূলক প্যাটার্ন সমাধান করা খুব সহজ (বর্ধমান অক্ষের জন্য একটি লম্ব লম্ব)। সহজ সমস্যাটি পেতে, ইনক্রিমেন্টিংটি ভগ্নাংশের অংশের জন্য পৃথকভাবে সমস্ত গণনা সম্পন্ন করে একটি পূর্ণসংখ্যার সাথে অফসেট করা হয়। সুতরাং .21 উপর বৃদ্ধি শুরু করার পরিবর্তে,

রিডমি কোডের চেয়ে সমাধানটি আরও ভালভাবে ব্যাখ্যা করে। আমি এটিকে সংশোধন করার পরিকল্পনা করছি যাতে কম মাথা ব্যথা হয়।

আমি জানি আমি এই প্রশ্নের প্রায় একবছর দেরিতে এসেছি তবে আমি আশা করি যে এই সমস্যাটির সমাধান খুঁজছেন এমন অন্যদের কাছে এটি পেয়ে গেল।

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