วันนี้ตอนที่ฉันกำลังศึกษาหนังสือ "HTML5+Javascript Animation Basics" ในส่วนที่สามของบทที่ 8 ฉันได้พูดถึงวิธีใช้สปริง 3 ตัวเพื่อเชื่อมต่อจุด 3 จุดเพื่อยืดกล้ามเนื้อ
หลังจากยกตัวอย่างเสร็จแล้วก็คิดว่าจะเป็นสี่จุดหรือห้าจุดล่ะ
ฉันเขียนโค้ดใหม่และทำให้จำนวนคะแนนแปรผัน ผลลัพธ์สุดท้ายคือต้องบรรลุการเคลื่อนไหวยืดครั้งสุดท้ายของแต่ละจุดให้สมดุล แต่การเชื่อมต่อระหว่างจุดนั้นดูไม่สวยงามนัก และบางจุดก็ไขว้กัน
ดังนั้นฉันจึงคิดว่าจะปรับพื้นที่นี้ให้เหมาะสมได้หรือไม่
หมุนเส้นจุดในตัวอย่างก่อนหน้านี้ทั้งหมดอยู่ในตำแหน่งสุ่ม ดังนั้นการเชื่อมต่อจึงไม่สามารถควบคุมได้ เลยอยากจะเริ่มเรื่องนี้ก่อน
ขั้นแรก ใช้จุดใดจุดหนึ่งเป็นจุดอ้างอิงเพื่อให้ได้มุมของจุดอื่นๆ ที่สัมพันธ์กับจุดนี้
จากนั้นเชื่อมต่อจุดเหล่านี้ตามมุมจากเล็กไปใหญ่เพื่อให้คุณสามารถวาดรูปหลายเหลี่ยมปกติได้
รหัสการใช้งานโดยประมาณมีดังนี้:
ให้ลูกบอล = []; ให้ ballNum = 6; ให้ firstBall = null; ในขณะที่ (ballNum--) { ให้ ball = ลูกบอลใหม่ (20, parseColor (Math.random () * 0xffffff)) ball.x = Math.random ( ) * width; ball.y = Math.random() * height; ball.push(ball) if (!firstBall) { firstBall = ball ball.angle = 0 } อื่น ๆ { const dx = ball.x - firstBall.x, dy = ball.y - firstBall.y; ball.angle = Math.atan2(dy, dx); }}// พยายามทำให้เส้นที่เชื่อมต่อลูกบอลเป็นรูปหลายเหลี่ยมปกติ = ลูกบอล .sort((ballA, ballB) => { ส่งคืน ballA.angle - ballB.angle})
ด้วยวิธีนี้ เมื่อการเชื่อมต่อถูกดึงออกมาในที่สุด มุมก็สามารถถูกดึงจากเล็กไปหาใหญ่ได้โดยการเคลื่อนที่ผ่านอาเรย์
เอฟเฟกต์มีดังนี้:
วิธีนี้สามารถลดจำนวนเส้นข้ามได้อย่างมาก แต่ก็ยังไม่สามารถหลีกเลี่ยงได้ทั้งหมด
ต่อไป ฉันต้องการลองปรับโซลูชันนี้ให้เหมาะสม ตัวอย่างเช่น ใช้ Math.abs เพื่อแก้ไขมุม หรือค้นหาจุดที่มีมุมที่เล็กที่สุดเพื่อเชื่อมต่อแต่ละจุด แต่ผลไม่ดีก็ข้ามเส้นไม่ได้
หมุนตามจุดศูนย์กลางความคิดอีกอย่างหนึ่งก็เข้ามาในใจ หากสามารถกำหนดจุดศูนย์กลางของรูปหลายเหลี่ยมได้ มุมของทุกจุดที่สัมพันธ์กับจุดศูนย์กลางก็สามารถคำนวณแยกกันได้ และจุดเหล่านี้สามารถเชื่อมต่อตามเข็มนาฬิกาหรือทวนเข็มนาฬิกาได้
อย่างไรก็ตาม หลังจากค้นหาบนอินเทอร์เน็ตเป็นเวลานาน อัลกอริธึมจุดทั้งหมดจำเป็นต้องมีชุดจุดจัดเรียงตามเข็มนาฬิกาที่แน่นอน
แต่ถ้าฉันมีจุดเหล่านี้ ฉันก็วาดรูปหลายเหลี่ยมได้แล้ว ต้องยอมแพ้
การแบ่งส่วนสองขั้วแกน Xด้วยความสิ้นหวัง ฉันต้องค้นหาใน Google แล้วฉันก็พบคำตอบที่ดีเกี่ยวกับ Zhihu: จะเชื่อมต่อกลุ่มจุดที่ไม่เป็นระเบียบบนเครื่องบินให้เป็นรูปหลายเหลี่ยมธรรมดาได้อย่างไร
สำหรับคำอธิบายอัลกอริทึมเฉพาะ เพียงแค่ดูคำตอบแล้วฉันจะไม่ลงรายละเอียด
อย่างไรก็ตาม เมื่อเชื่อมต่อโซ่บนและโซ่ล่าง คุณเพียงแต่ต้องแน่ใจว่าโซ่บนเชื่อมต่อกันโดยเรียงจากมากไปน้อยบนแกน X และโซ่ล่างเชื่อมต่อกันตามลำดับจากน้อยไปมากบนแกน X (วาดในทิศทางทวนเข็มนาฬิกา) . ส่วนจุดที่มีแกน X เท่ากันนั้นไม่สำคัญว่าแกน Y จะใหญ่กว่าหรือเล็กกว่า
เมื่อนำไปใช้แล้วจะถูกนำไปใช้อย่างเคร่งครัดตามอัลกอริธึมในคำตอบ
ในการตัดสินว่าจุดใดเป็นของสายโซ่บนหรือสายโซ่ล่าง แนวคิดเบื้องต้นคือการกำหนดสมการฟังก์ชันของเส้นตรงโดยใช้จุดสองจุด จากนั้นจึงแนะนำพิกัดของจุดสำหรับการคำนวณ แต่ต่อมาผมคิดว่าทุกจุดใช้ขั้วซ้ายสุดในการคำนวณมุมเอียง แล้วหารตามขนาดมุมซึ่งมองเห็นได้ง่ายกว่า
รหัสโดยประมาณมีดังนี้:
ให้ลูกบอล = []; ให้ tempBalls = []; ให้ ballNum = 6; ให้ isDragingBall = false; ในขณะที่ (ballNum--) { ให้ ball = new Ball (10, parseColor (Math.random () * 0xffffff)) ball x = Math.random() * width; ball.y = Math.random() * height; ปล่อยให้คะแนนเรียงลำดับจากน้อยไปหามากใน tempBalls.length -1];let smallXBalls = tempBalls.filter(ball => ball.x === firstBall.x), bigXBalls = tempBalls.filter(ball => ball.x === LastBall.x)// จัดการกับสถานการณ์ที่มีเสาซ้ายและขวาหลายอัน ถ้า (smallXBalls.length > 1) { smallXBalls.sort((ballA, ballB) => { return ballB.y - ballA.y })}if (bigXBalls.length > 1) { bigXBalls.sort((ballA, ballB) => { return ballB.y - ballA.y })}firstBall = smallXBalls[0]lastBall = bigXBalls[0]//รับมุมของการเชื่อมต่อเสา ให้ splitLineAngle = Math.atan2(lastBall.y - firstBall.y, LastBall.x - firstBall.x);ให้ upperBalls = [], lowerBalls = [];//จุดอื่นๆ ทั้งหมดคำนวณมุมด้วย firstBall// อะไรก็ตามที่ใหญ่กว่า splitLineAngle ก็คือดาวน์เชน // อื่นๆ ขึ้นเชน tempBalls.forEach(ball => { if (ball === firstBall || ball === LastBall) { return false } ให้มุม = Math.atan2(ball.y - firstBall.y, ball.x - firstBall.x); if (มุม > splitLineAngle) { lowerBalls.push(บอล) } else { upperBalls.push(ball) }})// จัดการการเรียงลำดับของสถานการณ์เดียวกันบนแกน X lowerBalls = lowerBalls.sort((ballA, ballB) => { if (ballA.x !== ballB.x) { return ballA.x - ballB.x } ส่งคืน ballB.y - ballA.y})upperBalls = upperBalls.sort((ballA, ballB) => { if (ballA.x !== ballB.x) { return ballB.x - ballA.x } return ballB.y - ballB.x})// เชื่อมต่อทุกจุด ลูกบอลทวนเข็มนาฬิกา = [firstBall].concat(lowerBalls, [lastBall], upperBalls)balls = ลูกบอล map ((บอล, i) => { ball.text = i + 1; กลับบอล})
ในที่สุดลูกบอลก็กลับมาคือจุดรูปหลายเหลี่ยมที่เรียงลำดับทวนเข็มนาฬิกา
เอฟเฟกต์มีดังนี้:
สถานะภายในของลูกบอลแต่ละลูกมีดังนี้:
ข้างต้นคือเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการศึกษาของทุกคน ฉันหวังว่าทุกคนจะสนับสนุน VeVb Wulin Network