Hoy, cuando estaba estudiando el libro "Conceptos básicos de animación HTML5 + Javascript", en la tercera sección del Capítulo 8, hablé sobre cómo usar tres resortes para conectar tres puntos y realizar movimientos de estiramiento.
Después de terminar el ejemplo, pensé qué pasaría si fueran cuatro puntos o cinco puntos.
Reescribí el código e hice variable el número de puntos. El efecto final es lograr el movimiento de estiramiento final de cada punto para equilibrarlo, pero las conexiones entre los puntos no son muy bonitas y algunas están cruzadas.
Entonces estaba pensando si esta área podría optimizarse.
rotar la lineaTodos los puntos del ejemplo anterior están en posiciones aleatorias, por lo que las conexiones son incontrolables. Entonces quiero comenzar con esto primero.
Primero, use un determinado punto como punto de referencia para obtener los ángulos de otros puntos con respecto a este punto.
Luego conecta estos puntos según el ángulo de pequeño a grande, para que puedas dibujar un polígono normal.
El código de implementación aproximado es el siguiente:
let bolas = [];let ballNum = 6;let firstBall = null; while(ballNum--) { let ball = new Ball(20, parseColor(Math.random() * 0xffffff)) ball.x = Math.random( ) * ancho; bola.y = Math.random() * altura; bolas.push(bola) if (!firstBall) { firstBall = bola ball.angle = 0 } else { const dx = ball.x - firstBall.x, dy = ball.y - firstBall.y; ball.angle = Math.atan2(dy, dx)// Intenta hacer que la línea que conecta las bolas sea un polígono regular; = bolas .sort((bolaA, bolaB) => { return bolaA.ángulo - bolaB.ángulo})
De esta manera, cuando finalmente se establece la conexión, el ángulo se puede dibujar de pequeño a grande atravesando la matriz.
El efecto es el siguiente:
Esto puede reducir en gran medida el número de líneas que se cruzan, pero aún así no se puede evitar por completo.
A continuación, quiero intentar optimizar esta solución. Por ejemplo, usar Math.abs para corregir el ángulo o encontrar el punto con el ángulo más pequeño para conectar cada punto. Pero el resultado no es bueno, no se pueden evitar cruzar líneas.
Girar según el punto centralEntonces me vino a la mente otra idea: si se puede determinar el punto central del polígono, entonces los ángulos de todos los puntos con respecto al punto central se pueden calcular por separado y estos puntos se pueden conectar en el sentido de las agujas del reloj o en el sentido contrario a las agujas del reloj.
Sin embargo, después de buscar durante mucho tiempo en Internet, todos los algoritmos de puntos requieren una serie de puntos dispuestos en un determinado orden en el sentido de las agujas del reloj.
Pero si tengo estos puntos, ya puedo dibujar el polígono. Tuve que rendirme
Segmentación bipolar del eje XDesesperado, tuve que buscar en Google y luego encontré una muy buena respuesta en Zhihu: ¿Cómo conectar un grupo de puntos desordenados en el plano en un polígono simple?
Para conocer la descripción específica del algoritmo, basta con mirar la respuesta y no entraré en detalles.
Sin embargo, al conectar la cadena superior y la cadena inferior, de hecho, solo necesita asegurarse de que la cadena superior esté conectada en orden descendente en el eje X y la cadena inferior esté conectada en orden ascendente en el eje X (dibujado en en sentido contrario a las agujas del reloj). En cuanto a los puntos con el mismo eje X, no importa si el eje Y es mayor o menor.
Cuando se implementa, se implementa estrictamente de acuerdo con el algoritmo de la respuesta.
Al juzgar si un punto pertenece a la cadena superior o inferior, la idea inicial es determinar la ecuación de la función de la línea recta en función de dos puntos y luego introducir las coordenadas de los puntos para el cálculo. Pero más tarde pensé que todos los puntos usan el polo más a la izquierda para calcular el ángulo oblicuo y luego dividirlo según el tamaño del ángulo, lo cual es más fácil de entender visualmente.
El código aproximado es el siguiente:
let ball = [];let tempBalls = [];let ballNum = 6;let isDragingBall = false; while(ballNum--) { let ball = new Ball(10, parseColor(Math.random() * 0xffffff)) ball. x = Math.random() * ancho; ball.y = Math.random() * alto; tempBalls.push(ball)}// Deje que los puntos se ordenen en orden ascendente en tempBalls.length -1]; let smallXBalls = tempBalls.filter(ball => ball.x === firstBall.x), bigXBalls = tempBalls.filter(ball => ball.x === lastBall.x)// Manejar la situación en la que hay varios polos izquierdo y derecho if (smallXBalls.length > 1) { smallXBalls.sort((ballA, ballB) => { return bolaB.y - bolaA.y })}if (bigXBalls.length > 1) { bigXBalls.sort((bolaA, bolaB) => { return ballB.y - ballA.y })}firstBall = smallXBalls[0]lastBall = bigXBalls[0]//Obtener el ángulo de la línea del poste let splitLineAngle = Math.atan2(lastBall.y - firstBall.y, lastBall.x - firstBall.x);let UpperBalls = [], lowerBalls = [];//Todos los demás puntos calculan ángulos con firstBall// Cualquier cosa más grande que splitLineAngle está en la cadena inferior // Otros están en la cadena superior tempBalls.forEach(ball => { if (ball === firstBall || ball === lastBall) { return false } let angle = Math.atan2(ball.y - primeraBall.y, bola.x - primeraBall.x); if (ángulo > splitLineAngle) { lowerBalls.push(ball) } else { UpperBalls.push(ball) }})// Maneja la clasificación de la misma situación en el eje X lowerBalls = lowerBalls.sort((ballA, ballB) => { if (ballA.x !== ballB.x) { return bolaA.x - bolaB.x } return bolaB.y - bolaA.y})upperBalls = UpperBalls.sort((bolaA, bolaB) => { if (bolaA.x !== ballB.x) { return ballB.x - ballA.x } return ballB.y - ballB.x})// Conecta todos los puntos en sentido antihorario bolas = [firstBall].concat(lowerBalls, [lastBall], UpperBalls)balls = bolas. mapa((bola, i) => { bola.texto = i + 1; devolver bola})
Las bolas finalmente devueltas son los puntos poligonales ordenados en sentido antihorario.
El efecto es el siguiente:
El estado interno de cada bola es el siguiente:
Lo anterior es el contenido completo de este artículo. Espero que sea útil para el estudio de todos. También espero que todos apoyen VeVb Wulin Network.