# Asymptote how to make the circles fading on opaque Torus

I need to draw points on the torus. 3D dot is not helpful since they are spheres. I successfully calculate the norm vectors and draw the circles on the torus, which I will fill later.

As one can see the torus is opaque, and the circles are all drawn normally. Is there a way to make, normally invisible circles, opaque?

One solution in my mind is, make a line to the perspective point from the center of the small circles and calculate the intersection points with the torus. If the distance of the point is the smallest then paint the circle normally, otherwise, paint it opaque.

Is there any better solution?

``````settings.outformat="pdf";

settings.prc=false;
settings.render=0;

import graph3;

size(4cm,0);

pen surfPen=white+opacity(0.2);
pen xarcPen=deepblue+0.7bp;
pen yarcPen=deepred+0.7bp;

currentprojection=perspective(5,5,6);

real R=3;       //Radius of big circle
real a=1;       //Radius of little circle

triple fs(pair t) {
return ((R+a*Cos(t.y))*Cos(t.x),(R+a*Cos(t.y))*Sin(t.x),a*Sin(t.y));
}

triple centerXYNormal(pair t) {

triple P = (((R)*Cos(t.x)),(R)*Sin(t.x),0);
triple T = fs(t);
return (T.x - P.x, T.y - P.y, T.z - P.z);

}

surface s=surface(fs,(0,0),(360,360),8,8,Spline);
draw(s,surfPen,render(compression=Low,merge=true));

int m=3;
int n=16;

pair p,q,v;

for(int i=1;i<=n;++i){
for(int j=0;j<m;++j){
p=(j*360/m,(i%n)*360/n);
path3 mycircle = circle(c=fs(p), r=0.1,normal=centerXYNormal(p));
draw(mycircle, blue);
}
}
``````
• interesting question! a related answer here tex.stackexchange.com/a/109041/140722 Jan 31, 2021 at 17:57
• @BlackMild I see, they all escaped the ray-tracing, as far as I can see. Jan 31, 2021 at 18:20

I think that you have two choices:

1. Find out by yourself which circles are hidden and which are in the foreground, and then draw them accordingly, as you suggest.
2. Choose `settings.render` different from `0`. In this case `asymptote` will spare you from doing the calculations under 1, but it also will produce pixel graphics rather than vector graphics.

In this example I choose option 2 and increase the opacity a bit to make the effect more visible.

``````settings.outformat="pdf";

settings.prc=false;
settings.render=10;

import graph3;

size(4cm,0);

pen surfPen=white+opacity(0.5);
pen xarcPen=deepblue+0.7bp;
pen yarcPen=deepred+0.7bp;

currentprojection=perspective(5,5,6);

real R=3;       //Radius of big circle
real a=1;       //Radius of little circle

triple fs(pair t) {
return ((R+a*Cos(t.y))*Cos(t.x),(R+a*Cos(t.y))*Sin(t.x),a*Sin(t.y));
}

triple centerXYNormal(pair t) {

triple P = (((R)*Cos(t.x)),(R)*Sin(t.x),0);
triple T = fs(t);
return (T.x - P.x, T.y - P.y, T.z - P.z);

}

surface s=surface(fs,(0,0),(360,360),8,8,Spline);
draw(s,surfPen,render(compression=Low,merge=true));

int m=3;
int n=16;

pair p,q,v;

for(int i=1;i<=n;++i){
for(int j=0;j<m;++j){
p=(j*360/m,(i%n)*360/n);
path3 mycircle = circle(c=fs(p), r=0.1,normal=centerXYNormal(p));
draw(mycircle, blue);
}
}
``````

P.S. The circles are not really on the torus but they are small enough that this does not really matter.

Pumuckl's answer is fine if one only wants pixel graphics that I don't. I went to implement it with ray tracing. For each circle, the line passing from the perspective point and the center of the circle is formed. The intersection of the line and the torus is calculated. The equations are taken from cosinekitty (no HTTPS!) and that helped alot, thanks. There were at most 4 unknowns so I've used `quarticroots` from the math. This function decreased the implementation time, thanks to the writer, too.

Then the minimum distance is found, however, I've worked a bug that due to floating-point calculations. I've solved it with testing

`if ( distance3D(min,fs(p)) < 0.005)`

The result is below and currently, ugly full code is at GitHub.