Raphael.path2curve n'honore pas le chemin original

J'ai un problème avec Raphael.path2curve () . La fonction modifie la chaîne de chemin SVG afin que toutes les commandes de chemin soient converties en courbes cubiques absolues (C). La fonction prend en charge toutes les commandes de chemin ( mlcqahvstMLCQAHVST , voir SVG SPEC ).

Le Raphael.path2curve () peut gérer des chemins bien dans de nombreux cas, par ex. Il peut même convertir des arcs en cubics correctement, ce qui n'est pas un calcul facile. J'ai fait de nombreux tests et j'ai compris que les chemins qui consistent en des commandes QT , CS ou HT conviennent bien. Il n'y a pas non plus de problèmes avec: MS, HS, VS, LS, TC, TH, TL, TV, QA, TA .

Mais il ne peut pas gérer les commandes QS, TS, AS, TT (dans cet ordre).

Si nous, par ex. Avoir un chemin comme celui-ci, la conversion échoue:

 M 0 0 T 205.4 112.9 S 260.8 23.36 82.45 72.86 

Mais cela convertit correctement:

 M 0 0 S 211.9 54.20 52.14 144.4 T 98.85 44.45 

Donc, MTS n'est pas OK, mais MST est. Les problèmes sont S et T, parce qu'ils sont toujours en question, quand quelque chose échoue.

J'ai fait un générateur de chemin aléatoire (lent, mais utilisez jsbin pour la vitesse), où vous pouvez obtenir un chemin aléatoire et le convertir en commandes cubiques à l'aide de Raphael.path2curve (). En violon, cliquez sur SVG ou appuyez sur Entrée dans le champ de saisie pour obtenir un nouveau chemin aléatoire. Répétez jusqu'à ce que vous trouviez un incorrect. Dans jsfiddle dans la fenêtre HTML est un paramètre var list = "st"; Où vous pouvez définir les commandes de chemin pour être randomisées.

C'est un exemple d'image. Le bleu est le chemin d'origine et le chemin rouge est converti. Ils devraient être identiques.

chemin

Que dois-je faire au code Raphael pour obtenir la conversion correcte?

(J'ai fait un rapport de bug , mais j'ai essayé de résoudre le problème plusieurs heures sans chance.

Il semble que je l'ai finalement corrigé. Testez! J'ai fait deux versions jsbin:

1) Version NON FIXE qui utilise Raphael lib libérée : jsbin.com/oqojan/33 .
2) Version FIXED où la fonction path2curve () est modifiée: jsbin.com/oqojan/32 .

Dans les deux versions, il existe un chemin noir (original) et blanc (normalisé). Si tout fonctionne bien, vous ne devriez pas voir le chemin blanc sous le chemin noir. Si vous voyez le chemin blanc, le code lib code comporte un bug (voir ci-dessous l'explication d'un scintillement mineur).

Maintenez la touche ENTER enfoncée sur le champ de saisie d'une minute ou deux. Le code génère des chemins aléatoires à plusieurs reprises tant que ENTER est en panne. Changer l'attribut var list = "mlcqahvstz"; Pour changer les lettres de base pour la randomisation.

Et voici l'explication de ce que je devais faire avec le code lib. Dans le code original Raphaël 2.1.0 lib, il existe une fonction path2curve (), qui comporte les lignes suivantes:

 case "S": nx = dx + (dx - (d.bx || dx)); ny = dy + (dy - (d.by || dy)); path = ["C", nx, ny][concat](path.slice(1)); break; case "T": d.qx = dx + (dx - (d.qx || dx)); d.qy = dy + (dy - (d.qy || dy)); path = ["C"][concat](q2c(dx, dy, d.qx, d.qy, path[1], path[2])); break; 

Quand je les ai changés à:

 case "S": if (pcom == "C" || pcom == "S") { // In "S" case we have to take into // account, if the previous command // is C/S. nx = dx * 2 - d.bx; // And reflect the previous ny = dy * 2 - d.by; // command's control point relative // to the current point. } else { // or some else or nothing nx = dx; ny = dy; } path = ["C", nx, ny][concat](path.slice(1)); break; case "T": if (pcom == "Q" || pcom == "T") { // In "T" case we have to take // into account, if the // previous command is Q/T. d.qx = dx * 2 - d.qx; // And make a reflection similar d.qy = dy * 2 - d.qy; // to case "S". } else { // or something else or nothing d.qx = dx; d.qy = dy; } path = ["C"][concat](q2c(dx, dy, d.qx, d.qy, path[1], path[2])); break; 

La fonction a fonctionné comme prévu (c'est-à-dire respecte la forme du chemin d'origine dans chaque combinaison de commande de chemin possible). pcom variable pcom réfère au segment précédent du chemin ORIGINAL et je devais également ajouter un moyen d'obtenir pcom , ce qui était plutôt simple, car en ce qui concerne toutes les autres commandes de chemin que A, la conversion du type de segment de chemin d'origine en courbe cubique (C) produit Une seule commande cubique. Dans le cas de A, la fonction peut produire plus d'une commande C (les angles courts produisent un ou peu de segments C et des angles plus grands produisent plus).

La seule incohérence mineure provient des commandes Z, car Raphaël convertit tout Z en C. Cela affecte l'apparence visuelle des débuts (ou des extrémités), mais la différence n'est pas énorme. Je suppose qu'il convertit Z en C pour créer des chemins animables. Si l'animation n'est pas nécessaire, vous pouvez envisager de modifier la fonction pour laisser Z: s non converti, auquel cas la fidélité à la conversion est excellente.

Je suis étonné que toutes les commandes de cheminement puissent être représentées comme des courbes cubiques si fiables!

J'espère que ce bug sera corrigé dans une future version de Raphaël.

EDIT: Made testbed aussi pour les animations de chemins:
1) NON FIXE: http://jsbin.com/oqojan/44
2) FIXE: http://jsbin.com/oqojan/42

Après des tests approfondis avec des chemins non animés et animés, je peux confirmer que ma fonction de correction à path2curve est stable et peut être implémentée dans le code de production. Si vous voulez être sûr, utilisez les bancs d'essai mentionnés ci-dessus.