การทดสอบที่เชื่อถือได้สำหรับจุดตัดของสองเส้นโค้ง Bezier


9

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

ฉันพบคำตอบหลายคำใน StackOverflow ที่ใช้กล่องขอบเขตของเส้นโค้งสำหรับการทดสอบ: นี่ไม่ใช่สิ่งที่ฉันตามมาเพราะการทดสอบดังกล่าวอาจรายงานจุดตัดแม้ว่าเส้นโค้งจะไม่ตัดกัน

สิ่งที่ใกล้เคียงที่สุดที่ฉันพบคือ " ขอบเขตลิ่ม " โดย Sederberg และ Meyers แต่มัน "เท่านั้น" แยกความแตกต่างระหว่างมากที่สุด - หนึ่ง - สองและ - หรือ - สี่แยกมากกว่าในขณะที่ฉันอยากจะรู้ว่ามี - ที่สุด - ศูนย์ และทางแยกอย่างน้อยหนึ่งรายการ


ฉันไม่แน่ใจว่ามันมีอยู่เช่นนี้การกำหนดความเป็นไปได้หรือมีความเป็นไปได้สำหรับ 0-1 หรือ 2 หรือมากกว่านั้นเป็นเรื่องเล็กน้อย แต่การกำหนดไม่ได้ทำให้มันง่ายจริงๆเพื่อให้แน่ใจว่า 0 หรือ 1 โดยไม่ต้องตรวจสอบจริง
joojaa

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

@ Dragonelel ดีฉันจะมีความสุขสำหรับการแก้ปัญหาใด ๆ จริง ๆ แต่เนื่องจากคุณถาม O (1) จะดี แต่การประมาณค่าส่วนโค้งด้วยส่วนของเส้นตรงจะนำไปสู่ปัญหาเช่นเดียวกับการทดสอบการซ้อนกล่อง ...
Ecir Hana

ปัญหาที่น่าสนใจ ฉันไม่คิดว่าจะมีคำตอบง่าย ๆ แต่ฉันอยากจะผิด คุณมีลิงค์สำหรับกระดาษ Sederberg และ Meyers หรือไม่?
Daniel M Gessel

@DanielMGessel ใช่ดูการแก้ไขด้านบน
Ecir Hana

คำตอบ:


6

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

หากต้องการให้ชัดเจนให้กำหนดเส้นโค้ง 2D คู่หนึ่งที่กำหนดโดย c1,c2:[0,1]R2กำหนดระยะห่างยกกำลังเป็น

f(u,v):[0,1]2R0|c2(v)c1(u)|2

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


ทำไมมันเป็นพหุนามระดับ 6 และไม่ใช่อันดับ 3 ถ้าเราพูดถึงลูกบาศก์เบซิเยร์ และทั้งสองวิธีที่คุณเชื่อมโยงเข้าด้วยกันพวกมันตอบสนองการค้นหาวิธีแก้ปัญหาเท่านั้น[0,1]2เมื่อเทียบกับทั้งหมด R2?
Ecir Hana

1
@EcirHana เป็นระดับที่ 6 เพราะมันเป็นระยะทางกำลังสอง (คุณสามารถสแควร์รูทได้ แต่จากนั้นมันจะไม่เป็นพหุนามอีกต่อไปและจะไม่ราบรื่นที่ศูนย์) โปรดทราบว่า[0,1]คือพื้นที่พารามิเตอร์ไม่ใช่พื้นที่ที่เส้นโค้งอยู่เช่นเหล่านี้เป็นเส้นโค้งที่มีจุดสิ้นสุด ไม่ว่าในกรณีใดวิธีการจะทำงานได้ดีR2แต่พวกเขาเพียง "เดินทางลงเนิน" จากการคาดเดาเริ่มต้นและค้นหาขั้นต่ำในท้องถิ่น จำเป็นต้องมีสิ่งเพิ่มเติมในการตรวจสอบพื้นที่พารามิเตอร์ทั้งหมดและค้นหาค่าต่ำสุดทั่วโลก การ จำกัด พื้นที่พารามิเตอร์อาจมีประโยชน์
Nathan Reed

1
นาธาน - สูตรที่ดี! ฉันเป็นสนิม แต่: ฉันคิดว่าคุณสามารถแบ่งเส้นโค้งเบซิเยร์ออกได้มากที่สุด 5 ส่วนโดยที่x หรือ y เปลี่ยนทิศทางในโค้ง xเป็นหน้าที่ของ ci เปลี่ยนทิศทางอย่างมากสองครั้ง (รากของอนุพันธ์) แบ่งเส้นโค้งเป็น 3 ส่วนซึ่ง 2 อาจถูกแบ่งอีกครั้งโดยการเปลี่ยนทิศทางของ y. ตอนนี้คุณมีไม่ใช่เซ็กเมนต์ที่ตรง แต่เซ็กเมนต์ที่ "ไม่โค้งมากเกินไป" ฉันคิดว่าถ้าคุณเริ่มการค้นหาของคุณที่ 25 คะแนนโดยการเลือกคู่เซ็กเมนต์คุณสามารถค้นหา minima ทั่วโลกได้ตลอดเวลา แต่ฉันไม่สามารถดูวิธีการพิสูจน์ (หรือหักล้าง) ได้
Daniel M Gessel

@ นาธาน: ฉันได้พิจารณาแล้ว แต่หลังจากใช้เวลาเขียนโค้ดเพื่อหา minima ในรูปแบบการบีบอัดพื้นผิวมันก็ดูน่าเกลียดไปหมด
Simon F

5

[ข้อสงวนสิทธิ์: ฉันคิดว่าสิ่งต่อไปนี้ควรใช้งานได้ แต่ไม่ได้เข้ารหัสด้วยตนเองจริง ๆ ]

ฉันไม่สามารถคิดถึงวิธี "เล็กน้อย" ในการสร้างคำตอบใช่ / ไม่ใช่ แต่ต่อไปนี้จะเป็นวิธีการที่สมเหตุสมผลในการแก้ปัญหาที่ใช้งานได้จริง

สมมติว่าส่วนโค้งของเราคือA (s)และB (t) ที่มีจุดควบคุม { A0, A1..An } และ { B0, .. Bm } ตามลำดับ

สำหรับผมแล้วดูเหมือนว่าด้วย 2D Beziers ที่เราต้องการตรวจสอบว่าทำหรือไม่ตัดกันมีหกกรณีที่ต้องพิจารณา:

  1. กรณีที่เราสามารถ "บังเอิญ" ได้ว่าพวกเขาไม่ตัดกัน

  2. กรณีที่พวกเขาตัดกันจำนวนครั้งที่ จำกัด และเราสามารถ "ง่าย" กำหนดว่าพวกเขาตัดกันอย่างน้อยหนึ่งครั้ง (แต่เราไม่สนใจว่าจะเกิดการแยกที่ใด)

  3. หนึ่งใน Beziers เสื่อมโทรมคือจุด (ซึ่งจะเกิดขึ้นหากจุดควบคุมทั้งหมดเหมือนกัน) เราสามารถสมมติว่าเราจัดการกรณีที่ทั้งสองเป็นจุดแล้ว

  4. มีการปิดโค้งอย่างน้อยหนึ่งเส้นเช่น A0 == เพื่อให้ชีวิตง่ายขึ้นเราจะแบ่งเส้นโค้งดังกล่าวแล้วเริ่มใหม่อีกครั้ง

  5. มีจำนวนจุดตัดที่ไม่สิ้นสุดเนื่องจากแต่ละจุดย่อยของ "แม่" Bezier และซ้อนทับกัน

  6. เราไม่แน่ใจเกี่ยวกับกรณีข้างต้นและต้องการการตรวจสอบเพิ่มเติม

สำหรับช่วงเวลาที่เราจะละเว้น 3 และ 4 แต่กลับมาหาพวกเขาในภายหลัง

กรณีที่ 1

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

ป้อนคำอธิบายรูปภาพที่นี่

กรณีที่ 2

หากการทดสอบกรณีที่ 1 ล้มเหลวคุณสามารถตรวจสอบการมีอยู่ของ "จุดตัด" เล็กน้อย ขณะนี้มีวิธีที่ดีกว่าในการทำเช่นนี้ แต่วิธีการดังกล่าวค่อนข้างถูกเกิดขึ้นกับฉัน:

พิจารณาเพียงการโค้ง A:

"เส้นไขมัน" ขอบเขตของ Bezier

เรารู้ว่าเส้นโค้งเริ่มต้นที่ A0สิ้นสุดที่เวลา Anและจะอยู่ข้างในตัวเรือนูน เพื่อความง่ายให้เราคำนวณทิศทางของส่วนของเส้นตรงA0An¯ และคำนวณขอบเขตทั้งสองด้าน (เช่นนำผลิตภัณฑ์ดอทของจุดควบคุมที่เหลือเทียบกับตั้งฉากกับ A0An¯)

หากเราทำเช่นเดียวกันกับเส้นโค้ง B เราจะได้รับกรณี (เป็นไปได้) ต่อไปนี้: ป้อนคำอธิบายรูปภาพที่นี่

หากเราพบ A0 และ Anอยู่นอกขอบเขตตรงข้ามของ B และนั่นB0 และ Bm อยู่ด้านนอกของขอบเขตของ A จากนั้นโดยความต่อเนื่องของเบซิเยร์ต้องมีจุดตัดอย่างน้อยหนึ่งจุด

กรณีที่ 6

หากเราไม่สามารถแสดงกรณีใดกรณีหนึ่งข้างต้นได้ทันทีให้แบ่ง Beziers แต่ละรายการออกเป็นสองส่วน "ครึ่งหนึ่ง" A1,A2,B1,B2. นี่เป็นเรื่องตรงไปตรงมา (จากการออกกำลังกายไปยังผู้อ่าน) แต่โดยเฉพาะอย่างยิ่งสำหรับเบซิเยร์กำลังสอง :

เปรียบเทียบชุดค่าผสม 4 แบบซ้ำ ๆ : (A1,B1),(A2,B1)...(A2,B2). เห็นได้ชัดว่าทุกกรณีผ่าน 1 ไม่มีจุดตัด หากล้มเหลว 1 ให้ดำเนินการทดสอบส่วนที่เหลือต่อด้วยเซตย่อยที่ลดลง

กรณีที่ 3 และ 5

นี่คือที่ที่มันน่าเบื่อกว่าเล็กน้อย

หาก "กรณีที่ 3" ผ่านการทดสอบ "กรณีที่ 1" ดูเหมือนว่าคุณต้องแก้ปัญหาสำหรับการตัดกันจริง เนื่องจากมีขั้นตอนง่าย ๆ ในการทำแผนที่จุดควบคุม N ของ Bezier, A (s), ไปยังจุด N-1 ของ Bezier, A (s) ซึ่งเป็นตัวแทนของอนุพันธ์อันดับที่ 1 ของมันแล้ว ค่อนข้างยากที่เรียกว่าสถานการณ์ "เสื่อม" ซึ่งอนุพันธ์อันดับที่ 1 มีค่าเป็นศูนย์) จากนั้นก็สามารถใช้การวนซ้ำของนิวตัน (ในมิติเดียว) เพื่อหาคำตอบที่อาจเกิดขึ้น
โปรดทราบว่าเนื่องจากจุดควบคุมของ A 'มีความผูกพันกับมูลค่าอนุพันธ์จึงมีความเป็นไปได้ที่จะทำการกำจัดบางกรณีในช่วงต้น

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


ใช่ แต่ฉันสนใจตัวบุคคลมากขึ้นในกรณีที่เกี่ยวกับกรณีที่ Bm และ / หรือ B0 มีทั้งภายในปริมาณสูงสุดและต่ำสุดของ A แต่ไม่เจาะมันแล้วคุณต้องแบ่งย่อยและในกรณีที่เลวร้ายที่สุดคำนวณการแยก จุด. วิธีที่ดีกว่าคือการใช้กล่องขอบเขตขั้นต่ำหรือที่รู้จักกันในชื่อการประมาณเส้นหนา
joojaa

เมื่อพิจารณาว่าด้วยการแบ่งไบนารีทุกส่วนความแตกต่างระหว่างส่วนโค้งและส่วนที่เชื่อมต่อจุดสิ้นสุดจะลดลงตามปัจจัยที่สมเหตุสมผล (และจากส่วนบนของหัวของฉันฉันคิดว่ามันอาจจะเป็น 4 เท่าสำหรับคว เพื่อบรรจบกับริบบิ้น "บาง" อย่างรวดเร็ว
Simon F

ใช่ แต่สถานการณ์กรณีที่เลวร้ายที่สุดคือว่าอีก bezier เริ่มต้นที่อื่น
joojaa

คุณหมายถึงตัวอย่างเช่น== B0 คุณกำหนดว่าเป็นทางแยกหรือไม่?
Simon F

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