Solución:
Aquí hay un enfoque de Sketch / TikZ.
Corriendo sketch
en este archivo:
def helix
def n_segs 600
sweep [draw=orange] n_segs, rotate(24*360 / n_segs, (1.5,0,0), [0,0,1]), rotate(1*360/n_segs, (0,0,0), [0,1,0]) (2.01,0,0)
def torus
def n_segs 60
sweep [draw=none, fill=cyan, fill opacity=0.75] n_segs, rotate(360/n_segs, (0,0,0), [0,1,0])
sweep n_segs, rotate(360/n_segs, (1.5,0,0), [0,0,1])
(2,0,0)
put view((10,4,2)) helix torus
global language tikz
genera un .tex
archivo que se puede compilar usando pdflatex
.
La hélice que gira alrededor de la hélice que gira alrededor de un toro.
se puede generar usando
def helix
def n_segs 10000
sweep [draw=orange]
n_segs,
rotate(1000*360 / n_segs, (2,0,0), [0,1,0]),
rotate(24*360 / n_segs, (1.5,0,0), [0,0,1]),
rotate(1*360/n_segs, (0,0,0), [0,1,0])
(2.04,0,0)
def torus
def n_segs 50
sweep [draw=none, fill=cyan, fill opacity=0.75] n_segs, rotate(360/n_segs, (0,0,0), [0,1,0])
sweep n_segs, rotate(360/n_segs, (1.5,0,0), [0,0,1])
(1.9,0,0)
put view((10,4,2)) torus helix
global language tikz
El ejemplo muestra la función
x(u,v)=(R1 + (R0 +RL*sin(u))*sin(k*v))*cos(v)-RL*cos(u)*sin(v)
y(u,v)=(R1 + (R0 +RL*sin(u))*sin(k*v))*sin(v)+RL*cos(u)*cos(v)
z(u,v)=(R0 + RL*sin(u))*cos(k*v)
con la configuración de parámetros que se muestra en el ejemplo. RL: radio de la línea de la bobina; R1: toro externo; R0: radio interior del toro; k: número de bobinas
ejecutarlo con xelatex
o latex>dvips>ps2pdf
(¡lleva algo de tiempo correr!)
documentclassminimal
usepackagepst-solides3d
pagestyleempty
begindocument
beginpspicture[solidmemory](-6,-4)(6,4)
pssetviewpoint=30 0 15 rtp2xyz,Decran=30,lightsrc=viewpoint
psSolid[object=tore,r1=5,r0=1,ngrid=36 36,
fillcolor=blue!30,action=none,name=Torus]%
%axesIIID(4.5,4.5,0)(5,5,4)
codejps/R1 5 def /RL 0.05 def /R0 1.1 def /k 25 def%
defFunction[algebraic]helix(u,v)
(R1 + (R0 +RL*sin(u))*sin(k*v))*cos(v)-RL*cos(u)*sin(v)
(R1 + (R0 +RL*sin(u))*sin(k*v))*sin(v)+RL*cos(u)*cos(v)
(R0 + RL*sin(u))*cos(k*v)
psSolid[object=surfaceparametree,
base=0 6.2831853 0 6.2831853,
linecolor=blue,linewidth=0.01,fillcolor=yellow,
ngrid=0.8 0.01,function=helix,action=none,name=Helix]%
psSolid[object=fusion,base=Torus Helix,grid=false]
%gridIIID[Zmin=-3,Zmax=3,showAxes=false](-2,2)(-2,2)
endpspicture
beginpspicture[solidmemory](-6,-6)(6,6)
pssetviewpoint=30 0 90 rtp2xyz,Decran=30,lightsrc=viewpoint
psSolid[object=tore,r1=5,r0=1,ngrid=36 36,
fillcolor=blue!30,action=none,name=Torus]%
%axesIIID(4.5,4.5,0)(5,5,4)
codejps/R1 5 def /RL 0.05 def /R0 1.1 def /k 25 def%
defFunction[algebraic]helix(u,v)
(R1 + (R0 +RL*sin(u))*sin(k*v))*cos(v)-RL*cos(u)*sin(v)
(R1 + (R0 +RL*sin(u))*sin(k*v))*sin(v)+RL*cos(u)*cos(v)
(R0 + RL*sin(u))*cos(k*v)
psSolid[object=surfaceparametree,
base=0 6.2831853 0 6.2831853,
linecolor=blue,linewidth=0.01,fillcolor=yellow,
ngrid=0.8 0.01,function=helix,action=none,name=Helix]%
psSolid[object=fusion,base=Torus Helix,grid=false]
%gridIIID[Zmin=-3,Zmax=3,showAxes=false](-2,2)(-2,2)
endpspicture
enddocument
una animación está aquí: http://tug.org/PSTricks/main.cgi?file=Animation/gif/gif
Con psSolid[object=fusion,base=Torus Helix,grid=false,opacity=0.5]
(configuración de transparencia) y una hélice más delgada (disminución / RL) se obtiene
y solo por diversión con
listfiles
documentclassminimal
usepackagepst-solides3d
begindocument
beginpspicture[solidmemory](-6.5,-3.5)(6.5,3)
pssetviewpoint=30 0 15 rtp2xyz,Decran=30,lightsrc=viewpoint
psSolid[object=tore,r1=5,r0=1,ngrid=36 36,tablez=0 0.05 1 for,
zcolor= 1 .5 .5 .5 .5 1,action=none,name=Torus]
pstVerb/R1 5 def /R0 1.2 def /k 20 def /RL 0.15 def /kRL 40 def%
defFunction[algebraic]helix(t)
(R1+R0*cos(k*t))*sin(t)+RL*sin(kRL*k*t)
(R1+R0*cos(k*t))*cos(t)+RL*cos(kRL*k*t)
R0*sin(k*t)+RL*sin(kRL*k*t)
psSolid[object=courbe,
resolution=7800,
fillcolor=black,incolor=black,
r=0,
range=0 6.2831853,
function=helix,action=none,name=Helix]%
psSolid[object=fusion,base=Torus Helix,grid]
endpspicture
enddocument
Actualizado: Incluye soluciones para dificultades anteriores con la compilación de rutas complejas.
Aquí hay un enfoque de asíntota que permite hélices de enésimo orden. Muestro ejemplos de una hélice de primer orden (que se envuelve una vez alrededor del toro, como en la pregunta original), una hélice de segundo orden y una hélice de tercer orden.
Aquí está el código (configurado para una hélice de primer orden):
settings.outformat = "png";
settings.render = 16;
settings.prc = false;
real unit = 2cm;
unitsize(unit);
import graph3;
void drawsafe(path3 longpath, pen p, int maxlength = 400)
int length = length(longpath);
if (length <= maxlength) draw(longpath, p);
else
int divider = floor(length/2);
drawsafe(subpath(longpath, 0, divider), p=p, maxlength=maxlength);
drawsafe(subpath(longpath, divider, length), p=p, maxlength=maxlength);
struct helix
path3 center;
path3 helix;
int numloops;
int pointsperloop = 12;
/* t should range from 0 to 1*/
triple centerpoint(real t)
return point(center, t*length(center));
triple helixpoint(real t)
return point(helix, t*length(helix));
triple helixdirection(real t)
return dir(helix, t*length(helix));
/* the vector from the center point to the point on the helix */
triple displacement(real t)
return helixpoint(t) - centerpoint(t);
bool iscyclic()
return cyclic(helix);
path3 operator cast(helix h)
return h.helix;
helix helixcircle(triple c = O, real r = 1, triple normal = Z)
helix toreturn;
toreturn.center = c;
toreturn.helix = Circle(c=O, r=r, normal=normal, n=toreturn.pointsperloop);
toreturn.numloops = 1;
return toreturn;
helix helixAbout(helix center, int numloops, real radius)
helix toreturn;
toreturn.numloops = numloops;
from toreturn unravel pointsperloop;
toreturn.center = center.helix;
int n = numloops * pointsperloop;
triple[] newhelix;
for (int i = 0; i <= n; ++i)
real theta = (i % pointsperloop) * 2pi / pointsperloop;
real t = i / n;
triple ihat = unit(center.displacement(t));
triple khat = center.helixdirection(t);
triple jhat = cross(khat, ihat);
triple newpoint = center.helixpoint(t) + radius*(cos(theta)*ihat + sin(theta)*jhat);
newhelix.push(newpoint);
toreturn.helix = graph(newhelix, operator ..);
return toreturn;
int loopfactor = 20;
real radiusfactor = 1/8;
helix wrap(helix input, int order, int initialloops = 10, real initialradius = 0.6, int loopfactor=loopfactor)
helix toreturn = input;
int loops = initialloops;
real radius = initialradius;
for (int i = 1; i <= order; ++i)
toreturn = helixAbout(toreturn, loops, radius);
loops *= loopfactor;
radius *= radiusfactor;
return toreturn;
currentprojection = perspective(12,0,6);
helix circle = helixcircle(r=2, c=O, normal=Z);
/* The variable part of the code starts here. */
int order = 1; // This line varies.
real helixradius = 0.5;
real safefactor = 1;
for (int i = 1; i < order; ++i)
safefactor -= radiusfactor^i;
real saferadius = helixradius * safefactor;
helix todraw = wrap(circle, order=order, initialradius = helixradius); // This line varies (optional loopfactor parameter).
surface torus = surface(Circle(c=2X, r=0.99*saferadius, normal=-Y, n=32), c=O, axis=Z, n=32);
material toruspen = material(diffusepen=gray, ambientpen=white);
draw(torus, toruspen);
drawsafe(todraw, p=0.5purple+linewidth(1pt)); // This line varies (linewidth only).
La salida:
Para una hélice de segundo orden, cambie la última parte del código anterior a lo siguiente:
/* The variable part of the code starts here. */
int order = 2; // This line varies.
real helixradius = 0.5;
real safefactor = 1;
for (int i = 1; i < order; ++i)
safefactor -= radiusfactor^i;
real saferadius = helixradius * safefactor;
helix todraw = wrap(circle, order=order, initialradius = helixradius, loopfactor=40); // This line varies (optional loopfactor parameter).
surface torus = surface(Circle(c=2X, r=0.99*saferadius, normal=-Y, n=32), c=O, axis=Z, n=32);
material toruspen = material(diffusepen=gray, ambientpen=white);
draw(torus, toruspen);
drawsafe(todraw, p=0.5purple+linewidth(0.6pt)); // This line varies (linewidth only).
La salida:
Para una hélice de tercer orden, cambie la parte "variable" del código a lo siguiente:
/* The variable part of the code starts here. */
int order = 3; // This line varies.
real helixradius = 0.5;
real safefactor = 1;
for (int i = 1; i < order; ++i)
safefactor -= radiusfactor^i;
real saferadius = helixradius * safefactor;
helix todraw = wrap(circle, order=order, initialradius = helixradius); // This line varies (optional loopfactor parameter).
surface torus = surface(Circle(c=2X, r=0.99*saferadius, normal=-Y, n=32), c=O, axis=Z, n=32);
material toruspen = material(diffusepen=gray, ambientpen=white);
draw(torus, toruspen);
drawsafe(todraw, p=0.5purple+linewidth(0.2pt)); // This line varies (linewidth only).
La salida:
Un comentario final: el mecanismo de renderizado en Asymptote para superficies translúcidas no funciona bien con más de una capa de superficie translúcida (es decir, cuando una superficie translúcida está oscureciendo otra superficie translúcida (o parte de una)). Aquí tienes un ejemplo de la dificultad:
Esto es un poco menos notorio en la respuesta de mrc, pero sigue ahí, al menos por ahora.
Sin embargo, esta dificultad se puede mitigar (cuando solo está involucrada una superficie y no tiene autointersecciones) clasificando los parches constituyentes para que se dibujen en orden de distancia desde la cámara:
settings.outformat = "png";
settings.render = 16;
settings.prc = false;
real unit = 2cm;
unitsize(unit);
import graph3;
void drawsafe(path3 longpath, pen p, int maxlength = 400)
int length = length(longpath);
if (length <= maxlength) draw(longpath, p);
else
int divider = floor(length/2);
drawsafe(subpath(longpath, 0, divider), p=p, maxlength=maxlength);
drawsafe(subpath(longpath, divider, length), p=p, maxlength=maxlength);
void sort(surface s)
projection P = currentprojection;
//The following code is copied from three_surface.asy
// Sort patches by mean distance from camera
triple camera=P.camera;
if(P.infinity)
triple m=min(s);
triple M=max(s);
camera=P.target+camerafactor*(abs(M-m)+abs(m-P.target))*unit(P.vector());
real[][] depth=new real[s.s.length][];
for(int i=0; i < depth.length; ++i)
depth[i]=new real[] abs(camera-s.s[i].cornermean()),i;
depth=sort(depth);
//end of copied code
int[] permutation = sequence(new int(int i) return (int)depth[i][4];, depth.length);
int[][] inversionTool = new int[permutation.length][5];
for (int i = 0; i < permutation.length; ++i)
inversionTool[i] = new int[] permutation[i], i;
inversionTool = sort(inversionTool);
int inverse(int i) return inversionTool[i][6];;
patch[] sortedS = new patch[depth.length];
for (int i = 0; i < sortedS.length; ++i)
sortedS[i] = s.s[permutation[i]];
s.s = sortedS;
for (int[] currentrow : s.index)
for (int i = 0; i < currentrow.length; ++i)
currentrow[i] = inverse(currentrow[i]);
struct helix
path3 center;
path3 helix;
int numloops;
int pointsperloop = 12;
/* t should range from 0 to 1*/
triple centerpoint(real t)
return point(center, t*length(center));
triple helixpoint(real t)
return point(helix, t*length(helix));
triple helixdirection(real t)
return dir(helix, t*length(helix));
/* the vector from the center point to the point on the helix */
triple displacement(real t)
return helixpoint(t) - centerpoint(t);
bool iscyclic()
return cyclic(helix);
path3 operator cast(helix h)
return h.helix;
helix helixcircle(triple c = O, real r = 1, triple normal = Z)
helix toreturn;
toreturn.center = c;
toreturn.helix = Circle(c=O, r=r, normal=normal, n=toreturn.pointsperloop);
toreturn.numloops = 1;
return toreturn;
helix helixAbout(helix center, int numloops, real radius)
helix toreturn;
toreturn.numloops = numloops;
from toreturn unravel pointsperloop;
toreturn.center = center.helix;
int n = numloops * pointsperloop;
triple[] newhelix;
for (int i = 0; i <= n; ++i)
real theta = (i % pointsperloop) * 2pi / pointsperloop;
real t = i / n;
triple ihat = unit(center.displacement(t));
triple khat = center.helixdirection(t);
triple jhat = cross(khat, ihat);
triple newpoint = center.helixpoint(t) + radius*(cos(theta)*ihat + sin(theta)*jhat);
newhelix.push(newpoint);
toreturn.helix = graph(newhelix, operator ..);
return toreturn;
int loopfactor = 20;
real radiusfactor = 1/8;
helix wrap(helix input, int order, int initialloops = 10, real initialradius = 0.6, int loopfactor=loopfactor)
helix toreturn = input;
int loops = initialloops;
real radius = initialradius;
for (int i = 1; i <= order; ++i)
toreturn = helixAbout(toreturn, loops, radius);
loops *= loopfactor;
radius *= radiusfactor;
return toreturn;
currentprojection = perspective(12,0,6);
helix circle = helixcircle(r=2, c=O, normal=Z);
/* The variable part of the code starts here. */
int order = 1; // This line varies.
real helixradius = 0.5;
real safefactor = 1;
for (int i = 1; i < order; ++i)
safefactor -= radiusfactor^i;
real saferadius = helixradius * safefactor;
helix todraw = wrap(circle, order=order, initialradius = helixradius); // This line varies (optional loopfactor parameter).
surface torus = surface(Circle(c=2X, r=0.99*saferadius, normal=-Y, n=32), c=O, axis=Z, n=32);
sort(torus);
material toruspen = material(diffusepen=gray + opacity(0.5), ambientpen=white);
draw(torus, toruspen);
drawsafe(todraw, p=0.4magenta+linewidth(1pt)); // This line varies (linewidth only).
Recuerda que te concedemos agregar una reseña si te fue útil.