จะตรวจจับการคลิกบนขอบของมัลติกราฟได้อย่างไร?

ฉันได้เขียนแอป GUI ที่ใช้ win32 api ซึ่งใช้คุณสมบัติ GDI+ เช่น DrawCurve() และ DrawLine()

แอปนี้วาดเส้นและเส้นโค้งที่แสดงถึงมัลติกราฟ

โครงสร้างข้อมูลสำหรับ Edge เป็นเพียงโครงสร้างของห้า int (x1, y1, x2, y2 และรหัส)

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

ตอนนี้ฉันมีคำถามสองข้อในการตรวจจับการคลิกที่ขอบ

  1. ในการค้นหาขอบเส้นตรง เพื่อลดเวลาในการค้นหา ฉันควรทำอย่างไร
    การตรวจสอบว่าพิกเซลที่คลิกนั้นอยู่บนส่วนของเส้นนั้นค่อนข้างง่าย แต่การเปรียบเทียบขอบทั้งหมดจะไม่มีประสิทธิภาพหากจำนวนขอบมีขนาดใหญ่ ดูเหมือนว่าเป็นไปได้ที่จะทำใน O(log n) โดยที่ n คือจำนวนขอบ
    แก้ไข: ณ จุดนี้ขอบ (คลาส Edge) จะถูกเก็บไว้ใน std::map ที่แมป edge id (int)' ไปยังวัตถุ Edge และฉันกำลังพิจารณาที่จะประกาศคอนเทนเนอร์อื่นที่แมปพิกเซลกับ edge id's
    ฉันกำลังพิจารณาใช้แผนผังการค้นหาแบบไบนารี แต่อะไรจะเป็นกุญแจสำคัญได้ หรือฉันควรใช้เพียงอาร์เรย์พิกเซล 2D?

  2. ฉันสามารถรับอาร์เรย์ของคะแนนที่ใช้โดย DrawCurve() ได้หรือไม่ หากเป็นไปไม่ได้ ฉันควรคำนวณคาร์ดินัลสไปลน์ใหม่ รับอาร์เรย์ของจุด และตรวจสอบว่าจุดที่ผู้ใช้คลิกตรงกับจุดใดๆ ในอาร์เรย์นั้นหรือไม่


person Jeffrey Goines    schedule 06.11.2012    source แหล่งที่มา
comment
จุดประสงค์คือเพียงตรวจสอบว่ามีการคลิกขอบหรือไม่ หรือคุณจำเป็นต้องดึงค่าตามตำแหน่งที่คลิกขอบนั้น   -  person    schedule 06.11.2012
comment
แค่ตรวจดูว่าขอบไหนถูกคลิกก็ไม่เป็นไร จากนั้น id ของ edge จะถูกดึงออกมา และ std::map‹id, ​​Edge*› จะถูกค้นหา   -  person Jeffrey Goines    schedule 06.11.2012


คำตอบ (1)


หากคุณมีเส้นที่มีรูปร่างซับซ้อน คุณสามารถทำได้ดังนี้:

  • สร้างบิตแมปภายในที่มีขนาดเท่ากราฟของคุณแล้วเติมด้วยสีดำ
  • เมื่อคุณเรนเดอร์กราฟของคุณ เรนเดอร์ไปที่บิตแมปนี้ด้วยขอบที่คุณต้องการให้คลิกได้ แต่เรนเดอร์ด้วยสีอื่น เก็บค่าสีเหล่านี้ไว้ในตารางพร้อมกับรหัสที่เกี่ยวข้อง สิ่งสำคัญตรงนี้ก็คือสีที่แตกต่างกัน(unique)
  • เมื่อคลิกกราฟ ให้ถ่ายโอนพิกัด X และ Y ไปยังบิตแมปภายในของคุณแล้วอ่านพิกเซล หากไม่ใช่สีดำ ให้ค้นหาค่าสีในตารางของคุณและรับ ID ที่เกี่ยวข้อง

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

หวังว่านี่จะช่วยได้!

(เคล็ดลับ: คุณสามารถเรนเดอร์บรรทัด "ภายใน" ด้วยปากกาที่กว้างขึ้นเพื่อให้ละเอียดอ่อนยิ่งขึ้น)

person Community    schedule 06.11.2012
comment
ในความละเอียด 1920 x 1080 ด้วย 32 bpp (ดังนั้นจำนวนขอบสูงสุดที่สามารถวาดได้ในแต่ละครั้งคือ 2 ^ 32) ต้องใช้พื้นที่ประมาณ 8 MB เพื่อตรวจจับการคลิกขอบสำหรับแต่ละมุมมองกราฟ (ที่นี่ ฉันถือว่าแคนวาส ขนาดได้รับการแก้ไขเนื่องจากการจัดสรรบัฟเฟอร์บิตแมปบ่อยครั้งจะลดประสิทธิภาพลงอย่างมาก) ฉันคิดว่านี่เป็นวิธีที่ง่ายที่สุดและเร็วที่สุด (O(1)) ในการติดตั้ง แต่ในตอนแรกดูเหมือนว่าจะเปลืองพื้นที่มากเกินไป (O(xy)~=O(n^2)) อย่างไรก็ตาม ฉันสามารถลด bpp และลดขนาดของบัฟเฟอร์บิตแมปได้ เนื่องจากในทางปฏิบัติเส้นโค้งมากกว่าสองสามพันจะไม่สามารถมองเห็นได้เมื่อวาดเข้าด้วยกัน - person Jeffrey Goines; 06.11.2012
comment
แน่นอนว่า หากมองไม่เห็น = ไม่สามารถคลิกได้ ดังนั้นคุณจึงสามารถกำจัดอินสแตนซ์ที่ทับซ้อนกันได้ และอย่างที่คุณพูด ยังสามารถหาปริมาณจุดคลิกได้โดยการลดบิตแมปลงครึ่งหนึ่งรวมถึงพิกัด x/y หรือแม้แต่ลดบิตแมปลงเหลือ 1/4 โดยมีแต่ละจุดที่สามารถคลิกได้ในพื้นที่พิกเซล 4x4 แต่หาก คุณมีข้อดีมากมายในเวลาเดียวกันซึ่งอาจไม่สะดวกนัก ฉันจะใช้เพียง 24 bpp (2 ^ 24 หรือ 16.8 ล้านสีที่แตกต่างกัน - หรือแม้แต่บิตแมป 16 บิต) เนื่องจากในพื้นที่ 1920x1080 คุณจะไม่สามารถใช้สีนั้นทั้งหมดได้เนื่องจากมีเพียงประมาณ 2 ล้านเท่านั้น พิกเซลที่ปรากฏบนหน้าจอ - person ; 06.11.2012