4

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?

enter image description here

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);
  }
}
2
5

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.

enter image description here

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.

1

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.

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.