การเรียงลำดับของคะแนนตามลำดับตามเข็มนาฬิกา


16

มีอัลกอริธึมในการเรียงลำดับอาร์เรย์ของคะแนน 2D ตามลำดับตามเข็มนาฬิกาหรือไม่?
ฉันกำลังจัดการสามเหลี่ยมมุมฉากในกรณีของฉันโดยเฉพาะดังนั้น 3 คะแนน

อย่างไรก็ตามฉันสนใจที่จะทราบว่ามีอัลกอริธึมอยู่หรือไม่หากไม่มีวิธีง่ายๆในการคืนค่า 3 คะแนนของสามเหลี่ยมตามลำดับตามเข็มนาฬิกา

แก้ไข: ฉันพยายามคำนวณคะแนนตามเข็มนาฬิกาที่สัมพันธ์กับเซนทรอยด์ของรูปหลายเหลี่ยมซึ่งเป็นรูปนูน

อัปเดต: นี่คือการนำไปใช้ที่ฉันใช้โดยใช้คำตอบที่เลือกไม่ใช่ประสิทธิภาพที่สำคัญและจะเกิดขึ้นเพียงครั้งเดียวเพื่อให้ได้ผล

ArrayList<PVector> pointList = new ArrayList<PVector>();
pointList.add(A);
pointList.add(B);
pointList.add(C);
Collections.sort( pointList, new TriangleVectorComparator(origin) );

return pointList;

// Comparator
package triangleeditor;

import java.util.Comparator;

import processing.core.PVector;

public class TriangleVectorComparator implements Comparator<PVector>  {
    private PVector M; 
    public TriangleVectorComparator(PVector origin) {
        M = origin;
    }

    public int compare(PVector o1, PVector o2) {
        double angle1 = Math.atan2(o1.y - M.y, o1.x - M.x);
        double angle2 = Math.atan2(o2.y - M.y, o2.x - M.x);

        //For counter-clockwise, just reverse the signs of the return values
        if(angle1 < angle2) return 1;
        else if (angle2 < angle1) return -1;
        return 0;
    }

}

1
return สามารถคืนค่า angle1 ได้ <angle2? 1: angle2> angle1 หรือไม่ -1: 0;
ademar111190

2
มันสามารถแสดงได้หลายวิธี แต่ฉันมักจะหลีกเลี่ยงผู้ประกอบการที่ประกอบไปด้วยสามโดยเฉพาะอย่างยิ่งเมื่อให้ตัวอย่าง
onedayit จะทำให้

@onedayitwillmake คุณสามารถย้ายรหัสที่คุณใช้เป็นคำตอบได้หรือไม่? มันไม่ได้เป็นของคำถาม แต่มีค่ามากสำหรับผู้อ่านในอนาคต
Anko

@ Anko ฉันคิดว่าคุณพูดถูก แต่ในเวลาเดียวกันฉันคิดว่ามันจะง่ายที่สุดสำหรับคนที่จะค้นพบวิธีนี้ นอกจากนี้ยังช่วยให้แน่ใจว่าฉันไม่ได้รับคำตอบจาก samhocevar ซึ่งเป็นไปตามที่ฉันคิด
onedayit จะทำให้

คำตอบ:


19

คำถามของคุณไม่แม่นยำพอ อาร์เรย์ของคะแนนนั้นเป็นเพียง«ตามเข็มนาฬิกา»หรือ«ทวนเข็มนาฬิกา»ที่สัมพันธ์กับจุดอ้างอิง มิฉะนั้นอาร์เรย์สามจุดใด ๆ สามารถเป็นได้ทั้ง CW หรือ CCW ดูภาพต่อไปนี้: ด้านซ้ายมีการเรียงลำดับตามเข็มนาฬิกา ทางด้านขวามีการสั่งให้คะแนนเดียวกันกับทวนเข็มนาฬิกา

clockwise or anticlockwise

ในกรณีของคุณฉันเชื่อว่าการใช้ barycenter ของคะแนนเป็นจุดอ้างอิงนั้นสมเหตุสมผล

วิธีการที่ดีสำหรับจำนวนคะแนนที่ไม่รู้จักอาจเป็นหนึ่งในวิธีต่อไปนี้:

  • ให้P[0], P[1], ... P[n-1]เป็นรายการของคะแนนเพื่อเรียงลำดับ
  • ให้ M เป็นศูนย์รวมของคะแนนทั้งหมด
  • คำนวณa[0], a[1], ... a[n-1]เช่นนั้นa[i] = atan2(P[i].y - M.y, P[i].x - M.x);
  • เรียงลำดับคะแนนสัมพันธ์กับaค่าของพวกเขาใช้qsortเป็นตัวอย่าง

อย่างไรก็ตามคุณสามารถมั่นใจได้ว่าอัลกอริทึมการเรียงลำดับที่ดีจะทำงานได้ไม่ดีโดยมีค่าอินพุตสามค่าเมื่อเปรียบเทียบกับวิธีการเฉพาะกิจ การใช้atan2ยังคงถูกต้อง qsortแต่ก็ไม่ได้ใช้


สิ่งนี้ทำงานได้อย่างสมบูรณ์แบบ :)
onedayitwillmake

1
วิธีนี้มีชื่อหรือไม่?
onedayitwillmake

1
ฉันเชื่อว่านี่เรียกง่ายๆว่า "การเรียงลำดับตามมุมขั้ว" มันเป็นองค์ประกอบของGraham Scanตัวอย่างเช่น
sam hocevar

ตีประสิทธิภาพการทำงานของที่นี่มีขนาดเล็กเมื่อเทียบกับqsort atan2

คำเตือนเล็ก ๆ นี้อาจจะผิดพลาดและการเผาไหม้ (ขึ้นอยู่กับการเขียนโปรแกรมภาษาและห้องสมุดที่ใช้) ถ้ามีจุดที่จะเกิดขึ้นตรงที่ barycentre (หรือสิ่งที่จุดอื่น ๆ ของการวางแนวที่คุณใช้) คุณอาจต้องการยกเว้นคะแนนดังกล่าวระหว่างขั้นตอนที่สองและสาม
Martin Sojka

3

ฉันเชื่อว่าสิ่งที่คุณถามจริงเกี่ยวกับที่นี่คือลำดับคดเคี้ยวของรูปสามเหลี่ยมซึ่งจริงๆแล้วค่อนข้างง่ายในการทดสอบ

เนื่องจากมีเพียงสามจุดในรูปสามเหลี่ยมของคุณรูปสามเหลี่ยมของคุณจึงอยู่ในลำดับตามเข็มนาฬิกาหรือทวนเข็มนาฬิกาแล้วดังนั้นสิ่งที่คุณต้องทำคือการตรวจสอบว่าทั้งสองนั้นเป็นแบบใดและเรียงลำดับดัชนีถ้าคดเคี้ยว ไม่ใช่คนที่คุณต้องการ

นี่คือความคิดทั่วไปโดยสมมติว่าจุดยอดสามจุดของสามเหลี่ยมคือa , bและcและคุณมีการลบเวกเตอร์อย่างง่าย:

Vector2 AToB = b - a;
Vector2 BToC = c - b;
float crossz = AToB.x * BToC.y - AToB.y * BToC.x;
if ( crossz > 0.0f )
{
  // clockwise
}
else
{
  // counter-clockwise.  Need to reverse the order of our vertices.
}

โปรดทราบว่าขึ้นอยู่กับวิธีที่คุณเน้นแกน + y ของคุณ (ขึ้นหรือลง) กรณี "ตามเข็มนาฬิกา" และ "ทวนเข็มนาฬิกา" อาจถูกย้อนกลับจากวิธีที่ฉันติดป้ายกำกับไว้ในความคิดเห็นในโค้ดตัวอย่างนี้


ฉันต้องผ่านจุดเหล่านี้ไปยัง Box2D (การติดตั้งจาวา) เพื่อสร้างรูปหลายเหลี่ยม ถึงแม้ว่ามันจะไม่ใช่สิ่งที่ฉันถาม แต่ก็มีความเข้าใจที่ดีมาก :)
onedayitwillmake

2

คุณสามารถให้ข้อมูลเพิ่มเติมได้หรือไม่ คุณต้องการลำดับของ CCW แต่จุดใดที่ควรเป็นจุดศูนย์กลางของการสั่งซื้อ

หากคุณมีเพียงสามเหลี่ยม (3 คะแนน) ในเครื่องบินคุณสามารถคำนวณดีเทอร์มีแนนต์จากเมทริกซ์โดยที่เส้นนั้นเป็นพิกัดของจุด (พิกัดที่ 3 คือ 1) หากดีเทอร์มิแนนต์คือ> 0 คะแนนจะอยู่ในลำดับ CCW ถ้าไม่คุณสามารถยกตัวอย่างเช่นสองคะแนนสุดท้ายและคุณจะได้รับคำสั่งซื้อ CCW

หากคุณมีคะแนน A, B, C แสดงว่าเมทริกซ์ของคุณมีลักษณะดังนี้:

|xA, yA, 1|
|xB, yB, 1|
|xC, yC, 1|

ตัวกำหนดคือ: xA * yB + xB * yC + xC * yA - yB * xC - yC * xA - yA * xB จากนั้นคุณสามารถเปรียบเทียบกับศูนย์ ถ้าเป็น> 0 ให้ส่งคืนแต้ม A, B, C หากไม่ใช่ให้ส่งคืน A, C, B

หากคุณมีจุดและรู้ว่าพวกเขาทำรูปหลายเหลี่ยมนูน (ทั้งหมดเป็นส่วนหนึ่งของฮัลล์นูน) และต้องการได้รับคำสั่งของพวกเขาคุณสามารถใช้เกรแฮมสแกนหรือจาร์วิสมีนาคม (เหล่านี้เป็นอัลกอริทึมเพื่อค้นหาฮัลล์นูนจากหลายจุด มันควรทำงานที่นี่ด้วย :))


เพื่อให้สิ่งที่ซาคาร์มาเรซพูดให้สมบูรณ์ถ้าคุณต้องการเรียงลำดับตามเข็มนาฬิกาตามรอบจุดเฉพาะคุณสามารถสร้างอาร์เรย์จากคู่ของโฟลตและจุดที่คุณเก็บคะแนนทั้งหมดด้วยมุมที่สอดคล้องกันจากจุดนั้นแล้วเรียงลำดับ อาร์เรย์นั้น
Ali1S232
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.