es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Crear una curva con grado de intersección entre dos líneas.

Quiero crear una hoja de arce como la de la bandera canadiense, pero tengo un problema para crear una curva cuando las líneas se intersecan, de modo que la curva esté solo en la intersección y crear cierto grado entre las líneas. Lo que quiero decir se muestra en el arco A,B,C, etc. en la imagen que muestro aquí abajo:

https://upload.wikimedia.org/wikipedia/commons/thumb/0/05/Flag_of_Canada_%28construction_sheet_-_leaf_geometry%29.svg/1024px-Flag_of_Canada_%28construction_sheet_-_leaf_geometry%29.svg.png

Esta es la función que he creado hasta ahora:

“`function drawMapleLeaf(ctx, x, y, width, height) {
let rx = width;
let ry = height;
let xc = x + rx / 2;
let yc = y + height;

<pre><code>let xPoints = new Array(26).fill(0);
let yPoints = new Array(26).fill(0);
xPoints[0] = (xc + rx * 0.021423);
yPoints[0] = (yc – ry * 0.215686);
xPoints[1] = (xc + rx * 0.270780);
yPoints[1] = (yc – ry * 0.203804);
xPoints[2] = (xc + rx * 0.271820);
yPoints[2] = (yc – ry * 0.295752);
xPoints[3] = (xc + rx * 0.482015);
yPoints[3] = (yc – ry * 0.411765);
xPoints[4] = (xc + rx * 0.443046);
yPoints[4] = (yc – ry * 0.483267);
xPoints[5] = (xc + rx * 0.500000);
yPoints[5] = (yc – ry * 0.587435);
xPoints[6] = (xc + rx * 0.363353);
yPoints[6] = (yc – ry * 0.619576);
xPoints[7] = (xc + rx * 0.342287);
yPoints[7] = (yc – ry * 0.693849);
xPoints[8] = (xc + rx * 0.153596);
yPoints[8] = (yc – ry * 0.612537);
xPoints[9] = (xc + rx * 0.201601);
yPoints[9] = (yc – ry * 0.918462);
xPoints[10] = (xc + rx * 0.093001);
yPoints[10] = (yc – ry * 0.894514);
xPoints[11] = xc;
yPoints[11] = (yc – ry);
xPoints[12] = (xc – rx * 0.093001);
yPoints[12] = yPoints[10];
xPoints[13] = (xc – rx * 0.201601);
yPoints[13] = yPoints[9];
xPoints[14] = (xc – rx * 0.153596);
yPoints[14] = yPoints[8];
xPoints[15] = (xc – rx * 0.342287);
yPoints[15] = yPoints[7];
xPoints[16] = (xc – rx * 0.363353);
yPoints[16] = yPoints[6];
xPoints[17] = (xc – rx * 0.500000);
yPoints[17] = yPoints[5];
xPoints[18] = (xc – rx * 0.443046);
yPoints[18] = yPoints[4];
xPoints[19] = (xc – rx * 0.482015);
yPoints[19] = yPoints[3];
xPoints[20] = (xc – rx * 0.271820);
yPoints[20] = yPoints[2];
xPoints[21] = (xc – rx * .2707796);
yPoints[21] = yPoints[1];
xPoints[22] = (xc – rx * 0.021423);
yPoints[22] = yPoints[0];
xPoints[23] = xPoints[22];
yPoints[23] = yc;
xPoints[24] = xPoints[0];
yPoints[24] = yPoints[23];
xPoints[25] = xPoints[0];
yPoints[25] = yPoints[0];
ctx.beginPath();
ctx.moveTo(xPoints[0], yPoints[0]);
for(let i = 1; i < xPoints.length; i++){
ctx.lineTo(xPoints[i], yPoints[i]);
}
//ctx.stroke();
ctx.fillStyle = 'red';
ctx.fill();
</code></pre>

} “`

Tags:  ,

Answer

  1. Avatar for davy.ai

    Para crear curvas cuando las líneas se intersectan en una hoja de arce como en la bandera canadiense, se puede utilizar el método quadraticCurveTo () del contexto del lienzo. Este método dibuja una curva de Bezier cuadrática que toma dos puntos como argumentos: el punto de control y el punto final de la curva. Para crear la curva deseada, es necesario encontrar los puntos de intersección de las líneas y utilizarlos como puntos de control para las curvas. Se puede hacer esto calculando la intersección de segmentos de línea adyacentes con fórmulas básicas de geometría.

    Aquí hay una función actualizada que agrega curvas a la hoja:

    function drawMapleLeaf (ctx,x,y,width,height) {
      let rx = width;
      let ry = height;
      let xc = x + rx / 2;
      let yc = y + height;
    
      let xPoints = [xc + rx * 0.021423, xc + rx * 0.270780, xc + rx * 0.271820, 
                     xc + rx * 0.482015, xc + rx * 0.443046, xc + rx * 0.500000,
                     xc + rx * 0.363353, xc + rx * 0.342287, xc + rx * 0.153596,
                     xc + rx * 0.201601, xc + rx * 0.093001, xc,
                     xc - rx * 0.093001, xc - rx * 0.201601, xc - rx * 0.153596,
                     xc - rx * 0.342287, xc - rx * 0.363353, xc - rx * 0.500000,
                     xc - rx * 0.443046, xc - rx * 0.482015, xc - rx * 0.271820,
                     xc - rx * 0.270780, xc - rx * 0.021423];
    
      let yPoints = [yc - ry * 0.215686, yc - ry * 0.203804, yc - ry * 0.295752,
                     yc - ry * 0.411765, yc - ry * 0.483267, yc - ry * 0.587435,
                     yc - ry * 0.619576, yc - ry * 0.693849, yc - ry * 0.612537,
                     yc - ry * 0.918462, yc - ry * 0.894514, yc - ry, 
                     yPoints[10], yPoints[9], yPoints[8], yPoints[7], yPoints[6],
                     yPoints[5], yPoints[4], yPoints[3], yPoints[2], yPoints[1],
                     yPoints[0]];
    
      let startIdx = 0;
      let endIdx = xPoints.length - 1;
    
      ctx.beginPath();
      ctx.moveTo(xPoints[startIdx], yPoints[startIdx]);
    
      // Dibujar líneas y curvas
      for(let i=startIdx+1; i<=endIdx; i++){
        if(i !== 11 && i !== 12 && i !== 23){ // Saltar puntos que coinciden con la línea central
          if(i === 2 || i === 20){ // Curva en la parte superior de la hoja
            let x1 = xPoints[i-1];
            let y1 = yPoints[i-1];
            let x2 = xPoints[i];
            let y2 = yPoints[i];
            let x3 = xPoints[i+1];
            let y3 = yPoints[i+1];
            let xi = (x1*y3 - y1*x3 + x3*y2 - y3*x2) / (x1 - 2*x2 + x3);
            let yi = (y1 + y3 - 2*y2 + x2*y1 - 2*x1*y2 + x1*y3) / (x1 - 2*x2 + x3);
            ctx.quadraticCurveTo(xi, yi, x2, y2);
          } else if(i > 2 && i < 20){ // Curva en los lados de la hoja
            let x1 = xPoints[i-1];
            let y1 = yPoints[i-1];
            let x2 = xPoints[i];
            let y2 = yPoints[i];
            let x3 = xPoints[i+1];
            let y3 = yPoints[i+1];
            let xi1 = (x1*y3 - y1*x3 + x3*y2 - y3*x2) / (x1 - 2*x2 + x3);
            let yi1 = (y1 + y3 - 2*y2 + x2*y1 - 2*x1*y2 + x1*y3) / (x1 - 2*x2 + x3);
            let xi2 = (x2*y3 - y2*x3 + x3*y1 - y3*x1) / (x2 - 2*x3 + x1);
            let yi2 = (y2 + y1 - 2*y3 + x3*y2 - 2*x2*y3 + x2*y1) / (x2 - 2*x3 + x1);
            ctx.quadraticCurveTo(xi1, yi1, x2, y2);
            ctx.quadraticCurveTo(xi2, yi2, x2, y2);
          } else { // Dibujar líneas rectas
            ctx.lineTo(xPoints[i], yPoints[i]);
          }
        }
      }
    
      ctx.fillStyle = 'red';
      ctx.fill();
    }
    

    Los if dentro del bucle manejan los diferentes casos: sin curva en la línea central, curvas en la parte superior de la hoja y curvas en los lados de la hoja. Los puntos de control de Bezier cuadrático se calculan usando la fórmula de intersección (x1*y3 - y1*x3 + x3*y2 - y3*x2) / (x1 - 2*x2 + x3) para xi y (y1 + y3 - 2*y2 + x2*y1 - 2*x1*y2 + x1*y3) / (x1 - 2*x2 + x3) para yi, donde (x1, y1), (x2, y2) y (x3, y3) son las coordenadas de tres puntos consecutivos en el contorno.

    La hoja resultante debería parecerse a la de la bandera canadiense. Hay que tener en cuenta que el método stroke() está comentado, ya que la hoja está rellena con color rojo. Siéntase libre de ajustar el ancho, alto y posición de la hoja cambiando los argumentos pasados a la función.

Comments are closed.