2
votes

Comment calculer l'arc de chemin SVG entre deux points le long de la tranche d'un cylindre

J'essaie d'utiliser les SVG pour dessiner dynamiquement des lignes sur une surface d'aspect cylindrique. Parce qu'elle est cylindrique, toute ligne droite entre deux points suivra en fait une tranche elliptique du cylindre, et devra donc être rendue comme une section d'un arc elliptique.

 section d'arc AB du cylindre

Comme le documents a>, les arcs SVG sont définis comme suit: "A rx ry x-axis-rotation large-arc-flag sweep-flag xy"

S'il vous plaît dites-moi où je suis erreur lors de la dérivation de cet arc (AB).

  1. Je connais donc évidemment mes points de départ et d'arrivée (AB).
  2. Je suppose que ry dans le cylindre et la tranche sont égaux.
  3. rx est la moitié de l'hypoténuse de la tranche.
  4. θ est la rotation de l'axe des x ... je pense?

    • C'est là que je pense avoir des ennuis. Comme vous pouvez le voir sur la deuxième image lorsque j'essaie de convertir tous mes chemins de ligne en arcs, certains ars s'avèrent parfaits lorsqu'ils ne sont pas tournés (ils sont parallèles à l'axe des x dans le plan rectangulaire, ce qui signifie qu'ils suivre la trajectoire de l'arc de l'ellipse cylindrique primaire), cependant, quelque chose de drôle se passe avec la rotation. Lorsque j'active le drapeau à grand arc, il est assez évident que les ellipses dessinées ne sont pas du tout alignées avec mon cylindre.

    • Je suis assez convaincu que l'hypoténuse est calculée correctement, car régler à zéro me donne le diamètre du cylindre, donc je suis un peu perplexe quant à l'endroit où je me trompe. p >

 l'étoile de dessin semble causer des erreurs de sur / sous rotation

TLDR: Compte tenu des données que j'ai fournies dans l'image 1 , comment feriez-vous pour dessiner l'arc AB.

EDIT 1: Voici un SVG d'un cylindre et d'une ligne pour jouer avec. Encore une fois, j'essaie de faire de la ligne un arc pour qu'elle s'adapte à la surface du cylindre afin qu'elle corresponde à l'arc d'ellipse formé par une tranche à travers le cylindre.

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <path id="cylinder" fill="none" stroke="#000000" stroke-width="2" d="M 0 32 a148 32 0 0 0 296 0 a148 32 0 0 0 -296 0 v185 a148 32 0 0 0 296 0 v-185"/>
    <path id="line_should_become_arc" fill="none" stroke="#000000" stroke-width="2" d="M 37 106 L 259 148"/>
</svg>


7 commentaires

Alors, quelles données avez-vous exactement? Veuillez également montrer le code court pour jouer avec.


J'ai toutes les données répertoriées dans l'image: rx & ry du cylindre et de la tranche, ainsi que les coordonnées x, y des points A et B à la fois sur le cylindre, et en coordonnées rectangulaires qui n'ont pas été transférées sur le cylindre ( imaginez «dérouler» le cylindre pour que les lignes soient droites). Avec cela, je calcule θ en utilisant la loi des cosinus basée sur les coordonnées rectangulaires.


Pour info, les lignes droites sur le cylindre ne sont pas obtenues en le découpant avec un plan et en obtenant des cercles ou des ellipses. Ce sont des hélices: en.wikipedia.org/wiki/Helix . Donc, si vous insistez sur les ellipses, je ne comprends pas comment vous décidez avec quel plan passant par A et B vous avez choisi de couper le cylindre pour trouver l'ellipse. Il y en a une infinité. Qu'est-ce que le "canonnical"? Voulez-vous l'ellipse pour laquelle le segment AB est parallèle au grand axe de l'ellipse?


@Futurologist, wow, vous avez raison à propos de l'hélice, je suppose que mon approche est complètement fausse. Savez-vous où je pourrais trouver des informations sur le mappage de points et de lignes dans un plan plat et rectangulaire sur une surface cylindrique? J'ai réfléchi / essayé de faire des recherches sur ce problème pendant des semaines sans trop de chance.


@toakleaf J'ai effectivement réalisé ce que vous essayez de faire, vous émuliez la projection d'une image 3D sur un plan 2D, et que les mesures que vous fournissez sur votre image sont en fait les mesures des objets à deux dimensions, pas de la 3D objets originaux. Cependant, même avec les élipses, le problème est intéressant, car, étant donné les cylindres rx et ry, le petit axe ry de l'autre ellipse et les coordonnées 2D des points A et B, il faut trouver les valeurs de l'angle thet, le grand axe de l'ellipse inclinée ry et l'emplacement du centre de l'ellipse inclinée.


@toakleaf Votre cylindre 3D original est-il un cylindre circulaire droit? Si vous voulez faire cela avec des hélices, vous devrez d'abord construire des choses en 3D, puis projeter en 2D. Les hélices, projetées en 2D, ne sont probablement pas si faciles à manipuler. Ainsi, lorsque vous dessinez les points 2D A et B, vous devrez calculer où ils se trouvent sur la 3D, trouver la formule de l'hélice 3D et la projeter en arrière. Mais je pense que cela peut être fait. Cependant, je ne sais pas comment fonctionne ce SVG. Je sais seulement comment faire la géométrie.


@toakleaf J'ai écrit les formules, avec quelques explications, pour construire l'hélice, vue comme une projection dans le plan 2D, si c'est ce que vous recherchez.


3 Réponses :


2
votes

Peut-être voulez-vous quelque chose comme ça
(Je ne suis pas familier avec JS, donc je ne sais pas comment fournir des paramètres calculés pour les courbes SVG)

L'angle AB en coordonnées rectangulaires est de 15 degrés, 1 / cos (15 ) = 1.035 - coefficient pour rx. Les coordonnées Y de l'arc bleu sont volontairement décalées de 10 pixels

entrez la description de l'image ici

<svg width="400" height="400" xmlns="http://www.w3.org/2000/svg">
  <path d="M50 50 L50 250" stroke="black" fill="transparent"/>
  <path d="M50 250 A100 40 0 0 0 250 250" stroke="black" fill="transparent"/>
  <path d="M250 250 L250 50 A100 40 0 0 0 50 50 A100 40 0 0 0 250 50" stroke="black" fill="transparent"/>
  <path d="M50 150 A103.5 40 15 0 0 250 200 A103.5 40 15 0 0 50 150" stroke="black" fill="transparent"/>
  <path d="M100 210 A103.5 40 15 0 0 200 232" stroke="blue" fill="transparent"/>
</svg>


0 commentaires

1
votes

C'est pratiquement plug and play. La seule chose qui a demandé un effort est les deux drapeaux dans la commande Arc.

J'ai commencé avec les deux extrémités de chemin de votre exemple SVG, et j'ai obtenu rx et ry de l'arc qui forme le sommet du cylindre. Mais vous n'avez pas fourni de thêta, alors j'en ai choisi un et j'ai dû ajuster les points d'extrémité pour que la tranche s'aligne avec les parois du cylindre.

<svg width="400" height="400">
    <path id="cylinder" fill="none" stroke="#000000" stroke-width="2" d="M 0 32 a148 32 0 0 0 296 0 a148 32 0 0 0 -296 0 v185 a148 32 0 0 0 296 0 v-185"/>
    <path id="slice" fill="none" stroke="#000000" stroke-width="2" d="M 0,0"/>
    <path id="line_should_become_arc" fill="none" stroke="#f00" stroke-width="2" d="M 0,0"/>
</svg>
var arc = document.getElementById("line_should_become_arc");
var slice = document.getElementById("slice");

var Ax = 57, Ay = 126;
var Bx = 279, By = 168;

var rx = 148;
var ry = 32;
var theta = 14;  // 14 deg

var slice_rx = rx / Math.cos(theta * Math.PI / 180);

arc.setAttribute("d", ['M', Ax,Ay, 'A', slice_rx, ry, theta, 0, 0, Bx,By].join(' '));

slice.setAttribute("d", ['M', Ax,Ay, 'A', slice_rx, ry, theta, 1, 1, Bx,By].join(' '));


0 commentaires

1
votes

Je suppose ce qui suit: vous avez un système de coordonnées 3D Oxyz et un cylindre circulaire droit de rayon a dont l'axe, courant le long du milieu du cylindre, coïncide avec l'axe Oy. Alors la base circulaire du cylindre est perpendiculaire à l'axe Oy et est donc parallèle (ou coïncide avec) le plan de coordonnées Oxz. Dans ce système de coordonnées, le cylindre peut être décrit comme tous les points 3D avec la propriété

x = a*cos(s/a)    
y = y_A + m*(s - s_A) - b*sin(s/a)  

Je suppose que le cylindre est projeté à partir du système de coordonnées 3D Oxyz sur le plan de coordonnées Oxy de sorte que le cercle , obtenue par l'intersection du cylindre avec le plan de coordonnées Oxz, est projetée comme une ellipse avec le grand axe de longueur a , aligné avec l'axe Ox, et le petit axe de longueur b code>, aligné sur l'axe Oz. Sur votre image a = cylindre rx et b = ry .

Ces informations nous permettent de déterminer la direction de projection:

x_3D = a*cos(s/a)
y_3D = y_A + m*(s - s_A)
z_3D = a*sin(s/a)

i.e. pour tout point P = [x_3D; y_3D; z_3D] dans le système 3D Oxyz, on prend la droite passant par P et parallèle au vecteur direction , et son intersection avec Oxy est la projection de P sur Oxy. La formule pour cela est

m = (y_B - y_A) / (s_B - s_A) 
  = (yB + (b/a)*sqrt(a^2-xB^2) - yA - (b/a)*sqrt(a^2-xA^2)) / (a*arccos(xB) - a*arccos(xA))
  = ((yB - yA) + (b/a)*(sqrt(a^2-xB^2) - sqrt(a^2-xA^2))) / (a*arccos(xB) - a*arccos(xA));

y = y_A + m*(s - s_A);

(il existe une autre option pour la direction: direction = [0; - b; a] si la projection est effectuée "de dessous" l'axe Oxz au lieu de "over", mais restons avec "over") Inversement, si on nous donne un point [x; y] sur le plan de coordonnées Oxy 2D, on peut récupérer deux points sur la surface du cylindre, qui se projettent sur [x; y]:

s_A = a*arccos(xA);
y_A = yA + (b/a)*sqrt(a^2 - xA^2);

s_B = a*arccos(xB);
y_B = yB + (b/a)*sqrt(a^2 - xB^2);

qui est le point sur le cylindre dans le demi-espace où l'axe Oz est positif, et

A_3D = [xA; yA + (b/a)*sqrt(a^2 - xA^2);  sqrt(a^2 - xA^2)];
B_3D = [xB; yB + (b/a)*sqrt(a^2 - xB^2);  sqrt(a^2 - xB^2)];

qui est sur le cylindre dans le demi-espace où l'axe) z est négatif.

La surface du cylindre peut être paramétrée en prenant un rectangle plan plat et en le pliant en 3D en collant ensemble deux des ses bords parallèles pour former le cylindre circulaire droit. Cette transformation peut être écrite comme

a, b, A = [xA; yA], B = [xB; yB]

Ensuite, une ligne droite générique sur le carré plat

x = a*cos(s/a)
y = y0 + m*(s - s0)
z = a*sin(s/a) 

se transforme en courbe 3D couché sur la surface du cylindre

y = y0 + m*(s - s0)

qui est une hélice.

Maintenant, vous êtes donné en entrée

[s; y] ---> [a*cos(s/a);  y;  a*sin(s/a)]

i.e.
x = a*cos(s/a)
y = y
z = a*sin(s/a) 


1 commentaires

Merci pour tous ces calculs. Je pense que je vais abandonner mon idée d'arc et adopter cette approche à la place.