Supongo que JavaFX está utilizando una técnica general para dibujar cualquier curva discontinua y que simplemente está usándola en un bezier en ese ejemplo.
La parte difícil es saber por dónde empezar y parar cada guión, que requiere conocer la arc length de su curva de 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 poco inteligente. Cuando el paso es demasiado grande para los guiones (pequeños) o la (gran) curva, el tamaño del paso no funcionará bien y los límites del trazo no caerán exactamente donde usted desea. Cuando el paso es demasiado pequeño, puede terminar haciendo lineTo()
s en puntos que están a una distancia de un píxel de distancia uno del otro, lo que hace que los artefactos de AA a veces. Filtrar las coordenadas de distancia subpíxel no es difícil, pero es ineficiente generar más 'vértices' de los que realmente necesitas. Venir con un mejor tamaño de paso es en realidad algo que consideraría atacar más analíticamente.
Hay una bonificación para usar este enfoque: si reemplaza bezier(controlPoints, t)
con cualquier otra cosa que se evalúe como una curva, ¡estará dibujando elementos punteados! - nuevamente con los mismos problemas potenciales enumerados en el párrafo anterior. Pero una solución realmente buena para el problema de granularidad podría funcionar para todas las curvas de 'buen comportamiento'.
Hay una aplicación inteligente de algo similar que puede ser capaz de adaptarse a las curvas discontinuas aquí: http://stackoverflow.com/questions/ 4576724/stroke-in-canvas en puntos Ejemplo en vivo aquí: http://phrogz.net/tmp/canvas_dashed_line.html – unmounted
Como dije, sé cómo trazar la línea punteada, el problema es cómo dibujar curvas discontinuas en el bezier path ... –
Supongo que podrías usar el mod op (%) en tu bez drawing algo. Ajuste alfa a cero para la posición par y alfa regular para la posición impar en la curva relativa a su longitud. Si me puedes dar tu bezier algo, no me importa tapar esta matemática. :) –