Pregunta

Para una de mis aplicaciones, necesitaría dibujar una curvas discontinuas en la ruta Bezier en el lienzo HTML5 ... la longitud del tablero y los huecos en el medio deberían ser variables ... es lograble en Javafx, Ver este enlace... Me gustaría lograr el mismo efecto usando el lienzo HTML5. Sé cómo dibujar líneas rectas discontinuas, pero no líneas curvas a lo largo del Bezier ...

Aunque no soy un experto, conozco el Algoritmo de dibujo de Bezier, El problema que veo con este algoritmo es que le permite identificar coordenadas en el Bezier utilizando el parámetro de tiempo que varía de 0 a 1 ...

Esto no es suficiente porque para dibujar un Bezier discontinuo, necesitaría dibujar muchos beziers pequeños, con un parámetro de longitud especificado y a la distancia de la brecha dada, en la ruta principal de Bezier. Debe haber algún algoritmo utilizado por Javafx. Si alguien puede ayudarme, sería genial.

¿Fue útil?

Solución

Supongo que Javafx está utilizando una técnica general para dibujar cualquier curva discontinua y simplemente lo usa en un Bezier en ese ejemplo.

La parte difícil es descubrir dónde comenzar y detener cada tablero, lo que requiere conocer el longitud de arco de su curva Bezier en varios puntos a lo largo de ella.

Hay un enfoque analítico, pero sugeriría lo siguiente:

var bezier = function(controlPoints, t) {
  /* your code here, I'll presume it returns a 2-element array of x and y. */
};

//just figure out the coordinates of all the points in each dash, don't draw.
//returns an array of arrays, each sub-array will have an even number of nu-
//merical elements, to wit, x and y pairs.

//Argument dashPattern should be an array of alternating dash and space
//lengths, e.g., [10, 10] would be dots, [30, 10] would be dashes,
//[30, 10, 10, 10] would be 30-length dash, 10-length spaces, 10-length dash
// and 10-length space.
var calculateDashedBezier = function(controlPoints, dashPattern) {
  var step = 0.001; //this really should be set by an intelligent method,
                    //rather than using a constant, but it serves as an
                    //example.

  //possibly gratuitous helper functions
  var delta = function(p0, p1) {
    return [p1[0] - p0[0], p1[1] - p0[1]];
  };
  var arcLength = function(p0, p1) {
    var d = delta(p0, p1);
    return Math.sqrt(d[0]*d[0] + d[1] * d[1]);
  };

  var subPaths = [];
  var loc = bezier(controlPoints, 0);
  var lastLoc = loc;

  var dashIndex = 0;
  var length = 0;
  var thisPath = [];
  for(var t = step; t <= 1; t += step) {
    loc = bezier(controlPoints, t);
    length += arcLength(lastLoc, loc);
    lastLoc = loc;

    //detect when we come to the end of a dash or space
    if(length >= dashPattern[dashIndex]) {

      //if we are on a dash, we need to record the path.
      if(dashIndex % 2 == 0)
        subPaths.push(thisPath);

      //go to the next dash or space in the pattern
      dashIndex = (dashIndex + 1) % dashPattern.length;

      //clear the arclength and path.
      thisPath = [];
      length = 0;
    }

    //if we are on a dash and not a space, add a point to the path.
    if(dashIndex % 2 == 0) {
      thisPath.push(loc[0], loc[1]);
    }
  }
  if(thisPath.length > 0)
    subPaths.push(thisPath);
  return subPaths;
};

//take output of the previous function and build an appropriate path
var pathParts = function(ctx, pathParts) {
  for(var i = 0; i < pathParts.length; i++) {
    var part = pathParts[i];
    if(part.length > 0)
      ctx.moveTo(part[0], part[1]);
    for(var j = 1; j < part.length / 2; j++) {
      ctx.lineTo(part[2*j], part[2*j+1]);
    }
  }
};

//combine the above two functions to actually draw a dashed curve.
var drawDashedBezier = function(ctx, controlPoints, dashPattern) {
  var dashes = calculateDashedBezier(controlPoints, dashPattern);
  ctx.beginPath();
  ctx.strokeStyle = /* ... */
  ctx.lineWidth = /* ... */
  pathParts(ctx, dashes);
  ctx.stroke();
};

El principal problema con este enfoque es su granularidad no inteligente. Cuando el paso es demasiado grande para sus guiones (pequeños) o curva (grande), el tamaño del paso no funcionará bien y los límites del tablero no caerán exactamente donde desea que lo hagan. Cuando el paso es demasiado pequeño, puede terminar haciendo lineTo()S en puntos que están a una distancia de subpíxeles el uno del otro, lo que a veces hace artefactos AA. Filtrar coordenadas de distancia de subpíxeles no es difícil, pero es ineficiente generar más 'vértices' de los que realmente necesita. Aparecer un mejor tamaño de paso es algo que consideraría atacar de manera más analítica.

Hay una bonificación para usar este enfoque: si reemplaza bezier(controlPoints, t) ¡Con cualquier otra cosa que se evalúe en una curva, dibujará discontense con los mismos problemas potenciales en el párrafo anterior. Pero una muy buena solución al problema de granularidad podría funcionar para todas las curvas 'bien comportadas'.

Otros consejos

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top