2011-09-08 5 views
8

Pour l'une de mes applications, il faudrait que je dessine des courbes en pointillés sur le chemin bezier en toile Html5 ... La longueur du tiret et les écarts entre les deux devraient être variables ... JavaFx, see this link ... Je voudrais obtenir le même effet en utilisant le canvas Html5. Je sais comment tracer des lignes droites pointillées, mais pas des lignes courbes le long du bezier ...Courbes en pointillés sur Html5 Toile Bezier

Bien que je ne sois pas un expert, je connais le bezier drawing algorithm, problème que je vois avec cet algorithme, il vous permet d'identifier les coordonnées sur le bézier en utilisant le paramètre de temps qui va de 0 à 1 ...

Cela ne suffit pas car pour dessiner un bezier en pointillé, je devrais dessiner beaucoup de petits béziers, avec un paramètre de longueur spécifié et à une distance d'entrefer donnée, sur le principal chemin de Bézier. Il doit y avoir un algorithme qui est utilisé par JavaFx. Si quelqu'un peut m'aider, ce serait génial.

+0

Il y a une mise en œuvre intelligente de quelque chose de similaire que vous pourriez être en mesure de s'adapter aux courbes pointillées ici: http://stackoverflow.com/questions/ 4576724/dotted-stroke-in-canvas Exemple en direct ici: http://phrogz.net/tmp/canvas_dashed_line.html – unmounted

+0

Comme je l'ai dit, je sais comment tracer la ligne pointillée, le problème est de savoir comment dessiner des courbes en pointillés sur le bezier path ... –

+0

Je suppose que vous pourriez utiliser le mod op (%) à votre alz dessin algo. Définissez alpha à zéro pour la position paire et alpha normal pour la position impaire sur la courbe par rapport à sa longueur. Si vous pouvez me fournir votre alz bezier, cela ne me dérange pas brancher ce maths. :) –

Répondre

4

Je suppose que JavaFX utilise une technique générale pour tracer n'importe quelle courbe en pointillé et qu'il arrive juste de l'utiliser sur un Bézier dans cet exemple. La partie difficile est de savoir où commencer et arrêter chaque tiret, ce qui nécessite de connaître le arc length de votre courbe bezier à divers points le long de celui-ci.

Il y a une approche analytique, mais je suggère ce qui suit:

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(); 
}; 

Le principal problème avec cette approche est sa granularité inintelligente. Lorsque le pas est trop grand pour vos (petits) tirets ou (grandes) courbes, la taille du pas ne fonctionnera pas bien et les limites du tableau de bord ne tomberont pas exactement où vous le souhaitez. Lorsque l'étape est trop petite, vous pouvez finir par faire lineTo() sur des points qui sont à une distance de moins de pixel les uns des autres, ce qui crée parfois des artefacts AA. Filtrer les coordonnées de distance sub-pixel n'est pas difficile, mais il est inefficace de générer plus de «sommets» que ce dont vous avez vraiment besoin. Venir avec une meilleure taille de pas est en fait quelque chose que je considérerais attaquer plus analytiquement.

Il y a un bonus à utiliser cette approche: si vous remplacez bezier(controlPoints, t) avec toute autre chose qui permet d'évaluer une courbe, vous dessinerez whatevers pointillées - encore une fois avec les mêmes problèmes potentiels énumérés au paragraphe précédent!. Mais une très bonne solution au problème de la granularité pourrait fonctionner pour toutes les courbes «bien agencées».

+1

Vous avez correctement identifié que, présumer que les étapes à l'étape = 0.001 est un grand risque parce que vous ne pouvez pas connaître la taille de bezier à l'avance. Il serait préférable que les étapes soient calculées de façon récursive en trouvant le point milieu jusqu'à ce que la distance de deux points devienne nulle ou que la courbe devienne droite ... –

+0

Une autre façon plus facile de le faire serait de régler 'step' égal à une approximation de la longueur d'arc de la courbe bezier divisé par la plus petite longueur de tiret. Cependant, une «étape» fixe fonctionnera correctement si vos courbes sont telles que «1/step» est beaucoup plus grand que la longueur d'arc divisée par la plus petite longueur de tiret. – ellisbben

+0

Ça a aidé, merci ... –

Questions connexes